Updating external id schema types and password validation.

This commit is contained in:
Bradley Shellnut 2024-02-16 16:38:02 -08:00
parent 0c4f93e39c
commit 858a356ddf
15 changed files with 2736 additions and 227 deletions

View file

@ -0,0 +1,7 @@
DO $$ BEGIN
CREATE TYPE "type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "external_ids" ALTER COLUMN "type" SET DATA TYPE type;

View file

@ -0,0 +1,7 @@
DO $$ BEGIN
CREATE TYPE "external_id_type" AS ENUM('game', 'category', 'mechanic', 'publisher', 'designer', 'artist');
EXCEPTION
WHEN duplicate_object THEN null;
END $$;
--> statement-breakpoint
ALTER TABLE "external_ids" ALTER COLUMN "type" SET DATA TYPE external_id_type;

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -57,6 +57,20 @@
"when": 1707951501716,
"tag": "0007_same_valeria_richards",
"breakpoints": true
},
{
"idx": 8,
"version": "5",
"when": 1708105454143,
"tag": "0008_complete_manta",
"breakpoints": true
},
{
"idx": 9,
"version": "5",
"when": 1708105890146,
"tag": "0009_equal_christian_walker",
"breakpoints": true
}
]
}

View file

@ -26,7 +26,7 @@
},
"devDependencies": {
"@melt-ui/pp": "^0.3.0",
"@melt-ui/svelte": "^0.73.0",
"@melt-ui/svelte": "^0.74.0",
"@playwright/test": "^1.41.2",
"@resvg/resvg-js": "^2.6.0",
"@sveltejs/adapter-auto": "^3.1.1",
@ -53,7 +53,7 @@
"prettier": "^3.2.5",
"prettier-plugin-svelte": "^3.2.1",
"prisma": "^5.9.1",
"sass": "^1.70.0",
"sass": "^1.71.0",
"satori": "^0.10.13",
"satori-html": "^0.3.2",
"svelte": "^4.2.11",
@ -61,7 +61,8 @@
"svelte-meta-tags": "^3.1.0",
"svelte-preprocess": "^5.1.3",
"svelte-sequential-preprocessor": "^2.0.1",
"sveltekit-flash-message": "^2.4.1",
"sveltekit-flash-message": "^2.4.2",
"sveltekit-rate-limiter": "^0.4.3",
"sveltekit-superforms": "^1.13.4",
"tailwindcss": "^3.4.1",
"ts-node": "^10.9.2",
@ -69,7 +70,7 @@
"tsx": "^4.7.1",
"typescript": "^5.3.3",
"vite": "^5.1.3",
"vitest": "^1.2.2",
"vitest": "^1.3.0",
"zod": "^3.22.4"
},
"type": "module",
@ -81,7 +82,7 @@
"@fontsource/fira-mono": "^5.0.8",
"@iconify-icons/line-md": "^1.2.26",
"@iconify-icons/mdi": "^1.2.47",
"@lucia-auth/adapter-drizzle": "^1.0.1",
"@lucia-auth/adapter-drizzle": "^1.0.2",
"@lucia-auth/adapter-prisma": "4.0.0",
"@lukeed/uuid": "^2.0.1",
"@neondatabase/serverless": "^0.8.1",

View file

