Creating recovery codes and starting to return to UI, adding seed data for initial admin user, and update dependencies.

This commit is contained in:
Bradley Shellnut 2024-04-04 15:08:18 -07:00
parent 8c5cda1ebc
commit 564c58a2c6
15 changed files with 1952 additions and 359 deletions

View file

@ -2,7 +2,8 @@
"useTabs": true,
"tabWidth": 2,
"singleQuote": true,
"trailingComma": "none",
"trailingComma": "all",
"bracketSpacing": true,
"printWidth": 100,
"plugins": ["prettier-plugin-svelte"],
"pluginSearchDirs": ["."],

View file

@ -0,0 +1,2 @@
ALTER TABLE "users" ALTER COLUMN "two_factor_secret" SET DEFAULT '';--> statement-breakpoint
ALTER TABLE "users" ADD COLUMN "two_factor_enabled" boolean DEFAULT false;

File diff suppressed because it is too large Load diff

View file

@ -64,6 +64,13 @@
"when": 1711757183163,
"tag": "0008_amusing_franklin_richards",
"breakpoints": true
},
{
"idx": 9,
"version": "5",
"when": 1711868447607,
"tag": "0009_gray_carlie_cooper",
"breakpoints": true
}
]
}

View file

@ -24,13 +24,13 @@
"@melt-ui/pp": "^0.3.0",
"@melt-ui/svelte": "^0.76.2",
"@playwright/test": "^1.42.1",
"@resvg/resvg-js": "^2.6.1",
"@sveltejs/adapter-auto": "^3.1.1",
"@resvg/resvg-js": "^2.6.2",
"@sveltejs/adapter-auto": "^3.2.0",
"@sveltejs/enhanced-img": "^0.1.9",
"@sveltejs/kit": "^2.5.4",
"@sveltejs/kit": "^2.5.5",
"@sveltejs/vite-plugin-svelte": "^3.0.2",
"@types/cookie": "^0.6.0",
"@types/node": "^20.11.30",
"@types/node": "^20.12.2",
"@types/pg": "^8.11.4",
"@typescript-eslint/eslint-plugin": "^6.21.0",
"@typescript-eslint/parser": "^6.21.0",
@ -59,13 +59,13 @@
"svelte-sequential-preprocessor": "^2.0.1",
"sveltekit-flash-message": "^2.4.4",
"sveltekit-rate-limiter": "^0.4.3",
"sveltekit-superforms": "^2.11.0",
"tailwindcss": "^3.4.1",
"sveltekit-superforms": "^2.12.2",
"tailwindcss": "^3.4.3",
"ts-node": "^10.9.2",
"tslib": "^2.6.1",
"tsx": "^4.7.1",
"typescript": "^5.4.3",
"vite": "^5.2.6",
"vite": "^5.2.7",
"vitest": "^1.4.0",
"zod": "^3.22.4"
},
@ -92,7 +92,7 @@
"class-variance-authority": "^0.7.0",
"clsx": "^2.1.0",
"cookie": "^0.6.0",
"drizzle-orm": "^0.30.4",
"drizzle-orm": "^0.30.6",
"feather-icons": "^4.29.1",
"formsnap": "^0.5.1",
"html-entities": "^2.5.2",
@ -103,8 +103,8 @@
"lucia": "3.1.1",
"lucide-svelte": "^0.358.0",
"open-props": "^1.6.21",
"oslo": "^1.1.3",
"pg": "^8.11.3",
"oslo": "^1.2.0",
"pg": "^8.11.4",
"postgres": "^3.4.4",
"qrcode": "^1.5.3",
"radix-svelte": "^0.9.0",

View file

