mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Adding totp enabled to session, restarting migrations, updating many Shadcn svelte components, and refactoring to move 2FA to its own page.
This commit is contained in:
parent
a8eed0d86d
commit
2609c28619
98 changed files with 5757 additions and 21633 deletions
2
.nvmrc
2
.nvmrc
|
|
@ -1 +1 @@
|
||||||
v20
|
20
|
||||||
|
|
@ -2,9 +2,9 @@ import 'dotenv/config';
|
||||||
import { defineConfig } from 'drizzle-kit';
|
import { defineConfig } from 'drizzle-kit';
|
||||||
|
|
||||||
export default defineConfig({
|
export default defineConfig({
|
||||||
|
dialect: 'postgresql',
|
||||||
schema: './src/db/schema/index.ts',
|
schema: './src/db/schema/index.ts',
|
||||||
out: './src/db/migrations',
|
out: './src/db/migrations',
|
||||||
driver: 'pg',
|
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
host: process.env.DATABASE_HOST || 'localhost',
|
host: process.env.DATABASE_HOST || 'localhost',
|
||||||
port: Number(process.env.DATABASE_PORT) || 5432,
|
port: Number(process.env.DATABASE_PORT) || 5432,
|
||||||
|
|
|
||||||
80
package.json
80
package.json
|
|
@ -15,59 +15,59 @@
|
||||||
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
"lint": "prettier --plugin-search-dir . --check . && eslint .",
|
||||||
"format": "prettier --plugin-search-dir . --write .",
|
"format": "prettier --plugin-search-dir . --write .",
|
||||||
"site:update": "pnpm update -i -L",
|
"site:update": "pnpm update -i -L",
|
||||||
"generate": "drizzle-kit generate:pg",
|
"generate": "drizzle-kit generate",
|
||||||
"migrate": "tsx src/db/migrate.ts",
|
"migrate": "tsx src/db/migrate.ts",
|
||||||
"seed": "tsx src/db/seed.ts",
|
"seed": "tsx src/db/seed.ts",
|
||||||
"push": "drizzle-kit push:pg"
|
"push": "drizzle-kit push"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@melt-ui/pp": "^0.3.1",
|
"@melt-ui/pp": "^0.3.2",
|
||||||
"@melt-ui/svelte": "^0.77.0",
|
"@melt-ui/svelte": "^0.81.0",
|
||||||
"@playwright/test": "^1.43.1",
|
"@playwright/test": "^1.44.1",
|
||||||
"@resvg/resvg-js": "^2.6.2",
|
"@resvg/resvg-js": "^2.6.2",
|
||||||
"@sveltejs/adapter-auto": "^3.2.0",
|
"@sveltejs/adapter-auto": "^3.2.1",
|
||||||
"@sveltejs/enhanced-img": "^0.2.0",
|
"@sveltejs/enhanced-img": "^0.2.1",
|
||||||
"@sveltejs/kit": "^2.5.7",
|
"@sveltejs/kit": "^2.5.10",
|
||||||
"@sveltejs/vite-plugin-svelte": "^3.1.0",
|
"@sveltejs/vite-plugin-svelte": "^3.1.1",
|
||||||
"@types/cookie": "^0.6.0",
|
"@types/cookie": "^0.6.0",
|
||||||
"@types/node": "^20.12.6",
|
"@types/node": "^20.14.2",
|
||||||
"@types/pg": "^8.11.5",
|
"@types/pg": "^8.11.6",
|
||||||
"@typescript-eslint/eslint-plugin": "^7.7.1",
|
"@typescript-eslint/eslint-plugin": "^7.8.0",
|
||||||
"@typescript-eslint/parser": "^7.7.1",
|
"@typescript-eslint/parser": "^7.8.0",
|
||||||
"autoprefixer": "^10.4.19",
|
"autoprefixer": "^10.4.19",
|
||||||
"dotenv": "^16.4.5",
|
"dotenv": "^16.4.5",
|
||||||
"drizzle-kit": "^0.20.17",
|
"drizzle-kit": "^0.22.4",
|
||||||
"eslint": "^8.57.0",
|
"eslint": "^8.57.0",
|
||||||
"eslint-config-prettier": "^9.1.0",
|
"eslint-config-prettier": "^9.1.0",
|
||||||
"eslint-plugin-svelte": "^2.38.0",
|
"eslint-plugin-svelte": "^2.39.0",
|
||||||
"just-clone": "^6.2.0",
|
"just-clone": "^6.2.0",
|
||||||
"just-debounce-it": "^3.2.0",
|
"just-debounce-it": "^3.2.0",
|
||||||
"postcss": "^8.4.38",
|
"postcss": "^8.4.38",
|
||||||
"postcss-import": "^16.1.0",
|
"postcss-import": "^16.1.0",
|
||||||
"postcss-load-config": "^5.0.3",
|
"postcss-load-config": "^5.1.0",
|
||||||
"postcss-preset-env": "^9.5.9",
|
"postcss-preset-env": "^9.5.14",
|
||||||
"prettier": "^3.2.5",
|
"prettier": "^3.3.1",
|
||||||
"prettier-plugin-svelte": "^3.2.3",
|
"prettier-plugin-svelte": "^3.2.4",
|
||||||
"sass": "^1.74.1",
|
"sass": "^1.77.4",
|
||||||
"satori": "^0.10.13",
|
"satori": "^0.10.13",
|
||||||
"satori-html": "^0.3.2",
|
"satori-html": "^0.3.2",
|
||||||
"svelte": "^4.2.15",
|
"svelte": "^4.2.18",
|
||||||
"svelte-check": "^3.7.0",
|
"svelte-check": "^3.8.0",
|
||||||
"svelte-headless-table": "^0.18.2",
|
"svelte-headless-table": "^0.18.2",
|
||||||
"svelte-meta-tags": "^3.1.2",
|
"svelte-meta-tags": "^3.1.2",
|
||||||
"svelte-preprocess": "^5.1.4",
|
"svelte-preprocess": "^5.1.4",
|
||||||
"svelte-sequential-preprocessor": "^2.0.1",
|
"svelte-sequential-preprocessor": "^2.0.1",
|
||||||
"sveltekit-flash-message": "^2.4.4",
|
"sveltekit-flash-message": "^2.4.4",
|
||||||
"sveltekit-rate-limiter": "^0.5.1",
|
"sveltekit-rate-limiter": "^0.5.1",
|
||||||
"sveltekit-superforms": "^2.12.6",
|
"sveltekit-superforms": "^2.14.0",
|
||||||
"tailwindcss": "^3.4.3",
|
"tailwindcss": "^3.4.4",
|
||||||
"ts-node": "^10.9.2",
|
"ts-node": "^10.9.2",
|
||||||
"tslib": "^2.6.1",
|
"tslib": "^2.6.3",
|
||||||
"tsx": "^4.7.3",
|
"tsx": "^4.12.0",
|
||||||
"typescript": "^5.4.4",
|
"typescript": "^5.4.5",
|
||||||
"vite": "^5.2.10",
|
"vite": "^5.2.12",
|
||||||
"vitest": "^1.5.2",
|
"vitest": "^1.6.0",
|
||||||
"zod": "^3.23.4"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|
@ -76,22 +76,22 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/fira-mono": "^5.0.13",
|
"@fontsource/fira-mono": "^5.0.13",
|
||||||
"@iconify-icons/line-md": "^1.2.26",
|
"@iconify-icons/line-md": "^1.2.30",
|
||||||
"@iconify-icons/mdi": "^1.2.47",
|
"@iconify-icons/mdi": "^1.2.48",
|
||||||
"@lucia-auth/adapter-drizzle": "^1.0.7",
|
"@lucia-auth/adapter-drizzle": "^1.0.7",
|
||||||
"@lukeed/uuid": "^2.0.1",
|
"@lukeed/uuid": "^2.0.1",
|
||||||
"@neondatabase/serverless": "^0.9.1",
|
"@neondatabase/serverless": "^0.9.3",
|
||||||
"@paralleldrive/cuid2": "^2.2.2",
|
"@paralleldrive/cuid2": "^2.2.2",
|
||||||
"@sveltejs/adapter-vercel": "^5.3.0",
|
"@sveltejs/adapter-vercel": "^5.3.1",
|
||||||
"@types/feather-icons": "^4.29.4",
|
"@types/feather-icons": "^4.29.4",
|
||||||
"@vercel/og": "^0.5.20",
|
"@vercel/og": "^0.5.20",
|
||||||
"bits-ui": "^0.21.5",
|
"bits-ui": "^0.21.10",
|
||||||
"boardgamegeekclient": "^1.9.1",
|
"boardgamegeekclient": "^1.9.1",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cookie": "^0.6.0",
|
"cookie": "^0.6.0",
|
||||||
"drizzle-orm": "^0.30.9",
|
"drizzle-orm": "^0.31.1",
|
||||||
"feather-icons": "^4.29.1",
|
"feather-icons": "^4.29.2",
|
||||||
"formsnap": "^1.0.0",
|
"formsnap": "^1.0.0",
|
||||||
"html-entities": "^2.5.2",
|
"html-entities": "^2.5.2",
|
||||||
"iconify-icon": "^2.1.0",
|
"iconify-icon": "^2.1.0",
|
||||||
|
|
@ -99,10 +99,10 @@
|
||||||
"just-kebab-case": "^4.2.0",
|
"just-kebab-case": "^4.2.0",
|
||||||
"loader": "^2.1.1",
|
"loader": "^2.1.1",
|
||||||
"lucia": "3.2.0",
|
"lucia": "3.2.0",
|
||||||
"lucide-svelte": "^0.373.0",
|
"lucide-svelte": "^0.390.0",
|
||||||
"open-props": "^1.7.4",
|
"open-props": "^1.7.4",
|
||||||
"oslo": "^1.2.0",
|
"oslo": "^1.2.0",
|
||||||
"pg": "^8.11.5",
|
"pg": "^8.12.0",
|
||||||
"postgres": "^3.4.4",
|
"postgres": "^3.4.4",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
"radix-svelte": "^0.9.0",
|
"radix-svelte": "^0.9.0",
|
||||||
|
|
@ -110,7 +110,7 @@
|
||||||
"svelte-lazy-loader": "^1.0.0",
|
"svelte-lazy-loader": "^1.0.0",
|
||||||
"tailwind-merge": "^2.3.0",
|
"tailwind-merge": "^2.3.0",
|
||||||
"tailwind-variants": "^0.2.1",
|
"tailwind-variants": "^0.2.1",
|
||||||
"tailwindcss-animate": "^1.0.6",
|
"tailwindcss-animate": "^1.0.7",
|
||||||
"zod-to-json-schema": "^3.23.0"
|
"zod-to-json-schema": "^3.23.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
8732
pnpm-lock.yaml
8732
pnpm-lock.yaml
File diff suppressed because it is too large
Load diff
|
|
@ -1,11 +1,5 @@
|
||||||
DO $$ BEGIN
|
|
||||||
CREATE TYPE "external_id_type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
--> statement-breakpoint
|
|
||||||
CREATE TABLE IF NOT EXISTS "categories" (
|
CREATE TABLE IF NOT EXISTS "categories" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"name" text,
|
"name" text,
|
||||||
"slug" text,
|
"slug" text,
|
||||||
|
|
@ -27,10 +21,10 @@ CREATE TABLE IF NOT EXISTS "categories_to_games" (
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "collection_items" (
|
CREATE TABLE IF NOT EXISTS "collection_items" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"collection_id" text NOT NULL,
|
"collection_id" uuid NOT NULL,
|
||||||
"game_id" text NOT NULL,
|
"game_id" uuid NOT NULL,
|
||||||
"times_played" integer DEFAULT 0,
|
"times_played" integer DEFAULT 0,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||||
|
|
@ -38,26 +32,17 @@ CREATE TABLE IF NOT EXISTS "collection_items" (
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "collections" (
|
CREATE TABLE IF NOT EXISTS "collections" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"user_id" text NOT NULL,
|
"user_id" uuid NOT NULL,
|
||||||
|
"name" text DEFAULT 'My Collection' NOT NULL,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "collections_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "collections_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "expansions" (
|
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
|
||||||
"cuid" text,
|
|
||||||
"base_game_id" text NOT NULL,
|
|
||||||
"game_id" text NOT NULL,
|
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
CONSTRAINT "expansions_cuid_unique" UNIQUE("cuid")
|
|
||||||
);
|
|
||||||
--> statement-breakpoint
|
|
||||||
CREATE TABLE IF NOT EXISTS "external_ids" (
|
CREATE TABLE IF NOT EXISTS "external_ids" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"type" "external_id_type" NOT NULL,
|
"type" "external_id_type" NOT NULL,
|
||||||
"external_id" text NOT NULL,
|
"external_id" text NOT NULL,
|
||||||
|
|
@ -65,7 +50,7 @@ CREATE TABLE IF NOT EXISTS "external_ids" (
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "games" (
|
CREATE TABLE IF NOT EXISTS "games" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"name" text,
|
"name" text,
|
||||||
"slug" text,
|
"slug" text,
|
||||||
|
|
@ -80,8 +65,7 @@ CREATE TABLE IF NOT EXISTS "games" (
|
||||||
"image_url" text,
|
"image_url" text,
|
||||||
"thumb_url" text,
|
"thumb_url" text,
|
||||||
"url" text,
|
"url" text,
|
||||||
"text_searchable_index" "tsvector",
|
"last_sync_at" timestamp,
|
||||||
"last_sync_at" timestamp (6) with time zone,
|
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "games_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "games_cuid_unique" UNIQUE("cuid")
|
||||||
|
|
@ -94,7 +78,7 @@ CREATE TABLE IF NOT EXISTS "games_to_external_ids" (
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "mechanics" (
|
CREATE TABLE IF NOT EXISTS "mechanics" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"name" text,
|
"name" text,
|
||||||
"slug" text,
|
"slug" text,
|
||||||
|
|
@ -117,13 +101,13 @@ CREATE TABLE IF NOT EXISTS "mechanics_to_games" (
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "password_reset_tokens" (
|
CREATE TABLE IF NOT EXISTS "password_reset_tokens" (
|
||||||
"id" text PRIMARY KEY NOT NULL,
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
"user_id" text NOT NULL,
|
"user_id" uuid NOT NULL,
|
||||||
"expires_at" timestamp (6) with time zone,
|
"expires_at" timestamp,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL
|
"created_at" timestamp DEFAULT now() NOT NULL
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "publishers" (
|
CREATE TABLE IF NOT EXISTS "publishers" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"name" text,
|
"name" text,
|
||||||
"slug" text,
|
"slug" text,
|
||||||
|
|
@ -144,34 +128,46 @@ CREATE TABLE IF NOT EXISTS "publishers_to_games" (
|
||||||
CONSTRAINT "publishers_to_games_publisher_id_game_id_pk" PRIMARY KEY("publisher_id","game_id")
|
CONSTRAINT "publishers_to_games_publisher_id_game_id_pk" PRIMARY KEY("publisher_id","game_id")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
|
CREATE TABLE IF NOT EXISTS "recovery_codes" (
|
||||||
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
|
"user_id" uuid NOT NULL,
|
||||||
|
"code" text NOT NULL,
|
||||||
|
"used" boolean DEFAULT false,
|
||||||
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp DEFAULT now() NOT NULL
|
||||||
|
);
|
||||||
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "roles" (
|
CREATE TABLE IF NOT EXISTS "roles" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text NOT NULL,
|
||||||
"name" text,
|
"name" text NOT NULL,
|
||||||
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
|
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "roles_cuid_unique" UNIQUE("cuid"),
|
CONSTRAINT "roles_cuid_unique" UNIQUE("cuid"),
|
||||||
CONSTRAINT "roles_name_unique" UNIQUE("name")
|
CONSTRAINT "roles_name_unique" UNIQUE("name")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "sessions" (
|
CREATE TABLE IF NOT EXISTS "sessions" (
|
||||||
"id" text PRIMARY KEY NOT NULL,
|
"id" text PRIMARY KEY NOT NULL,
|
||||||
"user_id" text NOT NULL,
|
"user_id" uuid NOT NULL,
|
||||||
"expires_at" timestamp with time zone NOT NULL,
|
"expires_at" timestamp with time zone NOT NULL,
|
||||||
"ip_country" text,
|
"ip_country" text,
|
||||||
"ip_address" text
|
"ip_address" text
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "user_roles" (
|
CREATE TABLE IF NOT EXISTS "user_roles" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"user_id" text NOT NULL,
|
"user_id" uuid NOT NULL,
|
||||||
"role_id" text NOT NULL,
|
"role_id" uuid NOT NULL,
|
||||||
|
"primary" boolean DEFAULT false,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "user_roles_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "user_roles_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "users" (
|
CREATE TABLE IF NOT EXISTS "users" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"username" text,
|
"username" text,
|
||||||
"hashed_password" text,
|
"hashed_password" text,
|
||||||
|
|
@ -181,6 +177,8 @@ CREATE TABLE IF NOT EXISTS "users" (
|
||||||
"verified" boolean DEFAULT false,
|
"verified" boolean DEFAULT false,
|
||||||
"receive_email" boolean DEFAULT false,
|
"receive_email" boolean DEFAULT false,
|
||||||
"theme" text DEFAULT 'system',
|
"theme" text DEFAULT 'system',
|
||||||
|
"two_factor_secret" text DEFAULT '',
|
||||||
|
"two_factor_enabled" boolean DEFAULT false,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "users_cuid_unique" UNIQUE("cuid"),
|
CONSTRAINT "users_cuid_unique" UNIQUE("cuid"),
|
||||||
|
|
@ -189,177 +187,176 @@ CREATE TABLE IF NOT EXISTS "users" (
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "wishlist_items" (
|
CREATE TABLE IF NOT EXISTS "wishlist_items" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"wishlist_id" text NOT NULL,
|
"wishlist_id" uuid NOT NULL,
|
||||||
"game_id" text NOT NULL,
|
"game_id" uuid NOT NULL,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "wishlist_items_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "wishlist_items_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE TABLE IF NOT EXISTS "wishlists" (
|
CREATE TABLE IF NOT EXISTS "wishlists" (
|
||||||
"id" uuid PRIMARY KEY NOT NULL,
|
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
||||||
"cuid" text,
|
"cuid" text,
|
||||||
"user_id" text NOT NULL,
|
"user_id" uuid NOT NULL,
|
||||||
|
"name" text DEFAULT 'My Wishlist' NOT NULL,
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
"created_at" timestamp DEFAULT now() NOT NULL,
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL,
|
"updated_at" timestamp DEFAULT now() NOT NULL,
|
||||||
CONSTRAINT "wishlists_cuid_unique" UNIQUE("cuid")
|
CONSTRAINT "wishlists_cuid_unique" UNIQUE("cuid")
|
||||||
);
|
);
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
CREATE INDEX IF NOT EXISTS "text_searchable_idx" ON "games" ("text_searchable_index");--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "categories"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."categories"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "categories_to_external_ids" ADD CONSTRAINT "categories_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "public"."external_ids"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "categories"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_category_id_categories_id_fk" FOREIGN KEY ("category_id") REFERENCES "public"."categories"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "categories_to_games" ADD CONSTRAINT "categories_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_collection_id_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "collections"("id") ON DELETE cascade ON UPDATE no action;
|
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_collection_id_collections_id_fk" FOREIGN KEY ("collection_id") REFERENCES "public"."collections"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE cascade ON UPDATE no action;
|
ALTER TABLE "collection_items" ADD CONSTRAINT "collection_items_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "collections" ADD CONSTRAINT "collections_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
ALTER TABLE "collections" ADD CONSTRAINT "collections_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "expansions" ADD CONSTRAINT "expansions_base_game_id_games_id_fk" FOREIGN KEY ("base_game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "expansions" ADD CONSTRAINT "expansions_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "public"."external_ids"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "public"."mechanics"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "games_to_external_ids" ADD CONSTRAINT "games_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "public"."external_ids"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "mechanics"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "public"."mechanics"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "mechanics_to_external_ids" ADD CONSTRAINT "mechanics_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_mechanic_id_mechanics_id_fk" FOREIGN KEY ("mechanic_id") REFERENCES "mechanics"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "password_reset_tokens" ADD CONSTRAINT "password_reset_tokens_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "mechanics_to_games" ADD CONSTRAINT "mechanics_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "public"."publishers"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "password_reset_tokens" ADD CONSTRAINT "password_reset_tokens_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "public"."external_ids"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "publishers"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "public"."publishers"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "publishers_to_external_ids" ADD CONSTRAINT "publishers_to_external_ids_external_id_external_ids_id_fk" FOREIGN KEY ("external_id") REFERENCES "external_ids"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE restrict ON UPDATE cascade;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_publisher_id_publishers_id_fk" FOREIGN KEY ("publisher_id") REFERENCES "publishers"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "recovery_codes" ADD CONSTRAINT "recovery_codes_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "publishers_to_games" ADD CONSTRAINT "publishers_to_games_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE restrict ON UPDATE cascade;
|
ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE no action ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "sessions" ADD CONSTRAINT "sessions_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE no action ON UPDATE no action;
|
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_role_id_roles_id_fk" FOREIGN KEY ("role_id") REFERENCES "public"."roles"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "user_roles" ADD CONSTRAINT "user_roles_role_id_roles_id_fk" FOREIGN KEY ("role_id") REFERENCES "roles"("id") ON DELETE cascade ON UPDATE no action;
|
ALTER TABLE "wishlist_items" ADD CONSTRAINT "wishlist_items_wishlist_id_wishlists_id_fk" FOREIGN KEY ("wishlist_id") REFERENCES "public"."wishlists"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "wishlist_items" ADD CONSTRAINT "wishlist_items_wishlist_id_wishlists_id_fk" FOREIGN KEY ("wishlist_id") REFERENCES "wishlists"("id") ON DELETE cascade ON UPDATE no action;
|
ALTER TABLE "wishlist_items" ADD CONSTRAINT "wishlist_items_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "public"."games"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
DO $$ BEGIN
|
||||||
ALTER TABLE "wishlist_items" ADD CONSTRAINT "wishlist_items_game_id_games_id_fk" FOREIGN KEY ("game_id") REFERENCES "games"("id") ON DELETE cascade ON UPDATE no action;
|
ALTER TABLE "wishlists" ADD CONSTRAINT "wishlists_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "public"."users"("id") ON DELETE cascade ON UPDATE no action;
|
||||||
EXCEPTION
|
EXCEPTION
|
||||||
WHEN duplicate_object THEN null;
|
WHEN duplicate_object THEN null;
|
||||||
END $$;
|
END $$;
|
||||||
--> statement-breakpoint
|
--> statement-breakpoint
|
||||||
DO $$ BEGIN
|
CREATE INDEX IF NOT EXISTS "search_index" ON "games" USING gin ((
|
||||||
ALTER TABLE "wishlists" ADD CONSTRAINT "wishlists_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE cascade ON UPDATE no action;
|
setweight(to_tsvector('english', "name"), 'A') ||
|
||||||
EXCEPTION
|
setweight(to_tsvector('english', "slug"), 'B')
|
||||||
WHEN duplicate_object THEN null;
|
));
|
||||||
END $$;
|
|
||||||
|
|
@ -1,6 +0,0 @@
|
||||||
ALTER TABLE "collection_items" ALTER COLUMN "collection_id" SET DATA TYPE uuid;--> statement-breakpoint
|
|
||||||
ALTER TABLE "collection_items" ALTER COLUMN "game_id" SET DATA TYPE uuid;--> statement-breakpoint
|
|
||||||
ALTER TABLE "expansions" ALTER COLUMN "base_game_id" SET DATA TYPE uuid;--> statement-breakpoint
|
|
||||||
ALTER TABLE "expansions" ALTER COLUMN "game_id" SET DATA TYPE uuid;--> statement-breakpoint
|
|
||||||
ALTER TABLE "wishlist_items" ALTER COLUMN "wishlist_id" SET DATA TYPE uuid;--> statement-breakpoint
|
|
||||||
ALTER TABLE "wishlist_items" ALTER COLUMN "game_id" SET DATA TYPE uuid;
|
|
||||||
|
|
@ -1,5 +0,0 @@
|
||||||
ALTER TABLE "collections" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
|
|
||||||
ALTER TABLE "password_reset_tokens" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
|
|
||||||
ALTER TABLE "sessions" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
|
|
||||||
ALTER TABLE "user_roles" ALTER COLUMN "user_id" SET DATA TYPE uuid;--> statement-breakpoint
|
|
||||||
ALTER TABLE "wishlists" ALTER COLUMN "user_id" SET DATA TYPE uuid;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
ALTER TABLE "user_roles" ALTER COLUMN "role_id" SET DATA TYPE uuid;
|
|
||||||
|
|
@ -1,13 +0,0 @@
|
||||||
ALTER TABLE "categories" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "collection_items" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "collections" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "expansions" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "external_ids" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "games" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "mechanics" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "publishers" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "roles" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "user_roles" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "users" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "wishlist_items" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();--> statement-breakpoint
|
|
||||||
ALTER TABLE "wishlists" ALTER COLUMN "id" SET DEFAULT gen_random_uuid();
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
ALTER TABLE "roles" ALTER COLUMN "cuid" SET NOT NULL;--> statement-breakpoint
|
|
||||||
ALTER TABLE "roles" ALTER COLUMN "name" SET NOT NULL;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
ALTER TABLE "user_roles" ADD COLUMN "default" boolean DEFAULT false;
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
ALTER TABLE "user_roles" RENAME COLUMN "default" TO "primary";
|
|
||||||
|
|
@ -1 +0,0 @@
|
||||||
ALTER TABLE "users" ADD COLUMN "two_factor_secret" text;
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
ALTER TABLE "users" ALTER COLUMN "two_factor_secret" SET DEFAULT '';--> statement-breakpoint
|
|
||||||
ALTER TABLE "users" ADD COLUMN "two_factor_enabled" boolean DEFAULT false;
|
|
||||||
|
|
@ -1,14 +0,0 @@
|
||||||
CREATE TABLE IF NOT EXISTS "recovery_codes" (
|
|
||||||
"id" uuid PRIMARY KEY DEFAULT gen_random_uuid() NOT NULL,
|
|
||||||
"user_id" uuid NOT NULL,
|
|
||||||
"code" text NOT NULL,
|
|
||||||
"used" boolean DEFAULT false,
|
|
||||||
"created_at" timestamp DEFAULT now() NOT NULL,
|
|
||||||
"updated_at" timestamp DEFAULT now() NOT NULL
|
|
||||||
);
|
|
||||||
--> statement-breakpoint
|
|
||||||
DO $$ BEGIN
|
|
||||||
ALTER TABLE "recovery_codes" ADD CONSTRAINT "recovery_codes_user_id_users_id_fk" FOREIGN KEY ("user_id") REFERENCES "users"("id") ON DELETE no action ON UPDATE no action;
|
|
||||||
EXCEPTION
|
|
||||||
WHEN duplicate_object THEN null;
|
|
||||||
END $$;
|
|
||||||
|
|
@ -1,2 +0,0 @@
|
||||||
ALTER TABLE "collections" ADD COLUMN "name" text DEFAULT 'My Collection' NOT NULL;--> statement-breakpoint
|
|
||||||
ALTER TABLE "wishlists" ADD COLUMN "name" text DEFAULT 'My Wishlist' NOT NULL;
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
{
|
{
|
||||||
"id": "176e5b1f-d146-4604-ab17-b16052da13c0",
|
"id": "9622fc3a-51a1-4f66-8535-fd1ceaf46fc2",
|
||||||
"prevId": "00000000-0000-0000-0000-000000000000",
|
"prevId": "00000000-0000-0000-0000-000000000000",
|
||||||
"version": "5",
|
"version": "7",
|
||||||
"dialect": "pg",
|
"dialect": "postgresql",
|
||||||
"tables": {
|
"tables": {
|
||||||
"categories": {
|
"public.categories": {
|
||||||
"name": "categories",
|
"name": "categories",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -12,7 +12,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -60,7 +61,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"categories_to_external_ids": {
|
"public.categories_to_external_ids": {
|
||||||
"name": "categories_to_external_ids",
|
"name": "categories_to_external_ids",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -117,7 +118,7 @@
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
"categories_to_games": {
|
"public.categories_to_games": {
|
||||||
"name": "categories_to_games",
|
"name": "categories_to_games",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -174,7 +175,7 @@
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
"collection_items": {
|
"public.collection_items": {
|
||||||
"name": "collection_items",
|
"name": "collection_items",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -182,7 +183,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -192,13 +194,13 @@
|
||||||
},
|
},
|
||||||
"collection_id": {
|
"collection_id": {
|
||||||
"name": "collection_id",
|
"name": "collection_id",
|
||||||
"type": "text",
|
"type": "uuid",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
"game_id": {
|
"game_id": {
|
||||||
"name": "game_id",
|
"name": "game_id",
|
||||||
"type": "text",
|
"type": "uuid",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
|
@ -264,7 +266,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"collections": {
|
"public.collections": {
|
||||||
"name": "collections",
|
"name": "collections",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -272,7 +274,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -282,10 +285,17 @@
|
||||||
},
|
},
|
||||||
"user_id": {
|
"user_id": {
|
||||||
"name": "user_id",
|
"name": "user_id",
|
||||||
"type": "text",
|
"type": "uuid",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'My Collection'"
|
||||||
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp",
|
||||||
|
|
@ -328,90 +338,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"expansions": {
|
"public.external_ids": {
|
||||||
"name": "expansions",
|
|
||||||
"schema": "",
|
|
||||||
"columns": {
|
|
||||||
"id": {
|
|
||||||
"name": "id",
|
|
||||||
"type": "uuid",
|
|
||||||
"primaryKey": true,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"cuid": {
|
|
||||||
"name": "cuid",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"base_game_id": {
|
|
||||||
"name": "base_game_id",
|
|
||||||
"type": "text",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": true
|
|
||||||
},
|
|
||||||
"game_id": {
|
|
||||||
"name": "game_id",
|
|
||||||
"type": "text",
|
|
||||||
"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",
|
"name": "external_ids",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -419,7 +346,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -430,6 +358,7 @@
|
||||||
"type": {
|
"type": {
|
||||||
"name": "type",
|
"name": "type",
|
||||||
"type": "external_id_type",
|
"type": "external_id_type",
|
||||||
|
"typeSchema": "public",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
|
@ -453,7 +382,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"games": {
|
"public.games": {
|
||||||
"name": "games",
|
"name": "games",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -461,7 +390,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -547,15 +477,9 @@
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
"text_searchable_index": {
|
|
||||||
"name": "text_searchable_index",
|
|
||||||
"type": "tsvector",
|
|
||||||
"primaryKey": false,
|
|
||||||
"notNull": false
|
|
||||||
},
|
|
||||||
"last_sync_at": {
|
"last_sync_at": {
|
||||||
"name": "last_sync_at",
|
"name": "last_sync_at",
|
||||||
"type": "timestamp (6) with time zone",
|
"type": "timestamp",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
|
@ -575,12 +499,20 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"indexes": {
|
"indexes": {
|
||||||
"text_searchable_idx": {
|
"search_index": {
|
||||||
"name": "text_searchable_idx",
|
"name": "search_index",
|
||||||
"columns": [
|
"columns": [
|
||||||
"text_searchable_index"
|
{
|
||||||
|
"expression": "(\n\t\t\t\t\t\tsetweight(to_tsvector('english', \"name\"), 'A') ||\n\t\t\t\t\t\tsetweight(to_tsvector('english', \"slug\"), 'B')\n\t\t\t\t\t)",
|
||||||
|
"asc": true,
|
||||||
|
"isExpression": true,
|
||||||
|
"nulls": "last"
|
||||||
|
}
|
||||||
],
|
],
|
||||||
"isUnique": false
|
"isUnique": false,
|
||||||
|
"concurrently": false,
|
||||||
|
"method": "gin",
|
||||||
|
"with": {}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"foreignKeys": {},
|
"foreignKeys": {},
|
||||||
|
|
@ -595,7 +527,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"games_to_external_ids": {
|
"public.games_to_external_ids": {
|
||||||
"name": "games_to_external_ids",
|
"name": "games_to_external_ids",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -652,7 +584,7 @@
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
"mechanics": {
|
"public.mechanics": {
|
||||||
"name": "mechanics",
|
"name": "mechanics",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -660,7 +592,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -708,7 +641,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"mechanics_to_external_ids": {
|
"public.mechanics_to_external_ids": {
|
||||||
"name": "mechanics_to_external_ids",
|
"name": "mechanics_to_external_ids",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -765,7 +698,7 @@
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
"mechanics_to_games": {
|
"public.mechanics_to_games": {
|
||||||
"name": "mechanics_to_games",
|
"name": "mechanics_to_games",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -822,7 +755,7 @@
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
"password_reset_tokens": {
|
"public.password_reset_tokens": {
|
||||||
"name": "password_reset_tokens",
|
"name": "password_reset_tokens",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -834,13 +767,13 @@
|
||||||
},
|
},
|
||||||
"user_id": {
|
"user_id": {
|
||||||
"name": "user_id",
|
"name": "user_id",
|
||||||
"type": "text",
|
"type": "uuid",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
"expires_at": {
|
"expires_at": {
|
||||||
"name": "expires_at",
|
"name": "expires_at",
|
||||||
"type": "timestamp (6) with time zone",
|
"type": "timestamp",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": false
|
||||||
},
|
},
|
||||||
|
|
@ -871,7 +804,7 @@
|
||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
"publishers": {
|
"public.publishers": {
|
||||||
"name": "publishers",
|
"name": "publishers",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -879,7 +812,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -927,7 +861,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"publishers_to_external_ids": {
|
"public.publishers_to_external_ids": {
|
||||||
"name": "publishers_to_external_ids",
|
"name": "publishers_to_external_ids",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -984,7 +918,7 @@
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
"publishers_to_games": {
|
"public.publishers_to_games": {
|
||||||
"name": "publishers_to_games",
|
"name": "publishers_to_games",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -1041,7 +975,71 @@
|
||||||
},
|
},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
"roles": {
|
"public.recovery_codes": {
|
||||||
|
"name": "recovery_codes",
|
||||||
|
"schema": "",
|
||||||
|
"columns": {
|
||||||
|
"id": {
|
||||||
|
"name": "id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": true,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
|
},
|
||||||
|
"user_id": {
|
||||||
|
"name": "user_id",
|
||||||
|
"type": "uuid",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"code": {
|
||||||
|
"name": "code",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true
|
||||||
|
},
|
||||||
|
"used": {
|
||||||
|
"name": "used",
|
||||||
|
"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": {
|
||||||
|
"recovery_codes_user_id_users_id_fk": {
|
||||||
|
"name": "recovery_codes_user_id_users_id_fk",
|
||||||
|
"tableFrom": "recovery_codes",
|
||||||
|
"tableTo": "users",
|
||||||
|
"columnsFrom": [
|
||||||
|
"user_id"
|
||||||
|
],
|
||||||
|
"columnsTo": [
|
||||||
|
"id"
|
||||||
|
],
|
||||||
|
"onDelete": "no action",
|
||||||
|
"onUpdate": "no action"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"compositePrimaryKeys": {},
|
||||||
|
"uniqueConstraints": {}
|
||||||
|
},
|
||||||
|
"public.roles": {
|
||||||
"name": "roles",
|
"name": "roles",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -1049,19 +1047,34 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": false
|
"notNull": true
|
||||||
},
|
},
|
||||||
"name": {
|
"name": {
|
||||||
"name": "name",
|
"name": "name",
|
||||||
"type": "text",
|
"type": "text",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": 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": {},
|
"indexes": {},
|
||||||
|
|
@ -1084,7 +1097,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"sessions": {
|
"public.sessions": {
|
||||||
"name": "sessions",
|
"name": "sessions",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -1096,7 +1109,7 @@
|
||||||
},
|
},
|
||||||
"user_id": {
|
"user_id": {
|
||||||
"name": "user_id",
|
"name": "user_id",
|
||||||
"type": "text",
|
"type": "uuid",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
|
@ -1138,7 +1151,7 @@
|
||||||
"compositePrimaryKeys": {},
|
"compositePrimaryKeys": {},
|
||||||
"uniqueConstraints": {}
|
"uniqueConstraints": {}
|
||||||
},
|
},
|
||||||
"user_roles": {
|
"public.user_roles": {
|
||||||
"name": "user_roles",
|
"name": "user_roles",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -1146,7 +1159,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -1156,16 +1170,23 @@
|
||||||
},
|
},
|
||||||
"user_id": {
|
"user_id": {
|
||||||
"name": "user_id",
|
"name": "user_id",
|
||||||
"type": "text",
|
"type": "uuid",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
"role_id": {
|
"role_id": {
|
||||||
"name": "role_id",
|
"name": "role_id",
|
||||||
"type": "text",
|
"type": "uuid",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
"primary": {
|
||||||
|
"name": "primary",
|
||||||
|
"type": "boolean",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": false,
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp",
|
||||||
|
|
@ -1221,7 +1242,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"users": {
|
"public.users": {
|
||||||
"name": "users",
|
"name": "users",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -1229,7 +1250,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -1288,6 +1310,20 @@
|
||||||
"notNull": false,
|
"notNull": false,
|
||||||
"default": "'system'"
|
"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": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp",
|
||||||
|
|
@ -1330,7 +1366,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wishlist_items": {
|
"public.wishlist_items": {
|
||||||
"name": "wishlist_items",
|
"name": "wishlist_items",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -1338,7 +1374,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -1348,13 +1385,13 @@
|
||||||
},
|
},
|
||||||
"wishlist_id": {
|
"wishlist_id": {
|
||||||
"name": "wishlist_id",
|
"name": "wishlist_id",
|
||||||
"type": "text",
|
"type": "uuid",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
"game_id": {
|
"game_id": {
|
||||||
"name": "game_id",
|
"name": "game_id",
|
||||||
"type": "text",
|
"type": "uuid",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
|
@ -1413,7 +1450,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"wishlists": {
|
"public.wishlists": {
|
||||||
"name": "wishlists",
|
"name": "wishlists",
|
||||||
"schema": "",
|
"schema": "",
|
||||||
"columns": {
|
"columns": {
|
||||||
|
|
@ -1421,7 +1458,8 @@
|
||||||
"name": "id",
|
"name": "id",
|
||||||
"type": "uuid",
|
"type": "uuid",
|
||||||
"primaryKey": true,
|
"primaryKey": true,
|
||||||
"notNull": true
|
"notNull": true,
|
||||||
|
"default": "gen_random_uuid()"
|
||||||
},
|
},
|
||||||
"cuid": {
|
"cuid": {
|
||||||
"name": "cuid",
|
"name": "cuid",
|
||||||
|
|
@ -1431,10 +1469,17 @@
|
||||||
},
|
},
|
||||||
"user_id": {
|
"user_id": {
|
||||||
"name": "user_id",
|
"name": "user_id",
|
||||||
"type": "text",
|
"type": "uuid",
|
||||||
"primaryKey": false,
|
"primaryKey": false,
|
||||||
"notNull": true
|
"notNull": true
|
||||||
},
|
},
|
||||||
|
"name": {
|
||||||
|
"name": "name",
|
||||||
|
"type": "text",
|
||||||
|
"primaryKey": false,
|
||||||
|
"notNull": true,
|
||||||
|
"default": "'My Wishlist'"
|
||||||
|
},
|
||||||
"created_at": {
|
"created_at": {
|
||||||
"name": "created_at",
|
"name": "created_at",
|
||||||
"type": "timestamp",
|
"type": "timestamp",
|
||||||
|
|
@ -1478,19 +1523,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"enums": {
|
"enums": {},
|
||||||
"external_id_type": {
|
|
||||||
"name": "external_id_type",
|
|
||||||
"values": {
|
|
||||||
"game": "game",
|
|
||||||
"category": "category",
|
|
||||||
"mechanic": "mechanic",
|
|
||||||
"publisher": "publisher",
|
|
||||||
"designer": "designer",
|
|
||||||
"artist": "artist"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"schemas": {},
|
"schemas": {},
|
||||||
"_meta": {
|
"_meta": {
|
||||||
"columns": {},
|
"columns": {},
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
|
@ -1,89 +1,12 @@
|
||||||
{
|
{
|
||||||
"version": "5",
|
"version": "7",
|
||||||
"dialect": "pg",
|
"dialect": "postgresql",
|
||||||
"entries": [
|
"entries": [
|
||||||
{
|
{
|
||||||
"idx": 0,
|
"idx": 0,
|
||||||
"version": "5",
|
"version": "7",
|
||||||
"when": 1710268038944,
|
"when": 1717548517806,
|
||||||
"tag": "0000_tricky_hitman",
|
"tag": "0000_spotty_changeling",
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 1,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1710268191378,
|
|
||||||
"tag": "0001_numerous_dragon_man",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 2,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1710268300740,
|
|
||||||
"tag": "0002_thick_lyja",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 3,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1710268371021,
|
|
||||||
"tag": "0003_mushy_madame_masque",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 4,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1710277583673,
|
|
||||||
"tag": "0004_glossy_enchantress",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 5,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1710366724519,
|
|
||||||
"tag": "0005_light_captain_marvel",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 6,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1710905422967,
|
|
||||||
"tag": "0006_wild_stone_men",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 7,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1710905572670,
|
|
||||||
"tag": "0007_large_miss_america",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 8,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1711757183163,
|
|
||||||
"tag": "0008_amusing_franklin_richards",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 9,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1711868447607,
|
|
||||||
"tag": "0009_gray_carlie_cooper",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 10,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1712271520175,
|
|
||||||
"tag": "0010_wakeful_metal_master",
|
|
||||||
"breakpoints": true
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"idx": 11,
|
|
||||||
"version": "5",
|
|
||||||
"when": 1713311328819,
|
|
||||||
"tag": "0011_charming_bucky",
|
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
|
import categoriesToExternalIds from './categoriesToExternalIds';
|
||||||
import categories_to_games from './categoriesToGames';
|
import categories_to_games from './categoriesToGames';
|
||||||
|
|
||||||
const categories = pgTable('categories', {
|
const categories = pgTable('categories', {
|
||||||
|
|
@ -10,8 +11,8 @@ const categories = pgTable('categories', {
|
||||||
.$defaultFn(() => cuid2()),
|
.$defaultFn(() => cuid2()),
|
||||||
name: text('name'),
|
name: text('name'),
|
||||||
slug: text('slug'),
|
slug: text('slug'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Categories = InferSelectModel<typeof categories>;
|
export type Categories = InferSelectModel<typeof categories>;
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ const collection_items = pgTable('collection_items', {
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => games.id, { onDelete: 'cascade' }),
|
.references(() => games.id, { onDelete: 'cascade' }),
|
||||||
times_played: integer('times_played').default(0),
|
times_played: integer('times_played').default(0),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type CollectionItems = InferSelectModel<typeof collection_items>;
|
export type CollectionItems = InferSelectModel<typeof collection_items>;
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ const collections = pgTable('collections', {
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.id, { onDelete: 'cascade' }),
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
name: text('name').notNull().default('My Collection'),
|
name: text('name').notNull().default('My Collection'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const collection_relations = relations(collections, ({ one }) => ({
|
export const collection_relations = relations(collections, ({ one }) => ({
|
||||||
|
|
|
||||||
|
|
@ -14,8 +14,8 @@ export const expansions = pgTable('expansions', {
|
||||||
game_id: uuid('game_id')
|
game_id: uuid('game_id')
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Expansions = InferSelectModel<typeof expansions>;
|
export type Expansions = InferSelectModel<typeof expansions>;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
import { index, integer, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { index, integer, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { tsvector } from '../../tsVector';
|
|
||||||
import { type InferSelectModel, relations, sql } from 'drizzle-orm';
|
import { type InferSelectModel, relations, sql } from 'drizzle-orm';
|
||||||
import categoriesToGames from './categoriesToGames';
|
import categoriesToGames from './categoriesToGames';
|
||||||
import gamesToExternalIds from './gamesToExternalIds';
|
import gamesToExternalIds from './gamesToExternalIds';
|
||||||
|
|
@ -27,22 +26,19 @@ const games = pgTable(
|
||||||
image_url: text('image_url'),
|
image_url: text('image_url'),
|
||||||
thumb_url: text('thumb_url'),
|
thumb_url: text('thumb_url'),
|
||||||
url: text('url'),
|
url: text('url'),
|
||||||
text_searchable_index: tsvector('text_searchable_index'),
|
last_sync_at: timestamp('last_sync_at'),
|
||||||
last_sync_at: timestamp('last_sync_at', {
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
withTimezone: true,
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
mode: 'date',
|
},
|
||||||
precision: 6,
|
(table) => ({
|
||||||
|
searchIndex: index('search_index').using(
|
||||||
|
'gin',
|
||||||
|
sql`(
|
||||||
|
setweight(to_tsvector('english', ${table.name}), 'A') ||
|
||||||
|
setweight(to_tsvector('english', ${table.slug}), 'B')
|
||||||
|
)`,
|
||||||
|
),
|
||||||
}),
|
}),
|
||||||
created_at: timestamp('created_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'`),
|
|
||||||
};
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
|
|
||||||
export const gameRelations = relations(games, ({ many }) => ({
|
export const gameRelations = relations(games, ({ many }) => ({
|
||||||
|
|
|
||||||
|
|
@ -10,13 +10,13 @@ export { default as roles, role_relations, type Roles } from './roles';
|
||||||
export { default as userRoles, user_role_relations, type UserRoles } from './userRoles';
|
export { default as userRoles, user_role_relations, type UserRoles } from './userRoles';
|
||||||
export { default as collections, collection_relations, type Collections } from './collections';
|
export { default as collections, collection_relations, type Collections } from './collections';
|
||||||
export {
|
export {
|
||||||
default as collectionItems,
|
default as collection_items,
|
||||||
collection_item_relations,
|
collection_item_relations,
|
||||||
type CollectionItems,
|
type CollectionItems,
|
||||||
} from './collectionItems';
|
} from './collectionItems';
|
||||||
export { default as wishlists, wishlists_relations, type Wishlists } from './wishlists';
|
export { default as wishlists, wishlists_relations, type Wishlists } from './wishlists';
|
||||||
export {
|
export {
|
||||||
default as wishlistItems,
|
default as wishlist_items,
|
||||||
wishlist_item_relations,
|
wishlist_item_relations,
|
||||||
type WishlistItems,
|
type WishlistItems,
|
||||||
} from './wishlistItems';
|
} from './wishlistItems';
|
||||||
|
|
@ -24,11 +24,11 @@ export { default as externalIds, type ExternalIds, type ExternalIdType } from '.
|
||||||
export { default as games, gameRelations, type Games } from './games';
|
export { default as games, gameRelations, type Games } from './games';
|
||||||
export { default as gamesToExternalIds } from './gamesToExternalIds';
|
export { default as gamesToExternalIds } from './gamesToExternalIds';
|
||||||
export { default as publishers, publishers_relations, type Publishers } from './publishers';
|
export { default as publishers, publishers_relations, type Publishers } from './publishers';
|
||||||
export { default as publishersToGames, publishers_to_games_relations } from './publishersToGames';
|
export { default as publishers_to_games, publishers_to_games_relations } from './publishersToGames';
|
||||||
export { default as publishersToExternalIds } from './publishersToExternalIds';
|
export { default as publishersToExternalIds } from './publishersToExternalIds';
|
||||||
export { default as categories, categories_relations, type Categories } from './categories';
|
export { default as categories, categories_relations, type Categories } from './categories';
|
||||||
export { default as categoriesToExternalIds } from './categoriesToExternalIds';
|
export { default as categoriesToExternalIds } from './categoriesToExternalIds';
|
||||||
export { default as categoriesToGames, categories_to_games_relations } from './categoriesToGames';
|
export { default as categories_to_games, categories_to_games_relations } from './categoriesToGames';
|
||||||
export { default as mechanics, mechanics_relations, type Mechanics } from './mechanics';
|
export { default as mechanics, mechanics_relations, type Mechanics } from './mechanics';
|
||||||
export { default as mechanicsToExternalIds } from './mechanicsToExternalIds';
|
export { default as mechanicsToExternalIds } from './mechanicsToExternalIds';
|
||||||
export { default as mechanicsToGames, mechanics_to_games_relations } from './mechanicsToGames';
|
export { default as mechanics_to_games, mechanics_to_games_relations } from './mechanicsToGames';
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ const mechanics = pgTable('mechanics', {
|
||||||
.$defaultFn(() => cuid2()),
|
.$defaultFn(() => cuid2()),
|
||||||
name: text('name'),
|
name: text('name'),
|
||||||
slug: text('slug'),
|
slug: text('slug'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Mechanics = InferSelectModel<typeof mechanics>;
|
export type Mechanics = InferSelectModel<typeof mechanics>;
|
||||||
|
|
|
||||||
|
|
@ -10,12 +10,8 @@ const password_reset_tokens = pgTable('password_reset_tokens', {
|
||||||
user_id: uuid('user_id')
|
user_id: uuid('user_id')
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.id, { onDelete: 'cascade' }),
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
expires_at: timestamp('expires_at', {
|
expires_at: timestamp('expires_at', { mode: 'string' }),
|
||||||
withTimezone: true,
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
mode: 'date',
|
|
||||||
precision: 6,
|
|
||||||
}),
|
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export type PasswordResetTokens = InferSelectModel<typeof password_reset_tokens>;
|
export type PasswordResetTokens = InferSelectModel<typeof password_reset_tokens>;
|
||||||
|
|
|
||||||
|
|
@ -11,8 +11,8 @@ const publishers = pgTable('publishers', {
|
||||||
.$defaultFn(() => cuid2()),
|
.$defaultFn(() => cuid2()),
|
||||||
name: text('name'),
|
name: text('name'),
|
||||||
slug: text('slug'),
|
slug: text('slug'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Publishers = InferSelectModel<typeof publishers>;
|
export type Publishers = InferSelectModel<typeof publishers>;
|
||||||
|
|
|
||||||
|
|
@ -9,8 +9,8 @@ const recovery_codes = pgTable('recovery_codes', {
|
||||||
.references(() => users.id),
|
.references(() => users.id),
|
||||||
code: text('code').notNull(),
|
code: text('code').notNull(),
|
||||||
used: boolean('used').default(false),
|
used: boolean('used').default(false),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type RecoveryCodes = InferSelectModel<typeof recovery_codes>;
|
export type RecoveryCodes = InferSelectModel<typeof recovery_codes>;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import user_roles from './userRoles';
|
import user_roles from './userRoles';
|
||||||
|
|
@ -10,6 +10,8 @@ const roles = pgTable('roles', {
|
||||||
.$defaultFn(() => cuid2())
|
.$defaultFn(() => cuid2())
|
||||||
.notNull(),
|
.notNull(),
|
||||||
name: text('name').unique().notNull(),
|
name: text('name').unique().notNull(),
|
||||||
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Roles = InferSelectModel<typeof roles>;
|
export type Roles = InferSelectModel<typeof roles>;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { boolean, pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
||||||
import users from './users';
|
import users from './users';
|
||||||
|
|
||||||
const sessions = pgTable('sessions', {
|
const sessions = pgTable('sessions', {
|
||||||
|
|
@ -12,6 +12,7 @@ const sessions = pgTable('sessions', {
|
||||||
}).notNull(),
|
}).notNull(),
|
||||||
ipCountry: text('ip_country'),
|
ipCountry: text('ip_country'),
|
||||||
ipAddress: text('ip_address'),
|
ipAddress: text('ip_address'),
|
||||||
|
isTwoFactorAuthenticated: boolean('is_two_factor_authenticated').default(false),
|
||||||
});
|
});
|
||||||
|
|
||||||
export default sessions;
|
export default sessions;
|
||||||
|
|
|
||||||
|
|
@ -16,8 +16,8 @@ const user_roles = pgTable('user_roles', {
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => roles.id, { onDelete: 'cascade' }),
|
.references(() => roles.id, { onDelete: 'cascade' }),
|
||||||
primary: boolean('primary').default(false),
|
primary: boolean('primary').default(false),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const user_role_relations = relations(user_roles, ({ one }) => ({
|
export const user_role_relations = relations(user_roles, ({ one }) => ({
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,8 @@ const users = pgTable('users', {
|
||||||
theme: text('theme').default('system'),
|
theme: text('theme').default('system'),
|
||||||
two_factor_secret: text('two_factor_secret').default(''),
|
two_factor_secret: text('two_factor_secret').default(''),
|
||||||
two_factor_enabled: boolean('two_factor_enabled').default(false),
|
two_factor_enabled: boolean('two_factor_enabled').default(false),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const user_relations = relations(users, ({ many }) => ({
|
export const user_relations = relations(users, ({ many }) => ({
|
||||||
|
|
|
||||||
|
|
@ -15,8 +15,8 @@ const wishlist_items = pgTable('wishlist_items', {
|
||||||
game_id: uuid('game_id')
|
game_id: uuid('game_id')
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => games.id, { onDelete: 'cascade' }),
|
.references(() => games.id, { onDelete: 'cascade' }),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type WishlistItems = InferSelectModel<typeof wishlist_items>;
|
export type WishlistItems = InferSelectModel<typeof wishlist_items>;
|
||||||
|
|
|
||||||
|
|
@ -12,8 +12,8 @@ const wishlists = pgTable('wishlists', {
|
||||||
.notNull()
|
.notNull()
|
||||||
.references(() => users.id, { onDelete: 'cascade' }),
|
.references(() => users.id, { onDelete: 'cascade' }),
|
||||||
name: text('name').notNull().default('My Wishlist'),
|
name: text('name').notNull().default('My Wishlist'),
|
||||||
created_at: timestamp('created_at').notNull().defaultNow(),
|
created_at: timestamp('created_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
updated_at: timestamp('updated_at').notNull().defaultNow(),
|
updated_at: timestamp('updated_at', { mode: 'string' }).notNull().defaultNow(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Wishlists = InferSelectModel<typeof wishlists>;
|
export type Wishlists = InferSelectModel<typeof wishlists>;
|
||||||
|
|
|
||||||
|
|
@ -32,11 +32,10 @@ export const authentication: Handle = async function ({ event, resolve }) {
|
||||||
if (session && session.fresh) {
|
if (session && session.fresh) {
|
||||||
const sessionCookie = lucia.createSessionCookie(session.id);
|
const sessionCookie = lucia.createSessionCookie(session.id);
|
||||||
console.log('sessionCookie', JSON.stringify(sessionCookie, null, 2));
|
console.log('sessionCookie', JSON.stringify(sessionCookie, null, 2));
|
||||||
// sveltekit types deviates from the de-facto standard
|
// sveltekit types deviates from the de-facto standard, you can use 'as any' too
|
||||||
// you can use 'as any' too
|
|
||||||
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||||
path: '.',
|
path: '.',
|
||||||
...sessionCookie.attributes
|
...sessionCookie.attributes,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
console.log('session from hooks', JSON.stringify(session, null, 2));
|
console.log('session from hooks', JSON.stringify(session, null, 2));
|
||||||
|
|
@ -45,7 +44,7 @@ export const authentication: Handle = async function ({ event, resolve }) {
|
||||||
console.log('blank sessionCookie', JSON.stringify(sessionCookie, null, 2));
|
console.log('blank sessionCookie', JSON.stringify(sessionCookie, null, 2));
|
||||||
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||||
path: '.',
|
path: '.',
|
||||||
...sessionCookie.attributes
|
...sessionCookie.attributes,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
event.locals.user = user;
|
event.locals.user = user;
|
||||||
|
|
@ -56,6 +55,6 @@ export const authentication: Handle = async function ({ event, resolve }) {
|
||||||
|
|
||||||
export const handle: Handle = sequence(
|
export const handle: Handle = sequence(
|
||||||
// Sentry.sentryHandle(),
|
// Sentry.sentryHandle(),
|
||||||
authentication
|
authentication,
|
||||||
);
|
);
|
||||||
// export const handleError = Sentry.handleErrorWithSentry();
|
// export const handleError = Sentry.handleErrorWithSentry();
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Avatar as AvatarPrimitive } from "bits-ui";
|
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = AvatarPrimitive.FallbackProps;
|
type $$Props = AvatarPrimitive.FallbackProps;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Avatar as AvatarPrimitive } from "bits-ui";
|
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = AvatarPrimitive.ImageProps;
|
type $$Props = AvatarPrimitive.ImageProps;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Avatar as AvatarPrimitive } from "bits-ui";
|
import { Avatar as AvatarPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = AvatarPrimitive.Props;
|
type $$Props = AvatarPrimitive.Props;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Button as ButtonPrimitive } from "bits-ui";
|
import { Button as ButtonPrimitive } from "bits-ui";
|
||||||
|
import { type Events, type Props, buttonVariants } from "./index.js";
|
||||||
import { cn } from "$lib/utils.js";
|
import { cn } from "$lib/utils.js";
|
||||||
import { buttonVariants, type Props, type Events } from "./index.js";
|
|
||||||
|
|
||||||
type $$Props = Props;
|
type $$Props = Props;
|
||||||
type $$Events = Events;
|
type $$Events = Events;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
import Root from "./button.svelte";
|
import { type VariantProps, tv } from "tailwind-variants";
|
||||||
import { tv, type VariantProps } from "tailwind-variants";
|
|
||||||
import type { Button as ButtonPrimitive } from "bits-ui";
|
import type { Button as ButtonPrimitive } from "bits-ui";
|
||||||
|
import Root from "./button.svelte";
|
||||||
|
|
||||||
const buttonVariants = tv({
|
const buttonVariants = tv({
|
||||||
base: "inline-flex items-center justify-center rounded-md text-sm font-medium whitespace-nowrap ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
base: "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50",
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
default: "bg-primary text-primary-foreground hover:bg-primary/90",
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cn } from "$lib/utils";
|
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLDivElement>;
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLParagraphElement>;
|
type $$Props = HTMLAttributes<HTMLParagraphElement>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLDivElement>;
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLDivElement>;
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
import { cn } from "$lib/utils";
|
import type { HeadingLevel } from "./index.js";
|
||||||
import type { HeadingLevel } from ".";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLHeadingElement> & {
|
type $$Props = HTMLAttributes<HTMLHeadingElement> & {
|
||||||
tag?: HeadingLevel;
|
tag?: HeadingLevel;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLDivElement>;
|
type $$Props = HTMLAttributes<HTMLDivElement>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Checkbox as CheckboxPrimitive } from "bits-ui";
|
import { Checkbox as CheckboxPrimitive } from "bits-ui";
|
||||||
import { Check, Minus } from "lucide-svelte";
|
import Check from "lucide-svelte/icons/check";
|
||||||
import { cn } from "$lib/utils";
|
import Minus from "lucide-svelte/icons/minus";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = CheckboxPrimitive.Props;
|
type $$Props = CheckboxPrimitive.Props;
|
||||||
type $$Events = CheckboxPrimitive.Events;
|
type $$Events = CheckboxPrimitive.Events;
|
||||||
|
|
@ -13,7 +14,7 @@
|
||||||
|
|
||||||
<CheckboxPrimitive.Root
|
<CheckboxPrimitive.Root
|
||||||
class={cn(
|
class={cn(
|
||||||
"box-content peer h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[disabled=true]:cursor-not-allowed data-[disabled=true]:opacity-50",
|
"peer box-content h-4 w-4 shrink-0 rounded-sm border border-primary ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 data-[disabled=true]:cursor-not-allowed data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground data-[disabled=true]:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
bind:checked
|
bind:checked
|
||||||
|
|
@ -21,7 +22,7 @@
|
||||||
on:click
|
on:click
|
||||||
>
|
>
|
||||||
<CheckboxPrimitive.Indicator
|
<CheckboxPrimitive.Indicator
|
||||||
class={cn("flex items-center justify-center text-current h-4 w-4")}
|
class={cn("flex h-4 w-4 items-center justify-center text-current")}
|
||||||
let:isChecked
|
let:isChecked
|
||||||
let:isIndeterminate
|
let:isIndeterminate
|
||||||
>
|
>
|
||||||
|
|
|
||||||
|
|
@ -2,5 +2,5 @@ import Root from "./checkbox.svelte";
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
//
|
//
|
||||||
Root as Checkbox
|
Root as Checkbox,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
import Check from "lucide-svelte/icons/check";
|
import Check from "lucide-svelte/icons/check";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
|
type $$Props = DropdownMenuPrimitive.CheckboxItemProps;
|
||||||
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;
|
type $$Events = DropdownMenuPrimitive.CheckboxItemEvents;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
import { cn, flyAndScale } from "$lib/utils";
|
import { cn, flyAndScale } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.ContentProps;
|
type $$Props = DropdownMenuPrimitive.ContentProps;
|
||||||
type $$Events = DropdownMenuPrimitive.ContentEvents;
|
type $$Events = DropdownMenuPrimitive.ContentEvents;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.ItemProps & {
|
type $$Props = DropdownMenuPrimitive.ItemProps & {
|
||||||
inset?: boolean;
|
inset?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.LabelProps & {
|
type $$Props = DropdownMenuPrimitive.LabelProps & {
|
||||||
inset?: boolean;
|
inset?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
import Circle from "lucide-svelte/icons/circle";
|
import Circle from "lucide-svelte/icons/circle";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.RadioItemProps;
|
type $$Props = DropdownMenuPrimitive.RadioItemProps;
|
||||||
type $$Events = DropdownMenuPrimitive.RadioItemEvents;
|
type $$Events = DropdownMenuPrimitive.RadioItemEvents;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.SeparatorProps;
|
type $$Props = DropdownMenuPrimitive.SeparatorProps;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cn } from "$lib/utils";
|
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
import { cn, flyAndScale } from "$lib/utils";
|
import { cn, flyAndScale } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.SubContentProps;
|
type $$Props = DropdownMenuPrimitive.SubContentProps;
|
||||||
type $$Events = DropdownMenuPrimitive.SubContentEvents;
|
type $$Events = DropdownMenuPrimitive.SubContentEvents;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
import { DropdownMenu as DropdownMenuPrimitive } from "bits-ui";
|
||||||
import ChevronRight from "lucide-svelte/icons/chevron-right";
|
import ChevronRight from "lucide-svelte/icons/chevron-right";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = DropdownMenuPrimitive.SubTriggerProps & {
|
type $$Props = DropdownMenuPrimitive.SubTriggerProps & {
|
||||||
inset?: boolean;
|
inset?: boolean;
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as Button from "$lib/components/ui/button";
|
import * as Button from "$lib/components/ui/button/index.js";
|
||||||
|
|
||||||
type $$Props = Button.Props;
|
type $$Props = Button.Props;
|
||||||
|
type $$Events = Button.Events;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<Button.Root type="submit" {...$$restProps}>
|
<Button.Root type="submit" on:click on:keydown {...$$restProps}>
|
||||||
<slot />
|
<slot />
|
||||||
</Button.Root>
|
</Button.Root>
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as FormPrimitive from "formsnap";
|
import * as FormPrimitive from "formsnap";
|
||||||
import { cn } from "$lib/utils";
|
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
type $$Props = HTMLAttributes<HTMLSpanElement>;
|
||||||
let className: string | undefined | null = undefined;
|
let className: string | undefined | null = undefined;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
<script lang="ts" context="module">
|
<script lang="ts" context="module">
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
import type { FormPathLeaves, SuperForm } from "sveltekit-superforms";
|
import type { FormPathLeaves, SuperForm } from "sveltekit-superforms";
|
||||||
type T = Record<string, unknown>;
|
type T = Record<string, unknown>;
|
||||||
type U = unknown;
|
type U = FormPathLeaves<T>;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPathLeaves<T>">
|
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPathLeaves<T>">
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
import * as FormPrimitive from "formsnap";
|
import * as FormPrimitive from "formsnap";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = FormPrimitive.ElementFieldProps<T, U> & HTMLAttributes<HTMLElement>;
|
type $$Props = FormPrimitive.ElementFieldProps<T, U> & HTMLAttributes<HTMLElement>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as FormPrimitive from "formsnap";
|
import * as FormPrimitive from "formsnap";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = FormPrimitive.FieldErrorsProps & {
|
type $$Props = FormPrimitive.FieldErrorsProps & {
|
||||||
errorClasses?: string | undefined | null;
|
errorClasses?: string | undefined | null;
|
||||||
|
|
|
||||||
|
|
@ -1,14 +1,13 @@
|
||||||
<script lang="ts" context="module">
|
<script lang="ts" context="module">
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
import type { FormPath, SuperForm } from "sveltekit-superforms";
|
import type { FormPath, SuperForm } from "sveltekit-superforms";
|
||||||
type T = Record<string, unknown>;
|
type T = Record<string, unknown>;
|
||||||
type U = unknown;
|
type U = FormPath<T>;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
|
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
|
||||||
import type { HTMLAttributes } from "svelte/elements";
|
import type { HTMLAttributes } from "svelte/elements";
|
||||||
import * as FormPrimitive from "formsnap";
|
import * as FormPrimitive from "formsnap";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = FormPrimitive.FieldProps<T, U> & HTMLAttributes<HTMLElement>;
|
type $$Props = FormPrimitive.FieldProps<T, U> & HTMLAttributes<HTMLElement>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
<script lang="ts" context="module">
|
<script lang="ts" context="module">
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
||||||
import type { FormPath, SuperForm } from "sveltekit-superforms";
|
import type { FormPath, SuperForm } from "sveltekit-superforms";
|
||||||
type T = Record<string, unknown>;
|
type T = Record<string, unknown>;
|
||||||
type U = unknown;
|
type U = FormPath<T>;
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
|
<script lang="ts" generics="T extends Record<string, unknown>, U extends FormPath<T>">
|
||||||
import * as FormPrimitive from "formsnap";
|
import * as FormPrimitive from "formsnap";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = FormPrimitive.FieldsetProps<T, U>;
|
type $$Props = FormPrimitive.FieldsetProps<T, U>;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import type { Label as LabelPrimitive } from "bits-ui";
|
import type { Label as LabelPrimitive } from "bits-ui";
|
||||||
import { getFormControl } from "formsnap";
|
import { getFormControl } from "formsnap";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
import { Label } from "$lib/components/ui/label";
|
import { Label } from "$lib/components/ui/label/index.js";
|
||||||
|
|
||||||
type $$Props = LabelPrimitive.Props;
|
type $$Props = LabelPrimitive.Props;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import * as FormPrimitive from "formsnap";
|
import * as FormPrimitive from "formsnap";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = FormPrimitive.LegendProps;
|
type $$Props = FormPrimitive.LegendProps;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Label as LabelPrimitive } from "bits-ui";
|
import { Label as LabelPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = LabelPrimitive.Props;
|
type $$Props = LabelPrimitive.Props;
|
||||||
type $$Events = LabelPrimitive.Events;
|
type $$Events = LabelPrimitive.Events;
|
||||||
|
|
|
||||||
|
|
@ -30,5 +30,5 @@ export {
|
||||||
Value as SelectValue,
|
Value as SelectValue,
|
||||||
Content as SelectContent,
|
Content as SelectContent,
|
||||||
Trigger as SelectTrigger,
|
Trigger as SelectTrigger,
|
||||||
Separator as SelectSeparator
|
Separator as SelectSeparator,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Select as SelectPrimitive } from "bits-ui";
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
import { cn, flyAndScale } from "$lib/utils";
|
|
||||||
import { scale } from "svelte/transition";
|
import { scale } from "svelte/transition";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = SelectPrimitive.ContentProps;
|
type $$Props = SelectPrimitive.ContentProps;
|
||||||
type $$Events = SelectPrimitive.ContentEvents;
|
type $$Events = SelectPrimitive.ContentEvents;
|
||||||
|
|
@ -13,7 +13,7 @@
|
||||||
export let outTransitionConfig: $$Props["outTransitionConfig"] = {
|
export let outTransitionConfig: $$Props["outTransitionConfig"] = {
|
||||||
start: 0.95,
|
start: 0.95,
|
||||||
opacity: 0,
|
opacity: 0,
|
||||||
duration: 50
|
duration: 50,
|
||||||
};
|
};
|
||||||
|
|
||||||
let className: $$Props["class"] = undefined;
|
let className: $$Props["class"] = undefined;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { cn } from "$lib/utils";
|
import Check from "lucide-svelte/icons/check";
|
||||||
import { Select as SelectPrimitive } from "bits-ui";
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
import { Check } from "lucide-svelte";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = SelectPrimitive.ItemProps;
|
type $$Props = SelectPrimitive.ItemProps;
|
||||||
type $$Events = SelectPrimitive.ItemEvents;
|
type $$Events = SelectPrimitive.ItemEvents;
|
||||||
|
|
@ -18,7 +18,7 @@
|
||||||
{disabled}
|
{disabled}
|
||||||
{label}
|
{label}
|
||||||
class={cn(
|
class={cn(
|
||||||
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:pointer-events-none data-[disabled]:opacity-50",
|
"relative flex w-full cursor-default select-none items-center rounded-sm py-1.5 pl-8 pr-2 text-sm outline-none data-[disabled]:pointer-events-none data-[highlighted]:bg-accent data-[highlighted]:text-accent-foreground data-[disabled]:opacity-50",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
|
|
@ -34,5 +34,7 @@
|
||||||
<Check class="h-4 w-4" />
|
<Check class="h-4 w-4" />
|
||||||
</SelectPrimitive.ItemIndicator>
|
</SelectPrimitive.ItemIndicator>
|
||||||
</span>
|
</span>
|
||||||
<slot />
|
<slot>
|
||||||
|
{label || value}
|
||||||
|
</slot>
|
||||||
</SelectPrimitive.Item>
|
</SelectPrimitive.Item>
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Select as SelectPrimitive } from "bits-ui";
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = SelectPrimitive.LabelProps;
|
type $$Props = SelectPrimitive.LabelProps;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Select as SelectPrimitive } from "bits-ui";
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = SelectPrimitive.SeparatorProps;
|
type $$Props = SelectPrimitive.SeparatorProps;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Select as SelectPrimitive } from "bits-ui";
|
import { Select as SelectPrimitive } from "bits-ui";
|
||||||
import { ChevronDown } from "lucide-svelte";
|
import ChevronDown from "lucide-svelte/icons/chevron-down";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = SelectPrimitive.TriggerProps;
|
type $$Props = SelectPrimitive.TriggerProps;
|
||||||
type $$Events = SelectPrimitive.TriggerEvents;
|
type $$Events = SelectPrimitive.TriggerEvents;
|
||||||
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
<SelectPrimitive.Trigger
|
<SelectPrimitive.Trigger
|
||||||
class={cn(
|
class={cn(
|
||||||
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-transparent px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1 line-clamp-1 truncate",
|
"flex h-10 w-full items-center justify-between rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background placeholder:text-muted-foreground focus:outline-none focus:ring-2 focus:ring-ring focus:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 [&>span]:line-clamp-1",
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@ import Root from "./switch.svelte";
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
//
|
//
|
||||||
Root as Switch
|
Root as Switch,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Switch as SwitchPrimitive } from "bits-ui";
|
import { Switch as SwitchPrimitive } from "bits-ui";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = SwitchPrimitive.Props;
|
type $$Props = SwitchPrimitive.Props;
|
||||||
|
type $$Events = SwitchPrimitive.Events;
|
||||||
|
|
||||||
let className: $$Props["class"] = undefined;
|
let className: $$Props["class"] = undefined;
|
||||||
export let checked: $$Props["checked"] = undefined;
|
export let checked: $$Props["checked"] = undefined;
|
||||||
|
|
@ -16,6 +17,8 @@
|
||||||
className
|
className
|
||||||
)}
|
)}
|
||||||
{...$$restProps}
|
{...$$restProps}
|
||||||
|
on:click
|
||||||
|
on:keydown
|
||||||
>
|
>
|
||||||
<SwitchPrimitive.Thumb
|
<SwitchPrimitive.Thumb
|
||||||
class={cn(
|
class={cn(
|
||||||
|
|
|
||||||
|
|
@ -1,24 +1,24 @@
|
||||||
|
import { type VariantProps, tv } from "tailwind-variants";
|
||||||
import Root from "./toggle.svelte";
|
import Root from "./toggle.svelte";
|
||||||
import { tv, type VariantProps } from "tailwind-variants";
|
|
||||||
|
|
||||||
export const toggleVariants = tv({
|
export const toggleVariants = tv({
|
||||||
base: "inline-flex items-center justify-center rounded-md text-sm font-medium transition-colors data-[state=on]:bg-accent data-[state=on]:text-accent-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 ring-offset-background hover:bg-muted hover:text-muted-foreground",
|
base: "inline-flex items-center justify-center rounded-md text-sm font-medium ring-offset-background transition-colors hover:bg-muted hover:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=on]:bg-accent data-[state=on]:text-accent-foreground",
|
||||||
variants: {
|
variants: {
|
||||||
variant: {
|
variant: {
|
||||||
default: "bg-transparent",
|
default: "bg-transparent",
|
||||||
outline:
|
outline:
|
||||||
"bg-transparent border border-input hover:bg-accent hover:text-accent-foreground"
|
"border border-input bg-transparent hover:bg-accent hover:text-accent-foreground",
|
||||||
},
|
},
|
||||||
size: {
|
size: {
|
||||||
default: "h-10 px-3",
|
default: "h-10 px-3",
|
||||||
sm: "h-9 px-2.5",
|
sm: "h-9 px-2.5",
|
||||||
lg: "h-11 px-5"
|
lg: "h-11 px-5",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
defaultVariants: {
|
defaultVariants: {
|
||||||
variant: "default",
|
variant: "default",
|
||||||
size: "default"
|
size: "default",
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export type Variant = VariantProps<typeof toggleVariants>["variant"];
|
export type Variant = VariantProps<typeof toggleVariants>["variant"];
|
||||||
|
|
@ -27,5 +27,5 @@ export type Size = VariantProps<typeof toggleVariants>["size"];
|
||||||
export {
|
export {
|
||||||
Root,
|
Root,
|
||||||
//
|
//
|
||||||
Root as Toggle
|
Root as Toggle,
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import { Toggle as TogglePrimitive } from "bits-ui";
|
import { Toggle as TogglePrimitive } from "bits-ui";
|
||||||
import { toggleVariants, type Variant, type Size } from ".";
|
import { type Size, type Variant, toggleVariants } from "./index.js";
|
||||||
import { cn } from "$lib/utils";
|
import { cn } from "$lib/utils.js";
|
||||||
|
|
||||||
type $$Props = TogglePrimitive.Props & {
|
type $$Props = TogglePrimitive.Props & {
|
||||||
variant?: Variant;
|
variant?: Variant;
|
||||||
|
|
|
||||||
15
src/lib/components/ui/tooltip/index.ts
Normal file
15
src/lib/components/ui/tooltip/index.ts
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
import { Tooltip as TooltipPrimitive } from "bits-ui";
|
||||||
|
import Content from "./tooltip-content.svelte";
|
||||||
|
|
||||||
|
const Root = TooltipPrimitive.Root;
|
||||||
|
const Trigger = TooltipPrimitive.Trigger;
|
||||||
|
|
||||||
|
export {
|
||||||
|
Root,
|
||||||
|
Trigger,
|
||||||
|
Content,
|
||||||
|
//
|
||||||
|
Root as Tooltip,
|
||||||
|
Content as TooltipContent,
|
||||||
|
Trigger as TooltipTrigger,
|
||||||
|
};
|
||||||
28
src/lib/components/ui/tooltip/tooltip-content.svelte
Normal file
28
src/lib/components/ui/tooltip/tooltip-content.svelte
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Tooltip as TooltipPrimitive } from "bits-ui";
|
||||||
|
import { cn, flyAndScale } from "$lib/utils.js";
|
||||||
|
|
||||||
|
type $$Props = TooltipPrimitive.ContentProps;
|
||||||
|
|
||||||
|
let className: $$Props["class"] = undefined;
|
||||||
|
export let sideOffset: $$Props["sideOffset"] = 4;
|
||||||
|
export let transition: $$Props["transition"] = flyAndScale;
|
||||||
|
export let transitionConfig: $$Props["transitionConfig"] = {
|
||||||
|
y: 8,
|
||||||
|
duration: 150,
|
||||||
|
};
|
||||||
|
export { className as class };
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<TooltipPrimitive.Content
|
||||||
|
{transition}
|
||||||
|
{transitionConfig}
|
||||||
|
{sideOffset}
|
||||||
|
class={cn(
|
||||||
|
"z-50 overflow-hidden rounded-md border bg-popover px-3 py-1.5 text-sm text-popover-foreground shadow-md",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...$$restProps}
|
||||||
|
>
|
||||||
|
<slot />
|
||||||
|
</TooltipPrimitive.Content>
|
||||||
|
|
@ -20,6 +20,7 @@ export const lucia = new Lucia(adapter, {
|
||||||
return {
|
return {
|
||||||
ipCountry: attributes.ip_country,
|
ipCountry: attributes.ip_country,
|
||||||
ipAddress: attributes.ip_address,
|
ipAddress: attributes.ip_address,
|
||||||
|
isTwoFactorAuthenticated: attributes.isTwoFactorAuthenticated,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
getUserAttributes: (attributes) => {
|
getUserAttributes: (attributes) => {
|
||||||
|
|
@ -53,6 +54,7 @@ declare module 'lucia' {
|
||||||
interface DatabaseSessionAttributes {
|
interface DatabaseSessionAttributes {
|
||||||
ip_country: string;
|
ip_country: string;
|
||||||
ip_address: string;
|
ip_address: string;
|
||||||
|
isTwoFactorAuthenticated: boolean;
|
||||||
}
|
}
|
||||||
interface DatabaseUserAttributes {
|
interface DatabaseUserAttributes {
|
||||||
username: string;
|
username: string;
|
||||||
|
|
|
||||||
|
|
@ -23,5 +23,8 @@ export const signInSchema = z.object({
|
||||||
.min(3, { message: 'Username must be at least 3 characters' })
|
.min(3, { message: 'Username must be at least 3 characters' })
|
||||||
.max(50, { message: 'Username must be less than 50 characters' }),
|
.max(50, { message: 'Username must be less than 50 characters' }),
|
||||||
password: z.string({ required_error: 'Password is required' }).trim(),
|
password: z.string({ required_error: 'Password is required' }).trim(),
|
||||||
totpToken: z.string().trim().min(6).max(10).optional(),
|
});
|
||||||
|
|
||||||
|
export const totpSchema = z.object({
|
||||||
|
totpToken: z.string().trim().min(6).max(10),
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
import { IntegerString } from '$lib/zodValidation';
|
||||||
|
|
||||||
export type ListGame = {
|
export type ListGame = {
|
||||||
id: string;
|
id: string;
|
||||||
|
|
@ -13,7 +14,7 @@ export type ListGame = {
|
||||||
};
|
};
|
||||||
|
|
||||||
export const modifyListGameSchema = z.object({
|
export const modifyListGameSchema = z.object({
|
||||||
id: z.string()
|
id: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ModifyListGame = typeof modifyListGameSchema;
|
export type ModifyListGame = typeof modifyListGameSchema;
|
||||||
|
|
@ -21,24 +22,62 @@ export type ModifyListGame = typeof modifyListGameSchema;
|
||||||
export const userSchema = z.object({
|
export const userSchema = z.object({
|
||||||
firstName: z.string().trim().optional(),
|
firstName: z.string().trim().optional(),
|
||||||
lastName: z.string().trim().optional(),
|
lastName: z.string().trim().optional(),
|
||||||
email: z.string()
|
email: z.string().trim().max(64, { message: 'Email must be less than 64 characters' }).optional(),
|
||||||
.trim()
|
|
||||||
.max(64, { message: 'Email must be less than 64 characters' })
|
|
||||||
.optional(),
|
|
||||||
username: z
|
username: z
|
||||||
.string()
|
.string()
|
||||||
.trim()
|
.trim()
|
||||||
.min(3, { message: 'Username must be at least 3 characters' })
|
.min(3, { message: 'Username must be at least 3 characters' })
|
||||||
.max(50, { message: 'Username must be less than 50 characters' }),
|
.max(50, { message: 'Username must be less than 50 characters' }),
|
||||||
password: z
|
password: z.string({ required_error: 'Password is required' }).trim(),
|
||||||
.string({ required_error: 'Password is required' })
|
confirm_password: z.string({ required_error: 'Confirm Password is required' }).trim(),
|
||||||
.trim(),
|
|
||||||
confirm_password: z
|
|
||||||
.string({ required_error: 'Confirm Password is required' })
|
|
||||||
.trim(),
|
|
||||||
verified: z.boolean().default(false),
|
verified: z.boolean().default(false),
|
||||||
token: z.string().optional(),
|
token: z.string().optional(),
|
||||||
receiveEmail: z.boolean().default(false),
|
receiveEmail: z.boolean().default(false),
|
||||||
createdAt: z.date().optional(),
|
createdAt: z.date().optional(),
|
||||||
updatedAt: z.date().optional()
|
updatedAt: z.date().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export const PaginationSchema = z.object({
|
||||||
|
skip: z.number().min(0).default(0),
|
||||||
|
limit: z.number().min(10).max(100).default(10),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type PaginationSchema = typeof PaginationSchema;
|
||||||
|
|
||||||
|
export const FilterSchema = z.object({
|
||||||
|
status: z.string(),
|
||||||
|
author: z.string(),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type FilterSchema = typeof FilterSchema;
|
||||||
|
|
||||||
|
export const SortSchema = z
|
||||||
|
.object({
|
||||||
|
sort: z.string(),
|
||||||
|
order: z.enum(['asc', 'desc']).default('asc'),
|
||||||
|
minAge: IntegerString(z.number().min(1).max(120).optional()),
|
||||||
|
minPlayers: IntegerString(z.number().min(1).max(50).optional()),
|
||||||
|
maxPlayers: IntegerString(z.number().min(1).max(50).optional()),
|
||||||
|
})
|
||||||
|
.superRefine(({ minPlayers, maxPlayers }, ctx) => {
|
||||||
|
console.log({ minPlayers, maxPlayers });
|
||||||
|
if (minPlayers && maxPlayers && minPlayers > maxPlayers) {
|
||||||
|
ctx.addIssue({
|
||||||
|
code: 'custom',
|
||||||
|
message: 'Min Players must be smaller than Max Players',
|
||||||
|
path: ['minPlayers'],
|
||||||
|
});
|
||||||
|
ctx.addIssue({
|
||||||
|
code: 'custom',
|
||||||
|
message: 'Min Players must be smaller than Max Players',
|
||||||
|
path: ['maxPlayers'],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
export const SearchSchema = z.object({
|
||||||
|
q: z.string(),
|
||||||
|
exact: z.preprocess((a) => Boolean(a), z.boolean().default(true)),
|
||||||
|
});
|
||||||
|
|
||||||
|
export type SearchSchema = typeof SearchSchema;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,7 @@ export const BoardGameSearch = z.object({
|
||||||
minAge: z.number(),
|
minAge: z.number(),
|
||||||
maxAge: z.number(),
|
maxAge: z.number(),
|
||||||
minPlayers: z.number(),
|
minPlayers: z.number(),
|
||||||
maxPlayers: z.number()
|
maxPlayers: z.number(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const saved_game_schema = z.object({
|
export const saved_game_schema = z.object({
|
||||||
|
|
@ -13,18 +13,18 @@ export const saved_game_schema = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
thumb_url: z.string(),
|
thumb_url: z.string(),
|
||||||
players: z.string(),
|
players: z.string(),
|
||||||
playtime: IntegerString(z.number())
|
playtime: IntegerString(z.number()),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const list_game_request_schema = z.object({
|
export const list_game_request_schema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
externalId: z.string()
|
externalId: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type ListGameSchema = typeof list_game_request_schema;
|
export type ListGameSchema = typeof list_game_request_schema;
|
||||||
|
|
||||||
// https://github.com/colinhacks/zod/discussions/330
|
// https://github.com/colinhacks/zod/discussions/330
|
||||||
function IntegerString<schema extends ZodNumber | ZodOptional<ZodNumber>>(schema: schema) {
|
export function IntegerString<schema extends ZodNumber | ZodOptional<ZodNumber>>(schema: schema) {
|
||||||
return z.preprocess(
|
return z.preprocess(
|
||||||
(value) =>
|
(value) =>
|
||||||
typeof value === 'string'
|
typeof value === 'string'
|
||||||
|
|
@ -32,7 +32,7 @@ function IntegerString<schema extends ZodNumber | ZodOptional<ZodNumber>>(schema
|
||||||
: typeof value === 'number'
|
: typeof value === 'number'
|
||||||
? value
|
? value
|
||||||
: undefined,
|
: undefined,
|
||||||
schema
|
schema,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -47,7 +47,7 @@ const Search = z.object({
|
||||||
sort: z.enum(['asc', 'desc']).optional(),
|
sort: z.enum(['asc', 'desc']).optional(),
|
||||||
sortBy: z.enum(['name', 'min_players', 'max_players', 'min_age', 'times_played']).optional(),
|
sortBy: z.enum(['name', 'min_players', 'max_players', 'min_age', 'times_played']).optional(),
|
||||||
limit: z.number().min(10).max(100).default(10),
|
limit: z.number().min(10).max(100).default(10),
|
||||||
skip: z.number().min(0).default(0)
|
skip: z.number().min(0).default(0),
|
||||||
});
|
});
|
||||||
|
|
||||||
// minAge: z
|
// minAge: z
|
||||||
|
|
@ -71,7 +71,7 @@ export const search_schema = z
|
||||||
sort: z.enum(['asc', 'desc']).optional(),
|
sort: z.enum(['asc', 'desc']).optional(),
|
||||||
order: z.enum(['name', 'min_players', 'max_players', 'min_age', 'times_played']).optional(),
|
order: z.enum(['name', 'min_players', 'max_players', 'min_age', 'times_played']).optional(),
|
||||||
limit: z.number().min(10).max(100).default(10),
|
limit: z.number().min(10).max(100).default(10),
|
||||||
skip: z.number().min(0).default(0)
|
skip: z.number().min(0).default(0),
|
||||||
})
|
})
|
||||||
.superRefine(
|
.superRefine(
|
||||||
({ minPlayers, maxPlayers, minAge, exactMinAge, exactMinPlayers, exactMaxPlayers }, ctx) => {
|
({ minPlayers, maxPlayers, minAge, exactMinAge, exactMinPlayers, exactMaxPlayers }, ctx) => {
|
||||||
|
|
@ -80,12 +80,12 @@ export const search_schema = z
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: 'custom',
|
code: 'custom',
|
||||||
message: 'Min Players must be smaller than Max Players',
|
message: 'Min Players must be smaller than Max Players',
|
||||||
path: ['minPlayers']
|
path: ['minPlayers'],
|
||||||
});
|
});
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: 'custom',
|
code: 'custom',
|
||||||
message: 'Min Players must be smaller than Max Players',
|
message: 'Min Players must be smaller than Max Players',
|
||||||
path: ['maxPlayers']
|
path: ['maxPlayers'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -93,7 +93,7 @@ export const search_schema = z
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: 'custom',
|
code: 'custom',
|
||||||
message: 'Min Age required when searching for exact min age',
|
message: 'Min Age required when searching for exact min age',
|
||||||
path: ['minAge']
|
path: ['minAge'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -101,7 +101,7 @@ export const search_schema = z
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: 'custom',
|
code: 'custom',
|
||||||
message: 'Min Players required when searching for exact min players',
|
message: 'Min Players required when searching for exact min players',
|
||||||
path: ['minPlayers']
|
path: ['minPlayers'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -109,20 +109,20 @@ export const search_schema = z
|
||||||
ctx.addIssue({
|
ctx.addIssue({
|
||||||
code: 'custom',
|
code: 'custom',
|
||||||
message: 'Max Players required when searching for exact max players',
|
message: 'Max Players required when searching for exact max players',
|
||||||
path: ['maxPlayers']
|
path: ['maxPlayers'],
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
export type SearchSchema = typeof search_schema;
|
export type SearchSchema = typeof search_schema;
|
||||||
|
|
||||||
export const BggForm = z.object({
|
export const BggForm = z.object({
|
||||||
link: z.string().trim().startsWith('https://boardgamegeek.com/boardgame/')
|
link: z.string().trim().startsWith('https://boardgamegeek.com/boardgame/'),
|
||||||
})
|
});
|
||||||
|
|
||||||
export const collection_search_schema = Search.extend({
|
export const collection_search_schema = Search.extend({
|
||||||
collection_id: z.string()
|
collection_id: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type CollectionSearchSchema = typeof collection_search_schema;
|
export type CollectionSearchSchema = typeof collection_search_schema;
|
||||||
|
|
@ -175,7 +175,7 @@ export const search_result_schema = z.object({
|
||||||
lt_reddit_count: z.number(),
|
lt_reddit_count: z.number(),
|
||||||
lt_reddit_week_count: z.number(),
|
lt_reddit_week_count: z.number(),
|
||||||
lt_reddit_day_count: z.number(),
|
lt_reddit_day_count: z.number(),
|
||||||
fields: z.string()
|
fields: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export type SearchResultSchema = typeof search_result_schema;
|
export type SearchResultSchema = typeof search_result_schema;
|
||||||
|
|
@ -199,18 +199,18 @@ export const game_schema = z.object({
|
||||||
min_age: z.number(),
|
min_age: z.number(),
|
||||||
description: z.string(),
|
description: z.string(),
|
||||||
players: z.string(),
|
players: z.string(),
|
||||||
playtime: z.string()
|
playtime: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const category_schema = z.object({
|
export const category_schema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string()
|
name: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const mechanics_schema = z.object({
|
export const mechanics_schema = z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
description: z.string().optional()
|
description: z.string().optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const gameSchema = z.object({
|
const gameSchema = z.object({
|
||||||
|
|
@ -234,24 +234,24 @@ const gameSchema = z.object({
|
||||||
.array(
|
.array(
|
||||||
z.object({
|
z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string()
|
name: z.string(),
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
publishers: z
|
publishers: z
|
||||||
.array(
|
.array(
|
||||||
z.object({
|
z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string()
|
name: z.string(),
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
artists: z
|
artists: z
|
||||||
.array(
|
.array(
|
||||||
z.object({
|
z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string()
|
name: z.string(),
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
names: z.array(z.string()).optional(),
|
names: z.array(z.string()).optional(),
|
||||||
|
|
@ -260,26 +260,26 @@ const gameSchema = z.object({
|
||||||
z.object({
|
z.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
year_published: z.number().optional()
|
year_published: z.number().optional(),
|
||||||
})
|
}),
|
||||||
)
|
)
|
||||||
.optional(),
|
.optional(),
|
||||||
primary_publisher: z
|
primary_publisher: z
|
||||||
.object({
|
.object({
|
||||||
id: z.string(),
|
id: z.string(),
|
||||||
name: z.string()
|
name: z.string(),
|
||||||
})
|
})
|
||||||
.optional()
|
.optional(),
|
||||||
});
|
});
|
||||||
|
|
||||||
const searchResultSchema = z.object({
|
const searchResultSchema = z.object({
|
||||||
games: z.array(gameSchema),
|
games: z.array(gameSchema),
|
||||||
count: z.number()
|
count: z.number(),
|
||||||
});
|
});
|
||||||
|
|
||||||
export const WishlistSchema = z.object({
|
export const WishlistSchema = z.object({
|
||||||
name: z.string(),
|
name: z.string(),
|
||||||
id: z.string()
|
id: z.string(),
|
||||||
});
|
});
|
||||||
|
|
||||||
// export const game_raw_schema_json = zodToJsonSchema(game_schema, {
|
// export const game_raw_schema_json = zodToJsonSchema(game_schema, {
|
||||||
|
|
|
||||||
|
|
@ -59,15 +59,16 @@ export const actions: Actions = {
|
||||||
console.log('user', JSON.stringify(user, null, 2));
|
console.log('user', JSON.stringify(user, null, 2));
|
||||||
|
|
||||||
if (!user?.hashed_password) {
|
if (!user?.hashed_password) {
|
||||||
|
console.log('invalid username/password');
|
||||||
form.data.password = '';
|
form.data.password = '';
|
||||||
return setError(form, '', 'Your username or password is incorrect.');
|
return setError(form, 'password', 'Your username or password is incorrect.');
|
||||||
}
|
}
|
||||||
|
|
||||||
const validPassword = await new Argon2id().verify(user.hashed_password, password);
|
const validPassword = await new Argon2id().verify(user.hashed_password, password);
|
||||||
if (!validPassword) {
|
if (!validPassword) {
|
||||||
console.log('invalid password');
|
console.log('invalid password');
|
||||||
form.data.password = '';
|
form.data.password = '';
|
||||||
return setError(form, '', 'Your username or password is incorrect.');
|
return setError(form, 'password', 'Your username or password is incorrect.');
|
||||||
}
|
}
|
||||||
|
|
||||||
// await db
|
// await db
|
||||||
|
|
@ -101,11 +102,13 @@ export const actions: Actions = {
|
||||||
const usedRecoveryCode = await checkRecoveryCode(form?.data?.totpToken, user.id);
|
const usedRecoveryCode = await checkRecoveryCode(form?.data?.totpToken, user.id);
|
||||||
if (!usedRecoveryCode) {
|
if (!usedRecoveryCode) {
|
||||||
console.log('invalid TOTP code');
|
console.log('invalid TOTP code');
|
||||||
form.errors.totpToken = ['Invalid code'];
|
form.data.password = '';
|
||||||
return fail(400, {
|
// form.errors.totpToken = ['Invalid code'];
|
||||||
form,
|
return setError(form, 'totpToken', 'Invalid code.');
|
||||||
twoFactorRequired: true,
|
// return fail(400, {
|
||||||
});
|
// form,
|
||||||
|
// twoFactorRequired: true,
|
||||||
|
// });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -114,6 +117,7 @@ export const actions: Actions = {
|
||||||
session = await lucia.createSession(user.id, {
|
session = await lucia.createSession(user.id, {
|
||||||
ip_country: locals.country,
|
ip_country: locals.country,
|
||||||
ip_address: locals.ip,
|
ip_address: locals.ip,
|
||||||
|
isTwoFactorAuthenticated: false,
|
||||||
});
|
});
|
||||||
console.log('logging in session', session);
|
console.log('logging in session', session);
|
||||||
sessionCookie = lucia.createSessionCookie(session.id);
|
sessionCookie = lucia.createSessionCookie(session.id);
|
||||||
|
|
|
||||||
153
src/routes/(auth)/totp/+page.server.ts
Normal file
153
src/routes/(auth)/totp/+page.server.ts
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
import { fail, error, type Actions } from '@sveltejs/kit';
|
||||||
|
import { and, eq } from 'drizzle-orm';
|
||||||
|
import { Argon2id } from 'oslo/password';
|
||||||
|
import { decodeHex } from 'oslo/encoding';
|
||||||
|
import { TOTPController } from 'oslo/otp';
|
||||||
|
import { zod } from 'sveltekit-superforms/adapters';
|
||||||
|
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||||
|
import { redirect } from 'sveltekit-flash-message/server';
|
||||||
|
import { RateLimiter } from 'sveltekit-rate-limiter/server';
|
||||||
|
import db from '../../../db';
|
||||||
|
import { lucia } from '$lib/server/auth';
|
||||||
|
import { totpSchema } from '$lib/validations/auth';
|
||||||
|
import { users, recovery_codes } from '$db/schema';
|
||||||
|
import type { PageServerLoad } from './$types';
|
||||||
|
|
||||||
|
export const load: PageServerLoad = async (event) => {
|
||||||
|
if (event.locals.user) {
|
||||||
|
const user = event.locals.user;
|
||||||
|
const dbUser = await db.query.users.findFirst({
|
||||||
|
where: eq(users.username, user.username),
|
||||||
|
});
|
||||||
|
|
||||||
|
const session = event.locals.session;
|
||||||
|
const isTwoFactorAuthenticated = session?.isTwoFactorAuthenticated;
|
||||||
|
|
||||||
|
if (isTwoFactorAuthenticated && dbUser?.two_factor_enabled && dbUser?.two_factor_secret) {
|
||||||
|
const message = { type: 'success', message: 'You are already signed in' } as const;
|
||||||
|
throw redirect('/', message, event);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = await superValidate(event, zod(totpSchema));
|
||||||
|
|
||||||
|
return {
|
||||||
|
form,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
const limiter = new RateLimiter({
|
||||||
|
// A rate is defined by [number, unit]
|
||||||
|
IPUA: [5, 'm'],
|
||||||
|
});
|
||||||
|
|
||||||
|
export const actions: Actions = {
|
||||||
|
default: async (event) => {
|
||||||
|
if (await limiter.isLimited(event)) {
|
||||||
|
throw error(429);
|
||||||
|
}
|
||||||
|
|
||||||
|
const { locals } = event;
|
||||||
|
const session = locals.session;
|
||||||
|
const user = locals.user;
|
||||||
|
|
||||||
|
if (!user || !session) {
|
||||||
|
throw fail(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
const dbUser = await db.query.users.findFirst({
|
||||||
|
where: eq(users.username, user.username),
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!dbUser) {
|
||||||
|
throw fail(401);
|
||||||
|
}
|
||||||
|
|
||||||
|
const isTwoFactorAuthenticated = session?.isTwoFactorAuthenticated;
|
||||||
|
|
||||||
|
if (isTwoFactorAuthenticated && dbUser?.two_factor_enabled && dbUser?.two_factor_secret) {
|
||||||
|
const message = { type: 'success', message: 'You are already signed in' } as const;
|
||||||
|
throw redirect('/', message, event);
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = await superValidate(event, zod(totpSchema));
|
||||||
|
|
||||||
|
if (!form.valid) {
|
||||||
|
form.data.totpToken = '';
|
||||||
|
return fail(400, {
|
||||||
|
form,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
let sessionCookie;
|
||||||
|
try {
|
||||||
|
const totpToken = form?.data?.totpToken;
|
||||||
|
|
||||||
|
if (dbUser?.two_factor_enabled && dbUser?.two_factor_secret && !totpToken) {
|
||||||
|
return fail(400, {
|
||||||
|
form,
|
||||||
|
});
|
||||||
|
} else if (dbUser?.two_factor_enabled && dbUser?.two_factor_secret && totpToken) {
|
||||||
|
console.log('totpToken',totpToken);
|
||||||
|
const validOTP = await new TOTPController().verify(
|
||||||
|
form.data.totpToken,
|
||||||
|
decodeHex(dbUser.two_factor_secret),
|
||||||
|
);
|
||||||
|
console.log('validOTP', validOTP);
|
||||||
|
|
||||||
|
if (!validOTP) {
|
||||||
|
console.log('invalid TOTP code check for recovery codes');
|
||||||
|
const usedRecoveryCode = await checkRecoveryCode(totpToken, dbUser.id);
|
||||||
|
if (!usedRecoveryCode) {
|
||||||
|
console.log('invalid TOTP code');
|
||||||
|
return setError(form, 'totpToken', 'Invalid code.');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
console.log('ip', locals.ip);
|
||||||
|
console.log('country', locals.country);
|
||||||
|
await lucia.invalidateSession(session.id);
|
||||||
|
const newSession = await lucia.createSession(dbUser.id, {
|
||||||
|
ip_country: locals.country,
|
||||||
|
ip_address: locals.ip,
|
||||||
|
isTwoFactorAuthenticated: true,
|
||||||
|
});
|
||||||
|
console.log('logging in session', newSession);
|
||||||
|
sessionCookie = lucia.createSessionCookie(newSession.id);
|
||||||
|
console.log('logging in session cookie', sessionCookie);
|
||||||
|
} catch (e) {
|
||||||
|
// TODO: need to return error message to the client
|
||||||
|
console.error(e);
|
||||||
|
return setError(form, 'totpToken', 'Error verifying TOTP code.');
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log('setting session cookie', sessionCookie);
|
||||||
|
event.cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||||
|
path: '.',
|
||||||
|
...sessionCookie.attributes,
|
||||||
|
});
|
||||||
|
|
||||||
|
form.data.totpToken = '';
|
||||||
|
const message = { type: 'success', message: 'Signed In!' } as const;
|
||||||
|
redirect(302, '/', message, event);
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async function checkRecoveryCode(recoveryCode: string, userId: string) {
|
||||||
|
const userRecoveryCodes = await db.query.recovery_codes.findMany({
|
||||||
|
where: and(eq(recovery_codes.used, false), eq(recovery_codes.userId, userId)),
|
||||||
|
});
|
||||||
|
for (const code of userRecoveryCodes) {
|
||||||
|
const validRecoveryCode = await new Argon2id().verify(code.code, recoveryCode);
|
||||||
|
if (validRecoveryCode) {
|
||||||
|
await db
|
||||||
|
.update(recovery_codes)
|
||||||
|
.set({
|
||||||
|
used: true,
|
||||||
|
})
|
||||||
|
.where(eq(recovery_codes.id, code.id));
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
123
src/routes/(auth)/totp/+page.svelte
Normal file
123
src/routes/(auth)/totp/+page.svelte
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { zodClient } from 'sveltekit-superforms/adapters';
|
||||||
|
import { superForm } from 'sveltekit-superforms/client';
|
||||||
|
import * as flashModule from 'sveltekit-flash-message/client';
|
||||||
|
import { AlertCircle } from "lucide-svelte";
|
||||||
|
import { signInSchema } from '$lib/validations/auth';
|
||||||
|
import * as Form from '$lib/components/ui/form';
|
||||||
|
import { Label } from '$components/ui/label';
|
||||||
|
import { Input } from '$components/ui/input';
|
||||||
|
import { Button } from '$components/ui/button';
|
||||||
|
import * as Alert from "$components/ui/alert";
|
||||||
|
import { boredState } from '$lib/stores/boredState.js';
|
||||||
|
|
||||||
|
export let data;
|
||||||
|
export let form;
|
||||||
|
|
||||||
|
const superLoginForm = superForm(data.form, {
|
||||||
|
onSubmit: () => boredState.update((n) => ({ ...n, loading: true })),
|
||||||
|
onResult: () => boredState.update((n) => ({ ...n, loading: false })),
|
||||||
|
flashMessage: {
|
||||||
|
module: flashModule,
|
||||||
|
onError: ({ result, message }) => {
|
||||||
|
// Error handling for the flash message:
|
||||||
|
// - result is the ActionResult
|
||||||
|
// - message is the flash store (not the status message store)
|
||||||
|
const errorMessage = result.error.message
|
||||||
|
message.set({ type: 'error', message: errorMessage });
|
||||||
|
}
|
||||||
|
},
|
||||||
|
syncFlashMessage: false,
|
||||||
|
taintedMessage: null,
|
||||||
|
validators: zodClient(signInSchema),
|
||||||
|
validationMethod: 'oninput',
|
||||||
|
delayMs: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const { form: loginForm, errors, enhance } = superLoginForm;
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<svelte:head>
|
||||||
|
<title>Bored Game | Login</title>
|
||||||
|
</svelte:head>
|
||||||
|
|
||||||
|
<div class="login">
|
||||||
|
<form method="POST" use:enhance>
|
||||||
|
<h2
|
||||||
|
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
||||||
|
>
|
||||||
|
Please enter your two factor code
|
||||||
|
</h2>
|
||||||
|
<Form.Field form={superLoginForm} name="username">
|
||||||
|
<Form.Control let:attrs>
|
||||||
|
<Form.Label for="username">Username</Form.Label>
|
||||||
|
<Input {...attrs} autocomplete="username" bind:value={$loginForm.username} />
|
||||||
|
</Form.Control>
|
||||||
|
<Form.FieldErrors />
|
||||||
|
</Form.Field>
|
||||||
|
<Form.Field form={superLoginForm} name="password">
|
||||||
|
<Form.Control let:attrs>
|
||||||
|
<Form.Label for="password">Password</Form.Label>
|
||||||
|
<Input {...attrs} autocomplete="current-password" type="password" bind:value={$loginForm.password} />
|
||||||
|
</Form.Control>
|
||||||
|
<Form.FieldErrors />
|
||||||
|
</Form.Field>
|
||||||
|
{#if form?.twoFactorRequired}
|
||||||
|
<Form.Field form={superLoginForm} name="totpToken">
|
||||||
|
<Form.Control let:attrs>
|
||||||
|
<Form.Label for="totpToken">Two Factor Code or Recovery Code</Form.Label>
|
||||||
|
<Input {...attrs} autocomplete="one-time-code" bind:value={$loginForm.totpToken} />
|
||||||
|
</Form.Control>
|
||||||
|
<Form.FieldErrors />
|
||||||
|
</Form.Field>
|
||||||
|
{/if}
|
||||||
|
<Form.Button>Login</Form.Button>
|
||||||
|
<p class="px-8 text-center text-sm text-muted-foreground">
|
||||||
|
By clicking continue, you agree to our
|
||||||
|
<a href="/terms" class="underline underline-offset-4 hover:text-primary">
|
||||||
|
Terms of Use
|
||||||
|
</a>
|
||||||
|
and
|
||||||
|
<a href="/privacy" class="underline underline-offset-4 hover:text-primary">
|
||||||
|
Privacy Policy
|
||||||
|
</a>.
|
||||||
|
</p>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
.loading {
|
||||||
|
position: fixed;
|
||||||
|
top: 50%;
|
||||||
|
left: 50%;
|
||||||
|
transform: translate(-50%, -50%);
|
||||||
|
z-index: 101;
|
||||||
|
display: grid;
|
||||||
|
place-items: center;
|
||||||
|
gap: 1rem;
|
||||||
|
|
||||||
|
h3 {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.login {
|
||||||
|
display: flex;
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
flex-direction: column;
|
||||||
|
justify-content: center;
|
||||||
|
width: 100%;
|
||||||
|
margin-right: auto;
|
||||||
|
margin-left: auto;
|
||||||
|
|
||||||
|
@media (min-width: 640px) {
|
||||||
|
width: 350px;
|
||||||
|
}
|
||||||
|
|
||||||
|
form {
|
||||||
|
display: grid;
|
||||||
|
gap: 0.5rem;
|
||||||
|
align-items: center;
|
||||||
|
max-width: 24rem;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
@ -3,10 +3,28 @@ import db from '../../../../db';
|
||||||
import { asc, desc, eq, ilike, or } from 'drizzle-orm';
|
import { asc, desc, eq, ilike, or } from 'drizzle-orm';
|
||||||
import { games } from '$db/schema';
|
import { games } from '$db/schema';
|
||||||
import kebabCase from 'just-kebab-case';
|
import kebabCase from 'just-kebab-case';
|
||||||
|
import {
|
||||||
|
FilterSchema,
|
||||||
|
PaginationSchema,
|
||||||
|
SearchSchema,
|
||||||
|
SortSchema,
|
||||||
|
} from '$lib/validations/zod-schemas';
|
||||||
|
|
||||||
// Search a user's collection
|
// Search a user's collection
|
||||||
export const GET = async ({ url, locals }) => {
|
export const GET = async ({ url, locals }) => {
|
||||||
const searchParams = Object.fromEntries(url.searchParams);
|
const searchParams = Object.fromEntries(url.searchParams);
|
||||||
|
|
||||||
|
const searchGames = PaginationSchema.merge(FilterSchema)
|
||||||
|
.merge(SortSchema)
|
||||||
|
.merge(SearchSchema)
|
||||||
|
.parse(searchParams);
|
||||||
|
|
||||||
|
if (searchGames.status !== 'success') {
|
||||||
|
error(400, 'Invalid request');
|
||||||
|
}
|
||||||
|
|
||||||
|
const { q, limit, skip, order, exact } = searchGames;
|
||||||
|
|
||||||
const q = searchParams?.q?.trim() || '';
|
const q = searchParams?.q?.trim() || '';
|
||||||
const limit = parseInt(searchParams?.limit) || 10;
|
const limit = parseInt(searchParams?.limit) || 10;
|
||||||
const skip = parseInt(searchParams?.skip) || 0;
|
const skip = parseInt(searchParams?.skip) || 0;
|
||||||
|
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
||||||
import { customType } from 'drizzle-orm/pg-core';
|
|
||||||
import {sql} from "drizzle-orm";
|
|
||||||
|
|
||||||
function genExpWithWeights(input: string[]) {
|
|
||||||
const columnExpressions = input.map((column, index) => {
|
|
||||||
const weight = String.fromCharCode(index + 65);
|
|
||||||
return sql`setweight(to_tsvector('english', coalesce(${column}, '')), '${weight}')`;
|
|
||||||
});
|
|
||||||
|
|
||||||
return sql`tsvector GENERATED ALWAYS AS (${columnExpressions.join(' || ')}) STORED`;
|
|
||||||
}
|
|
||||||
|
|
||||||
export const tsvector = customType<{
|
|
||||||
data: string;
|
|
||||||
config: { sources: string[]; weighted: boolean };
|
|
||||||
}>({
|
|
||||||
dataType(config) {
|
|
||||||
if (config) {
|
|
||||||
const sources = config.sources.join(" || ' ' || ");
|
|
||||||
return config.weighted
|
|
||||||
? genExpWithWeights(config.sources)
|
|
||||||
: sql`tsvector generated always as (to_tsvector('english', ${sources})) stored`;
|
|
||||||
} else {
|
|
||||||
return sql`tsvector`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Loading…
Reference in a new issue