@ -15,8 +15,8 @@ dependencies:
specifier: ^1.2.47
version: 1.2.48
'@lucia-auth/adapter-drizzle':
specifier: ^1.0.1
version: 1.0.1(lucia@3.0.1)
specifier: ^1.0.2
version: 1.0.2(lucia@3.0.1)
'@lucia-auth/adapter-prisma':
specifier: 4.0.0
version: 4.0.0(@prisma/client@5.9.1)(lucia@3.0.1)
@ -132,10 +132,10 @@ dependencies:
devDependencies:
'@melt-ui/pp':
specifier: ^0.3.0
version: 0.3.0(@melt-ui/svelte@0.73.0)(svelte@4.2.11)
version: 0.3.0(@melt-ui/svelte@0.74.0)(svelte@4.2.11)
'@melt-ui/svelte':
specifier: ^0.73.0
version: 0.73.0(svelte@4.2.11)
specifier: ^0.74.0
version: 0.74.0(svelte@4.2.11)
'@playwright/test':
specifier: ^1.41.2
version: 1.41.2
@ -215,8 +215,8 @@ devDependencies:
specifier: ^5.9.1
version: 5.9.1
sass:
specifier: ^1.70.0
version: 1.70.0
specifier: ^1.71.0
version: 1.71.0
satori:
specifier: ^0.10.13
version: 0.10.13
@ -228,19 +228,22 @@ devDependencies:
version: 4.2.11
svelte-check:
specifier: ^3.6.4
version: 3.6.4(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.70.0)(svelte@4.2.11)
version: 3.6.4(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.71.0)(svelte@4.2.11)
svelte-meta-tags:
specifier: ^3.1.0
version: 3.1.0(svelte@4.2.11)(typescript@5.3.3)
svelte-preprocess:
specifier: ^5.1.3
version: 5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.70.0)(svelte@4.2.11)(typescript@5.3.3)
version: 5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.71.0)(svelte@4.2.11)(typescript@5.3.3)
svelte-sequential-preprocessor:
specifier: ^2.0.1
version: 2.0.1
sveltekit-flash-message:
specifier: ^2.4.1
version: 2.4.1(@sveltejs/kit@2.5.0)(svelte@4.2.11)
specifier: ^2.4.2
version: 2.4.2(@sveltejs/kit@2.5.0)(svelte@4.2.11)
sveltekit-rate-limiter:
specifier: ^0.4.3
version: 0.4.3(@sveltejs/kit@2.5.0)
sveltekit-superforms:
specifier: ^1.13.4
version: 1.13.4(@sveltejs/kit@2.5.0)(svelte@4.2.11)(zod@3.22.4)
@ -261,10 +264,10 @@ devDependencies:
version: 5.3.3
vite:
specifier: ^5.1.3
version: 5.1.3(@types/node@20.11.19)(sass@1.70.0)
version: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
vitest:
specifier: ^1.2.2
version: 1.2.2(@types/node@20.11.19)(sass@1.70.0)
specifier: ^1.3.0
version: 1.3.0(@types/node@20.11.19)(sass@1.71.0)
zod:
specifier: ^3.22.4
version: 3.22.4
@ -1391,19 +1394,11 @@ packages:
'@floating-ui/utils': 0.1.6
dev: false
/@floating-ui/dom@1.6.1:
resolution: {integrity: sha512-iA8qE43/H5iGozC3W0YSnVSW42Vh522yyM1gj+BqRwVsTNOyr231PsXDaV04yT39PsO0QL2QpbI/M0ZaLUQgRQ==}
dependencies:
'@floating-ui/core': 1.6.0
'@floating-ui/utils': 0.2.1
dev: true
/@floating-ui/dom@1.6.3:
resolution: {integrity: sha512-RnDthu3mzPlQ31Ss/BTwQ1zjzIhr3lk1gZB1OC56h/1vEtaXkESrOqL5fQVMfXpwGtRwX+YsZBdyHtJMQnkArw==}
dependencies:
'@floating-ui/core': 1.6.0
'@floating-ui/utils': 0.2.1
dev: false
/@floating-ui/utils@0.1.6:
resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==}
@ -1644,6 +1639,18 @@ packages:
resolution: {integrity: sha512-LUQIfwU9e+Fmutc/DpRTGXSdgYZLBegi4wygCWDSVmUdLTaMHsQyASDiJtREwanwKuQLq0hY76fCJ9J/9I2xOQ==}
dependencies:
'@swc/helpers': 0.5.6
dev: false
/@internationalized/date@3.5.2:
resolution: {integrity: sha512-vo1yOMUt2hzp63IutEaTUxROdvQg1qlMRsbCvbay2AK2Gai7wIgCyK5weEX3nHkiLgo4qCXHijFNC/ILhlRpOQ==}
dependencies:
'@swc/helpers': 0.5.6
dev: true
/@isaacs/ttlcache@1.4.1:
resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==}
engines: {node: '>=12'}
dev: true
/@jest/schemas@29.6.3:
resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==}
@ -1690,8 +1697,8 @@ packages:
'@jridgewell/resolve-uri': 3.1.1
'@jridgewell/sourcemap-codec': 1.4.15
/@lucia-auth/adapter-drizzle@1.0.1(lucia@3.0.1):
resolution: {integrity: sha512-xHgYwVh3ZmccEGsmkYWCALp2GlhCnomrpO5sgABCkIWgHvsmMZuJ5BYfgfaKmed1PDok81Dk6xFbj1tMH/uD6A==}
/@lucia-auth/adapter-drizzle@1.0.2(lucia@3.0.1):
resolution: {integrity: sha512-GT2Mp0NaUZ5O4OAvzoNcX9bGotoxBfADo6mTzIEKKJ+uar3HgtQVn/m5Ogj3I2iMv0YBHWgMmlnkUHXN5xFNow==}
peerDependencies:
lucia: 3.x
dependencies:
@ -1738,14 +1745,14 @@ packages:
- supports-color
dev: false
/@melt-ui/pp@0.3.0(@melt-ui/svelte@0.73.0)(svelte@4.2.11):
/@melt-ui/pp@0.3.0(@melt-ui/svelte@0.74.0)(svelte@4.2.11):
resolution: {integrity: sha512-b07Bdh8l2KcwKVCXOY+SoBw1dk9eWvQfMSi6SoacpRVyVmmfpi0kV4oGt3HYF0tUCB3sEmVicxse50ZzZxEzEA==}
engines: {pnpm: '>=8.6.3'}
peerDependencies:
'@melt-ui/svelte': '>= 0.29.0'
svelte: ^3.55.0 || ^4.0.0 || ^5.0.0-next.1
dependencies:
'@melt-ui/svelte': 0.73.0(svelte@4.2.11)
'@melt-ui/svelte': 0.74.0(svelte@4.2.11)
estree-walker: 3.0.3
magic-string: 0.30.5
svelte: 4.2.11
@ -1765,14 +1772,14 @@ packages:
svelte: 4.2.11
dev: false
/@melt-ui/svelte@0.73.0(svelte@4.2.11):
resolution: {integrity: sha512-KD9Z+5DDhnZmDUZv1GQ0+LGeXjxl1zwrB8JAwmGeMN6EigTvXMsTPtrFRUYC+TtEjVq82eTlJzuf4C/a88MkjA==}
/@melt-ui/svelte@0.74.0(svelte@4.2.11):
resolution: {integrity: sha512-4rFhTkO34OK5lflvcj13/in1YQ+exsD2A7YSNIYw2iyNeBYFxOgM0n4qH5Y4Tf7vcekkkQ+SEqgiD3XNmVBHzw==}
peerDependencies:
svelte: '>=3 <5'
dependencies:
'@floating-ui/core': 1.6.0
'@floating-ui/dom': 1.6.1
'@internationalized/date': 3.5.1
'@floating-ui/dom': 1.6.3
'@internationalized/date': 3.5.2
dequal: 2.0.3
focus-trap: 7.5.4
nanoid: 5.0.5
@ -2994,7 +3001,7 @@ packages:
sirv: 2.0.4
svelte: 4.2.11
tiny-glob: 0.2.9
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0)
vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
/@sveltejs/vite-plugin-svelte-inspector@2.0.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3):
resolution: {integrity: sha512-gjr9ZFg1BSlIpfZ4PRewigrvYmHWbDrq2uvvPB1AmTWKuM+dI1JXQSUu2pIrYLb/QncyiIGkFDFKTwJ0XqQZZg==}
@ -3007,7 +3014,7 @@ packages:
'@sveltejs/vite-plugin-svelte': 3.0.2(svelte@4.2.11)(vite@5.1.3)
debug: 4.3.4
svelte: 4.2.11
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0)
vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
transitivePeerDependencies:
- supports-color
@ -3025,7 +3032,7 @@ packages:
magic-string: 0.30.5
svelte: 4.2.11
svelte-hmr: 0.15.3(svelte@4.2.11)
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0)
vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
vitefu: 0.2.5(vite@5.1.3)
transitivePeerDependencies:
- supports-color
@ -3264,38 +3271,38 @@ packages:
yoga-wasm-web: 0.3.3
dev: false
/@vitest/expect@1.2.2:
resolution: {integrity: sha512-3jpcdPAD7LwHUUiT2pZTj2U82I2Tcgg2oVPvKxhn6mDI2On6tfvPQTjAI4628GUGDZrCm4Zna9iQHm5cEexOAg==}
/@vitest/expect@1.3.0:
resolution: {integrity: sha512-7bWt0vBTZj08B+Ikv70AnLRicohYwFgzNjFqo9SxxqHHxSlUJGSXmCRORhOnRMisiUryKMdvsi1n27Bc6jL9DQ==}
dependencies:
'@vitest/spy': 1.2.2
'@vitest/utils': 1.2.2
'@vitest/spy': 1.3.0
'@vitest/utils': 1.3.0
chai: 4.3.10
dev: true
/@vitest/runner@1.2.2:
resolution: {integrity: sha512-JctG7QZ4LSDXr5CsUweFgcpEvrcxOV1Gft7uHrvkQ+fsAVylmWQvnaAr/HDp3LAH1fztGMQZugIheTWjaGzYIg==}
/@vitest/runner@1.3.0:
resolution: {integrity: sha512-1Jb15Vo/Oy7mwZ5bXi7zbgszsdIBNjc4IqP8Jpr/8RdBC4nF1CTzIAn2dxYvpF1nGSseeL39lfLQ2uvs5u1Y9A==}
dependencies:
'@vitest/utils': 1.2.2
'@vitest/utils': 1.3.0
p-limit: 5.0.0
pathe: 1.1.1
dev: true
/@vitest/snapshot@1.2.2:
resolution: {integrity: sha512-SmGY4saEw1+bwE1th6S/cZmPxz/Q4JWsl7LvbQIky2tKE35US4gd0Mjzqfr84/4OD0tikGWaWdMja/nWL5NIPA==}
/@vitest/snapshot@1.3.0:
resolution: {integrity: sha512-swmktcviVVPYx9U4SEQXLV6AEY51Y6bZ14jA2yo6TgMxQ3h+ZYiO0YhAHGJNp0ohCFbPAis1R9kK0cvN6lDPQA==}
dependencies:
magic-string: 0.30.5
pathe: 1.1.1
pretty-format: 29.7.0
dev: true
/@vitest/spy@1.2.2:
resolution: {integrity: sha512-k9Gcahssw8d7X3pSLq3e3XEu/0L78mUkCjivUqCQeXJm9clfXR/Td8+AP+VC1O6fKPIDLcHDTAmBOINVuv6+7g==}
/@vitest/spy@1.3.0:
resolution: {integrity: sha512-AkCU0ThZunMvblDpPKgjIi025UxR8V7MZ/g/EwmAGpjIujLVV2X6rGYGmxE2D4FJbAy0/ijdROHMWa2M/6JVMw==}
dependencies:
tinyspy: 2.2.0
tinyspy: 2.2.1
dev: true
/@vitest/utils@1.2.2:
resolution: {integrity: sha512-WKITBHLsBHlpjnDQahr+XK6RE7MiAsgrIkr0pGhQ9ygoxBfUeG0lUG5iLlzqjmKSlBv3+j5EGsriBzh+C3Tq9g==}
/@vitest/utils@1.3.0:
resolution: {integrity: sha512-/LibEY/fkaXQufi4GDlQZhikQsPO2entBKtfuyIpr1jV4DpaeasqkeHjhdOhU24vSHshcSuEyVlWdzvv2XmYCw==}
dependencies:
diff-sequences: 29.6.3
estree-walker: 3.0.3
@ -4974,6 +4981,10 @@ packages:
resolution: {integrity: sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==}
hasBin: true
/js-tokens@8.0.3:
resolution: {integrity: sha512-UfJMcSJc+SEXEl9lH/VLHSZbThQyLpw1vLO1Lb+j4RWDvG3N2f7yj3PVQA3cmkTBNldJ9eFnM+xEXxHIXrYiJw==}
dev: true
/js-yaml@3.14.1:
resolution: {integrity: sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==}
hasBin: true
@ -6451,8 +6462,8 @@ packages:
mkdirp: 0.5.6
rimraf: 2.7.1
/sass@1.70.0:
resolution: {integrity: sha512-uUxNQ3zAHeAx5nRFskBnrWzDUJrrvpCPD5FNAoRvTi0WwremlheES3tg+56PaVtCs5QDRX5CBLxxKMDJMEa1WQ==}
/sass@1.71.0:
resolution: {integrity: sha512-HKKIKf49Vkxlrav3F/w6qRuPcmImGVbIXJ2I3Kg0VMA+3Bav+8yE9G5XmP5lMj6nl4OlqbPftGAscNaNu28b8w==}
engines: {node: '>=14.0.0'}
hasBin: true
dependencies:
@ -6712,10 +6723,10 @@ packages:
engines: {node: '>=8'}
dev: true
/strip-literal@1.3.0:
resolution: {integrity: sha512-PugKzOsyXpArk0yWmUwqOZecSO0GH0bPoctLcqNDH9J04pVW3lflYE0ujElBGTloevcxF5MofAOZ7C5l2b+wLg==}
/strip-literal@2.0.0:
resolution: {integrity: sha512-f9vHgsCWBq2ugHAkGMiiYY+AYG0D/cbloKKg0nhaaaSNsujdGIpVXCNsrJpCKr5M0f4aI31mr13UjY6GAuXCKA==}
dependencies:
acorn: 8.11.2
js-tokens: 8.0.3
dev: true
/strnum@1.0.5:
@ -6753,7 +6764,7 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
/svelte-check@3.6.4(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.70.0)(svelte@4.2.11):
/svelte-check@3.6.4(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.71.0)(svelte@4.2.11):
resolution: {integrity: sha512-mY/dqucqm46p72M8yZmn81WPZx9mN6uuw8UVfR3ZKQeLxQg5HDGO3HHm5AZuWZPYNMLJ+TRMn+TeN53HfQ/vsw==}
hasBin: true
peerDependencies:
@ -6766,7 +6777,7 @@ packages:
picocolors: 1.0.0
sade: 1.8.1
svelte: 4.2.11
svelte-preprocess: 5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.70.0)(svelte@4.2.11)(typescript@5.3.3)
svelte-preprocess: 5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.71.0)(svelte@4.2.11)(typescript@5.3.3)
typescript: 5.3.3
transitivePeerDependencies:
- '@babel/core'
@ -6837,7 +6848,7 @@ packages:
svelte: 4.2.11
dev: true
/svelte-preprocess@5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.70.0)(svelte@4.2.11)(typescript@5.3.3):
/svelte-preprocess@5.1.3(postcss-load-config@5.0.3)(postcss@8.4.35)(sass@1.71.0)(svelte@4.2.11)(typescript@5.3.3):
resolution: {integrity: sha512-xxAkmxGHT+J/GourS5mVJeOXZzne1FR5ljeOUAMXUkfEhkLEllRreXpbl3dIYJlcJRfL1LO1uIAPpBpBfiqGPw==}
engines: {node: '>= 16.0.0', pnpm: ^8.0.0}
requiresBuild: true
@ -6880,7 +6891,7 @@ packages:
magic-string: 0.30.5
postcss: 8.4.35
postcss-load-config: 5.0.3(postcss@8.4.35)
sass: 1.70.0
sass: 1.71.0
sorcery: 0.11.0
strip-indent: 3.0.0
svelte: 4.2.11
@ -6922,16 +6933,25 @@ packages:
magic-string: 0.30.5
periscopic: 3.1.0
/sveltekit-flash-message@2.4.1(@sveltejs/kit@2.5.0)(svelte@4.2.11):
resolution: {integrity: sha512-n01N62FkXL6tp3VK3u4eCHKz1RwZVgqEEj63pUG/Pj3caHWkjtTUHKX8GRb14kpt9bkML8t93D/B1l1UorskvA==}
/sveltekit-flash-message@2.4.2(@sveltejs/kit@2.5.0)(svelte@4.2.11):
resolution: {integrity: sha512-iXZSOp8La7kHQuOsXOcjIp7x24J/Ycs2uPoHwtjsbObVCbjgxZrtvjd0XUfA0mYZBp97BtAQ5SW5owRDJCWq6A==}
peerDependencies:
'@sveltejs/kit': 1.x || 2.x
svelte: 3.x || 4.x
svelte: 3.x || 4.x || >=5.0.0-next.51
dependencies:
'@sveltejs/kit': 2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3)
svelte: 4.2.11
dev: true
/sveltekit-rate-limiter@0.4.3(@sveltejs/kit@2.5.0):
resolution: {integrity: sha512-BKkD2tvgyz5j4Fn1vt0y7FLF0zZ01f9thjWPGDb6fyX3tBXyMrtZ8ISK8M7zjz9Cik/2KrkvFtmldhXF6/hjqw==}
peerDependencies:
'@sveltejs/kit': 1.x || 2.x
dependencies:
'@isaacs/ttlcache': 1.4.1
'@sveltejs/kit': 2.5.0(@sveltejs/vite-plugin-svelte@3.0.2)(svelte@4.2.11)(vite@5.1.3)
dev: true
/sveltekit-superforms@1.13.4(@sveltejs/kit@2.5.0)(svelte@4.2.11)(zod@3.22.4):
resolution: {integrity: sha512-rM2+Ictaw7OAIorCLmvg82orci/mtO9ZouI4emtx8SyYngx9aED+eNZlHPLufgB6D7geL2a+hMSFtM3zmMQixQ==}
peerDependencies:
@ -7058,8 +7078,8 @@ packages:
engines: {node: '>=14.0.0'}
dev: true
/tinyspy@2.2.0:
resolution: {integrity: sha512-d2eda04AN/cPOR89F7Xv5bK/jrQEhmcLFe6HFldoeO9AJtps+fqEnh486vnT/8y4bw38pSyxDcTCAq+Ks2aJTg==}
/tinyspy@2.2.1:
resolution: {integrity: sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==}
engines: {node: '>=14.0.0'}
dev: true
@ -7278,8 +7298,8 @@ packages:
- rollup
dev: true
/vite-node@1.2.2(@types/node@20.11.19)(sass@1.70.0):
resolution: {integrity: sha512-1as4rDTgVWJO3n1uHmUYqq7nsFgINQ9u+mRcXpjeOMJUmviqNKjcZB7UfRZrlM7MjYXMKpuWp5oGkjaFLnjawg==}
/vite-node@1.3.0(@types/node@20.11.19)(sass@1.71.0):
resolution: {integrity: sha512-D/oiDVBw75XMnjAXne/4feCkCEwcbr2SU1bjAhCcfI5Bq3VoOHji8/wCPAfUkDIeohJ5nSZ39fNxM3dNZ6OBOA==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
dependencies:
@ -7287,7 +7307,7 @@ packages:
debug: 4.3.4
pathe: 1.1.1
picocolors: 1.0.0
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0)
vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
transitivePeerDependencies:
- '@types/node'
- less
@ -7299,7 +7319,7 @@ packages:
- terser
dev: true
/vite@5.1.3(@types/node@20.11.19)(sass@1.70.0):
/vite@5.1.3(@types/node@20.11.19)(sass@1.71.0):
resolution: {integrity: sha512-UfmUD36DKkqhi/F75RrxvPpry+9+tTkrXfMNZD+SboZqBCMsxKtO52XeGzzuh7ioz+Eo/SYDBbdb0Z7vgcDJew==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
@ -7331,7 +7351,7 @@ packages:
esbuild: 0.19.12
postcss: 8.4.35
rollup: 4.9.6
sass: 1.70.0
sass: 1.71.0
optionalDependencies:
fsevents: 2.3.3
@ -7343,17 +7363,17 @@ packages:
vite:
optional: true
dependencies:
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0)
vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
/vitest@1.2.2(@types/node@20.11.19)(sass@1.70.0):
resolution: {integrity: sha512-d5Ouvrnms3GD9USIK36KG8OZ5bEvKEkITFtnGv56HFaSlbItJuYr7hv2Lkn903+AvRAgSixiamozUVfORUekjw==}
/vitest@1.3.0(@types/node@20.11.19)(sass@1.71.0):
resolution: {integrity: sha512-V9qb276J1jjSx9xb75T2VoYXdO1UKi+qfflY7V7w93jzX7oA/+RtYE6TcifxksxsZvygSSMwu2Uw6di7yqDMwg==}
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
peerDependencies:
'@edge-runtime/vm': '*'
'@types/node': ^18.0.0 || >=20.0.0
'@vitest/browser': ^1.0.0
'@vitest/ui': ^1.0.0
'@vitest/browser': 1.3.0
'@vitest/ui': 1.3.0
happy-dom: '*'
jsdom: '*'
peerDependenciesMeta:
@ -7371,13 +7391,12 @@ packages:
optional: true
dependencies:
'@types/node': 20.11.19
'@vitest/expect': 1.2.2
'@vitest/runner': 1.2.2
'@vitest/snapshot': 1.2.2
'@vitest/spy': 1.2.2
'@vitest/utils': 1.2.2
'@vitest/expect': 1.3.0
'@vitest/runner': 1.3.0
'@vitest/snapshot': 1.3.0
'@vitest/spy': 1.3.0
'@vitest/utils': 1.3.0
acorn-walk: 8.3.2
cac: 6.7.14
chai: 4.3.10
debug: 4.3.4
execa: 8.0.1
@ -7386,11 +7405,11 @@ packages:
pathe: 1.1.1
picocolors: 1.0.0
std-env: 3.7.0
strip-literal: 1.3.0
strip-literal: 2.0.0
tinybench: 2.5.1
tinypool: 0.8.2
vite: 5.1.3(@types/node@20.11.19)(sass@1.70.0)
vite-node: 1.2.2(@types/node@20.11.19)(sass@1.70.0)
vite: 5.1.3(@types/node@20.11.19)(sass@1.71.0)
vite-node: 1.3.0(@types/node@20.11.19)(sass@1.71.0)
why-is-node-running: 2.2.2
transitivePeerDependencies:
- less