@ -31,10 +31,10 @@ dependencies:
version: 1.16.0
'@sentry/sveltekit':
specifier: ^7.100.1
version: 7.100.1(@sveltejs/kit@2.5.4)(svelte@4.2.12)
version: 7.100.1(@sveltejs/kit@2.5.5)(svelte@4.2.12)
'@sveltejs/adapter-vercel':
specifier: ^5.2.0
version: 5.2.0(@sveltejs/kit@2.5.4)
version: 5.2.0(@sveltejs/kit@2.5.5)
'@types/feather-icons':
specifier: ^4.29.4
version: 4.29.4
@ -57,14 +57,14 @@ dependencies:
specifier: ^0.6.0
version: 0.6.0
drizzle-orm:
specifier: ^0.30.4
version: 0.30.4(@neondatabase/serverless@0.9.0)(@planetscale/database@1.16.0)(@types/pg@8.11.4)(pg@8.11.3)(postgres@3.4.4)
specifier: ^0.30.6
version: 0.30.6(@neondatabase/serverless@0.9.0)(@planetscale/database@1.16.0)(@types/pg@8.11.4)(pg@8.11.4)(postgres@3.4.4)
feather-icons:
specifier: ^4.29.1
version: 4.29.1
formsnap:
specifier: ^0.5.1
version: 0.5.1(svelte@4.2.12)(sveltekit-superforms@2.11.0)
version: 0.5.1(svelte@4.2.12)(sveltekit-superforms@2.12.2)
html-entities:
specifier: ^2.5.2
version: 2.5.2
@ -90,11 +90,11 @@ dependencies:
specifier: ^1.6.21
version: 1.6.21
oslo:
specifier: ^1.1.3
version: 1.1.3
specifier: ^1.2.0
version: 1.2.0
pg:
specifier: ^8.11.3
version: 8.11.3
specifier: ^8.11.4
version: 8.11.4
postgres:
specifier: ^3.4.4
version: 3.4.4
@ -115,10 +115,10 @@ dependencies:
version: 2.2.2
tailwind-variants:
specifier: ^0.2.1
version: 0.2.1(tailwindcss@3.4.1)
version: 0.2.1(tailwindcss@3.4.3)
tailwindcss-animate:
specifier: ^1.0.6
version: 1.0.7(tailwindcss@3.4.1)
version: 1.0.7(tailwindcss@3.4.3)
zod-to-json-schema:
specifier: ^3.22.5
version: 3.22.5(zod@3.22.4)
@ -134,26 +134,26 @@ devDependencies:
specifier: ^1.42.1
version: 1.42.1
'@resvg/resvg-js':
specifier: ^2.6.1
version: 2.6.1
specifier: ^2.6.2
version: 2.6.2
'@sveltejs/adapter-auto':
specifier: ^3.1.1
version: 3.1.1(@sveltejs/kit@2.5.4)
specifier: ^3.2.0
version: 3.2.0(@sveltejs/kit@2.5.5)
'@sveltejs/enhanced-img':
specifier: ^0.1.9
version: 0.1.9(svelte@4.2.12)
'@sveltejs/kit':
specifier: ^2.5.4
version: 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6)
specifier: ^2.5.5
version: 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7)
'@sveltejs/vite-plugin-svelte':
specifier: ^3.0.2
version: 3.0.2(svelte@4.2.12)(vite@5.2.6)
version: 3.0.2(svelte@4.2.12)(vite@5.2.7)
'@types/cookie':
specifier: ^0.6.0
version: 0.6.0
'@types/node':
specifier: ^20.11.30
version: 20.11.30
specifier: ^20.12.2
version: 20.12.2
'@types/pg':
specifier: ^8.11.4
version: 8.11.4
@ -234,19 +234,19 @@ devDependencies:
version: 2.0.1
sveltekit-flash-message:
specifier: ^2.4.4
version: 2.4.4(@sveltejs/kit@2.5.4)(svelte@4.2.12)
version: 2.4.4(@sveltejs/kit@2.5.5)(svelte@4.2.12)
sveltekit-rate-limiter:
specifier: ^0.4.3
version: 0.4.3(@sveltejs/kit@2.5.4)
version: 0.4.3(@sveltejs/kit@2.5.5)
sveltekit-superforms:
specifier: ^2.11.0
version: 2.11.0(@sveltejs/kit@2.5.4)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12)
specifier: ^2.12.2
version: 2.12.2(@sveltejs/kit@2.5.5)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12)
tailwindcss:
specifier: ^3.4.1
version: 3.4.1(ts-node@10.9.2)
specifier: ^3.4.3
version: 3.4.3(ts-node@10.9.2)
ts-node:
specifier: ^10.9.2
version: 10.9.2(@types/node@20.11.30)(typescript@5.4.3)
version: 10.9.2(@types/node@20.12.2)(typescript@5.4.3)
tslib:
specifier: ^2.6.1
version: 2.6.2
@ -257,11 +257,11 @@ devDependencies:
specifier: ^5.4.3
version: 5.4.3
vite:
specifier: ^5.2.6
version: 5.2.6(@types/node@20.11.30)(sass@1.72.0)
specifier: ^5.2.7
version: 5.2.7(@types/node@20.12.2)(sass@1.72.0)
vitest:
specifier: ^1.4.0
version: 1.4.0(@types/node@20.11.30)(sass@1.72.0)
version: 1.4.0(@types/node@20.12.2)(sass@1.72.0)
zod:
specifier: ^3.22.4
version: 3.22.4
@ -763,8 +763,8 @@ packages:
dev: false
optional: true
/@emnapi/core@1.1.0:
resolution: {integrity: sha512-gNEVZo0HhUfVjhr6rFG//HZXbauclxueiDxaKGBZHcK5h8i9pslABNPfG8kMwYTubAn3mV7AyOZN8gfPRgbU8A==}
/@emnapi/core@1.1.1:
resolution: {integrity: sha512-eu4KjHfXg3I+UUR7vSuwZXpRo4c8h4Rtb5Lu2F7Z4JqJFl/eidquONEBiRs6viXKpWBC3BaJBy68xGJ2j56idw==}
requiresBuild: true
dependencies:
tslib: 2.6.2
@ -778,8 +778,8 @@ packages:
tslib: 2.6.2
optional: true
/@emnapi/runtime@1.1.0:
resolution: {integrity: sha512-gCGlE0fJGWalfy+wbFApjhKn6uoSVvopru77IPyxNKkjkaiSx2HxDS7eOYSmo9dcMIhmmIvoxiC3N9TM1c3EaA==}
/@emnapi/runtime@1.1.1:
resolution: {integrity: sha512-3bfqkzuR1KLx57nZfjr2NLnFOobvyS0aTszaEGCGqmYMVDRaGvgIZbjGSV/MHSSmLgQ/b9JFHQ5xm5WRZYd+XQ==}
requiresBuild: true
dependencies:
tslib: 2.6.2
@ -1674,8 +1674,8 @@ packages:
resolution: {integrity: sha512-1uFRjqCcxVv4F31PjyLm8o4oNlT5ywwh6OwcDGkZbafOeFZHXekvholS9IlfZkRsZvVhSbFRHT/5iDib4KTtpg==}
dev: false
/@gcornut/valibot-json-schema@0.0.26(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(valibot@0.30.0):
resolution: {integrity: sha512-8eZpGLP1awX9UGEK+VUFiyXnjiIV/h5RPC7wt2KQG6O7YkXEw7t2pUxHhR5ULcoN0BsZ3FOWZqyzu3tFF7aXxw==}
/@gcornut/valibot-json-schema@0.0.27(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(valibot@0.30.0):
resolution: {integrity: sha512-xcMaUStVgQzPrK3d7PuLFbQ+3qSp6LzaLExAm52E3FKmUfjQa7Sw5cDK6Hfu/8WT0yfGsuSCuJ5uT1sosjR9Qg==}
hasBin: true
requiresBuild: true
peerDependencies:
@ -2082,8 +2082,8 @@ packages:
resolution: {integrity: sha512-8JuczewTFIZ/XIjHQ+YlQUydHvlKx2hkcxtuGwh+t/t5zWyZct6YG4+xjHcq8xyc/e7FmFwf42Zj2YgICwmlvA==}
requiresBuild: true
dependencies:
'@emnapi/core': 1.1.0
'@emnapi/runtime': 1.1.0
'@emnapi/core': 1.1.1
'@emnapi/runtime': 1.1.1
'@tybys/wasm-util': 0.8.1
dev: false
optional: true
@ -2739,8 +2739,8 @@ packages:
requiresBuild: true
optional: true
/@resvg/resvg-js-android-arm-eabi@2.6.1:
resolution: {integrity: sha512-oXmXUUqTzinvXwkVBDdNKocAeF1zLGJYasTNRmoqF3gyOm04qRYT1On0m6oK2jbTiUAOUTqi0ZSizcecnwcSDA==}
/@resvg/resvg-js-android-arm-eabi@2.6.2:
resolution: {integrity: sha512-FrJibrAk6v29eabIPgcTUMPXiEz8ssrAk7TXxsiZzww9UTQ1Z5KAbFJs+Z0Ez+VZTYgnE5IQJqBcoSiMebtPHA==}
engines: {node: '>= 10'}
cpu: [arm]
os: [android]
@ -2748,8 +2748,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-android-arm64@2.6.1:
resolution: {integrity: sha512-vcCZoBx8s/3/+t6nDd9fB/LL70I4B2YmgDT7uP6wyqVCUPniNeLR9VYIuvpMHw6oVyL5Mpt8F2YXV1zQE2X2hw==}
/@resvg/resvg-js-android-arm64@2.6.2:
resolution: {integrity: sha512-VcOKezEhm2VqzXpcIJoITuvUS/fcjIw5NA/w3tjzWyzmvoCdd+QXIqy3FBGulWdClvp4g+IfUemigrkLThSjAQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [android]
@ -2757,8 +2757,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-darwin-arm64@2.6.1:
resolution: {integrity: sha512-uO0WvEQqQlAL8u7nI7k1yL5wSsZYU2YCSsN1hAhr1LjyvmWmyC09xUEdWPUVVT1nL2YK4Ueh0LR+pxOT3QlCng==}
/@resvg/resvg-js-darwin-arm64@2.6.2:
resolution: {integrity: sha512-nmok2LnAd6nLUKI16aEB9ydMC6Lidiiq2m1nEBDR1LaaP7FGs4AJ90qDraxX+CWlVuRlvNjyYJTNv8qFjtL9+A==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [darwin]
@ -2766,8 +2766,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-darwin-x64@2.6.1:
resolution: {integrity: sha512-aW15HMQSk85GPHE4gsc56G0Fqi2IGVkDfPWEWHEyDBpCZ17RKweAwg5V3ioz9aGX1nmhjQa9tJ2xgVwX+sqIjw==}
/@resvg/resvg-js-darwin-x64@2.6.2:
resolution: {integrity: sha512-GInyZLjgWDfsVT6+SHxQVRwNzV0AuA1uqGsOAW+0th56J7Nh6bHHKXHBWzUrihxMetcFDmQMAX1tZ1fZDYSRsw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [darwin]
@ -2775,8 +2775,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-linux-arm-gnueabihf@2.6.1:
resolution: {integrity: sha512-7vpBFzCMONnRzK0uCBT5h+Dmsa8dWsoLFqB6xgutNfKkldjuCOiLNe0tT7hneGF8tw5H+W6hX/VLx2ktDwsS4Q==}
/@resvg/resvg-js-linux-arm-gnueabihf@2.6.2:
resolution: {integrity: sha512-YIV3u/R9zJbpqTTNwTZM5/ocWetDKGsro0SWp70eGEM9eV2MerWyBRZnQIgzU3YBnSBQ1RcxRZvY/UxwESfZIw==}
engines: {node: '>= 10'}
cpu: [arm]
os: [linux]
@ -2784,8 +2784,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-linux-arm64-gnu@2.6.1:
resolution: {integrity: sha512-+Gi3OIOJFFiCdm72AsDa7KPnkogitLQ6yfF1O/J25adUrlWjvKAM9+8b5sTI9waeLERZHNJpIVESpdIxI2/5sQ==}
/@resvg/resvg-js-linux-arm64-gnu@2.6.2:
resolution: {integrity: sha512-zc2BlJSim7YR4FZDQ8OUoJg5holYzdiYMeobb9pJuGDidGL9KZUv7SbiD4E8oZogtYY42UZEap7dqkkYuA91pg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@ -2793,8 +2793,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-linux-arm64-musl@2.6.1:
resolution: {integrity: sha512-lnRGWG/LwpX6UsV1neHAavPnek3WlCnGMdBZ/7JbpamK5VmtDZmsV2esOFpME6pKnWL40UX4WjPsCBtKkhMUMA==}
/@resvg/resvg-js-linux-arm64-musl@2.6.2:
resolution: {integrity: sha512-3h3dLPWNgSsD4lQBJPb4f+kvdOSJHa5PjTYVsWHxLUzH4IFTJUAnmuWpw4KqyQ3NA5QCyhw4TWgxk3jRkQxEKg==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [linux]
@ -2802,8 +2802,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-linux-x64-gnu@2.6.1:
resolution: {integrity: sha512-2S1N7fHl5480AUrUtxsfjFOh3t8NQ2qKavROZRDKWJqFXBrNOUsirDa33LtpFGDkFW18SjP/FCs1xfHLzzz43g==}
/@resvg/resvg-js-linux-x64-gnu@2.6.2:
resolution: {integrity: sha512-IVUe+ckIerA7xMZ50duAZzwf1U7khQe2E0QpUxu5MBJNao5RqC0zwV/Zm965vw6D3gGFUl7j4m+oJjubBVoftw==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@ -2811,8 +2811,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-linux-x64-musl@2.6.1:
resolution: {integrity: sha512-G5GMmpvFiyclkp44eVPVWnN2lhLx9eMIcxGnBFWjnpI3TxrjBt7aVic2N8CsZ0vt2rrnJkQI0IKjUQQIi138Hw==}
/@resvg/resvg-js-linux-x64-musl@2.6.2:
resolution: {integrity: sha512-UOf83vqTzoYQO9SZ0fPl2ZIFtNIz/Rr/y+7X8XRX1ZnBYsQ/tTb+cj9TE+KHOdmlTFBxhYzVkP2lRByCzqi4jQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [linux]
@ -2820,8 +2820,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-win32-arm64-msvc@2.6.1:
resolution: {integrity: sha512-m9TBMrGs2tML0oz14D/x40tPedqCgNFy/DH7/z/bvnP9bH59fivaInmHTjd8oSFfGRZ/DasXMFcAL+LS1+hfSQ==}
/@resvg/resvg-js-win32-arm64-msvc@2.6.2:
resolution: {integrity: sha512-7C/RSgCa+7vqZ7qAbItfiaAWhyRSoD4l4BQAbVDqRRsRgY+S+hgS3in0Rxr7IorKUpGE69X48q6/nOAuTJQxeQ==}
engines: {node: '>= 10'}
cpu: [arm64]
os: [win32]
@ -2829,8 +2829,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-win32-ia32-msvc@2.6.1:
resolution: {integrity: sha512-Ma+MJXesViT0A7JqTobsB9DOCO0AkfmLxsgkvxq0IiWkpU9Z4Gp+RkDsFQbMhJwVXaz7b8L6y+EIvf95iCbJQw==}
/@resvg/resvg-js-win32-ia32-msvc@2.6.2:
resolution: {integrity: sha512-har4aPAlvjnLcil40AC77YDIk6loMawuJwFINEM7n0pZviwMkMvjb2W5ZirsNOZY4aDbo5tLx0wNMREp5Brk+w==}
engines: {node: '>= 10'}
cpu: [ia32]
os: [win32]
@ -2838,8 +2838,8 @@ packages:
dev: true
optional: true
/@resvg/resvg-js-win32-x64-msvc@2.6.1:
resolution: {integrity: sha512-mWIlgEuFWBrlldCbhLPvG4tt0r0D1RZ8eR2+zxTtQ15d/lbVjwnGpw2l1noV3zhV5S6mAVzoZeQ1emoov63Y/A==}
/@resvg/resvg-js-win32-x64-msvc@2.6.2:
resolution: {integrity: sha512-ZXtYhtUr5SSaBrUDq7DiyjOFJqBVL/dOBN7N/qmi/pO0IgiWW/f/ue3nbvu9joWE5aAKDoIzy/CxsY0suwGosQ==}
engines: {node: '>= 10'}
cpu: [x64]
os: [win32]
@ -2847,22 +2847,22 @@ packages:
dev: true
optional: true
/@resvg/resvg-js@2.6.1:
resolution: {integrity: sha512-CVGUWPvgr3b96+PooncXCsvu93CMwfEoueqIxIJr9AuUA8OaIPcZjOgFhas62fcHRdWMmxQqF1Rp+89bQsj/RA==}
/@resvg/resvg-js@2.6.2:
resolution: {integrity: sha512-xBaJish5OeGmniDj9cW5PRa/PtmuVU3ziqrbr5xJj901ZDN4TosrVaNZpEiLZAxdfnhAe7uQ7QFWfjPe9d9K2Q==}
engines: {node: '>= 10'}
optionalDependencies:
'@resvg/resvg-js-android-arm-eabi': 2.6.1
'@resvg/resvg-js-android-arm64': 2.6.1
'@resvg/resvg-js-darwin-arm64': 2.6.1
'@resvg/resvg-js-darwin-x64': 2.6.1
'@resvg/resvg-js-linux-arm-gnueabihf': 2.6.1
'@resvg/resvg-js-linux-arm64-gnu': 2.6.1
'@resvg/resvg-js-linux-arm64-musl': 2.6.1
'@resvg/resvg-js-linux-x64-gnu': 2.6.1
'@resvg/resvg-js-linux-x64-musl': 2.6.1
'@resvg/resvg-js-win32-arm64-msvc': 2.6.1
'@resvg/resvg-js-win32-ia32-msvc': 2.6.1
'@resvg/resvg-js-win32-x64-msvc': 2.6.1
'@resvg/resvg-js-android-arm-eabi': 2.6.2
'@resvg/resvg-js-android-arm64': 2.6.2
'@resvg/resvg-js-darwin-arm64': 2.6.2
'@resvg/resvg-js-darwin-x64': 2.6.2
'@resvg/resvg-js-linux-arm-gnueabihf': 2.6.2
'@resvg/resvg-js-linux-arm64-gnu': 2.6.2
'@resvg/resvg-js-linux-arm64-musl': 2.6.2
'@resvg/resvg-js-linux-x64-gnu': 2.6.2
'@resvg/resvg-js-linux-x64-musl': 2.6.2
'@resvg/resvg-js-win32-arm64-msvc': 2.6.2
'@resvg/resvg-js-win32-ia32-msvc': 2.6.2
'@resvg/resvg-js-win32-x64-msvc': 2.6.2
dev: true
/@resvg/resvg-wasm@2.6.0:
@ -3126,7 +3126,7 @@ packages:
svelte: 4.2.12
dev: false
/@sentry/sveltekit@7.100.1(@sveltejs/kit@2.5.4)(svelte@4.2.12):
/@sentry/sveltekit@7.100.1(@sveltejs/kit@2.5.5)(svelte@4.2.12):
resolution: {integrity: sha512-t6JaivTmw5oIqOpKQ8PNbGjNP99AQY6vMPkhxzVuwPa3A3o2WtmzQoIXNxdrkux5XkoBI9CsT6TsM5TbaMDwjQ==}
engines: {node: '>=16'}
peerDependencies:
@ -3140,7 +3140,7 @@ packages:
'@sentry/types': 7.100.1
'@sentry/utils': 7.100.1
'@sentry/vite-plugin': 0.6.1
'@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6)
'@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7)
magicast: 0.2.8
sorcery: 0.11.0
transitivePeerDependencies:
@ -3229,21 +3229,21 @@ packages:
requiresBuild: true
optional: true
/@sveltejs/adapter-auto@3.1.1(@sveltejs/kit@2.5.4):
resolution: {integrity: sha512-6LeZft2Fo/4HfmLBi5CucMYmgRxgcETweQl/yQoZo/895K3S9YWYN4Sfm/IhwlIpbJp3QNvhKmwCHbsqQNYQpw==}
/@sveltejs/adapter-auto@3.2.0(@sveltejs/kit@2.5.5):
resolution: {integrity: sha512-She5nKT47kwHE18v9NMe6pbJcvULr82u0V3yZ0ej3n1laWKGgkgdEABE9/ak5iDPs93LqsBkuIo51kkwCLBjJA==}
peerDependencies:
'@sveltejs/kit': ^2.0.0
dependencies:
'@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6)
'@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7)
import-meta-resolve: 4.0.0
dev: true
/@sveltejs/adapter-vercel@5.2.0(@sveltejs/kit@2.5.4):
/@sveltejs/adapter-vercel@5.2.0(@sveltejs/kit@2.5.5):
resolution: {integrity: sha512-872y13DxKcOBxgnXc4C2YHRw1ow9N1CpUxMH34NYFqCn6PUO6f34qle8v/Byr8sHEC/d+PZIAI3MJs3c8f7TfA==}
peerDependencies:
'@sveltejs/kit': ^2.4.0
dependencies:
'@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6)
'@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7)
'@vercel/nft': 0.26.4
esbuild: 0.19.12
transitivePeerDependencies:
@ -3262,8 +3262,8 @@ packages:
- svelte
dev: true
/@sveltejs/kit@2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6):
resolution: {integrity: sha512-eDxK2d4EGzk99QsZNoPXe7jlzA5EGqfcCpUwZ912bhnalsZ2ZsG5wGRthkydupVjYyqdmzEanVKFhLxU2vkPSQ==}
/@sveltejs/kit@2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7):
resolution: {integrity: sha512-ULe3PB00q4+wYRL+IS5FDPsCEVnhEITofm7b9Yz8malcH3r1SAnW/JJ6T13hIMeu8QNRIuVQWo+P4+2VklbnLQ==}
engines: {node: '>=18.13'}
hasBin: true
requiresBuild: true
@ -3272,7 +3272,7 @@ packages:
svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.3
dependencies:
'@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.12)(vite@5.2.6)
'@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.12)(vite@5.2.7)
'@types/cookie': 0.6.0
cookie: 0.6.0
devalue: 4.3.2
@ -3286,9 +3286,9 @@ packages:
sirv: 2.0.4
svelte: 4.2.12
tiny-glob: 0.2.9
vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0)
vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0)
/@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6):
/@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7):
resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==}
engines: {node: ^18.0.0 || >=20}
peerDependencies:
@ -3296,29 +3296,29 @@ packages:
svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.0
dependencies:
'@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.12)(vite@5.2.6)
'@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.12)(vite@5.2.7)
debug: 4.3.4
svelte: 4.2.12
vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0)
vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0)
transitivePeerDependencies:
- supports-color
/@sveltejs/vite-plugin-svelte@3.0.2(svelte@4.2.12)(vite@5.2.6):
/@sveltejs/vite-plugin-svelte@3.0.2(svelte@4.2.12)(vite@5.2.7):
resolution: {integrity: sha512-MpmF/cju2HqUls50WyTHQBZUV3ovV/Uk8k66AN2gwHogNAG8wnW8xtZDhzNBsFJJuvmq1qnzA5kE7YfMJNFv2Q==}
engines: {node: ^18.0.0 || >=20}
peerDependencies:
svelte: ^4.0.0 || ^5.0.0-next.0
vite: ^5.0.0
dependencies:
'@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6)
'@sveltejs/vite-plugin-svelte-inspector': 2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7)
debug: 4.3.4
deepmerge: 4.3.1
kleur: 4.1.5
magic-string: 0.30.5
svelte: 4.2.12
svelte-hmr: 0.15.3(svelte@4.2.12)
vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0)
vitefu: 0.2.5(vite@5.2.6)
vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0)
vitefu: 0.2.5(vite@5.2.7)
transitivePeerDependencies:
- supports-color
@ -3360,22 +3360,22 @@ packages:
/@types/json-schema@7.0.15:
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
/@types/node@20.11.30:
resolution: {integrity: sha512-dHM6ZxwlmuZaRmUPfv1p+KrdD1Dci04FbdEm/9wEMouFqxYoFl5aMkt0VMAUtYRQDyYvD41WJLukhq/ha3YuTw==}
/@types/node@20.12.2:
resolution: {integrity: sha512-zQ0NYO87hyN6Xrclcqp7f8ZbXNbRfoGWNcMvHTPQp9UUrwI0mI7XBz+cu7/W6/VClYo2g63B0cjull/srU7LgQ==}
dependencies:
undici-types: 5.26.5
/@types/pg@8.11.4:
resolution: {integrity: sha512-yw3Bwbda6vO+NvI1Ue/YKOwtl31AYvvd/e73O3V4ZkNzuGpTDndLSyc0dQRB2xrQqDePd20pEGIfqSp/GH3pRw==}
dependencies:
'@types/node': 20.11.30
'@types/node': 20.12.2
pg-protocol: 1.6.0
pg-types: 4.0.2
/@types/pg@8.6.6:
resolution: {integrity: sha512-O2xNmXebtwVekJDD+02udOncjVcMZQuTEQEMpKJ0ZRf5E7/9JJX3izhKUcUifBkyKpljyUM6BTgy2trmviKlpw==}
dependencies:
'@types/node': 20.11.30
'@types/node': 20.12.2
pg-protocol: 1.6.0
pg-types: 2.2.0
dev: false
@ -3863,11 +3863,6 @@ packages:
/buffer-from@1.1.2:
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
/buffer-writer@2.0.0:
resolution: {integrity: sha512-a7ZpuTZU1TRtnwyCNW3I5dc0wWNC3VR9S++Ewyk2HHZdrO3CQJqSpd+95Us590V6AL7JqUAH2IwZ/398PmNFgw==}
engines: {node: '>=4'}
dev: false
/cac@6.7.14:
resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==}
engines: {node: '>=8'}
@ -4317,11 +4312,12 @@ packages:
- supports-color
dev: true
/drizzle-orm@0.30.4(@neondatabase/serverless@0.9.0)(@planetscale/database@1.16.0)(@types/pg@8.11.4)(pg@8.11.3)(postgres@3.4.4):
resolution: {integrity: sha512-kWoSMGbrOFkmkAweLTFtHJMpN+nwhx89q0mLELqT2aEU+1szNV8jrnBmJwZ0WGNp7J7yQn/ezEtxBI/qzTSElQ==}
/drizzle-orm@0.30.6(@neondatabase/serverless@0.9.0)(@planetscale/database@1.16.0)(@types/pg@8.11.4)(pg@8.11.4)(postgres@3.4.4):
resolution: {integrity: sha512-8RgNUmY7J03GRuRgBV5SaJNbYgLVPjdSWNS/bRkIMIHt2TFCA439lJsNpqYX8asyKMqkw8ceBiamUnCIXZIt9w==}
peerDependencies:
'@aws-sdk/client-rds-data': '>=3'
'@cloudflare/workers-types': '>=3'
'@electric-sql/pglite': '>=0.1.1'
'@libsql/client': '*'
'@neondatabase/serverless': '>=0.1'
'@op-engineering/op-sqlite': '>=2'
@ -4349,6 +4345,8 @@ packages:
optional: true
'@cloudflare/workers-types':
optional: true
'@electric-sql/pglite':
optional: true
'@libsql/client':
optional: true
'@neondatabase/serverless':
@ -4397,7 +4395,7 @@ packages:
'@neondatabase/serverless': 0.9.0
'@planetscale/database': 1.16.0
'@types/pg': 8.11.4
pg: 8.11.3
pg: 8.11.4
postgres: 3.4.4
dev: false
@ -4900,7 +4898,7 @@ packages:
is-callable: 1.2.7
dev: false
/formsnap@0.5.1(svelte@4.2.12)(sveltekit-superforms@2.11.0):
/formsnap@0.5.1(svelte@4.2.12)(sveltekit-superforms@2.12.2):
resolution: {integrity: sha512-8ppOlOu7llBEJbV0PzUz/KWh1J8KfiGqwjiyb8emQ2m+/nYXohLBtMcLVpW3XwlMkUbYaIXM+5lhfGjw8xbGJw==}
peerDependencies:
svelte: ^4.0.0
@ -4908,7 +4906,7 @@ packages:
dependencies:
nanoid: 5.0.6
svelte: 4.2.12
sveltekit-superforms: 2.11.0(@sveltejs/kit@2.5.4)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12)
sveltekit-superforms: 2.12.2(@sveltejs/kit@2.5.5)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12)
dev: false
/fraction.js@4.3.7:
@ -5876,8 +5874,8 @@ packages:
'@node-rs/bcrypt': 1.9.2
dev: false
/oslo@1.1.3:
resolution: {integrity: sha512-hCz528UlNTiegplcyBg6AvG0HLNrnq06EJMp88Ze308GX1hszkb8u3puhNC4aqLMbYQ0hXpl+wQGnwxMtt5+5w==}
/oslo@1.2.0:
resolution: {integrity: sha512-OoFX6rDsNcOQVAD2gQD/z03u4vEjWZLzJtwkmgfRF+KpQUXwdgEXErD7zNhyowmHwHefP+PM9Pw13pgpHMRlzw==}
dependencies:
'@node-rs/argon2': 1.7.0
'@node-rs/bcrypt': 1.9.0
@ -5921,10 +5919,6 @@ packages:
engines: {node: '>=6'}
dev: false
/packet-reader@1.0.0:
resolution: {integrity: sha512-HAKu/fG3HpHFO0AA8WE8q2g+gBJaZ9MG7fcKk+IJPLTGAD6Psw4443l+9DGRbOIh3/aXr7Phy0TjilYivJo5XQ==}
dev: false
/pako@0.2.9:
resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==}
@ -5996,8 +5990,8 @@ packages:
dev: false
optional: true
/pg-connection-string@2.6.2:
resolution: {integrity: sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==}
/pg-connection-string@2.6.3:
resolution: {integrity: sha512-77FxhhKJQH+xJx6tDqkhhMa0nZvv3U1HYLDQgwZxZafVD583++O5LXn5oo5HaQZ0vXwYcZA1koYAJM3JvD6Gtw==}
dev: false
/pg-int8@1.0.1:
@ -6008,17 +6002,21 @@ packages:
resolution: {integrity: sha512-BM/Thnrw5jm2kKLE5uJkXqqExRUY/toLHda65XgFTBTFYZyopbKjBe29Ii3RbkvlsMoFwD+tHeGaCjjv0gHlyw==}
engines: {node: '>=4'}
/pg-pool@3.6.1(pg@8.11.3):
resolution: {integrity: sha512-jizsIzhkIitxCGfPRzJn1ZdcosIt3pz9Sh3V01fm1vZnbnCMgmGl5wvGGdNN2EL9Rmb0EcFoCkixH4Pu+sP9Og==}
/pg-pool@3.6.2(pg@8.11.4):
resolution: {integrity: sha512-Htjbg8BlwXqSBQ9V8Vjtc+vzf/6fVUuak/3/XXKA9oxZprwW3IMDQTGHP+KDmVL7rtd+R1QjbnCFPuTHm3G4hg==}
peerDependencies:
pg: '>=8.0'
dependencies:
pg: 8.11.3
pg: 8.11.4
dev: false
/pg-protocol@1.6.0:
resolution: {integrity: sha512-M+PDm637OY5WM307051+bsDia5Xej6d9IR4GwJse1qA1DIhiKlksvrneZOYQq42OM+spubpcNYEo2FcKQrDk+Q==}
/pg-protocol@1.6.1:
resolution: {integrity: sha512-jPIlvgoD63hrEuihvIg+tJhoGjUsLPn6poJY9N5CnlPd91c2T18T/9zBtLxZSb1EhYxBRoZJtzScCaWlYLtktg==}
dev: false
/pg-types@2.2.0:
resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==}
engines: {node: '>=4'}
@ -6042,8 +6040,8 @@ packages:
postgres-interval: 3.0.0
postgres-range: 1.1.4
/pg@8.11.3:
resolution: {integrity: sha512-+9iuvG8QfaaUrrph+kpF24cXkH1YOOUeArRNYIxq1viYHZagBxrTno7cecY1Fa44tJeZvaoG+Djpkc3JwehN5g==}
/pg@8.11.4:
resolution: {integrity: sha512-pWb7JKPxGk1UFbtq7jQ0m3IfPpb7LLACCEyN8/u9DYEom+Q/BSKy+4TRl4+Hh003AOYhppB/z+QK87/hx/bk0w==}
engines: {node: '>= 8.0.0'}
peerDependencies:
pg-native: '>=3.0.1'
@ -6051,11 +6049,9 @@ packages:
pg-native:
optional: true
dependencies:
buffer-writer: 2.0.0
packet-reader: 1.0.0
pg-connection-string: 2.6.2
pg-pool: 3.6.1(pg@8.11.3)
pg-protocol: 1.6.0
pg-connection-string: 2.6.3
pg-pool: 3.6.2(pg@8.11.4)
pg-protocol: 1.6.1
pg-types: 2.2.0
pgpass: 1.0.5
optionalDependencies:
@ -6338,7 +6334,7 @@ packages:
dependencies:
lilconfig: 2.1.0
postcss: 8.4.38
ts-node: 10.9.2(@types/node@20.11.30)(typescript@5.4.3)
ts-node: 10.9.2(@types/node@20.12.2)(typescript@5.4.3)
yaml: 1.10.2
dev: true
@ -6356,7 +6352,7 @@ packages:
dependencies:
lilconfig: 3.0.0
postcss: 8.4.38
ts-node: 10.9.2(@types/node@20.11.30)(typescript@5.4.3)
ts-node: 10.9.2(@types/node@20.12.2)(typescript@5.4.3)
yaml: 2.3.4
/postcss-load-config@5.0.3(postcss@8.4.38):
@ -7345,56 +7341,39 @@ packages:
magic-string: 0.30.7
periscopic: 3.1.0
/sveltekit-flash-message@2.4.4(@sveltejs/kit@2.5.4)(svelte@4.2.12):
/sveltekit-flash-message@2.4.4(@sveltejs/kit@2.5.5)(svelte@4.2.12):
resolution: {integrity: sha512-CFN03chH/FMEJcBZ/8zKm7RqGee/pwb57Spbbx8QCQPhe7N9ofZHd9iYV2vVy4E9glBo/oQ1IG7VQje6L092wg==}
peerDependencies:
'@sveltejs/kit': 1.x || 2.x
svelte: 3.x || 4.x || >=5.0.0-next.51
dependencies:
'@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6)
'@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7)
svelte: 4.2.12
dev: true
/sveltekit-rate-limiter@0.4.3(@sveltejs/kit@2.5.4):
/sveltekit-rate-limiter@0.4.3(@sveltejs/kit@2.5.5):
resolution: {integrity: sha512-BKkD2tvgyz5j4Fn1vt0y7FLF0zZ01f9thjWPGDb6fyX3tBXyMrtZ8ISK8M7zjz9Cik/2KrkvFtmldhXF6/hjqw==}
peerDependencies:
'@sveltejs/kit': 1.x || 2.x
dependencies:
'@isaacs/ttlcache': 1.4.1
'@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6)
'@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7)
dev: true
/sveltekit-superforms@2.11.0(@sveltejs/kit@2.5.4)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12):
resolution: {integrity: sha512-wRAznfYi9sOp4aQd2kb/SIafqHX4LROn5ojIXEbp2Pss9EPy69tmArQFm3JaiBC0hU72bAlUOTFSmVABTF9TEA==}
/sveltekit-superforms@2.12.2(@sveltejs/kit@2.5.5)(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(svelte@4.2.12):
resolution: {integrity: sha512-fFOXaluP1os/Tamx7gzwhT3tXPAfqZ8KYRC0UfXdXeUtlUIUfiGrIifDJ26/9uePmF8Zhqy2M0XjG8W9kQnJpg==}
peerDependencies:
'@sveltejs/kit': 1.x || 2.x
svelte: 3.x || 4.x || >=5.0.0-next.51
peerDependenciesMeta:
'@sinclair/typebox':
optional: true
'@vinejs/vine':
optional: true
arktype:
optional: true
joi:
optional: true
superstruct:
optional: true
valibot:
optional: true
yup:
optional: true
zod:
optional: true
dependencies:
'@sveltejs/kit': 2.5.4(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.6)
'@sveltejs/kit': 2.5.5(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.12)(vite@5.2.7)
devalue: 4.3.2
just-clone: 6.2.0
memoize-weak: 1.0.2
svelte: 4.2.12
ts-deepmerge: 7.0.0
optionalDependencies:
'@gcornut/valibot-json-schema': 0.0.26(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(valibot@0.30.0)
'@gcornut/valibot-json-schema': 0.0.27(@types/json-schema@7.0.15)(esbuild-runner@2.2.2)(esbuild@0.20.2)(valibot@0.30.0)
'@sinclair/typebox': 0.32.20
'@sodaru/yup-to-json-schema': 2.0.1
'@vinejs/vine': 1.8.0
@ -7419,26 +7398,26 @@ packages:
'@babel/runtime': 7.24.1
dev: false
/tailwind-variants@0.2.1(tailwindcss@3.4.1):
/tailwind-variants@0.2.1(tailwindcss@3.4.3):
resolution: {integrity: sha512-2xmhAf4UIc3PijOUcJPA1LP4AbxhpcHuHM2C26xM0k81r0maAO6uoUSHl3APmvHZcY5cZCY/bYuJdfFa4eGoaw==}
engines: {node: '>=16.x', pnpm: '>=7.x'}
peerDependencies:
tailwindcss: '*'
dependencies:
tailwind-merge: 2.2.2
tailwindcss: 3.4.1(ts-node@10.9.2)
tailwindcss: 3.4.3(ts-node@10.9.2)
dev: false
/tailwindcss-animate@1.0.7(tailwindcss@3.4.1):
/tailwindcss-animate@1.0.7(tailwindcss@3.4.3):
resolution: {integrity: sha512-bl6mpH3T7I3UFxuvDEXLxy/VuFxBk5bbzplh7tXI68mwMokNYd1t9qPBHlnyTwfa4JGC4zP516I1hYYtQ/vspA==}
peerDependencies:
tailwindcss: '>=3.0.0 || insiders'
dependencies:
tailwindcss: 3.4.1(ts-node@10.9.2)
tailwindcss: 3.4.3(ts-node@10.9.2)
dev: false
/tailwindcss@3.4.1(ts-node@10.9.2):
resolution: {integrity: sha512-qAYmXRfk3ENzuPBakNK0SRrUDipP8NQnEY6772uDhflcQz5EhRdD7JNZxyrFHVQNCwULPBn6FNPp9brpO7ctcA==}
/tailwindcss@3.4.3(ts-node@10.9.2):
resolution: {integrity: sha512-U7sxQk/n397Bmx4JHbJx/iSOOv5G+II3f1kpLpY2QeUv5DcPdcTsYLlusZfq1NthHS1c1cZoyFmmkex1rzke0A==}
engines: {node: '>=14.0.0'}
hasBin: true
dependencies:
@ -7578,7 +7557,7 @@ packages:
/ts-interface-checker@0.1.13:
resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==}
/ts-node@10.9.2(@types/node@20.11.30)(typescript@5.4.3):
/ts-node@10.9.2(@types/node@20.12.2)(typescript@5.4.3):
resolution: {integrity: sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==}
hasBin: true
peerDependencies:
@ -7597,7 +7576,7 @@ packages:
'@tsconfig/node12': 1.0.11
'@tsconfig/node14': 1.0.3
'@tsconfig/node16': 1.0.4
'@types/node': 20.11.30
'@types/node': 20.12.2
acorn: 8.11.2
acorn-walk: 8.3.0
arg: 4.1.3
@ -7746,7 +7725,7 @@ packages:
- rollup
dev: true
/vite-node@1.4.0(@types/node@20.11.30)(sass@1.72.0):
/vite-node@1.4.0(@types/node@20.12.2)(sass@1.72.0):
resolution: {integrity: sha512-VZDAseqjrHgNd4Kh8icYHWzTKSCZMhia7GyHfhtzLW33fZlG9SwsB6CEhgyVOWkJfJ2pFLrp/Gj1FSfAiqH9Lw==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
@ -7755,7 +7734,7 @@ packages:
debug: 4.3.4
pathe: 1.1.2
picocolors: 1.0.0
vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0)
vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0)
transitivePeerDependencies:
- '@types/node'
- less
@ -7767,8 +7746,8 @@ packages:
- terser
dev: true
/vite@5.2.6(@types/node@20.11.30)(sass@1.72.0):
resolution: {integrity: sha512-FPtnxFlSIKYjZ2eosBQamz4CbyrTizbZ3hnGJlh/wMtCrlp1Hah6AzBLjGI5I2urTfNnpovpHdrL6YRuBOPnCA==}
/vite@5.2.7(@types/node@20.12.2)(sass@1.72.0):
resolution: {integrity: sha512-k14PWOKLI6pMaSzAuGtT+Cf0YmIx12z9YGon39onaJNy8DLBfBJrzg9FQEmkAM5lpHBZs9wksWAsyF/HkpEwJA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
@ -7795,7 +7774,7 @@ packages:
terser:
optional: true
dependencies:
'@types/node': 20.11.30
'@types/node': 20.12.2
esbuild: 0.20.2
postcss: 8.4.38
rollup: 4.13.0
@ -7803,7 +7782,7 @@ packages:
optionalDependencies:
fsevents: 2.3.3
/vitefu@0.2.5(vite@5.2.6):
/vitefu@0.2.5(vite@5.2.7):
resolution: {integrity: sha512-SgHtMLoqaeeGnd2evZ849ZbACbnwQCIwRH57t18FxcXoZop0uQu0uzlIhJBlF/eWVzuce0sHeqPcDo+evVcg8Q==}
peerDependencies:
vite: ^3.0.0 || ^4.0.0 || ^5.0.0
@ -7811,9 +7790,9 @@ packages:
vite:
optional: true
dependencies:
vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0)
vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0)
/vitest@1.4.0(@types/node@20.11.30)(sass@1.72.0):
/vitest@1.4.0(@types/node@20.12.2)(sass@1.72.0):
resolution: {integrity: sha512-gujzn0g7fmwf83/WzrDTnncZt2UiXP41mHuFYFrdwaLRVQ6JYQEiME2IfEjU3vcFL3VKa75XhI3lFgn+hfVsQw==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
@ -7838,7 +7817,7 @@ packages:
jsdom:
optional: true
dependencies:
'@types/node': 20.11.30
'@types/node': 20.12.2
'@vitest/expect': 1.4.0
'@vitest/runner': 1.4.0
'@vitest/snapshot': 1.4.0
@ -7856,8 +7835,8 @@ packages:
strip-literal: 2.0.0
tinybench: 2.6.0
tinypool: 0.8.2
vite: 5.2.6(@types/node@20.11.30)(sass@1.72.0)
vite-node: 1.4.0(@types/node@20.11.30)(sass@1.72.0)
vite: 5.2.7(@types/node@20.12.2)(sass@1.72.0)
vite-node: 1.4.0(@types/node@20.12.2)(sass@1.72.0)
why-is-node-running: 2.2.2
transitivePeerDependencies:
- less

2
src/app.d.ts vendored
View file

@ -6,7 +6,7 @@
declare global {
namespace App {
interface PageData {
flash?: { type: 'success' | 'error' | 'info'; message: string };
flash?: { type: 'success' | 'error' | 'info'; message: string; data: any };
}
interface Locals {
auth: import('lucia').AuthRequest;

View file

@ -17,38 +17,37 @@ export const load: PageServerLoad = async (event) => {
const { user } = event.locals;
const dbUser = await db.query
.users
.findFirst({
where: eq(users.id, user.id)
});
const dbUser = await db.query.users.findFirst({
where: eq(users.id, user.id),
});
const profileForm = await superValidate(zod(profileSchema), {
defaults: {
firstName: dbUser?.first_name ?? '',
lastName: dbUser?.last_name ?? '',
username: dbUser?.username ?? '',
}
},
});
const emailForm = await superValidate(zod(changeEmailSchema), {
defaults: {
email: dbUser?.email ?? '',
}
},
});
return {
profileForm,
emailForm,
hasSetupTwoFactor: !!dbUser?.two_factor_secret
hasSetupTwoFactor: !!dbUser?.two_factor_secret,
};
};
const changeEmailIfNotEmpty = z.object({
email: z.string()
email: z
.string()
.trim()
.max(64, { message: 'Email must be less than 64 characters' })
.email({ message: 'Please enter a valid email' })
});
.email({ message: 'Please enter a valid email' }),
});
export const actions: Actions = {
profileUpdate: async (event) => {
@ -56,7 +55,7 @@ export const actions: Actions = {
if (!form.valid) {
return fail(400, {
form
form,
});
}
if (!event.locals.user) {
@ -68,12 +67,9 @@ export const actions: Actions = {
const user = event.locals.user;
const newUsername = form.data.username;
const existingUser = await db.query
.users
.findFirst({
where: eq(users.username, newUsername)
}
);
const existingUser = await db.query.users.findFirst({
where: eq(users.username, newUsername),
});
if (existingUser && existingUser.id !== user.id) {
return setError(form, 'username', 'That username is already taken');
@ -84,7 +80,7 @@ export const actions: Actions = {
.set({
first_name: form.data.firstName,
last_name: form.data.lastName,
username: form.data.username
username: form.data.username,
})
.where(eq(users.id, user.id));
} catch (e) {
@ -102,29 +98,30 @@ export const actions: Actions = {
const form = await superValidate(event, zod(changeEmailSchema));
const newEmail = form.data?.email;
if (!form.valid || !newEmail || (newEmail !== '' && !changeEmailIfNotEmpty.safeParse(form.data).success)) {
if (
!form.valid ||
!newEmail ||
(newEmail !== '' && !changeEmailIfNotEmpty.safeParse(form.data).success)
) {
return fail(400, {
form
form,
});
}
if (!event.locals.user) {
redirect(302, '/login', notSignedInMessage, event);
redirect(302, '/login', notSignedInMessage, event);
}
const user = event.locals.user;
const existingUser = await db.query.users.findFirst({
where: eq(users.email, newEmail)
where: eq(users.email, newEmail),
});
if (existingUser && existingUser.id !== user.id) {
return setError(form, 'email', 'That email is already taken');
}
await db
.update(users)
.set({ email: form.data.email })
.where(eq(users.id, user.id));
await db.update(users).set({ email: form.data.email }).where(eq(users.id, user.id));
if (user.email !== form.data.email) {
// Send email to confirm new email?
@ -143,5 +140,5 @@ export const actions: Actions = {
}
return message(form, { type: 'success', message: 'Email updated successfully!' });
}
},
};

View file

@ -1,19 +1,19 @@
import { encodeHex } from 'oslo/encoding';
import { type Actions, fail } from '@sveltejs/kit';
import { eq } from 'drizzle-orm';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { encodeHex, decodeHex } from 'oslo/encoding';
import { Argon2id } from 'oslo/password';
import { createTOTPKeyURI } from 'oslo/otp';
import { createTOTPKeyURI, TOTPController } from 'oslo/otp';
import { HMAC } from 'oslo/crypto';
import QRCode from 'qrcode';
import { zod } from 'sveltekit-superforms/adapters';
import { setError, superValidate } from 'sveltekit-superforms/server';
import { message, setError, superValidate } from 'sveltekit-superforms/server';
import { redirect } from 'sveltekit-flash-message/server';
import type { Cookie } from 'lucia';
import type { PageServerLoad } from '../../$types';
import { addTwoFactorSchema } from '$lib/validations/account';
import { notSignedInMessage } from '$lib/flashMessages';
import { type Actions, fail } from '@sveltejs/kit';
import db from '$lib/drizzle';
import { eq } from 'drizzle-orm';
import { users } from '../../../../../../schema';
import QRCode from 'qrcode';
import { recovery_codes, users } from '../../../../../../schema';
export const load: PageServerLoad = async (event) => {
const form = await superValidate(event, zod(addTwoFactorSchema));
@ -23,25 +23,42 @@ export const load: PageServerLoad = async (event) => {
redirect(302, '/login', notSignedInMessage, event);
}
const dbUser = await db.query.users.findFirst({
where: eq(users.id, user.id),
});
if (dbUser?.two_factor_enabled) {
const message = {
type: 'info',
message: 'Two-Factor Authentication is already enabled',
} as const;
throw redirect('/profile', message, event);
}
const twoFactorSecret = await new HMAC('SHA-1').generateKey();
await db
.update(users)
.set({ two_factor_secret: encodeHex(twoFactorSecret) })
.set({
two_factor_secret: encodeHex(twoFactorSecret),
two_factor_enabled: false,
})
.where(eq(users.id, user.id));
const issuer = 'bored-game';
const accountName = user.email || user.username;
// pass the website's name and the user identifier (e.g. email, username)
const uri = createTOTPKeyURI(issuer, accountName, twoFactorSecret);
const qrCode = await QRCode.toDataURL(uri);
const totpUri = createTOTPKeyURI(issuer, accountName, twoFactorSecret);
const qrCode = QRCode.toDataURL(totpUri);
form.data = {
current_password: '',
two_factor_code: ''
two_factor_code: '',
};
return {
form,
qrCode
twoFactorEnabled: false,
totpUri,
qrCode,
};
};
@ -51,11 +68,10 @@ export const actions: Actions = {
if (!form.valid) {
return fail(400, {
form
form,
});
}
console.log('updating profile');
if (!event.locals.user) {
redirect(302, '/login', notSignedInMessage, event);
}
@ -67,7 +83,7 @@ export const actions: Actions = {
const user = event.locals.user;
const dbUser = await db.query.users.findFirst({
where: eq(users.id, user.id)
where: eq(users.id, user.id),
});
if (!dbUser?.hashed_password) {
@ -75,47 +91,60 @@ export const actions: Actions = {
form.data.two_factor_code = '';
return setError(
form,
'Error occurred. Please try again or contact support if you need further help.'
'Error occurred. Please try again or contact support if you need further help.',
);
}
if (dbUser?.two_factor_secret === '' || dbUser?.two_factor_secret === null) {
form.data.current_password = '';
form.data.two_factor_code = '';
return setError(
form,
'Error occurred. Please try again or contact support if you need further help.',
);
}
const currentPasswordVerified = await new Argon2id().verify(
dbUser.hashed_password,
form.data.current_password
form.data.current_password,
);
if (!currentPasswordVerified) {
return setError(form, 'current_password', 'Your password is incorrect');
}
if (user?.username) {
let sessionCookie: Cookie;
try {
} catch (e) {
console.error(e);
form.data.password = '';
form.data.confirm_password = '';
form.data.current_password = '';
return setError(form, 'current_password', 'Your password is incorrect.');
}
event.cookies.set(sessionCookie.name, sessionCookie.value, {
path: '.',
...sessionCookie.attributes
});
const message = {
type: 'success',
message: 'Password Updated. Please sign in.'
} as const;
redirect(302, '/login', message, event);
if (form.data.two_factor_code === '') {
return setError(form, 'two_factor_code', 'Please enter a code');
}
return setError(
form,
'Error occurred. Please try again or contact support if you need further help.'
const twoFactorCode = form.data.two_factor_code;
const validOTP = await new TOTPController().verify(
twoFactorCode,
decodeHex(dbUser.two_factor_secret),
);
// TODO: Add toast instead?
// form.data.password = '';
// form.data.confirm_password = '';
// form.data.current_password = '';
// return message(form, 'Profile updated successfully.');
}
if (!validOTP) {
return setError(form, 'two_factor_code', 'Invalid code');
}
await db.update(users).set({ two_factor_enabled: true }).where(eq(users.id, user.id));
const recoveryCodes = generateRecoveryCodes();
if (recoveryCodes) {
for (const code of recoveryCodes) {
await db.insert(recovery_codes).values({
userId: user.id,
code: await new Argon2id().hash(code),
});
}
}
form.data.current_password = '';
form.data.two_factor_code = '';
return { recoveryCodes };
},
};
function generateRecoveryCodes() {
return Array.from({ length: 5 }, () => cuid2());
}

View file

@ -2,28 +2,28 @@
import { zodClient } from 'sveltekit-superforms/adapters';
import { superForm } from 'sveltekit-superforms/client';
import { AlertTriangle } from 'lucide-svelte';
import * as Alert from "$components/ui/alert";
import * as Alert from '$components/ui/alert';
import * as Form from '$components/ui/form';
import { Input } from '$components/ui/input';
import { addTwoFactorSchema } from '$lib/validations/account';
export let data;
export let form;
console.log('recovery codes', form.recoveryCodes)
const { qrCode } = data;
console.log('qrCode', qrCode)
const form = superForm(data.form, {
const twoFactorForm = superForm(data.form, {
taintedMessage: null,
validators: zodClient(addTwoFactorSchema),
delayMs: 500,
multipleSubmits: 'prevent'
multipleSubmits: 'prevent',
});
const { form: formData, enhance } = form;
const { form: formData, enhance } = twoFactorForm;
</script>
<h1>Two-Factor Authentication</h1>
<img src={qrCode} alt="QR Code" />

View file

@ -91,7 +91,8 @@ export const actions: Actions = {
verified: false,
receive_email: false,
theme: 'system',
two_factor_secret: null
two_factor_secret: '',
two_factor_enabled: false
})
.returning();
console.log('signup user', user);

View file

@ -8,7 +8,7 @@ import {
index,
pgEnum,
primaryKey,
uuid
uuid,
} from 'drizzle-orm/pg-core';
import { createId as cuid2 } from '@paralleldrive/cuid2';
import { tsvector } from './tsVector';
@ -28,13 +28,25 @@ export const users = pgTable('users', {
verified: boolean('verified').default(false),
receive_email: boolean('receive_email').default(false),
theme: text('theme').default('system'),
two_factor_secret: text('two_factor_secret'),
two_factor_secret: text('two_factor_secret').default(''),
two_factor_enabled: boolean('two_factor_enabled').default(false),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export const recovery_codes = pgTable('recovery_codes', {
id: uuid('id').primaryKey().defaultRandom(),
userId: uuid('user_id')
.notNull()
.references(() => users.id),
code: text('code').notNull(),
used: boolean('used').default(false),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export const user_relations = relations(users, ({ many }) => ({
user_roles: many(user_roles)
user_roles: many(user_roles),
}));
export type Users = InferSelectModel<typeof users>;
@ -46,10 +58,10 @@ export const sessions = pgTable('sessions', {
.references(() => users.id),
expiresAt: timestamp('expires_at', {
withTimezone: true,
mode: 'date'
mode: 'date',
}).notNull(),
ipCountry: text('ip_country'),
ipAddress: text('ip_address')
ipAddress: text('ip_address'),
});
export const roles = pgTable('roles', {
@ -58,13 +70,13 @@ export const roles = pgTable('roles', {
.unique()
.$defaultFn(() => cuid2())
.notNull(),
name: text('name').unique().notNull()
name: text('name').unique().notNull(),
});
export type Roles = InferSelectModel<typeof roles>;
export const role_relations = relations(roles, ({ many }) => ({
user_roles: many(user_roles)
user_roles: many(user_roles),
}));
export const user_roles = pgTable('user_roles', {
@ -80,18 +92,18 @@ export const user_roles = pgTable('user_roles', {
.references(() => roles.id, { onDelete: 'cascade' }),
primary: boolean('primary').default(false),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export const user_role_relations = relations(user_roles, ({ one }) => ({
role: one(roles, {
fields: [user_roles.role_id],
references: [roles.id]
references: [roles.id],
}),
user: one(users, {
fields: [user_roles.user_id],
references: [users.id]
})
references: [users.id],
}),
}));
export type UserRoles = InferSelectModel<typeof user_roles>;
@ -106,16 +118,16 @@ export const password_reset_tokens = pgTable('password_reset_tokens', {
expires_at: timestamp('expires_at', {
withTimezone: true,
mode: 'date',
precision: 6
precision: 6,
}),
created_at: timestamp('created_at').notNull().defaultNow()
created_at: timestamp('created_at').notNull().defaultNow(),
});
export const password_reset_token_relations = relations(password_reset_tokens, ({ one }) => ({
user: one(users, {
fields: [password_reset_tokens.user_id],
references: [users.id]
})
references: [users.id],
}),
}));
export const collections = pgTable('collections', {
@ -127,14 +139,14 @@ export const collections = pgTable('collections', {
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export const collection_relations = relations(collections, ({ one }) => ({
user: one(users, {
fields: [collections.user_id],
references: [users.id]
})
references: [users.id],
}),
}));
export const collection_items = pgTable('collection_items', {
@ -150,7 +162,7 @@ export const collection_items = pgTable('collection_items', {
.references(() => games.id, { onDelete: 'cascade' }),
times_played: integer('times_played').default(0),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export type CollectionItems = InferSelectModel<typeof collection_items>;
@ -158,12 +170,12 @@ export type CollectionItems = InferSelectModel<typeof collection_items>;
export const collection_item_relations = relations(collection_items, ({ one }) => ({
collection: one(collections, {
fields: [collection_items.collection_id],
references: [collections.id]
references: [collections.id],
}),
game: one(games, {
fields: [collection_items.game_id],
references: [games.id]
})
references: [games.id],
}),
}));
export const wishlists = pgTable('wishlists', {
@ -175,7 +187,7 @@ export const wishlists = pgTable('wishlists', {
.notNull()
.references(() => users.id, { onDelete: 'cascade' }),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export type Wishlists = InferSelectModel<typeof wishlists>;
@ -183,8 +195,8 @@ export type Wishlists = InferSelectModel<typeof wishlists>;
export const wishlists_relations = relations(wishlists, ({ one }) => ({
user: one(users, {
fields: [wishlists.user_id],
references: [users.id]
})
references: [users.id],
}),
}));
export const wishlist_items = pgTable('wishlist_items', {
@ -199,7 +211,7 @@ export const wishlist_items = pgTable('wishlist_items', {
.notNull()
.references(() => games.id, { onDelete: 'cascade' }),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export type WishlistItems = InferSelectModel<typeof wishlist_items>;
@ -207,12 +219,12 @@ export type WishlistItems = InferSelectModel<typeof wishlist_items>;
export const wishlist_item_relations = relations(wishlist_items, ({ one }) => ({
wishlist: one(wishlists, {
fields: [wishlist_items.wishlist_id],
references: [wishlists.id]
references: [wishlists.id],
}),
game: one(games, {
fields: [wishlist_items.game_id],
references: [games.id]
})
references: [games.id],
}),
}));
// Game and related table schemas
@ -223,7 +235,7 @@ export const externalIdType = pgEnum('external_id_type', [
'mechanic',
'publisher',
'designer',
'artist'
'artist',
]);
export const externalIds = pgTable('external_ids', {
@ -232,7 +244,7 @@ export const externalIds = pgTable('external_ids', {
.unique()
.$defaultFn(() => cuid2()),
type: externalIdType('type').notNull(),
externalId: text('external_id').notNull()
externalId: text('external_id').notNull(),
});
export type ExternalIds = InferSelectModel<typeof externalIds>;
@ -261,18 +273,18 @@ export const games = pgTable(
last_sync_at: timestamp('last_sync_at', {
withTimezone: true,
mode: 'date',
precision: 6
precision: 6,
}),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
},
(table) => {
return {
text_searchable_idx: index('text_searchable_idx')
.on(table.text_searchable_index)
.using(sql`'gin'`)
.using(sql`'gin'`),
};
}
},
);
export type Games = InferSelectModel<typeof games>;
@ -285,22 +297,22 @@ export const gamesToExternalIds = pgTable(
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
externalId: uuid('external_id')
.notNull()
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' })
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
gamesToExternalIdsPkey: primaryKey({
columns: [table.gameId, table.externalId]
})
columns: [table.gameId, table.externalId],
}),
};
}
},
);
export const gameRelations = relations(games, ({ many }) => ({
categories_to_games: many(categories_to_games),
mechanics_to_games: many(mechanics_to_games),
publishers_to_games: many(publishers_to_games),
gamesToExternalIds: many(gamesToExternalIds)
gamesToExternalIds: many(gamesToExternalIds),
}));
export const expansions = pgTable('expansions', {
@ -315,7 +327,7 @@ export const expansions = pgTable('expansions', {
.notNull()
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export type Expansions = InferSelectModel<typeof expansions>;
@ -323,12 +335,12 @@ export type Expansions = InferSelectModel<typeof expansions>;
export const expansion_relations = relations(expansions, ({ one }) => ({
baseGame: one(games, {
fields: [expansions.base_game_id],
references: [games.id]
references: [games.id],
}),
game: one(games, {
fields: [expansions.game_id],
references: [games.id]
})
references: [games.id],
}),
}));
export const publishers = pgTable('publishers', {
@ -339,7 +351,7 @@ export const publishers = pgTable('publishers', {
name: text('name'),
slug: text('slug'),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export type Publishers = InferSelectModel<typeof publishers>;
@ -352,20 +364,20 @@ export const publishersToExternalIds = pgTable(
.references(() => publishers.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
externalId: uuid('external_id')
.notNull()
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' })
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
publishersToExternalIdsPkey: primaryKey({
columns: [table.publisherId, table.externalId]
})
columns: [table.publisherId, table.externalId],
}),
};
}
},
);
export const publishers_relations = relations(publishers, ({ many }) => ({
publishers_to_games: many(publishers_to_games),
publishersToExternalIds: many(publishersToExternalIds)
publishersToExternalIds: many(publishersToExternalIds),
}));
export const categories = pgTable('categories', {
@ -376,7 +388,7 @@ export const categories = pgTable('categories', {
name: text('name'),
slug: text('slug'),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export type Categories = InferSelectModel<typeof categories>;
@ -389,15 +401,15 @@ export const categoriesToExternalIds = pgTable(
.references(() => categories.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
externalId: uuid('external_id')
.notNull()
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' })
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
categoriesToExternalIdsPkey: primaryKey({
columns: [table.categoryId, table.externalId]
})
columns: [table.categoryId, table.externalId],
}),
};
}
},
);
export const categories_to_games = pgTable(
@ -408,31 +420,31 @@ export const categories_to_games = pgTable(
.references(() => categories.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
game_id: uuid('game_id')
.notNull()
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' })
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
categoriesToGamesPkey: primaryKey({
columns: [table.category_id, table.game_id]
})
columns: [table.category_id, table.game_id],
}),
};
}
},
);
export const categories_to_games_relations = relations(categories_to_games, ({ one }) => ({
category: one(categories, {
fields: [categories_to_games.category_id],
references: [categories.id]
references: [categories.id],
}),
game: one(games, {
fields: [categories_to_games.game_id],
references: [games.id]
})
references: [games.id],
}),
}));
export const categories_relations = relations(categories, ({ many }) => ({
categories_to_games: many(categories_to_games),
categoriesToExternalIds: many(categoriesToExternalIds)
categoriesToExternalIds: many(categoriesToExternalIds),
}));
export const mechanics = pgTable('mechanics', {
@ -443,7 +455,7 @@ export const mechanics = pgTable('mechanics', {
name: text('name'),
slug: text('slug'),
created_at: timestamp('created_at').notNull().defaultNow(),
updated_at: timestamp('updated_at').notNull().defaultNow()
updated_at: timestamp('updated_at').notNull().defaultNow(),
});
export type Mechanics = InferSelectModel<typeof mechanics>;
@ -456,20 +468,20 @@ export const mechanicsToExternalIds = pgTable(
.references(() => mechanics.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
externalId: uuid('external_id')
.notNull()
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' })
.references(() => externalIds.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
mechanicsToExternalIdsPkey: primaryKey({
columns: [table.mechanicId, table.externalId]
})
columns: [table.mechanicId, table.externalId],
}),
};
}
},
);
export const mechanic_relations = relations(mechanics, ({ many }) => ({
mechanics_to_games: many(mechanics_to_games),
mechanicsToExternalIds: many(mechanicsToExternalIds)
mechanicsToExternalIds: many(mechanicsToExternalIds),
}));
export const mechanics_to_games = pgTable(
@ -480,26 +492,26 @@ export const mechanics_to_games = pgTable(
.references(() => mechanics.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
game_id: uuid('game_id')
.notNull()
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' })
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
mechanicsToGamesPkey: primaryKey({
columns: [table.mechanic_id, table.game_id]
})
columns: [table.mechanic_id, table.game_id],
}),
};
}
},
);
export const mechanics_to_games_relations = relations(mechanics_to_games, ({ one }) => ({
mechanic: one(mechanics, {
fields: [mechanics_to_games.mechanic_id],
references: [mechanics.id]
references: [mechanics.id],
}),
game: one(games, {
fields: [mechanics_to_games.game_id],
references: [games.id]
})
references: [games.id],
}),
}));
export const publishers_to_games = pgTable(
@ -510,24 +522,24 @@ export const publishers_to_games = pgTable(
.references(() => publishers.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
game_id: uuid('game_id')
.notNull()
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' })
.references(() => games.id, { onDelete: 'restrict', onUpdate: 'cascade' }),
},
(table) => {
return {
publishersToGamesPkey: primaryKey({
columns: [table.publisher_id, table.game_id]
})
columns: [table.publisher_id, table.game_id],
}),
};
}
},
);
export const publishers_to_games_relations = relations(publishers_to_games, ({ one }) => ({
publisher: one(publishers, {
fields: [publishers_to_games.publisher_id],
references: [publishers.id]
references: [publishers.id],
}),
game: one(games, {
fields: [publishers_to_games.game_id],
references: [games.id]
})
references: [games.id],
}),
}));

View file

@ -2,40 +2,71 @@ import 'dotenv/config';
import { drizzle } from 'drizzle-orm/node-postgres';
import pg from 'pg';
import * as schema from './schema';
import {Argon2id} from "oslo/password";
// create the connection
const pool = new pg.Pool({
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
host: process.env.DATABASE_HOST,
port: new Number(process.env.DATABASE_PORT).valueOf(),
port: Number(process.env.DATABASE_PORT).valueOf(),
database: process.env.DATABASE_DB,
ssl: process.env.DATABASE_HOST === 'localhost' ? false : true
ssl: process.env.DATABASE_HOST !== 'localhost'
});
const db = drizzle(pool, { schema: schema });
const existingRoles = await db.query.roles.findMany();
console.log('Existing roles', existingRoles);
console.log('Creating roles ...');
await db
const adminRole = await db
.insert(schema.roles)
.values([{ name: 'admin' }])
.onConflictDoNothing();
await db
.onConflictDoNothing()
.returning();
const userRole = await db
.insert(schema.roles)
.values([{ name: 'user' }])
.onConflictDoNothing();
.onConflictDoNothing()
.returning();
await db
.insert(schema.roles)
.values([{ name: 'editor' }])
.onConflictDoNothing();
console.log('Roles created.');
await db
.insert(schema.roles)
.values([{ name: 'moderator' }])
.onConflictDoNothing();
console.log('Roles created.');
console.log('Admin Role: ', adminRole);
const adminUser = await db
.insert(schema.users)
.values({
username: `${process.env.ADMIN_USERNAME}`,
email: '',
hashed_password: await new Argon2id().hash(`${process.env.ADMIN_PASSWORD}`),
first_name: 'Brad',
last_name: 'S',
verified: true
})
.returning()
.onConflictDoNothing();
console.log('Admin user created.', adminUser);
await db.insert(schema.user_roles).values({
user_id: adminUser[0].id,
role_id: adminRole[0].id
}).onConflictDoNothing();
console.log('Admin user given admin role.');
await db.insert(schema.user_roles).values({
user_id: adminUser[0].id,
role_id: userRole[0].id
}).onConflictDoNothing();
console.log('Admin user given user role.');
await pool.end();
process.exit();