diff --git a/.prettierrc b/.prettierrc index f2a56ee..b6cceea 100644 --- a/.prettierrc +++ b/.prettierrc @@ -2,7 +2,8 @@ "useTabs": true, "tabWidth": 2, "singleQuote": true, - "trailingComma": "none", + "trailingComma": "all", + "bracketSpacing": true, "printWidth": 100, "plugins": ["prettier-plugin-svelte"], "pluginSearchDirs": ["."], diff --git a/drizzle/0009_gray_carlie_cooper.sql b/drizzle/0009_gray_carlie_cooper.sql new file mode 100644 index 0000000..868957f --- /dev/null +++ b/drizzle/0009_gray_carlie_cooper.sql @@ -0,0 +1,2 @@ +ALTER TABLE "users" ALTER COLUMN "two_factor_secret" SET DEFAULT '';--> statement-breakpoint +ALTER TABLE "users" ADD COLUMN "two_factor_enabled" boolean DEFAULT false; \ No newline at end of file diff --git a/drizzle/meta/0009_snapshot.json b/drizzle/meta/0009_snapshot.json new file mode 100644 index 0000000..72d7d38 --- /dev/null +++ b/drizzle/meta/0009_snapshot.json @@ -0,0 +1,1534 @@ +{ + "id": "2cd87f0c-6fe2-4809-903d-e6c443da604a", + "prevId": "0b2ae1c1-86b0-4925-af3e-24d0c095fd7b", + "version": "5", + "dialect": "pg", + "tables": { + "categories": { + "name": "categories", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "categories_cuid_unique": { + "name": "categories_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + }, + "categories_to_external_ids": { + "name": "categories_to_external_ids", + "schema": "", + "columns": { + "category_id": { + "name": "category_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "categories_to_external_ids_category_id_categories_id_fk": { + "name": "categories_to_external_ids_category_id_categories_id_fk", + "tableFrom": "categories_to_external_ids", + "tableTo": "categories", + "columnsFrom": [ + "category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + }, + "categories_to_external_ids_external_id_external_ids_id_fk": { + "name": "categories_to_external_ids_external_id_external_ids_id_fk", + "tableFrom": "categories_to_external_ids", + "tableTo": "external_ids", + "columnsFrom": [ + "external_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": { + "categories_to_external_ids_category_id_external_id_pk": { + "name": "categories_to_external_ids_category_id_external_id_pk", + "columns": [ + "category_id", + "external_id" + ] + } + }, + "uniqueConstraints": {} + }, + "categories_to_games": { + "name": "categories_to_games", + "schema": "", + "columns": { + "category_id": { + "name": "category_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "categories_to_games_category_id_categories_id_fk": { + "name": "categories_to_games_category_id_categories_id_fk", + "tableFrom": "categories_to_games", + "tableTo": "categories", + "columnsFrom": [ + "category_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + }, + "categories_to_games_game_id_games_id_fk": { + "name": "categories_to_games_game_id_games_id_fk", + "tableFrom": "categories_to_games", + "tableTo": "games", + "columnsFrom": [ + "game_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": { + "categories_to_games_category_id_game_id_pk": { + "name": "categories_to_games_category_id_game_id_pk", + "columns": [ + "category_id", + "game_id" + ] + } + }, + "uniqueConstraints": {} + }, + "collection_items": { + "name": "collection_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "collection_id": { + "name": "collection_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "times_played": { + "name": "times_played", + "type": "integer", + "primaryKey": false, + "notNull": false, + "default": 0 + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "collection_items_collection_id_collections_id_fk": { + "name": "collection_items_collection_id_collections_id_fk", + "tableFrom": "collection_items", + "tableTo": "collections", + "columnsFrom": [ + "collection_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "collection_items_game_id_games_id_fk": { + "name": "collection_items_game_id_games_id_fk", + "tableFrom": "collection_items", + "tableTo": "games", + "columnsFrom": [ + "game_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "collection_items_cuid_unique": { + "name": "collection_items_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + }, + "collections": { + "name": "collections", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "collections_user_id_users_id_fk": { + "name": "collections_user_id_users_id_fk", + "tableFrom": "collections", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "collections_cuid_unique": { + "name": "collections_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + }, + "expansions": { + "name": "expansions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "base_game_id": { + "name": "base_game_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "expansions_base_game_id_games_id_fk": { + "name": "expansions_base_game_id_games_id_fk", + "tableFrom": "expansions", + "tableTo": "games", + "columnsFrom": [ + "base_game_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + }, + "expansions_game_id_games_id_fk": { + "name": "expansions_game_id_games_id_fk", + "tableFrom": "expansions", + "tableTo": "games", + "columnsFrom": [ + "game_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "expansions_cuid_unique": { + "name": "expansions_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + }, + "external_ids": { + "name": "external_ids", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "type": { + "name": "type", + "type": "external_id_type", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "external_ids_cuid_unique": { + "name": "external_ids_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + }, + "games": { + "name": "games", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "year_published": { + "name": "year_published", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "min_players": { + "name": "min_players", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "max_players": { + "name": "max_players", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "playtime": { + "name": "playtime", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "min_playtime": { + "name": "min_playtime", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "max_playtime": { + "name": "max_playtime", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "min_age": { + "name": "min_age", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "thumb_url": { + "name": "thumb_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "text_searchable_index": { + "name": "text_searchable_index", + "type": "tsvector", + "primaryKey": false, + "notNull": false + }, + "last_sync_at": { + "name": "last_sync_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": { + "text_searchable_idx": { + "name": "text_searchable_idx", + "columns": [ + "text_searchable_index" + ], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "games_cuid_unique": { + "name": "games_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + }, + "games_to_external_ids": { + "name": "games_to_external_ids", + "schema": "", + "columns": { + "game_id": { + "name": "game_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "games_to_external_ids_game_id_games_id_fk": { + "name": "games_to_external_ids_game_id_games_id_fk", + "tableFrom": "games_to_external_ids", + "tableTo": "games", + "columnsFrom": [ + "game_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + }, + "games_to_external_ids_external_id_external_ids_id_fk": { + "name": "games_to_external_ids_external_id_external_ids_id_fk", + "tableFrom": "games_to_external_ids", + "tableTo": "external_ids", + "columnsFrom": [ + "external_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": { + "games_to_external_ids_game_id_external_id_pk": { + "name": "games_to_external_ids_game_id_external_id_pk", + "columns": [ + "game_id", + "external_id" + ] + } + }, + "uniqueConstraints": {} + }, + "mechanics": { + "name": "mechanics", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "mechanics_cuid_unique": { + "name": "mechanics_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + }, + "mechanics_to_external_ids": { + "name": "mechanics_to_external_ids", + "schema": "", + "columns": { + "mechanic_id": { + "name": "mechanic_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "mechanics_to_external_ids_mechanic_id_mechanics_id_fk": { + "name": "mechanics_to_external_ids_mechanic_id_mechanics_id_fk", + "tableFrom": "mechanics_to_external_ids", + "tableTo": "mechanics", + "columnsFrom": [ + "mechanic_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + }, + "mechanics_to_external_ids_external_id_external_ids_id_fk": { + "name": "mechanics_to_external_ids_external_id_external_ids_id_fk", + "tableFrom": "mechanics_to_external_ids", + "tableTo": "external_ids", + "columnsFrom": [ + "external_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": { + "mechanics_to_external_ids_mechanic_id_external_id_pk": { + "name": "mechanics_to_external_ids_mechanic_id_external_id_pk", + "columns": [ + "mechanic_id", + "external_id" + ] + } + }, + "uniqueConstraints": {} + }, + "mechanics_to_games": { + "name": "mechanics_to_games", + "schema": "", + "columns": { + "mechanic_id": { + "name": "mechanic_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "mechanics_to_games_mechanic_id_mechanics_id_fk": { + "name": "mechanics_to_games_mechanic_id_mechanics_id_fk", + "tableFrom": "mechanics_to_games", + "tableTo": "mechanics", + "columnsFrom": [ + "mechanic_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + }, + "mechanics_to_games_game_id_games_id_fk": { + "name": "mechanics_to_games_game_id_games_id_fk", + "tableFrom": "mechanics_to_games", + "tableTo": "games", + "columnsFrom": [ + "game_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": { + "mechanics_to_games_mechanic_id_game_id_pk": { + "name": "mechanics_to_games_mechanic_id_game_id_pk", + "columns": [ + "mechanic_id", + "game_id" + ] + } + }, + "uniqueConstraints": {} + }, + "password_reset_tokens": { + "name": "password_reset_tokens", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp (6) with time zone", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "password_reset_tokens_user_id_users_id_fk": { + "name": "password_reset_tokens_user_id_users_id_fk", + "tableFrom": "password_reset_tokens", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "publishers": { + "name": "publishers", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "publishers_cuid_unique": { + "name": "publishers_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + }, + "publishers_to_external_ids": { + "name": "publishers_to_external_ids", + "schema": "", + "columns": { + "publisher_id": { + "name": "publisher_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "external_id": { + "name": "external_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "publishers_to_external_ids_publisher_id_publishers_id_fk": { + "name": "publishers_to_external_ids_publisher_id_publishers_id_fk", + "tableFrom": "publishers_to_external_ids", + "tableTo": "publishers", + "columnsFrom": [ + "publisher_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + }, + "publishers_to_external_ids_external_id_external_ids_id_fk": { + "name": "publishers_to_external_ids_external_id_external_ids_id_fk", + "tableFrom": "publishers_to_external_ids", + "tableTo": "external_ids", + "columnsFrom": [ + "external_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": { + "publishers_to_external_ids_publisher_id_external_id_pk": { + "name": "publishers_to_external_ids_publisher_id_external_id_pk", + "columns": [ + "publisher_id", + "external_id" + ] + } + }, + "uniqueConstraints": {} + }, + "publishers_to_games": { + "name": "publishers_to_games", + "schema": "", + "columns": { + "publisher_id": { + "name": "publisher_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "publishers_to_games_publisher_id_publishers_id_fk": { + "name": "publishers_to_games_publisher_id_publishers_id_fk", + "tableFrom": "publishers_to_games", + "tableTo": "publishers", + "columnsFrom": [ + "publisher_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + }, + "publishers_to_games_game_id_games_id_fk": { + "name": "publishers_to_games_game_id_games_id_fk", + "tableFrom": "publishers_to_games", + "tableTo": "games", + "columnsFrom": [ + "game_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "restrict", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": { + "publishers_to_games_publisher_id_game_id_pk": { + "name": "publishers_to_games_publisher_id_game_id_pk", + "columns": [ + "publisher_id", + "game_id" + ] + } + }, + "uniqueConstraints": {} + }, + "roles": { + "name": "roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "roles_cuid_unique": { + "name": "roles_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + }, + "roles_name_unique": { + "name": "roles_name_unique", + "nullsNotDistinct": false, + "columns": [ + "name" + ] + } + } + }, + "sessions": { + "name": "sessions", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "expires_at": { + "name": "expires_at", + "type": "timestamp with time zone", + "primaryKey": false, + "notNull": true + }, + "ip_country": { + "name": "ip_country", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "sessions_user_id_users_id_fk": { + "name": "sessions_user_id_users_id_fk", + "tableFrom": "sessions", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "user_roles": { + "name": "user_roles", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "role_id": { + "name": "role_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "primary": { + "name": "primary", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "user_roles_user_id_users_id_fk": { + "name": "user_roles_user_id_users_id_fk", + "tableFrom": "user_roles", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_roles_role_id_roles_id_fk": { + "name": "user_roles_role_id_roles_id_fk", + "tableFrom": "user_roles", + "tableTo": "roles", + "columnsFrom": [ + "role_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "user_roles_cuid_unique": { + "name": "user_roles_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + }, + "users": { + "name": "users", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "hashed_password": { + "name": "hashed_password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "first_name": { + "name": "first_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "last_name": { + "name": "last_name", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "verified": { + "name": "verified", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "receive_email": { + "name": "receive_email", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "theme": { + "name": "theme", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "'system'" + }, + "two_factor_secret": { + "name": "two_factor_secret", + "type": "text", + "primaryKey": false, + "notNull": false, + "default": "''" + }, + "two_factor_enabled": { + "name": "two_factor_enabled", + "type": "boolean", + "primaryKey": false, + "notNull": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "users_cuid_unique": { + "name": "users_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + }, + "users_username_unique": { + "name": "users_username_unique", + "nullsNotDistinct": false, + "columns": [ + "username" + ] + }, + "users_email_unique": { + "name": "users_email_unique", + "nullsNotDistinct": false, + "columns": [ + "email" + ] + } + } + }, + "wishlist_items": { + "name": "wishlist_items", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "wishlist_id": { + "name": "wishlist_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "game_id": { + "name": "game_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "wishlist_items_wishlist_id_wishlists_id_fk": { + "name": "wishlist_items_wishlist_id_wishlists_id_fk", + "tableFrom": "wishlist_items", + "tableTo": "wishlists", + "columnsFrom": [ + "wishlist_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "wishlist_items_game_id_games_id_fk": { + "name": "wishlist_items_game_id_games_id_fk", + "tableFrom": "wishlist_items", + "tableTo": "games", + "columnsFrom": [ + "game_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "wishlist_items_cuid_unique": { + "name": "wishlist_items_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + }, + "wishlists": { + "name": "wishlists", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "gen_random_uuid()" + }, + "cuid": { + "name": "cuid", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "user_id": { + "name": "user_id", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "wishlists_user_id_users_id_fk": { + "name": "wishlists_user_id_users_id_fk", + "tableFrom": "wishlists", + "tableTo": "users", + "columnsFrom": [ + "user_id" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": { + "wishlists_cuid_unique": { + "name": "wishlists_cuid_unique", + "nullsNotDistinct": false, + "columns": [ + "cuid" + ] + } + } + } + }, + "enums": { + "external_id_type": { + "name": "external_id_type", + "values": { + "game": "game", + "category": "category", + "mechanic": "mechanic", + "publisher": "publisher", + "designer": "designer", + "artist": "artist" + } + } + }, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index be102db..d2c0b7c 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -64,6 +64,13 @@ "when": 1711757183163, "tag": "0008_amusing_franklin_richards", "breakpoints": true + }, + { + "idx": 9, + "version": "5", + "when": 1711868447607, + "tag": "0009_gray_carlie_cooper", + "breakpoints": true } ] } \ No newline at end of file diff --git a/package.json b/package.json index 04efc7e..bcb9297 100644 --- a/package.json +++ b/package.json @@ -24,13 +24,13 @@ "@melt-ui/pp": "^0.3.0", "@melt-ui/svelte": "^0.76.2", "@playwright/test": "^1.42.1", - "@resvg/resvg-js": "^2.6.1", - "@sveltejs/adapter-auto": "^3.1.1", + "@resvg/resvg-js": "^2.6.2", + "@sveltejs/adapter-auto": "^3.2.0", "@sveltejs/enhanced-img": "^0.1.9", - "@sveltejs/kit": "^2.5.4", + "@sveltejs/kit": "^2.5.5", "@sveltejs/vite-plugin-svelte": "^3.0.2", "@types/cookie": "^0.6.0", - "@types/node": "^20.11.30", + "@types/node": "^20.12.2", "@types/pg": "^8.11.4", "@typescript-eslint/eslint-plugin": "^6.21.0", "@typescript-eslint/parser": "^6.21.0", @@ -59,13 +59,13 @@ "svelte-sequential-preprocessor": "^2.0.1", "sveltekit-flash-message": "^2.4.4", "sveltekit-rate-limiter": "^0.4.3", - "sveltekit-superforms": "^2.11.0", - "tailwindcss": "^3.4.1", + "sveltekit-superforms": "^2.12.2", + "tailwindcss": "^3.4.3", "ts-node": "^10.9.2", "tslib": "^2.6.1", "tsx": "^4.7.1", "typescript": "^5.4.3", - "vite": "^5.2.6", + "vite": "^5.2.7", "vitest": "^1.4.0", "zod": "^3.22.4" }, @@ -92,7 +92,7 @@ "class-variance-authority": "^0.7.0", "clsx": "^2.1.0", "cookie": "^0.6.0", - "drizzle-orm": "^0.30.4", + "drizzle-orm": "^0.30.6", "feather-icons": "^4.29.1", "formsnap": "^0.5.1", "html-entities": "^2.5.2", @@ -103,8 +103,8 @@ "lucia": "3.1.1", "lucide-svelte": "^0.358.0", "open-props": "^1.6.21", - "oslo": "^1.1.3", - "pg": "^8.11.3", + "oslo": "^1.2.0", + "pg": "^8.11.4", "postgres": "^3.4.4", "qrcode": "^1.5.3", "radix-svelte": "^0.9.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4f65723..53af9f1 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -31,10 +31,10 @@ dependencies: version: 1.16.0 '@sentry/sveltekit': specifier: ^7.100.1 - version: 7.100.1(@sveltejs/kit@2.5.4)(svelte@4.2.12) + version: 7.100.1(@sveltejs/kit@2.5.5)(svelte@4.2.12) '@sveltejs/adapter-vercel': specifier: ^5.2.0 - version: 5.2.0(@sveltejs/kit@2.5.4) + version: 5.2.0(@sveltejs/kit@2.5.5) '@types/feather-icons': specifier: ^4.29.4 version: 4.29.4 @@ -57,14 +57,14 @@ dependencies: specifier: ^0.6.0 version: 0.6.0 drizzle-orm: - specifier: ^0.30.4 - version: 0.30.4(@neondatabase/serverless@0.9.0)(@planetscale/database@1.16.0)(@types/pg@8.11.4)(pg@8.11.3)(postgres@3.4.4) + specifier: ^0.30.6 + version: 0.30.6(@neondatabase/serverless@0.9.0)(@planetscale/database@1.16.0)(@types/pg@8.11.4)(pg@8.11.4)(postgres@3.4.4) feather-icons: specifier: ^4.29.1 version: 4.29.1 formsnap: specifier: ^0.5.1 - version: 0.5.1(svelte@4.2.12)(sveltekit-superforms@2.11.0) + version: 0.5.1(svelte@4.2.12)(sveltekit-superforms@2.12.2) html-entities: specifier: ^2.5.2 version: 2.5.2 @@ -90,11 +90,11 @@ dependencies: specifier: ^1.6.21 version: 1.6.21 oslo: - specifier: ^1.1.3 - version: 1.1.3 + specifier: ^1.2.0 + version: 1.2.0 pg: - specifier: ^8.11.3 - version: 8.11.3 + specifier: ^8.11.4 + version: 8.11.4 postgres: specifier: ^3.4.4 version: 3.4.4 @@ -115,10 +115,10 @@ dependencies: version: 2.2.2 tailwind-variants: specifier: ^0.2.1 - version: 0.2.1(tailwindcss@3.4.1) + version: 0.2.1(tailwindcss@3.4.3) tailwindcss-animate: specifier: ^1.0.6 - version: 1.0.7(tailwindcss@3.4.1) + version: 1.0.7(tailwindcss@3.4.3) zod-to-json-schema: specifier: ^3.22.5 version: 3.22.5(zod@3.22.4) @@ -134,26 +134,26 @@ devDependencies: specifier: ^1.42.1 version: 1.42.1 '@resvg/resvg-js': - specifier: ^2.6.1 - version: 2.6.1 + specifier: ^2.6.2 + version: 2.6.2 '@sveltejs/adapter-auto': - specifier: ^3.1.1 - version: 3.1.1(@sveltejs/kit@2.5.4) + specifier: ^3.2.0 + version: 3.2.0(@sveltejs/kit@2.5.5) '@sveltejs/enhanced-img': specifier: ^0.1.9 version: 0.1.9(svelte@4.2.12) '@sveltejs/kit': - specifier: ^2.5.4 - version: 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6) + specifier: ^2.5.5 + version: 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7) '@sveltejs/vite-plugin-svelte': specifier: ^3.0.2 - version: 3.0.2(svelte@4.2.12)(vite@5.2.6) + version: 3.0.2(svelte@4.2.12)(vite@5.2.7) '@types/cookie': specifier: ^0.6.0 version: 0.6.0 '@types/node': - specifier: ^20.11.30 - version: 20.11.30 + specifier: ^20.12.2 + version: 20.12.2 '@types/pg': specifier: ^8.11.4 version: 8.11.4 @@ -234,19 +234,19 @@ devDependencies: version: 2.0.1 sveltekit-flash-message: specifier: ^2.4.4 - version: 2.4.4(@sveltejs/kit@2.5.4)(svelte@4.2.12) + version: 2.4.4(@sveltejs/kit@2.5.5)(svelte@4.2.12) sveltekit-rate-limiter: specifier: ^0.4.3 - version: 0.4.3(@sveltejs/kit@2.5.4) + version: 0.4.3(@sveltejs/kit@2.5.5) sveltekit-superforms: - specifier: ^2.11.0 - version: 2.11.0(@sveltejs/kit@2.5.4)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12) + specifier: ^2.12.2 + version: 2.12.2(@sveltejs/kit@2.5.5)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12) tailwindcss: - specifier: ^3.4.1 - version: 3.4.1(ts-node@10.9.2) + specifier: ^3.4.3 + version: 3.4.3(ts-node@10.9.2) ts-node: specifier: ^10.9.2 - version: 10.9.2(@types/node@20.11.30)(typescript@5.4.3) + version: 10.9.2(@types/node@20.12.2)(typescript@5.4.3) tslib: specifier: ^2.6.1 version: 2.6.2 @@ -257,11 +257,11 @@ devDependencies: specifier: ^5.4.3 version: 5.4.3 vite: - specifier: ^5.2.6 - version: 5.2.6(@types/node@20.11.30)(sass@1.72.0) + specifier: ^5.2.7 + version: 5.2.7(@types/node@20.12.2)(sass@1.72.0) vitest: specifier: ^1.4.0 - version: 1.4.0(@types/node@20.11.30)(sass@1.72.0) + version: 1.4.0(@types/node@20.12.2)(sass@1.72.0) zod: specifier: ^3.22.4 version: 3.22.4 @@ -763,8 +763,8 @@ packages: dev: false optional: true - /@emnapi/core@1.1.0: - resolution: {integrity: sha512-gNEVZo0HhUfVjhr6rFG//HZXbauclxueiDxaKGBZHcK5h8i9pslABNPfG8kMwYTubAn3mV7AyOZN8gfPRgbU8A==} + /@emnapi/core@1.1.1: + resolution: {integrity: sha512-eu4KjHfXg3I+UUR7vSuwZXpRo4c8h4Rtb5Lu2F7Z4JqJFl/eidquONEBiRs6viXKpWBC3BaJBy68xGJ2j56idw==} requiresBuild: true dependencies: tslib: 2.6.2 @@ -778,8 +778,8 @@ packages: tslib: 2.6.2 optional: true - /@emnapi/runtime@1.1.0: - resolution: {integrity: sha512-gCGlE0fJGWalfy+wbFApjhKn6uoSVvopru77IPyxNKkjkaiSx2HxDS7eOYSmo9dcMIhmmIvoxiC3N9TM1c3EaA==} + /@emnapi/runtime@1.1.1: + resolution: {integrity: sha512-3bfqkzuR1KLx57nZfjr2NLnFOobvyS0aTszaEGCGqmYMVDRaGvgIZbjGSV/MHSSmLgQ/b9JFHQ5xm5WRZYd+XQ==} requiresBuild: true dependencies: tslib: 2.6.2 @@ -1674,8 +1674,8 @@ packages: resolution: {integrity: sha512-1uFRjqCcxVv4F31PjyLm8o4oNlT5ywwh6OwcDGkZbafOeFZHXekvholS9IlfZkRsZvVhSbFRHT/5iDib4KTtpg==} dev: false - /@gcornut/valibot-json-schema@0.0.26(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(valibot@0.30.0): - resolution: {integrity: sha512-8eZpGLP1awX9UGEK+VUFiyXnjiIV/h5RPC7wt2KQG6O7YkXEw7t2pUxHhR5ULcoN0BsZ3FOWZqyzu3tFF7aXxw==} + /@gcornut/valibot-json-schema@0.0.27(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(valibot@0.30.0): + resolution: {integrity: sha512-xcMaUStVgQzPrK3d7PuLFbQ+3qSp6LzaLExAm52E3FKmUfjQa7Sw5cDK6Hfu/8WT0yfGsuSCuJ5uT1sosjR9Qg==} hasBin: true requiresBuild: true peerDependencies: @@ -2082,8 +2082,8 @@ packages: resolution: {integrity: sha512-8JuczewTFIZ/XIjHQ+YlQUydHvlKx2hkcxtuGwh+t/t5zWyZct6YG4+xjHcq8xyc/e7FmFwf42Zj2YgICwmlvA==} requiresBuild: true dependencies: - '@emnapi/core': 1.1.0 - '@emnapi/runtime': 1.1.0 + '@emnapi/core': 1.1.1 + '@emnapi/runtime': 1.1.1 '@tybys/wasm-util': 0.8.1 dev: false optional: true @@ -2739,8 +2739,8 @@ packages: requiresBuild: true optional: true - /@resvg/resvg-js-android-arm-eabi@2.6.1: - resolution: {integrity: sha512-oXmXUUqTzinvXwkVBDdNKocAeF1zLGJYasTNRmoqF3gyOm04qRYT1On0m6oK2jbTiUAOUTqi0ZSizcecnwcSDA==} + /@resvg/resvg-js-android-arm-eabi@2.6.2: + resolution: {integrity: sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==} engines: {node: '>= 10'} cpu: [arm] os: [android] @@ -2748,8 +2748,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-android-arm64@2.6.1: - resolution: {integrity: sha512-vcCZoBx8s/3/+t6nDd9fB/LL70I4B2YmgDT7uP6wyqVCUPniNeLR9VYIuvpMHw6oVyL5Mpt8F2YXV1zQE2X2hw==} + /@resvg/resvg-js-android-arm64@2.6.2: + resolution: {integrity: sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] @@ -2757,8 +2757,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-darwin-arm64@2.6.1: - resolution: {integrity: sha512-uO0WvEQqQlAL8u7nI7k1yL5wSsZYU2YCSsN1hAhr1LjyvmWmyC09xUEdWPUVVT1nL2YK4Ueh0LR+pxOT3QlCng==} + /@resvg/resvg-js-darwin-arm64@2.6.2: + resolution: {integrity: sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] @@ -2766,8 +2766,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-darwin-x64@2.6.1: - resolution: {integrity: sha512-aW15HMQSk85GPHE4gsc56G0Fqi2IGVkDfPWEWHEyDBpCZ17RKweAwg5V3ioz9aGX1nmhjQa9tJ2xgVwX+sqIjw==} + /@resvg/resvg-js-darwin-x64@2.6.2: + resolution: {integrity: sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] @@ -2775,8 +2775,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-linux-arm-gnueabihf@2.6.1: - resolution: {integrity: sha512-7vpBFzCMONnRzK0uCBT5h+Dmsa8dWsoLFqB6xgutNfKkldjuCOiLNe0tT7hneGF8tw5H+W6hX/VLx2ktDwsS4Q==} + /@resvg/resvg-js-linux-arm-gnueabihf@2.6.2: + resolution: {integrity: sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==} engines: {node: '>= 10'} cpu: [arm] os: [linux] @@ -2784,8 +2784,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-linux-arm64-gnu@2.6.1: - resolution: {integrity: sha512-+Gi3OIOJFFiCdm72AsDa7KPnkogitLQ6yfF1O/J25adUrlWjvKAM9+8b5sTI9waeLERZHNJpIVESpdIxI2/5sQ==} + /@resvg/resvg-js-linux-arm64-gnu@2.6.2: + resolution: {integrity: sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -2793,8 +2793,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-linux-arm64-musl@2.6.1: - resolution: {integrity: sha512-lnRGWG/LwpX6UsV1neHAavPnek3WlCnGMdBZ/7JbpamK5VmtDZmsV2esOFpME6pKnWL40UX4WjPsCBtKkhMUMA==} + /@resvg/resvg-js-linux-arm64-musl@2.6.2: + resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] @@ -2802,8 +2802,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-linux-x64-gnu@2.6.1: - resolution: {integrity: sha512-2S1N7fHl5480AUrUtxsfjFOh3t8NQ2qKavROZRDKWJqFXBrNOUsirDa33LtpFGDkFW18SjP/FCs1xfHLzzz43g==} + /@resvg/resvg-js-linux-x64-gnu@2.6.2: + resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -2811,8 +2811,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-linux-x64-musl@2.6.1: - resolution: {integrity: sha512-G5GMmpvFiyclkp44eVPVWnN2lhLx9eMIcxGnBFWjnpI3TxrjBt7aVic2N8CsZ0vt2rrnJkQI0IKjUQQIi138Hw==} + /@resvg/resvg-js-linux-x64-musl@2.6.2: + resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] @@ -2820,8 +2820,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-win32-arm64-msvc@2.6.1: - resolution: {integrity: sha512-m9TBMrGs2tML0oz14D/x40tPedqCgNFy/DH7/z/bvnP9bH59fivaInmHTjd8oSFfGRZ/DasXMFcAL+LS1+hfSQ==} + /@resvg/resvg-js-win32-arm64-msvc@2.6.2: + resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] @@ -2829,8 +2829,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-win32-ia32-msvc@2.6.1: - resolution: {integrity: sha512-Ma+MJXesViT0A7JqTobsB9DOCO0AkfmLxsgkvxq0IiWkpU9Z4Gp+RkDsFQbMhJwVXaz7b8L6y+EIvf95iCbJQw==} + /@resvg/resvg-js-win32-ia32-msvc@2.6.2: + resolution: {integrity: sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==} engines: {node: '>= 10'} cpu: [ia32] os: [win32] @@ -2838,8 +2838,8 @@ packages: dev: true optional: true - /@resvg/resvg-js-win32-x64-msvc@2.6.1: - resolution: {integrity: sha512-mWIlgEuFWBrlldCbhLPvG4tt0r0D1RZ8eR2+zxTtQ15d/lbVjwnGpw2l1noV3zhV5S6mAVzoZeQ1emoov63Y/A==} + /@resvg/resvg-js-win32-x64-msvc@2.6.2: + resolution: {integrity: sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==} engines: {node: '>= 10'} cpu: [x64] os: [win32] @@ -2847,22 +2847,22 @@ packages: dev: true optional: true - /@resvg/resvg-js@2.6.1: - resolution: {integrity: sha512-CVGUWPvgr3b96+PooncXCsvu93CMwfEoueqIxIJr9AuUA8OaIPcZjOgFhas62fcHRdWMmxQqF1Rp+89bQsj/RA==} + /@resvg/resvg-js@2.6.2: + resolution: {integrity: sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==} engines: {node: '>= 10'} optionalDependencies: - '@resvg/resvg-js-android-arm-eabi': 2.6.1 - '@resvg/resvg-js-android-arm64': 2.6.1 - '@resvg/resvg-js-darwin-arm64': 2.6.1 - '@resvg/resvg-js-darwin-x64': 2.6.1 - '@resvg/resvg-js-linux-arm-gnueabihf': 2.6.1 - '@resvg/resvg-js-linux-arm64-gnu': 2.6.1 - '@resvg/resvg-js-linux-arm64-musl': 2.6.1 - '@resvg/resvg-js-linux-x64-gnu': 2.6.1 - '@resvg/resvg-js-linux-x64-musl': 2.6.1 - '@resvg/resvg-js-win32-arm64-msvc': 2.6.1 - '@resvg/resvg-js-win32-ia32-msvc': 2.6.1 - '@resvg/resvg-js-win32-x64-msvc': 2.6.1 + '@resvg/resvg-js-android-arm-eabi': 2.6.2 + '@resvg/resvg-js-android-arm64': 2.6.2 + '@resvg/resvg-js-darwin-arm64': 2.6.2 + '@resvg/resvg-js-darwin-x64': 2.6.2 + '@resvg/resvg-js-linux-arm-gnueabihf': 2.6.2 + '@resvg/resvg-js-linux-arm64-gnu': 2.6.2 + '@resvg/resvg-js-linux-arm64-musl': 2.6.2 + '@resvg/resvg-js-linux-x64-gnu': 2.6.2 + '@resvg/resvg-js-linux-x64-musl': 2.6.2 + '@resvg/resvg-js-win32-arm64-msvc': 2.6.2 + '@resvg/resvg-js-win32-ia32-msvc': 2.6.2 + '@resvg/resvg-js-win32-x64-msvc': 2.6.2 dev: true /@resvg/resvg-wasm@2.6.0: @@ -3126,7 +3126,7 @@ packages: svelte: 4.2.12 dev: false - /@sentry/sveltekit@7.100.1(@sveltejs/kit@2.5.4)(svelte@4.2.12): + /@sentry/sveltekit@7.100.1(@sveltejs/kit@2.5.5)(svelte@4.2.12): resolution: {integrity: sha512-t6JaivTmw5oIqOpKQ8PNbGjNP99AQY6vMPkhxzVuwPa3A3o2WtmzQoIXNxdrkux5XkoBI9CsT6TsM5TbaMDwjQ==} engines: {node: '>=16'} peerDependencies: @@ -3140,7 +3140,7 @@ packages: '@sentry/types': 7.100.1 '@sentry/utils': 7.100.1 '@sentry/vite-plugin': 0.6.1 - '@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6) + '@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7) magicast: 0.2.8 sorcery: 0.11.0 transitivePeerDependencies: @@ -3229,21 +3229,21 @@ packages: requiresBuild: true optional: true - /@sveltejs/adapter-auto@3.1.1(@sveltejs/kit@2.5.4): - resolution: {integrity: sha512-6LeZft2Fo/4HfmLBi5CucMYmgRxgcETweQl/yQoZo/895K3S9YWYN4Sfm/IhwlIpbJp3QNvhKmwCHbsqQNYQpw==} + /@sveltejs/adapter-auto@3.2.0(@sveltejs/kit@2.5.5): + resolution: {integrity: sha512-She5nKT47kwHE18v9NMe6pbJcvULr82u0V3yZ0ej3n1laWKGgkgdEABE9/ak5iDPs93LqsBkuIo51kkwCLBjJA==} peerDependencies: '@sveltejs/kit': ^2.0.0 dependencies: - '@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6) + '@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7) import-meta-resolve: 4.0.0 dev: true - /@sveltejs/adapter-vercel@5.2.0(@sveltejs/kit@2.5.4): + /@sveltejs/adapter-vercel@5.2.0(@sveltejs/kit@2.5.5): resolution: {integrity: sha512-872y13DxKcOBxgnXc4C2YHRw1ow9N1CpUxMH34NYFqCn6PUO6f34qle8v/Byr8sHEC/d+PZIAI3MJs3c8f7TfA==} peerDependencies: '@sveltejs/kit': ^2.4.0 dependencies: - '@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6) + '@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7) '@vercel/nft': 0.26.4 esbuild: 0.19.12 transitivePeerDependencies: @@ -3262,8 +3262,8 @@ packages: - svelte dev: true - /@sveltejs/kit@2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6): - resolution: {integrity: sha512-eDxK2d4EGzk99QsZNoPXe7jlzA5EGqfcCpUwZ912bhnalsZ2ZsG5wGRthkydupVjYyqdmzEanVKFhLxU2vkPSQ==} + /@sveltejs/kit@2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7): + resolution: {integrity: sha512-ULe3PB00q4+wYRL+IS5FDPsCEVnhEITofm7b9Yz8malcH3r1SAnW/JJ6T13hIMeu8QNRIuVQWo+P4+2VklbnLQ==} engines: {node: '>=18.13'} hasBin: true requiresBuild: true @@ -3272,7 +3272,7 @@ packages: svelte: ^4.0.0 || ^5.0.0-next.0 vite: ^5.0.3 dependencies: - '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.12)(vite@5.2.6) + '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.12)(vite@5.2.7) '@types/cookie': 0.6.0 cookie: 0.6.0 devalue: 4.3.2 @@ -3286,9 +3286,9 @@ packages: sirv: 2.0.4 svelte: 4.2.12 tiny-glob: 0.2.9 - vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0) + vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0) - /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6): + /@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7): resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==} engines: {node: ^18.0.0 || >=20} peerDependencies: @@ -3296,29 +3296,29 @@ packages: svelte: ^4.0.0 || ^5.0.0-next.0 vite: ^5.0.0 dependencies: - '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.12)(vite@5.2.6) + '@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.12)(vite@5.2.7) debug: 4.3.4 svelte: 4.2.12 - vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0) + vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0) transitivePeerDependencies: - supports-color - /@sveltejs/vite-plugin-svelte@3.0.2(svelte@4.2.12)(vite@5.2.6): + /@sveltejs/vite-plugin-svelte@3.0.2(svelte@4.2.12)(vite@5.2.7): resolution: {integrity: sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==} engines: {node: ^18.0.0 || >=20} peerDependencies: svelte: ^4.0.0 || ^5.0.0-next.0 vite: ^5.0.0 dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6) + '@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7) debug: 4.3.4 deepmerge: 4.3.1 kleur: 4.1.5 magic-string: 0.30.5 svelte: 4.2.12 svelte-hmr: 0.15.3(svelte@4.2.12) - vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0) - vitefu: 0.2.5(vite@5.2.6) + vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0) + vitefu: 0.2.5(vite@5.2.7) transitivePeerDependencies: - supports-color @@ -3360,22 +3360,22 @@ packages: /@types/json-schema@7.0.15: resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - /@types/node@20.11.30: - resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==} + /@types/node@20.12.2: + resolution: {integrity: sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==} dependencies: undici-types: 5.26.5 /@types/pg@8.11.4: resolution: {integrity: sha512-yw3Bwbda6vO+NvI1Ue/YKOwtl31AYvvd/e73O3V4ZkNzuGpTDndLSyc0dQRB2xrQqDePd20pEGIfqSp/GH3pRw==} dependencies: - '@types/node': 20.11.30 + '@types/node': 20.12.2 pg-protocol: 1.6.0 pg-types: 4.0.2 /@types/pg@8.6.6: resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==} dependencies: - '@types/node': 20.11.30 + '@types/node': 20.12.2 pg-protocol: 1.6.0 pg-types: 2.2.0 dev: false @@ -3863,11 +3863,6 @@ packages: /buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - /buffer-writer@2.0.0: - resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==} - engines: {node: '>=4'} - dev: false - /cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} @@ -4317,11 +4312,12 @@ packages: - supports-color dev: true - /drizzle-orm@0.30.4(@neondatabase/serverless@0.9.0)(@planetscale/database@1.16.0)(@types/pg@8.11.4)(pg@8.11.3)(postgres@3.4.4): - resolution: {integrity: sha512-kWoSMGbrOFkmkAweLTFtHJMpN+nwhx89q0mLELqT2aEU+1szNV8jrnBmJwZ0WGNp7J7yQn/ezEtxBI/qzTSElQ==} + /drizzle-orm@0.30.6(@neondatabase/serverless@0.9.0)(@planetscale/database@1.16.0)(@types/pg@8.11.4)(pg@8.11.4)(postgres@3.4.4): + resolution: {integrity: sha512-8RgNUmY7J03GRuRgBV5SaJNbYgLVPjdSWNS/bRkIMIHt2TFCA439lJsNpqYX8asyKMqkw8ceBiamUnCIXZIt9w==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' '@cloudflare/workers-types': '>=3' + '@electric-sql/pglite': '>=0.1.1' '@libsql/client': '*' '@neondatabase/serverless': '>=0.1' '@op-engineering/op-sqlite': '>=2' @@ -4349,6 +4345,8 @@ packages: optional: true '@cloudflare/workers-types': optional: true + '@electric-sql/pglite': + optional: true '@libsql/client': optional: true '@neondatabase/serverless': @@ -4397,7 +4395,7 @@ packages: '@neondatabase/serverless': 0.9.0 '@planetscale/database': 1.16.0 '@types/pg': 8.11.4 - pg: 8.11.3 + pg: 8.11.4 postgres: 3.4.4 dev: false @@ -4900,7 +4898,7 @@ packages: is-callable: 1.2.7 dev: false - /formsnap@0.5.1(svelte@4.2.12)(sveltekit-superforms@2.11.0): + /formsnap@0.5.1(svelte@4.2.12)(sveltekit-superforms@2.12.2): resolution: {integrity: sha512-8ppOlOu7llBEJbV0PzUz/KWh1J8KfiGqwjiyb8emQ2m+/nYXohLBtMcLVpW3XwlMkUbYaIXM+5lhfGjw8xbGJw==} peerDependencies: svelte: ^4.0.0 @@ -4908,7 +4906,7 @@ packages: dependencies: nanoid: 5.0.6 svelte: 4.2.12 - sveltekit-superforms: 2.11.0(@sveltejs/kit@2.5.4)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12) + sveltekit-superforms: 2.12.2(@sveltejs/kit@2.5.5)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12) dev: false /fraction.js@4.3.7: @@ -5876,8 +5874,8 @@ packages: '@node-rs/bcrypt': 1.9.2 dev: false - /oslo@1.1.3: - resolution: {integrity: sha512-hCz528UlNTiegplcyBg6AvG0HLNrnq06EJMp88Ze308GX1hszkb8u3puhNC4aqLMbYQ0hXpl+wQGnwxMtt5+5w==} + /oslo@1.2.0: + resolution: {integrity: sha512-OoFX6rDsNcOQVAD2gQD/z03u4vEjWZLzJtwkmgfRF+KpQUXwdgEXErD7zNhyowmHwHefP+PM9Pw13pgpHMRlzw==} dependencies: '@node-rs/argon2': 1.7.0 '@node-rs/bcrypt': 1.9.0 @@ -5921,10 +5919,6 @@ packages: engines: {node: '>=6'} dev: false - /packet-reader@1.0.0: - resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==} - dev: false - /pako@0.2.9: resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} @@ -5996,8 +5990,8 @@ packages: dev: false optional: true - /pg-connection-string@2.6.2: - resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==} + /pg-connection-string@2.6.3: + resolution: {integrity: sha512-77FxhhKJQH+xJx6tDqkhhMa0nZvv3U1HYLDQgwZxZafVD583++O5LXn5oo5HaQZ0vXwYcZA1koYAJM3JvD6Gtw==} dev: false /pg-int8@1.0.1: @@ -6008,17 +6002,21 @@ packages: resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==} engines: {node: '>=4'} - /pg-pool@3.6.1(pg@8.11.3): - resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==} + /pg-pool@3.6.2(pg@8.11.4): + resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==} peerDependencies: pg: '>=8.0' dependencies: - pg: 8.11.3 + pg: 8.11.4 dev: false /pg-protocol@1.6.0: resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==} + /pg-protocol@1.6.1: + resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==} + dev: false + /pg-types@2.2.0: resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} engines: {node: '>=4'} @@ -6042,8 +6040,8 @@ packages: postgres-interval: 3.0.0 postgres-range: 1.1.4 - /pg@8.11.3: - resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==} + /pg@8.11.4: + resolution: {integrity: sha512-pWb7JKPxGk1UFbtq7jQ0m3IfPpb7LLACCEyN8/u9DYEom+Q/BSKy+4TRl4+Hh003AOYhppB/z+QK87/hx/bk0w==} engines: {node: '>= 8.0.0'} peerDependencies: pg-native: '>=3.0.1' @@ -6051,11 +6049,9 @@ packages: pg-native: optional: true dependencies: - buffer-writer: 2.0.0 - packet-reader: 1.0.0 - pg-connection-string: 2.6.2 - pg-pool: 3.6.1(pg@8.11.3) - pg-protocol: 1.6.0 + pg-connection-string: 2.6.3 + pg-pool: 3.6.2(pg@8.11.4) + pg-protocol: 1.6.1 pg-types: 2.2.0 pgpass: 1.0.5 optionalDependencies: @@ -6338,7 +6334,7 @@ packages: dependencies: lilconfig: 2.1.0 postcss: 8.4.38 - ts-node: 10.9.2(@types/node@20.11.30)(typescript@5.4.3) + ts-node: 10.9.2(@types/node@20.12.2)(typescript@5.4.3) yaml: 1.10.2 dev: true @@ -6356,7 +6352,7 @@ packages: dependencies: lilconfig: 3.0.0 postcss: 8.4.38 - ts-node: 10.9.2(@types/node@20.11.30)(typescript@5.4.3) + ts-node: 10.9.2(@types/node@20.12.2)(typescript@5.4.3) yaml: 2.3.4 /postcss-load-config@5.0.3(postcss@8.4.38): @@ -7345,56 +7341,39 @@ packages: magic-string: 0.30.7 periscopic: 3.1.0 - /sveltekit-flash-message@2.4.4(@sveltejs/kit@2.5.4)(svelte@4.2.12): + /sveltekit-flash-message@2.4.4(@sveltejs/kit@2.5.5)(svelte@4.2.12): resolution: {integrity: sha512-CFN03chH/FMEJcBZ/8zKm7RqGee/pwb57Spbbx8QCQPhe7N9ofZHd9iYV2vVy4E9glBo/oQ1IG7VQje6L092wg==} peerDependencies: '@sveltejs/kit': 1.x || 2.x svelte: 3.x || 4.x || >=5.0.0-next.51 dependencies: - '@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6) + '@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7) svelte: 4.2.12 dev: true - /sveltekit-rate-limiter@0.4.3(@sveltejs/kit@2.5.4): + /sveltekit-rate-limiter@0.4.3(@sveltejs/kit@2.5.5): resolution: {integrity: sha512-BKkD2tvgyz5j4Fn1vt0y7FLF0zZ01f9thjWPGDb6fyX3tBXyMrtZ8ISK8M7zjz9Cik/2KrkvFtmldhXF6/hjqw==} peerDependencies: '@sveltejs/kit': 1.x || 2.x dependencies: '@isaacs/ttlcache': 1.4.1 - '@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6) + '@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7) dev: true - /sveltekit-superforms@2.11.0(@sveltejs/kit@2.5.4)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12): - resolution: {integrity: sha512-wRAznfYi9sOp4aQd2kb/SIafqHX4LROn5ojIXEbp2Pss9EPy69tmArQFm3JaiBC0hU72bAlUOTFSmVABTF9TEA==} + /sveltekit-superforms@2.12.2(@sveltejs/kit@2.5.5)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12): + resolution: {integrity: sha512-fFOXaluP1os/Tamx7gzwhT3tXPAfqZ8KYRC0UfXdXeUtlUIUfiGrIifDJ26/9uePmF8Zhqy2M0XjG8W9kQnJpg==} peerDependencies: '@sveltejs/kit': 1.x || 2.x svelte: 3.x || 4.x || >=5.0.0-next.51 - peerDependenciesMeta: - '@sinclair/typebox': - optional: true - '@vinejs/vine': - optional: true - arktype: - optional: true - joi: - optional: true - superstruct: - optional: true - valibot: - optional: true - yup: - optional: true - zod: - optional: true dependencies: - '@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6) + '@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7) devalue: 4.3.2 just-clone: 6.2.0 memoize-weak: 1.0.2 svelte: 4.2.12 ts-deepmerge: 7.0.0 optionalDependencies: - '@gcornut/valibot-json-schema': 0.0.26(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(valibot@0.30.0) + '@gcornut/valibot-json-schema': 0.0.27(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(valibot@0.30.0) '@sinclair/typebox': 0.32.20 '@sodaru/yup-to-json-schema': 2.0.1 '@vinejs/vine': 1.8.0 @@ -7419,26 +7398,26 @@ packages: '@babel/runtime': 7.24.1 dev: false - /tailwind-variants@0.2.1(tailwindcss@3.4.1): + /tailwind-variants@0.2.1(tailwindcss@3.4.3): resolution: {integrity: sha512-2xmhAf4UIc3PijOUcJPA1LP4AbxhpcHuHM2C26xM0k81r0maAO6uoUSHl3APmvHZcY5cZCY/bYuJdfFa4eGoaw==} engines: {node: '>=16.x', pnpm: '>=7.x'} peerDependencies: tailwindcss: '*' dependencies: tailwind-merge: 2.2.2 - tailwindcss: 3.4.1(ts-node@10.9.2) + tailwindcss: 3.4.3(ts-node@10.9.2) dev: false - /tailwindcss-animate@1.0.7(tailwindcss@3.4.1): + /tailwindcss-animate@1.0.7(tailwindcss@3.4.3): resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==} peerDependencies: tailwindcss: '>=3.0.0 || insiders' dependencies: - tailwindcss: 3.4.1(ts-node@10.9.2) + tailwindcss: 3.4.3(ts-node@10.9.2) dev: false - /tailwindcss@3.4.1(ts-node@10.9.2): - resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==} + /tailwindcss@3.4.3(ts-node@10.9.2): + resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==} engines: {node: '>=14.0.0'} hasBin: true dependencies: @@ -7578,7 +7557,7 @@ packages: /ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} - /ts-node@10.9.2(@types/node@20.11.30)(typescript@5.4.3): + /ts-node@10.9.2(@types/node@20.12.2)(typescript@5.4.3): resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==} hasBin: true peerDependencies: @@ -7597,7 +7576,7 @@ packages: '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.11.30 + '@types/node': 20.12.2 acorn: 8.11.2 acorn-walk: 8.3.0 arg: 4.1.3 @@ -7746,7 +7725,7 @@ packages: - rollup dev: true - /vite-node@1.4.0(@types/node@20.11.30)(sass@1.72.0): + /vite-node@1.4.0(@types/node@20.12.2)(sass@1.72.0): resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -7755,7 +7734,7 @@ packages: debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0) + vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0) transitivePeerDependencies: - '@types/node' - less @@ -7767,8 +7746,8 @@ packages: - terser dev: true - /vite@5.2.6(@types/node@20.11.30)(sass@1.72.0): - resolution: {integrity: sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==} + /vite@5.2.7(@types/node@20.12.2)(sass@1.72.0): + resolution: {integrity: sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true peerDependencies: @@ -7795,7 +7774,7 @@ packages: terser: optional: true dependencies: - '@types/node': 20.11.30 + '@types/node': 20.12.2 esbuild: 0.20.2 postcss: 8.4.38 rollup: 4.13.0 @@ -7803,7 +7782,7 @@ packages: optionalDependencies: fsevents: 2.3.3 - /vitefu@0.2.5(vite@5.2.6): + /vitefu@0.2.5(vite@5.2.7): resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==} peerDependencies: vite: ^3.0.0 || ^4.0.0 || ^5.0.0 @@ -7811,9 +7790,9 @@ packages: vite: optional: true dependencies: - vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0) + vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0) - /vitest@1.4.0(@types/node@20.11.30)(sass@1.72.0): + /vitest@1.4.0(@types/node@20.12.2)(sass@1.72.0): resolution: {integrity: sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -7838,7 +7817,7 @@ packages: jsdom: optional: true dependencies: - '@types/node': 20.11.30 + '@types/node': 20.12.2 '@vitest/expect': 1.4.0 '@vitest/runner': 1.4.0 '@vitest/snapshot': 1.4.0 @@ -7856,8 +7835,8 @@ packages: strip-literal: 2.0.0 tinybench: 2.6.0 tinypool: 0.8.2 - vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0) - vite-node: 1.4.0(@types/node@20.11.30)(sass@1.72.0) + vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0) + vite-node: 1.4.0(@types/node@20.12.2)(sass@1.72.0) why-is-node-running: 2.2.2 transitivePeerDependencies: - less diff --git a/src/app.d.ts b/src/app.d.ts index 20e0cdc..7cf65d5 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -6,7 +6,7 @@ declare global { namespace App { interface PageData { - flash?: { type: 'success' | 'error' | 'info'; message: string }; + flash?: { type: 'success' | 'error' | 'info'; message: string; data: any }; } interface Locals { auth: import('lucia').AuthRequest; diff --git a/src/routes/(app)/(protected)/profile/+page.server.ts b/src/routes/(app)/(protected)/profile/+page.server.ts index 40122a8..efab70d 100644 --- a/src/routes/(app)/(protected)/profile/+page.server.ts +++ b/src/routes/(app)/(protected)/profile/+page.server.ts @@ -17,38 +17,37 @@ export const load: PageServerLoad = async (event) => { const { user } = event.locals; - const dbUser = await db.query - .users - .findFirst({ - where: eq(users.id, user.id) - }); + const dbUser = await db.query.users.findFirst({ + where: eq(users.id, user.id), + }); const profileForm = await superValidate(zod(profileSchema), { defaults: { firstName: dbUser?.first_name ?? '', lastName: dbUser?.last_name ?? '', username: dbUser?.username ?? '', - } + }, }); const emailForm = await superValidate(zod(changeEmailSchema), { defaults: { email: dbUser?.email ?? '', - } + }, }); return { profileForm, emailForm, - hasSetupTwoFactor: !!dbUser?.two_factor_secret + hasSetupTwoFactor: !!dbUser?.two_factor_secret, }; }; const changeEmailIfNotEmpty = z.object({ - email: z.string() + email: z + .string() .trim() .max(64, { message: 'Email must be less than 64 characters' }) - .email({ message: 'Please enter a valid email' }) - }); + .email({ message: 'Please enter a valid email' }), +}); export const actions: Actions = { profileUpdate: async (event) => { @@ -56,7 +55,7 @@ export const actions: Actions = { if (!form.valid) { return fail(400, { - form + form, }); } if (!event.locals.user) { @@ -68,12 +67,9 @@ export const actions: Actions = { const user = event.locals.user; const newUsername = form.data.username; - const existingUser = await db.query - .users - .findFirst({ - where: eq(users.username, newUsername) - } - ); + const existingUser = await db.query.users.findFirst({ + where: eq(users.username, newUsername), + }); if (existingUser && existingUser.id !== user.id) { return setError(form, 'username', 'That username is already taken'); @@ -84,7 +80,7 @@ export const actions: Actions = { .set({ first_name: form.data.firstName, last_name: form.data.lastName, - username: form.data.username + username: form.data.username, }) .where(eq(users.id, user.id)); } catch (e) { @@ -102,29 +98,30 @@ export const actions: Actions = { const form = await superValidate(event, zod(changeEmailSchema)); const newEmail = form.data?.email; - if (!form.valid || !newEmail || (newEmail !== '' && !changeEmailIfNotEmpty.safeParse(form.data).success)) { + if ( + !form.valid || + !newEmail || + (newEmail !== '' && !changeEmailIfNotEmpty.safeParse(form.data).success) + ) { return fail(400, { - form + form, }); } if (!event.locals.user) { - redirect(302, '/login', notSignedInMessage, event); + redirect(302, '/login', notSignedInMessage, event); } const user = event.locals.user; const existingUser = await db.query.users.findFirst({ - where: eq(users.email, newEmail) + where: eq(users.email, newEmail), }); if (existingUser && existingUser.id !== user.id) { return setError(form, 'email', 'That email is already taken'); } - await db - .update(users) - .set({ email: form.data.email }) - .where(eq(users.id, user.id)); + await db.update(users).set({ email: form.data.email }).where(eq(users.id, user.id)); if (user.email !== form.data.email) { // Send email to confirm new email? @@ -143,5 +140,5 @@ export const actions: Actions = { } return message(form, { type: 'success', message: 'Email updated successfully!' }); - } + }, }; diff --git a/src/routes/(app)/(protected)/profile/security/two-factor/+page.server.ts b/src/routes/(app)/(protected)/profile/security/two-factor/+page.server.ts index 140a542..daeb5e0 100644 --- a/src/routes/(app)/(protected)/profile/security/two-factor/+page.server.ts +++ b/src/routes/(app)/(protected)/profile/security/two-factor/+page.server.ts @@ -1,19 +1,19 @@ -import { encodeHex } from 'oslo/encoding'; +import { type Actions, fail } from '@sveltejs/kit'; +import { eq } from 'drizzle-orm'; +import { createId as cuid2 } from '@paralleldrive/cuid2'; +import { encodeHex, decodeHex } from 'oslo/encoding'; import { Argon2id } from 'oslo/password'; -import { createTOTPKeyURI } from 'oslo/otp'; +import { createTOTPKeyURI, TOTPController } from 'oslo/otp'; import { HMAC } from 'oslo/crypto'; +import QRCode from 'qrcode'; import { zod } from 'sveltekit-superforms/adapters'; -import { setError, superValidate } from 'sveltekit-superforms/server'; +import { message, setError, superValidate } from 'sveltekit-superforms/server'; import { redirect } from 'sveltekit-flash-message/server'; -import type { Cookie } from 'lucia'; import type { PageServerLoad } from '../../$types'; import { addTwoFactorSchema } from '$lib/validations/account'; import { notSignedInMessage } from '$lib/flashMessages'; -import { type Actions, fail } from '@sveltejs/kit'; import db from '$lib/drizzle'; -import { eq } from 'drizzle-orm'; -import { users } from '../../../../../../schema'; -import QRCode from 'qrcode'; +import { recovery_codes, users } from '../../../../../../schema'; export const load: PageServerLoad = async (event) => { const form = await superValidate(event, zod(addTwoFactorSchema)); @@ -23,25 +23,42 @@ export const load: PageServerLoad = async (event) => { redirect(302, '/login', notSignedInMessage, event); } + const dbUser = await db.query.users.findFirst({ + where: eq(users.id, user.id), + }); + + if (dbUser?.two_factor_enabled) { + const message = { + type: 'info', + message: 'Two-Factor Authentication is already enabled', + } as const; + throw redirect('/profile', message, event); + } + const twoFactorSecret = await new HMAC('SHA-1').generateKey(); await db .update(users) - .set({ two_factor_secret: encodeHex(twoFactorSecret) }) + .set({ + two_factor_secret: encodeHex(twoFactorSecret), + two_factor_enabled: false, + }) .where(eq(users.id, user.id)); const issuer = 'bored-game'; const accountName = user.email || user.username; // pass the website's name and the user identifier (e.g. email, username) - const uri = createTOTPKeyURI(issuer, accountName, twoFactorSecret); - const qrCode = await QRCode.toDataURL(uri); + const totpUri = createTOTPKeyURI(issuer, accountName, twoFactorSecret); + const qrCode = QRCode.toDataURL(totpUri); form.data = { current_password: '', - two_factor_code: '' + two_factor_code: '', }; return { form, - qrCode + twoFactorEnabled: false, + totpUri, + qrCode, }; }; @@ -51,11 +68,10 @@ export const actions: Actions = { if (!form.valid) { return fail(400, { - form + form, }); } - console.log('updating profile'); if (!event.locals.user) { redirect(302, '/login', notSignedInMessage, event); } @@ -67,7 +83,7 @@ export const actions: Actions = { const user = event.locals.user; const dbUser = await db.query.users.findFirst({ - where: eq(users.id, user.id) + where: eq(users.id, user.id), }); if (!dbUser?.hashed_password) { @@ -75,47 +91,60 @@ export const actions: Actions = { form.data.two_factor_code = ''; return setError( form, - 'Error occurred. Please try again or contact support if you need further help.' + 'Error occurred. Please try again or contact support if you need further help.', + ); + } + + if (dbUser?.two_factor_secret === '' || dbUser?.two_factor_secret === null) { + form.data.current_password = ''; + form.data.two_factor_code = ''; + return setError( + form, + 'Error occurred. Please try again or contact support if you need further help.', ); } const currentPasswordVerified = await new Argon2id().verify( dbUser.hashed_password, - form.data.current_password + form.data.current_password, ); if (!currentPasswordVerified) { return setError(form, 'current_password', 'Your password is incorrect'); } - if (user?.username) { - let sessionCookie: Cookie; - try { - } catch (e) { - console.error(e); - form.data.password = ''; - form.data.confirm_password = ''; - form.data.current_password = ''; - return setError(form, 'current_password', 'Your password is incorrect.'); - } - event.cookies.set(sessionCookie.name, sessionCookie.value, { - path: '.', - ...sessionCookie.attributes - }); - const message = { - type: 'success', - message: 'Password Updated. Please sign in.' - } as const; - redirect(302, '/login', message, event); + if (form.data.two_factor_code === '') { + return setError(form, 'two_factor_code', 'Please enter a code'); } - return setError( - form, - 'Error occurred. Please try again or contact support if you need further help.' + + const twoFactorCode = form.data.two_factor_code; + const validOTP = await new TOTPController().verify( + twoFactorCode, + decodeHex(dbUser.two_factor_secret), ); - // TODO: Add toast instead? - // form.data.password = ''; - // form.data.confirm_password = ''; - // form.data.current_password = ''; - // return message(form, 'Profile updated successfully.'); - } + + if (!validOTP) { + return setError(form, 'two_factor_code', 'Invalid code'); + } + + await db.update(users).set({ two_factor_enabled: true }).where(eq(users.id, user.id)); + + const recoveryCodes = generateRecoveryCodes(); + if (recoveryCodes) { + for (const code of recoveryCodes) { + await db.insert(recovery_codes).values({ + userId: user.id, + code: await new Argon2id().hash(code), + }); + } + } + + form.data.current_password = ''; + form.data.two_factor_code = ''; + return { recoveryCodes }; + }, }; + +function generateRecoveryCodes() { + return Array.from({ length: 5 }, () => cuid2()); +} diff --git a/src/routes/(app)/(protected)/profile/security/two-factor/+page.svelte b/src/routes/(app)/(protected)/profile/security/two-factor/+page.svelte index 15915ae..e3fe49b 100644 --- a/src/routes/(app)/(protected)/profile/security/two-factor/+page.svelte +++ b/src/routes/(app)/(protected)/profile/security/two-factor/+page.svelte @@ -2,28 +2,28 @@ import { zodClient } from 'sveltekit-superforms/adapters'; import { superForm } from 'sveltekit-superforms/client'; import { AlertTriangle } from 'lucide-svelte'; - import * as Alert from "$components/ui/alert"; + import * as Alert from '$components/ui/alert'; import * as Form from '$components/ui/form'; import { Input } from '$components/ui/input'; import { addTwoFactorSchema } from '$lib/validations/account'; export let data; + export let form; + + console.log('recovery codes', form.recoveryCodes) const { qrCode } = data; - console.log('qrCode', qrCode) - - const form = superForm(data.form, { + const twoFactorForm = superForm(data.form, { taintedMessage: null, validators: zodClient(addTwoFactorSchema), delayMs: 500, - multipleSubmits: 'prevent' + multipleSubmits: 'prevent', }); - const { form: formData, enhance } = form; + const { form: formData, enhance } = twoFactorForm;

Two-Factor Authentication

QR Code - diff --git a/src/routes/(app)/(protected)/profile/security/two-factor/recovery-codes/+page.server.ts b/src/routes/(app)/(protected)/profile/security/two-factor/recovery-codes/+page.server.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/(app)/(protected)/profile/security/two-factor/recovery-codes/+page.svelte b/src/routes/(app)/(protected)/profile/security/two-factor/recovery-codes/+page.svelte new file mode 100644 index 0000000..e69de29 diff --git a/src/routes/(auth)/sign-up/+page.server.ts b/src/routes/(auth)/sign-up/+page.server.ts index 66e3170..8bd15e1 100644 --- a/src/routes/(auth)/sign-up/+page.server.ts +++ b/src/routes/(auth)/sign-up/+page.server.ts @@ -91,7 +91,8 @@ export const actions: Actions = { verified: false, receive_email: false, theme: 'system', - two_factor_secret: null + two_factor_secret: '', + two_factor_enabled: false }) .returning(); console.log('signup user', user); diff --git a/src/schema.ts b/src/schema.ts index c20eb66..19c9dc4 100644 --- a/src/schema.ts +++ b/src/schema.ts @@ -8,7 +8,7 @@ import { index, pgEnum, primaryKey, - uuid + uuid, } from 'drizzle-orm/pg-core'; import { createId as cuid2 } from '@paralleldrive/cuid2'; import { tsvector } from './tsVector'; @@ -28,13 +28,25 @@ export const users = pgTable('users', { verified: boolean('verified').default(false), receive_email: boolean('receive_email').default(false), theme: text('theme').default('system'), - two_factor_secret: text('two_factor_secret'), + two_factor_secret: text('two_factor_secret').default(''), + two_factor_enabled: boolean('two_factor_enabled').default(false), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), +}); + +export const recovery_codes = pgTable('recovery_codes', { + id: uuid('id').primaryKey().defaultRandom(), + userId: uuid('user_id') + .notNull() + .references(() => users.id), + code: text('code').notNull(), + used: boolean('used').default(false), + created_at: timestamp('created_at').notNull().defaultNow(), + updated_at: timestamp('updated_at').notNull().defaultNow(), }); export const user_relations = relations(users, ({ many }) => ({ - user_roles: many(user_roles) + user_roles: many(user_roles), })); export type Users = InferSelectModel; @@ -46,10 +58,10 @@ export const sessions = pgTable('sessions', { .references(() => users.id), expiresAt: timestamp('expires_at', { withTimezone: true, - mode: 'date' + mode: 'date', }).notNull(), ipCountry: text('ip_country'), - ipAddress: text('ip_address') + ipAddress: text('ip_address'), }); export const roles = pgTable('roles', { @@ -58,13 +70,13 @@ export const roles = pgTable('roles', { .unique() .$defaultFn(() => cuid2()) .notNull(), - name: text('name').unique().notNull() + name: text('name').unique().notNull(), }); export type Roles = InferSelectModel; export const role_relations = relations(roles, ({ many }) => ({ - user_roles: many(user_roles) + user_roles: many(user_roles), })); export const user_roles = pgTable('user_roles', { @@ -80,18 +92,18 @@ export const user_roles = pgTable('user_roles', { .references(() => roles.id, { onDelete: 'cascade' }), primary: boolean('primary').default(false), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), }); export const user_role_relations = relations(user_roles, ({ one }) => ({ role: one(roles, { fields: [user_roles.role_id], - references: [roles.id] + references: [roles.id], }), user: one(users, { fields: [user_roles.user_id], - references: [users.id] - }) + references: [users.id], + }), })); export type UserRoles = InferSelectModel; @@ -106,16 +118,16 @@ export const password_reset_tokens = pgTable('password_reset_tokens', { expires_at: timestamp('expires_at', { withTimezone: true, mode: 'date', - precision: 6 + precision: 6, }), - created_at: timestamp('created_at').notNull().defaultNow() + created_at: timestamp('created_at').notNull().defaultNow(), }); export const password_reset_token_relations = relations(password_reset_tokens, ({ one }) => ({ user: one(users, { fields: [password_reset_tokens.user_id], - references: [users.id] - }) + references: [users.id], + }), })); export const collections = pgTable('collections', { @@ -127,14 +139,14 @@ export const collections = pgTable('collections', { .notNull() .references(() => users.id, { onDelete: 'cascade' }), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), }); export const collection_relations = relations(collections, ({ one }) => ({ user: one(users, { fields: [collections.user_id], - references: [users.id] - }) + references: [users.id], + }), })); export const collection_items = pgTable('collection_items', { @@ -150,7 +162,7 @@ export const collection_items = pgTable('collection_items', { .references(() => games.id, { onDelete: 'cascade' }), times_played: integer('times_played').default(0), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), }); export type CollectionItems = InferSelectModel; @@ -158,12 +170,12 @@ export type CollectionItems = InferSelectModel; export const collection_item_relations = relations(collection_items, ({ one }) => ({ collection: one(collections, { fields: [collection_items.collection_id], - references: [collections.id] + references: [collections.id], }), game: one(games, { fields: [collection_items.game_id], - references: [games.id] - }) + references: [games.id], + }), })); export const wishlists = pgTable('wishlists', { @@ -175,7 +187,7 @@ export const wishlists = pgTable('wishlists', { .notNull() .references(() => users.id, { onDelete: 'cascade' }), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), }); export type Wishlists = InferSelectModel; @@ -183,8 +195,8 @@ export type Wishlists = InferSelectModel; export const wishlists_relations = relations(wishlists, ({ one }) => ({ user: one(users, { fields: [wishlists.user_id], - references: [users.id] - }) + references: [users.id], + }), })); export const wishlist_items = pgTable('wishlist_items', { @@ -199,7 +211,7 @@ export const wishlist_items = pgTable('wishlist_items', { .notNull() .references(() => games.id, { onDelete: 'cascade' }), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), }); export type WishlistItems = InferSelectModel; @@ -207,12 +219,12 @@ export type WishlistItems = InferSelectModel; export const wishlist_item_relations = relations(wishlist_items, ({ one }) => ({ wishlist: one(wishlists, { fields: [wishlist_items.wishlist_id], - references: [wishlists.id] + references: [wishlists.id], }), game: one(games, { fields: [wishlist_items.game_id], - references: [games.id] - }) + references: [games.id], + }), })); // Game and related table schemas @@ -223,7 +235,7 @@ export const externalIdType = pgEnum('external_id_type', [ 'mechanic', 'publisher', 'designer', - 'artist' + 'artist', ]); export const externalIds = pgTable('external_ids', { @@ -232,7 +244,7 @@ export const externalIds = pgTable('external_ids', { .unique() .$defaultFn(() => cuid2()), type: externalIdType('type').notNull(), - externalId: text('external_id').notNull() + externalId: text('external_id').notNull(), }); export type ExternalIds = InferSelectModel; @@ -261,18 +273,18 @@ export const games = pgTable( last_sync_at: timestamp('last_sync_at', { withTimezone: true, mode: 'date', - precision: 6 + precision: 6, }), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), }, (table) => { return { text_searchable_idx: index('text_searchable_idx') .on(table.text_searchable_index) - .using(sql`'gin'`) + .using(sql`'gin'`), }; - } + }, ); export type Games = InferSelectModel; @@ -285,22 +297,22 @@ export const gamesToExternalIds = pgTable( .references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }), externalId: uuid('external_id') .notNull() - .references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }) + .references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }), }, (table) => { return { gamesToExternalIdsPkey: primaryKey({ - columns: [table.gameId, table.externalId] - }) + columns: [table.gameId, table.externalId], + }), }; - } + }, ); export const gameRelations = relations(games, ({ many }) => ({ categories_to_games: many(categories_to_games), mechanics_to_games: many(mechanics_to_games), publishers_to_games: many(publishers_to_games), - gamesToExternalIds: many(gamesToExternalIds) + gamesToExternalIds: many(gamesToExternalIds), })); export const expansions = pgTable('expansions', { @@ -315,7 +327,7 @@ export const expansions = pgTable('expansions', { .notNull() .references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), }); export type Expansions = InferSelectModel; @@ -323,12 +335,12 @@ export type Expansions = InferSelectModel; export const expansion_relations = relations(expansions, ({ one }) => ({ baseGame: one(games, { fields: [expansions.base_game_id], - references: [games.id] + references: [games.id], }), game: one(games, { fields: [expansions.game_id], - references: [games.id] - }) + references: [games.id], + }), })); export const publishers = pgTable('publishers', { @@ -339,7 +351,7 @@ export const publishers = pgTable('publishers', { name: text('name'), slug: text('slug'), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), }); export type Publishers = InferSelectModel; @@ -352,20 +364,20 @@ export const publishersToExternalIds = pgTable( .references(() => publishers.id, { onDelete: 'restrict', onUpdate: 'cascade' }), externalId: uuid('external_id') .notNull() - .references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }) + .references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }), }, (table) => { return { publishersToExternalIdsPkey: primaryKey({ - columns: [table.publisherId, table.externalId] - }) + columns: [table.publisherId, table.externalId], + }), }; - } + }, ); export const publishers_relations = relations(publishers, ({ many }) => ({ publishers_to_games: many(publishers_to_games), - publishersToExternalIds: many(publishersToExternalIds) + publishersToExternalIds: many(publishersToExternalIds), })); export const categories = pgTable('categories', { @@ -376,7 +388,7 @@ export const categories = pgTable('categories', { name: text('name'), slug: text('slug'), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), }); export type Categories = InferSelectModel; @@ -389,15 +401,15 @@ export const categoriesToExternalIds = pgTable( .references(() => categories.id, { onDelete: 'restrict', onUpdate: 'cascade' }), externalId: uuid('external_id') .notNull() - .references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }) + .references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }), }, (table) => { return { categoriesToExternalIdsPkey: primaryKey({ - columns: [table.categoryId, table.externalId] - }) + columns: [table.categoryId, table.externalId], + }), }; - } + }, ); export const categories_to_games = pgTable( @@ -408,31 +420,31 @@ export const categories_to_games = pgTable( .references(() => categories.id, { onDelete: 'restrict', onUpdate: 'cascade' }), game_id: uuid('game_id') .notNull() - .references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }) + .references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }), }, (table) => { return { categoriesToGamesPkey: primaryKey({ - columns: [table.category_id, table.game_id] - }) + columns: [table.category_id, table.game_id], + }), }; - } + }, ); export const categories_to_games_relations = relations(categories_to_games, ({ one }) => ({ category: one(categories, { fields: [categories_to_games.category_id], - references: [categories.id] + references: [categories.id], }), game: one(games, { fields: [categories_to_games.game_id], - references: [games.id] - }) + references: [games.id], + }), })); export const categories_relations = relations(categories, ({ many }) => ({ categories_to_games: many(categories_to_games), - categoriesToExternalIds: many(categoriesToExternalIds) + categoriesToExternalIds: many(categoriesToExternalIds), })); export const mechanics = pgTable('mechanics', { @@ -443,7 +455,7 @@ export const mechanics = pgTable('mechanics', { name: text('name'), slug: text('slug'), created_at: timestamp('created_at').notNull().defaultNow(), - updated_at: timestamp('updated_at').notNull().defaultNow() + updated_at: timestamp('updated_at').notNull().defaultNow(), }); export type Mechanics = InferSelectModel; @@ -456,20 +468,20 @@ export const mechanicsToExternalIds = pgTable( .references(() => mechanics.id, { onDelete: 'restrict', onUpdate: 'cascade' }), externalId: uuid('external_id') .notNull() - .references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }) + .references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }), }, (table) => { return { mechanicsToExternalIdsPkey: primaryKey({ - columns: [table.mechanicId, table.externalId] - }) + columns: [table.mechanicId, table.externalId], + }), }; - } + }, ); export const mechanic_relations = relations(mechanics, ({ many }) => ({ mechanics_to_games: many(mechanics_to_games), - mechanicsToExternalIds: many(mechanicsToExternalIds) + mechanicsToExternalIds: many(mechanicsToExternalIds), })); export const mechanics_to_games = pgTable( @@ -480,26 +492,26 @@ export const mechanics_to_games = pgTable( .references(() => mechanics.id, { onDelete: 'restrict', onUpdate: 'cascade' }), game_id: uuid('game_id') .notNull() - .references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }) + .references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }), }, (table) => { return { mechanicsToGamesPkey: primaryKey({ - columns: [table.mechanic_id, table.game_id] - }) + columns: [table.mechanic_id, table.game_id], + }), }; - } + }, ); export const mechanics_to_games_relations = relations(mechanics_to_games, ({ one }) => ({ mechanic: one(mechanics, { fields: [mechanics_to_games.mechanic_id], - references: [mechanics.id] + references: [mechanics.id], }), game: one(games, { fields: [mechanics_to_games.game_id], - references: [games.id] - }) + references: [games.id], + }), })); export const publishers_to_games = pgTable( @@ -510,24 +522,24 @@ export const publishers_to_games = pgTable( .references(() => publishers.id, { onDelete: 'restrict', onUpdate: 'cascade' }), game_id: uuid('game_id') .notNull() - .references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }) + .references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }), }, (table) => { return { publishersToGamesPkey: primaryKey({ - columns: [table.publisher_id, table.game_id] - }) + columns: [table.publisher_id, table.game_id], + }), }; - } + }, ); export const publishers_to_games_relations = relations(publishers_to_games, ({ one }) => ({ publisher: one(publishers, { fields: [publishers_to_games.publisher_id], - references: [publishers.id] + references: [publishers.id], }), game: one(games, { fields: [publishers_to_games.game_id], - references: [games.id] - }) + references: [games.id], + }), })); diff --git a/src/seed.ts b/src/seed.ts index 1ecf409..de556c7 100644 --- a/src/seed.ts +++ b/src/seed.ts @@ -2,40 +2,71 @@ import 'dotenv/config'; import { drizzle } from 'drizzle-orm/node-postgres'; import pg from 'pg'; import * as schema from './schema'; +import {Argon2id} from "oslo/password"; // create the connection const pool = new pg.Pool({ user: process.env.DATABASE_USER, password: process.env.DATABASE_PASSWORD, host: process.env.DATABASE_HOST, - port: new Number(process.env.DATABASE_PORT).valueOf(), + port: Number(process.env.DATABASE_PORT).valueOf(), database: process.env.DATABASE_DB, - ssl: process.env.DATABASE_HOST === 'localhost' ? false : true + ssl: process.env.DATABASE_HOST !== 'localhost' }); const db = drizzle(pool, { schema: schema }); -const existingRoles = await db.query.roles.findMany(); -console.log('Existing roles', existingRoles); console.log('Creating roles ...'); -await db +const adminRole = await db .insert(schema.roles) .values([{ name: 'admin' }]) - .onConflictDoNothing(); -await db + .onConflictDoNothing() + .returning(); +const userRole = await db .insert(schema.roles) .values([{ name: 'user' }]) - .onConflictDoNothing(); + .onConflictDoNothing() + .returning(); await db .insert(schema.roles) .values([{ name: 'editor' }]) .onConflictDoNothing(); -console.log('Roles created.'); await db .insert(schema.roles) .values([{ name: 'moderator' }]) .onConflictDoNothing(); console.log('Roles created.'); +console.log('Admin Role: ', adminRole); + +const adminUser = await db + .insert(schema.users) + .values({ + username: `${process.env.ADMIN_USERNAME}`, + email: '', + hashed_password: await new Argon2id().hash(`${process.env.ADMIN_PASSWORD}`), + first_name: 'Brad', + last_name: 'S', + verified: true + }) + .returning() + .onConflictDoNothing(); + +console.log('Admin user created.', adminUser); + +await db.insert(schema.user_roles).values({ + user_id: adminUser[0].id, + role_id: adminRole[0].id +}).onConflictDoNothing(); + +console.log('Admin user given admin role.'); + +await db.insert(schema.user_roles).values({ + user_id: adminUser[0].id, + role_id: userRole[0].id +}).onConflictDoNothing(); + +console.log('Admin user given user role.'); + await pool.end(); process.exit();