View file

@ -1,20 +1,20 @@
<script lang="ts">
import { applyAction, enhance } from '$app/forms';
import toast from 'svelte-french-toast';
import { ListChecks, ListTodo, LogOut, User } from 'lucide-svelte';
import * as DropdownMenu from "$components/ui/dropdown-menu";
import * as Avatar from "$components/ui/avatar";
import Logo from '$components/logo.svelte';
import { invalidateAll } from '$app/navigation';
import toast from 'svelte-french-toast';
import Logo from '$components/logo.svelte';
export let user;
export let user: User | null;
let avatar = user?.username.slice(0, 1).toUpperCase() || '?';
</script>
<header>
<div class="corner">
<a href="/" class="main-logo" title="Home">
<a href="/" title="Home">
<div class="logo-image">
<Logo />
</div>
@ -155,8 +155,4 @@
text-decoration: underline;
color: var(--accent-color);
}
.separator {
@apply m-[5px] h-[1px] bg-black;
}
</style>

View file

@ -1,4 +1,5 @@
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-go-game" viewBox="0 0 24 24" stroke-width="1" stroke="var(--fg)" fill="none" stroke-linecap="round" stroke-linejoin="round">
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-go-game" viewBox="0 0 24 24"
stroke-width="1" stroke="var(--fg)" fill="none" stroke-linecap="round" stroke-linejoin="round">
<path stroke="none" d="M0 0h24v24H0z" fill="none"/>
<path d="M6 6m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />
<path d="M12 12m-2 0a2 2 0 1 0 4 0a2 2 0 1 0 -4 0" />

Before

Width:  |  Height:  |  Size: 668 B

After

Width:  |  Height:  |  Size: 671 B

View file

@ -55,18 +55,7 @@ export const signUpSchema = userSchema
terms: true
})
.superRefine(({ confirm_password, password }, ctx) => {
if (confirm_password !== password) {
// ctx.addIssue({
// code: 'custom',
// message: 'Password and Confirm Password must match',
// path: ['password']
// });
ctx.addIssue({
code: 'custom',
message: ' Password and Confirm Password must match',
path: ['confirm_password']
});
}
refinePasswords(confirm_password, password, ctx);
});
export const signInSchema = userSchema.pick({
@ -77,18 +66,7 @@ export const signInSchema = userSchema.pick({
export const updateUserPasswordSchema = userSchema
.pick({ password: true, confirm_password: true })
.superRefine(({ confirm_password, password }, ctx) => {
if (confirm_password !== password) {
ctx.addIssue({
code: 'custom',
message: 'Password and Confirm Password must match',
path: ['password']
});
ctx.addIssue({
code: 'custom',
message: 'Password and Confirm Password must match',
path: ['confirm_password']
});
}
refinePasswords(confirm_password, password, ctx);
});
export const changeUserPasswordSchema = z
@ -96,25 +74,91 @@ export const changeUserPasswordSchema = z
current_password: z.string({ required_error: 'Current Password is required' }),
password: z
.string({ required_error: 'Password is required' })
.trim()
.min(8, { message: 'Password must be at least 8 characters' })
.max(128, { message: 'Password must be less than 128 characters' }),
.trim(),
confirm_password: z
.string({ required_error: 'Confirm Password is required' })
.trim()
.min(8, { message: 'Confirm Password must be at least 8 characters' })
})
.superRefine(({ confirm_password, password }, ctx) => {
if (confirm_password !== password) {
ctx.addIssue({
code: 'custom',
message: 'Password and Confirm Password must match',
path: ['password']
});
ctx.addIssue({
code: 'custom',
message: 'Password and Confirm Password must match',
path: ['confirm_password']
});
}
refinePasswords(confirm_password, password, ctx);
});
const refinePasswords = async function(confirm_password: string, password: string, ctx: z.RefinementCtx) {
comparePasswords(confirm_password, password, ctx);
checkPasswordStrength(password, ctx);
}
const comparePasswords = async function(confirm_password: string, password: string, ctx: z.RefinementCtx) {
if (confirm_password !== password) {
ctx.addIssue({
code: 'custom',
message: 'Password and Confirm Password must match',
path: ['confirm_password']
});
}
}
const checkPasswordStrength = async function (password: string, ctx: z.RefinementCtx) {
const minimumLength = password.length < 8;
const maximumLength = password.length > 128;
const containsUppercase = (ch: string) => /[A-Z]/.test(ch);
const containsLowercase = (ch: string) => /[a-z]/.test(ch);
const containsSpecialChar = (ch: string) =>
/[`!@#$%^&*()_\-+=\[\]{};':"\\|,.<>\/?~ ]/.test(ch);
let countOfUpperCase = 0,
countOfLowerCase = 0,
countOfNumbers = 0,
countOfSpecialChar = 0;
for (let i = 0; i < password.length; i++) {
const char = password.charAt(i);
if (!isNaN(+char)) countOfNumbers++;
else if (containsUppercase(char)) countOfUpperCase++;
else if (containsLowercase(char)) countOfLowerCase++;
else if (containsSpecialChar(char)) countOfSpecialChar++;
}
let errors = {
upperCase: { pass: true, message: "At least one upper case." },
lowerCase: { pass: true, message: "At least one lower case." },
specialCharacter: { pass: true, message: "At least one special character." },
totalNumber: { pass: true, message: "At least one number." },
minimumLength: { pass: true, message: "At least 8 characters." },
maximumLength: { pass: true, message: "At most 128 characters." },
};
if (countOfLowerCase < 1) {
errors = { ...errors, lowerCase: { ...errors.lowerCase, pass: false } };
}
if (countOfNumbers < 1) {
errors = {
...errors,
totalNumber: { ...errors.totalNumber, pass: false },
};
}
if (countOfUpperCase < 1) {
errors = { ...errors, upperCase: { ...errors.upperCase, pass: false } };
}
if (countOfSpecialChar < 1) {
errors = { ...errors, specialCharacter: { ...errors.specialCharacter, pass: false } };
}
if (minimumLength) {
errors = { ...errors, minimumLength: { ...errors.minimumLength, pass: false } };
}
if (maximumLength) {
errors = { ...errors, maximumLength: { ...errors.maximumLength, pass: false } };
}
if (
countOfLowerCase < 1 ||
countOfUpperCase < 1 ||
countOfSpecialChar < 1 ||
countOfNumbers < 1
) {
ctx.addIssue({
code: "custom",
message: JSON.stringify(errors),
path: ["password"]
});
}
}

View file

@ -1,6 +1,12 @@
import { drizzle } from "drizzle-orm/node-postgres";
import { drizzle } from 'drizzle-orm/node-postgres';
import pg from 'pg';
import { DATABASE_USER, DATABASE_PASSWORD, DATABASE_HOST, DATABASE_DB, DATABASE_PORT } from '$env/static/private';
import {
DATABASE_USER,
DATABASE_PASSWORD,
DATABASE_HOST,
DATABASE_DB,
DATABASE_PORT
} from '$env/static/private';
import * as schema from '../schema';
// create the connection
@ -8,8 +14,8 @@ const pool = new pg.Pool({
user: DATABASE_USER,
password: DATABASE_PASSWORD,
host: DATABASE_HOST,
port: new Number(DATABASE_PORT).valueOf(),
database: DATABASE_DB,
port: Number(DATABASE_PORT).valueOf(),
database: DATABASE_DB
});
const db = drizzle(pool, { schema });

View file

@ -1,10 +1,12 @@
import { fail, redirect, type Actions } from "@sveltejs/kit";
import { message, setError, superValidate } from 'sveltekit-superforms/server';
import { setError, superValidate } from 'sveltekit-superforms/server';
import { Argon2id } from "oslo/password";
import { changeUserPasswordSchema } from '$lib/config/zod-schemas.js';
import { lucia } from '$lib/server/auth.js';
import type { PageServerLoad } from "./$types";
import prisma from "$lib/prisma";
import db from "$lib/drizzle";
import { eq } from "drizzle-orm";
import { users } from "../../../../../schema";
export const load: PageServerLoad = async (event) => {
const form = await superValidate(event, changeUserPasswordSchema);
@ -41,10 +43,8 @@ export const actions: Actions = {
const user = event.locals.user;
const dbUser = await prisma.user.findUnique({
where: {
id: user.id
}
const dbUser = await db.query.users.findFirst({
where: eq(users.id, user.id)
});
if (!dbUser || !dbUser.hashed_password) {
@ -70,16 +70,11 @@ export const actions: Actions = {
}
const hashedPassword = await new Argon2id().hash(form.data.password);
await lucia.invalidateUserSessions(user.id);
await prisma.user.update({
where: {
id: user.id
},
data: {
hashed_password: hashedPassword
}
});
await db.update(users)
.set({ hashed_password: hashedPassword })
.where(eq(users.id, user.id));
const session = await lucia.createSession(user.id, {
country: event.locals.session.ip,
country: event.locals.session?.ip,
});
const sessionCookie = lucia.createSessionCookie(session.id);
return new Response(null, {

View file

@ -1,11 +1,10 @@
<script lang="ts">
import { superForm } from 'sveltekit-superforms/client';
//import SuperDebug from 'sveltekit-superforms/client/SuperDebug.svelte';
import { changeUserPasswordSchema, userSchema } from '$lib/config/zod-schemas';
import { AlertTriangle, KeyRound } from 'lucide-svelte';
import { Label } from '$components/ui/label';
import { Input } from '$components/ui/input';
import { Button } from '$components/ui/button';
import { string } from 'zod';
export let data;
const { form, errors, enhance, delayed, message } = superForm(data.form, {
@ -34,7 +33,7 @@
<small>{$errors.current_password}</small>
{/if}
</div>
<div class="mt-6">
<div class="mt-6 grid">
<Label for="password">New Password</Label>
<Input type="password" id="password" name="password" placeholder="Password" autocomplete="given-name" data-invalid={$errors.password} bind:value={$form.password} />
{#if $errors.password}

View file

@ -3,23 +3,37 @@
</script>
<div class="container">
<div class="logo">
<Logo />
<div class="site-logo">
<div class="logo">
<Logo />
</div>
Bored Game
</div>
<h1>Welcome to Bored Game</h1>
<h2>Keep track of your board games!</h2>
<p>The ones you own, the ones you want, and whether you play them enough.</p>
<p>Get started by joinging the <a href="/waitlist">waitlist</a> or <a href="/login">signing in</a>.</p>
<h1>Welcome to Bored Game!</h1>
<h2>Track the board games you own, the ones you want, and whether you play them enough.</h2>
<p>Get started by joining the <a href="/waitlist">wait list</a> or <a href="/login">log in</a> if you already have an account.</p>
</div>
<style lang="postcss">
a {
text-decoration: underline;
}
.site-logo {
display: flex;
place-items: center;
}
.container {
max-width: 900px;
display: grid;
place-content: center;
max-width: 900px;
gap: 0.25rem;
}
.logo {
display: flex;
align-items: center;
width: 4rem;
height: 4rem;
}

View file

@ -1,5 +1,14 @@
import { relations, sql, type InferSelectModel } from 'drizzle-orm';
import { pgTable, timestamp, varchar, boolean, integer, text, index, pgEnum } from 'drizzle-orm/pg-core';
import {
pgTable,
timestamp,
varchar,
boolean,
integer,
text,
index,
pgEnum
} from 'drizzle-orm/pg-core';
import { nanoid } from 'nanoid';
import { tsvector } from './tsVector';
@ -77,7 +86,7 @@ export type Roles = InferSelectModel<typeof roles>;
export const role_relations = relations(roles, ({ many }) => ({
user_roles: many(user_roles)
}))
}));
export const user_roles = pgTable('user_roles', {
id: varchar('id', {
@ -259,7 +268,12 @@ export const wishlist_item_relations = relations(wishlist_items, ({ one }) => ({
// Game and related table schemas
export const externalIdType = pgEnum('external_id_type', [
'game', 'category', 'mechanic', 'publisher', 'designer', 'artist'
'game',
'category',
'mechanic',
'publisher',
'designer',
'artist'
]);
export const externalIds = pgTable('external_ids', {
@ -268,64 +282,68 @@ export const externalIds = pgTable('external_ids', {
})
.primaryKey()
.$defaultFn(() => nanoid()),
type: varchar('type', {
length: 255
}).notNull(),
type: externalIdType('type').notNull(),
externalId: varchar('external_id', {
length: 255
}).notNull()
});
export const games = pgTable('games', {
id: varchar('id', {
length: 255
})
.primaryKey()
.$defaultFn(() => nanoid()),
name: varchar('name', {
length: 255
}),
slug: varchar('slug', {
length: 255
}),
description: text('description'),
year_published: integer('year_published'),
min_players: integer('min_players'),
max_players: integer('max_players'),
playtime: integer('playtime'),
min_playtime: integer('min_playtime'),
max_playtime: integer('max_playtime'),
min_age: integer('min_age'),
image_url: varchar('image_url', {
length: 255
}),
thumb_url: varchar('thumb_url', {
length: 255
}),
url: varchar('url', {
length: 255
}),
text_searchable_index: tsvector('text_searchable_index'),
last_sync_at: timestamp('last_sync_at', {
withTimezone: true,
mode: 'date',
precision: 6
}),
created_at: timestamp('created_at', {
withTimezone: true,
mode: 'date',
precision: 6
}).default(sql`now()`),
updated_at: timestamp('updated_at', {
withTimezone: true,
mode: 'date',
precision: 6
}).default(sql`now()`)
}, (table) => {
return {
text_searchable_idx: index("text_searchable_idx").on(table.text_searchable_index).using(sql`'gin'`)
}
});
export const games = pgTable(
'games',
{
id: varchar('id', {
length: 255
})
.primaryKey()
.$defaultFn(() => nanoid()),
name: varchar('name', {
length: 255
}),
slug: varchar('slug', {
length: 255
}),
description: text('description'),
year_published: integer('year_published'),
min_players: integer('min_players'),
max_players: integer('max_players'),
playtime: integer('playtime'),
min_playtime: integer('min_playtime'),
max_playtime: integer('max_playtime'),
min_age: integer('min_age'),
image_url: varchar('image_url', {
length: 255
}),
thumb_url: varchar('thumb_url', {
length: 255
}),
url: varchar('url', {
length: 255
}),
text_searchable_index: tsvector('text_searchable_index'),
last_sync_at: timestamp('last_sync_at', {
withTimezone: true,
mode: 'date',
precision: 6
}),
created_at: timestamp('created_at', {
withTimezone: true,
mode: 'date',
precision: 6
}).default(sql`now()`),
updated_at: timestamp('updated_at', {
withTimezone: true,
mode: 'date',
precision: 6
}).default(sql`now()`)
},
(table) => {
return {
text_searchable_idx: index('text_searchable_idx')
.on(table.text_searchable_index)
.using(sql`'gin'`)
};
}
);
export type Games = InferSelectModel<typeof games>;
@ -339,14 +357,14 @@ export const gamesToExternalIds = pgTable('games_to_external_ids', {
length: 255
})
.notNull()
.references(() => externalIds.id, { onDelete: 'cascade' }),
.references(() => externalIds.id, { onDelete: 'cascade' })
});
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', {
@ -387,7 +405,7 @@ export const expansionsToExternalIds = pgTable('expansions_to_external_ids', {
length: 255
})
.notNull()
.references(() => externalIds.id, { onDelete: 'cascade' }),
.references(() => externalIds.id, { onDelete: 'cascade' })
});
export const expansion_relations = relations(expansions, ({ one, many }) => ({
@ -437,7 +455,7 @@ export const publishersToExternalIds = pgTable('publishers_to_external_ids', {
length: 255
})
.notNull()
.references(() => externalIds.id, { onDelete: 'cascade' }),
.references(() => externalIds.id, { onDelete: 'cascade' })
});
export const publishers_relations = relations(publishers, ({ many }) => ({
@ -480,8 +498,8 @@ export const categoriesToExternalIds = pgTable('categories_to_external_ids', {
length: 255
})
.notNull()
.references(() => externalIds.id, { onDelete: 'cascade' }),
})
.references(() => externalIds.id, { onDelete: 'cascade' })
});
export const categories_to_games = pgTable('categories_to_games', {
category_id: varchar('category_id', {
@ -543,8 +561,8 @@ export const mechanicsToExternalIds = pgTable('mechanics_to_external_ids', {
length: 255
})
.notNull()
.references(() => externalIds.id, { onDelete: 'cascade' }),
})
.references(() => externalIds.id, { onDelete: 'cascade' })
});
export const mechanic_relations = relations(mechanics, ({ many }) => ({
mechanics_to_games: many(mechanics_to_games),