mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
commit
4dd211d3cb
13 changed files with 251 additions and 201 deletions
1
.node-version
Normal file
1
.node-version
Normal file
|
|
@ -0,0 +1 @@
|
|||
20.6.1
|
||||
12
package.json
12
package.json
|
|
@ -32,23 +32,23 @@
|
|||
"@types/cookie": "^0.6.0",
|
||||
"@types/node": "^20.14.10",
|
||||
"@types/pg": "^8.11.6",
|
||||
"@typescript-eslint/eslint-plugin": "^7.13.0",
|
||||
"@typescript-eslint/parser": "^7.13.0",
|
||||
"@typescript-eslint/eslint-plugin": "^7.16.0",
|
||||
"@typescript-eslint/parser": "^7.16.0",
|
||||
"autoprefixer": "^10.4.19",
|
||||
"drizzle-kit": "^0.23.0",
|
||||
"eslint": "^8.57.0",
|
||||
"eslint-config-prettier": "^9.1.0",
|
||||
"eslint-plugin-svelte": "^2.41.0",
|
||||
"eslint-plugin-svelte": "^2.42.0",
|
||||
"just-clone": "^6.2.0",
|
||||
"just-debounce-it": "^3.2.0",
|
||||
"postcss": "^8.4.39",
|
||||
"postcss-import": "^16.1.0",
|
||||
"postcss-load-config": "^5.1.0",
|
||||
"postcss-preset-env": "^9.6.0",
|
||||
"prettier": "^3.3.2",
|
||||
"prettier": "^3.3.3",
|
||||
"prettier-plugin-svelte": "^3.2.5",
|
||||
"sass": "^1.77.8",
|
||||
"satori": "^0.10.13",
|
||||
"satori": "^0.10.14",
|
||||
"satori-html": "^0.3.2",
|
||||
"svelte": "5.0.0-next.175",
|
||||
"svelte-check": "^3.8.4",
|
||||
|
|
@ -100,7 +100,7 @@
|
|||
"just-kebab-case": "^4.2.0",
|
||||
"loader": "^2.1.1",
|
||||
"lucia": "3.2.0",
|
||||
"lucide-svelte": "^0.407.0",
|
||||
"lucide-svelte": "^0.408.0",
|
||||
"open-props": "^1.7.5",
|
||||
"oslo": "^1.2.1",
|
||||
"pg": "^8.12.0",
|
||||
|
|
|
|||
162
pnpm-lock.yaml
162
pnpm-lock.yaml
|
|
@ -87,8 +87,8 @@ importers:
|
|||
specifier: 3.2.0
|
||||
version: 3.2.0
|
||||
lucide-svelte:
|
||||
specifier: ^0.407.0
|
||||
version: 0.407.0(svelte@5.0.0-next.175)
|
||||
specifier: ^0.408.0
|
||||
version: 0.408.0(svelte@5.0.0-next.175)
|
||||
open-props:
|
||||
specifier: ^1.7.5
|
||||
version: 1.7.5
|
||||
|
|
@ -160,11 +160,11 @@ importers:
|
|||
specifier: ^8.11.6
|
||||
version: 8.11.6
|
||||
'@typescript-eslint/eslint-plugin':
|
||||
specifier: ^7.13.0
|
||||
version: 7.13.0(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3)
|
||||
specifier: ^7.16.0
|
||||
version: 7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/parser':
|
||||
specifier: ^7.13.0
|
||||
version: 7.13.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
specifier: ^7.16.0
|
||||
version: 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
autoprefixer:
|
||||
specifier: ^10.4.19
|
||||
version: 10.4.19(postcss@8.4.39)
|
||||
|
|
@ -178,8 +178,8 @@ importers:
|
|||
specifier: ^9.1.0
|
||||
version: 9.1.0(eslint@8.57.0)
|
||||
eslint-plugin-svelte:
|
||||
specifier: ^2.41.0
|
||||
version: 2.41.0(eslint@8.57.0)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3))
|
||||
specifier: ^2.42.0
|
||||
version: 2.42.0(eslint@8.57.0)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3))
|
||||
just-clone:
|
||||
specifier: ^6.2.0
|
||||
version: 6.2.0
|
||||
|
|
@ -199,17 +199,17 @@ importers:
|
|||
specifier: ^9.6.0
|
||||
version: 9.6.0(postcss@8.4.39)
|
||||
prettier:
|
||||
specifier: ^3.3.2
|
||||
version: 3.3.2
|
||||
specifier: ^3.3.3
|
||||
version: 3.3.3
|
||||
prettier-plugin-svelte:
|
||||
specifier: ^3.2.5
|
||||
version: 3.2.5(prettier@3.3.2)(svelte@5.0.0-next.175)
|
||||
version: 3.2.5(prettier@3.3.3)(svelte@5.0.0-next.175)
|
||||
sass:
|
||||
specifier: ^1.77.8
|
||||
version: 1.77.8
|
||||
satori:
|
||||
specifier: ^0.10.13
|
||||
version: 0.10.13
|
||||
specifier: ^0.10.14
|
||||
version: 0.10.14
|
||||
satori-html:
|
||||
specifier: ^0.3.2
|
||||
version: 0.3.2
|
||||
|
|
@ -1923,8 +1923,8 @@ packages:
|
|||
'@types/validator@13.12.0':
|
||||
resolution: {integrity: sha512-nH45Lk7oPIJ1RVOF6JgFI6Dy0QpHEzq4QecZhvguxYPDwT8c93prCMqAtiIttm39voZ+DDR+qkNnMpJmMBRqag==}
|
||||
|
||||
'@typescript-eslint/eslint-plugin@7.13.0':
|
||||
resolution: {integrity: sha512-FX1X6AF0w8MdVFLSdqwqN/me2hyhuQg4ykN6ZpVhh1ij/80pTvDKclX1sZB9iqex8SjQfVhwMKs3JtnnMLzG9w==}
|
||||
'@typescript-eslint/eslint-plugin@7.16.0':
|
||||
resolution: {integrity: sha512-py1miT6iQpJcs1BiJjm54AMzeuMPBSPuKPlnT8HlfudbcS5rYeX5jajpLf3mrdRh9dA/Ec2FVUY0ifeVNDIhZw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
'@typescript-eslint/parser': ^7.0.0
|
||||
|
|
@ -1934,8 +1934,8 @@ packages:
|
|||
typescript:
|
||||
optional: true
|
||||
|
||||
'@typescript-eslint/parser@7.13.0':
|
||||
resolution: {integrity: sha512-EjMfl69KOS9awXXe83iRN7oIEXy9yYdqWfqdrFAYAAr6syP8eLEFI7ZE4939antx2mNgPRW/o1ybm2SFYkbTVA==}
|
||||
'@typescript-eslint/parser@7.16.0':
|
||||
resolution: {integrity: sha512-ar9E+k7CU8rWi2e5ErzQiC93KKEFAXA2Kky0scAlPcxYblLt8+XZuHUZwlyfXILyQa95P6lQg+eZgh/dDs3+Vw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.56.0
|
||||
|
|
@ -1944,12 +1944,12 @@ packages:
|
|||
typescript:
|
||||
optional: true
|
||||
|
||||
'@typescript-eslint/scope-manager@7.13.0':
|
||||
resolution: {integrity: sha512-ZrMCe1R6a01T94ilV13egvcnvVJ1pxShkE0+NDjDzH4nvG1wXpwsVI5bZCvE7AEDH1mXEx5tJSVR68bLgG7Dng==}
|
||||
'@typescript-eslint/scope-manager@7.16.0':
|
||||
resolution: {integrity: sha512-8gVv3kW6n01Q6TrI1cmTZ9YMFi3ucDT7i7aI5lEikk2ebk1AEjrwX8MDTdaX5D7fPXMBLvnsaa0IFTAu+jcfOw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
|
||||
'@typescript-eslint/type-utils@7.13.0':
|
||||
resolution: {integrity: sha512-xMEtMzxq9eRkZy48XuxlBFzpVMDurUAfDu5Rz16GouAtXm0TaAoTFzqWUFPPuQYXI/CDaH/Bgx/fk/84t/Bc9A==}
|
||||
'@typescript-eslint/type-utils@7.16.0':
|
||||
resolution: {integrity: sha512-j0fuUswUjDHfqV/UdW6mLtOQQseORqfdmoBNDFOqs9rvNVR2e+cmu6zJu/Ku4SDuqiJko6YnhwcL8x45r8Oqxg==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.56.0
|
||||
|
|
@ -1958,12 +1958,12 @@ packages:
|
|||
typescript:
|
||||
optional: true
|
||||
|
||||
'@typescript-eslint/types@7.13.0':
|
||||
resolution: {integrity: sha512-QWuwm9wcGMAuTsxP+qz6LBBd3Uq8I5Nv8xb0mk54jmNoCyDspnMvVsOxI6IsMmway5d1S9Su2+sCKv1st2l6eA==}
|
||||
'@typescript-eslint/types@7.16.0':
|
||||
resolution: {integrity: sha512-fecuH15Y+TzlUutvUl9Cc2XJxqdLr7+93SQIbcZfd4XRGGKoxyljK27b+kxKamjRkU7FYC6RrbSCg0ALcZn/xw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
|
||||
'@typescript-eslint/typescript-estree@7.13.0':
|
||||
resolution: {integrity: sha512-cAvBvUoobaoIcoqox1YatXOnSl3gx92rCZoMRPzMNisDiM12siGilSM4+dJAekuuHTibI2hVC2fYK79iSFvWjw==}
|
||||
'@typescript-eslint/typescript-estree@7.16.0':
|
||||
resolution: {integrity: sha512-a5NTvk51ZndFuOLCh5OaJBELYc2O3Zqxfl3Js78VFE1zE46J2AaVuW+rEbVkQznjkmlzWsUI15BG5tQMixzZLw==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
typescript: '*'
|
||||
|
|
@ -1971,14 +1971,14 @@ packages:
|
|||
typescript:
|
||||
optional: true
|
||||
|
||||
'@typescript-eslint/utils@7.13.0':
|
||||
resolution: {integrity: sha512-jceD8RgdKORVnB4Y6BqasfIkFhl4pajB1wVxrF4akxD2QPM8GNYjgGwEzYS+437ewlqqrg7Dw+6dhdpjMpeBFQ==}
|
||||
'@typescript-eslint/utils@7.16.0':
|
||||
resolution: {integrity: sha512-PqP4kP3hb4r7Jav+NiRCntlVzhxBNWq6ZQ+zQwII1y/G/1gdIPeYDCKr2+dH6049yJQsWZiHU6RlwvIFBXXGNA==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^8.56.0
|
||||
|
||||
'@typescript-eslint/visitor-keys@7.13.0':
|
||||
resolution: {integrity: sha512-nxn+dozQx+MK61nn/JP+M4eCkHDSxSLDpgE3WcQo0+fkjEolnaB5jswvIKC4K56By8MMgIho7f1PVxERHEo8rw==}
|
||||
'@typescript-eslint/visitor-keys@7.16.0':
|
||||
resolution: {integrity: sha512-rMo01uPy9C7XxG7AFsxa8zLnWXTF8N3PYclekWSrurvhwiw1eW88mrKiAYe6s53AUY57nTRz8dJsuuXdkAhzCg==}
|
||||
engines: {node: ^18.18.0 || >=20.0.0}
|
||||
|
||||
'@ungap/structured-clone@1.2.0':
|
||||
|
|
@ -2592,12 +2592,12 @@ packages:
|
|||
peerDependencies:
|
||||
eslint: '>=7.0.0'
|
||||
|
||||
eslint-plugin-svelte@2.41.0:
|
||||
resolution: {integrity: sha512-gjU9Q/psxbWG1VNwYbEb0Q6U4W5PBGaDpYmO2zlQ+zlAMVS3Qt0luAK0ACi/tMSwRK6JENiySvMyJbO0YWmXSg==}
|
||||
eslint-plugin-svelte@2.42.0:
|
||||
resolution: {integrity: sha512-mHP6z0DWq97KZvoQcApZHdF9m9epcDV/ICKufeEH18Vh+8vl7S+gwt8WdUohEqKNVMuXRkbvy1suMcVvUDiOGw==}
|
||||
engines: {node: ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
eslint: ^7.0.0 || ^8.0.0-0 || ^9.0.0-0
|
||||
svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.155
|
||||
svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.181
|
||||
peerDependenciesMeta:
|
||||
svelte:
|
||||
optional: true
|
||||
|
|
@ -3016,8 +3016,8 @@ packages:
|
|||
lucia@3.2.0:
|
||||
resolution: {integrity: sha512-eXMxXwk6hqtjRTj4W/x3EnTUtAztLPm0p2N2TEBMDEbakDLXiYnDQ9z/qahjPdPdhPguQc+vwO0/88zIWxlpuw==}
|
||||
|
||||
lucide-svelte@0.407.0:
|
||||
resolution: {integrity: sha512-gtFkn8/+4XedQh1WMm6FVed7v1yny4q8IjjIlhlhZZ5syAUVFrsnuPPuzCgmb0zNSo/fvn4RnytO/DX4iP3iUQ==}
|
||||
lucide-svelte@0.408.0:
|
||||
resolution: {integrity: sha512-5rJvcnHvE+K/2ebff/tKvG1FmIut01hDUaibMk6pG2Je+82TCPflVvhMvgCjP0fkM0ztj5t/ma1s5WYyketOSA==}
|
||||
peerDependencies:
|
||||
svelte: ^3 || ^4 || ^5.0.0-next.42
|
||||
|
||||
|
|
@ -3078,6 +3078,10 @@ packages:
|
|||
resolution: {integrity: sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minimatch@9.0.5:
|
||||
resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==}
|
||||
engines: {node: '>=16 || 14 >=14.17'}
|
||||
|
||||
minimist@1.2.8:
|
||||
resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==}
|
||||
|
||||
|
|
@ -3647,8 +3651,8 @@ packages:
|
|||
prettier: ^3.0.0
|
||||
svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0
|
||||
|
||||
prettier@3.3.2:
|
||||
resolution: {integrity: sha512-rAVeHYMcv8ATV5d508CFdn+8/pHPpXeIid1DdrPwXnaAdH7cqjVbpJaT5eq4yRAFU/lsbwYwSF/n5iNrdJHPQA==}
|
||||
prettier@3.3.3:
|
||||
resolution: {integrity: sha512-i2tDNA0O5IrMO757lfrdQZCc2jPNDVntV0m/+4whiDfWaTKfMNgR7Qz0NAeGz/nRqF4m5/6CLzbP4/liHt12Ew==}
|
||||
engines: {node: '>=14'}
|
||||
hasBin: true
|
||||
|
||||
|
|
@ -3762,8 +3766,8 @@ packages:
|
|||
satori-html@0.3.2:
|
||||
resolution: {integrity: sha512-wjTh14iqADFKDK80e51/98MplTGfxz2RmIzh0GqShlf4a67+BooLywF17TvJPD6phO0Hxm7Mf1N5LtRYvdkYRA==}
|
||||
|
||||
satori@0.10.13:
|
||||
resolution: {integrity: sha512-klCwkVYMQ/ZN5inJLHzrUmGwoRfsdP7idB5hfpJ1jfiJk1ErDitK8Hkc6Kll1+Ox2WtqEuGecSZLnmup3CGzvQ==}
|
||||
satori@0.10.14:
|
||||
resolution: {integrity: sha512-abovcqmwl97WKioxpkfuMeZmndB1TuDFY/R+FymrZyiGP+pMYomvgSzVPnbNMWHHESOPosVHGL352oFbdAnJcA==}
|
||||
engines: {node: '>=16'}
|
||||
|
||||
satori@0.10.9:
|
||||
|
|
@ -3911,11 +3915,11 @@ packages:
|
|||
peerDependencies:
|
||||
svelte: ^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0
|
||||
|
||||
svelte-eslint-parser@0.39.2:
|
||||
resolution: {integrity: sha512-87UwLuWTtDIuzWOhOi1zBL5wYVd07M5BK1qZ57YmXJB5/UmjUNJqGy3XSOhPqjckY1dATNV9y+mx+nI0WH6HPA==}
|
||||
svelte-eslint-parser@0.40.0:
|
||||
resolution: {integrity: sha512-M+v1HhC5T1WKYVxWexUCS4o6oIBS88XKzOZuhl2ew+eGxol7eC21e+VE8TC4rXJ3iT3iXT0qlZsZcpKjVo5/zQ==}
|
||||
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
|
||||
peerDependencies:
|
||||
svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.115
|
||||
svelte: ^3.37.0 || ^4.0.0 || ^5.0.0-next.181
|
||||
peerDependenciesMeta:
|
||||
svelte:
|
||||
optional: true
|
||||
|
|
@ -5705,14 +5709,14 @@ snapshots:
|
|||
'@types/validator@13.12.0':
|
||||
optional: true
|
||||
|
||||
'@typescript-eslint/eslint-plugin@7.13.0(@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3)':
|
||||
'@typescript-eslint/eslint-plugin@7.16.0(@typescript-eslint/parser@7.16.0(eslint@8.57.0)(typescript@5.5.3))(eslint@8.57.0)(typescript@5.5.3)':
|
||||
dependencies:
|
||||
'@eslint-community/regexpp': 4.10.0
|
||||
'@typescript-eslint/parser': 7.13.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/scope-manager': 7.13.0
|
||||
'@typescript-eslint/type-utils': 7.13.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/utils': 7.13.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/visitor-keys': 7.13.0
|
||||
'@typescript-eslint/parser': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/scope-manager': 7.16.0
|
||||
'@typescript-eslint/type-utils': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/utils': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/visitor-keys': 7.16.0
|
||||
eslint: 8.57.0
|
||||
graphemer: 1.4.0
|
||||
ignore: 5.3.1
|
||||
|
|
@ -5723,12 +5727,12 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/parser@7.13.0(eslint@8.57.0)(typescript@5.5.3)':
|
||||
'@typescript-eslint/parser@7.16.0(eslint@8.57.0)(typescript@5.5.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/scope-manager': 7.13.0
|
||||
'@typescript-eslint/types': 7.13.0
|
||||
'@typescript-eslint/typescript-estree': 7.13.0(typescript@5.5.3)
|
||||
'@typescript-eslint/visitor-keys': 7.13.0
|
||||
'@typescript-eslint/scope-manager': 7.16.0
|
||||
'@typescript-eslint/types': 7.16.0
|
||||
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3)
|
||||
'@typescript-eslint/visitor-keys': 7.16.0
|
||||
debug: 4.3.4
|
||||
eslint: 8.57.0
|
||||
optionalDependencies:
|
||||
|
|
@ -5736,15 +5740,15 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/scope-manager@7.13.0':
|
||||
'@typescript-eslint/scope-manager@7.16.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 7.13.0
|
||||
'@typescript-eslint/visitor-keys': 7.13.0
|
||||
'@typescript-eslint/types': 7.16.0
|
||||
'@typescript-eslint/visitor-keys': 7.16.0
|
||||
|
||||
'@typescript-eslint/type-utils@7.13.0(eslint@8.57.0)(typescript@5.5.3)':
|
||||
'@typescript-eslint/type-utils@7.16.0(eslint@8.57.0)(typescript@5.5.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/typescript-estree': 7.13.0(typescript@5.5.3)
|
||||
'@typescript-eslint/utils': 7.13.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3)
|
||||
'@typescript-eslint/utils': 7.16.0(eslint@8.57.0)(typescript@5.5.3)
|
||||
debug: 4.3.5
|
||||
eslint: 8.57.0
|
||||
ts-api-utils: 1.3.0(typescript@5.5.3)
|
||||
|
|
@ -5753,16 +5757,16 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/types@7.13.0': {}
|
||||
'@typescript-eslint/types@7.16.0': {}
|
||||
|
||||
'@typescript-eslint/typescript-estree@7.13.0(typescript@5.5.3)':
|
||||
'@typescript-eslint/typescript-estree@7.16.0(typescript@5.5.3)':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 7.13.0
|
||||
'@typescript-eslint/visitor-keys': 7.13.0
|
||||
'@typescript-eslint/types': 7.16.0
|
||||
'@typescript-eslint/visitor-keys': 7.16.0
|
||||
debug: 4.3.4
|
||||
globby: 11.1.0
|
||||
is-glob: 4.0.3
|
||||
minimatch: 9.0.4
|
||||
minimatch: 9.0.5
|
||||
semver: 7.6.2
|
||||
ts-api-utils: 1.3.0(typescript@5.5.3)
|
||||
optionalDependencies:
|
||||
|
|
@ -5770,20 +5774,20 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@typescript-eslint/utils@7.13.0(eslint@8.57.0)(typescript@5.5.3)':
|
||||
'@typescript-eslint/utils@7.16.0(eslint@8.57.0)(typescript@5.5.3)':
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
|
||||
'@typescript-eslint/scope-manager': 7.13.0
|
||||
'@typescript-eslint/types': 7.13.0
|
||||
'@typescript-eslint/typescript-estree': 7.13.0(typescript@5.5.3)
|
||||
'@typescript-eslint/scope-manager': 7.16.0
|
||||
'@typescript-eslint/types': 7.16.0
|
||||
'@typescript-eslint/typescript-estree': 7.16.0(typescript@5.5.3)
|
||||
eslint: 8.57.0
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
- typescript
|
||||
|
||||
'@typescript-eslint/visitor-keys@7.13.0':
|
||||
'@typescript-eslint/visitor-keys@7.16.0':
|
||||
dependencies:
|
||||
'@typescript-eslint/types': 7.13.0
|
||||
'@typescript-eslint/types': 7.16.0
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
|
|
@ -6380,7 +6384,7 @@ snapshots:
|
|||
dependencies:
|
||||
eslint: 8.57.0
|
||||
|
||||
eslint-plugin-svelte@2.41.0(eslint@8.57.0)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)):
|
||||
eslint-plugin-svelte@2.42.0(eslint@8.57.0)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.14.10)(typescript@5.5.3)):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.0)
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
|
|
@ -6393,7 +6397,7 @@ snapshots:
|
|||
postcss-safe-parser: 6.0.0(postcss@8.4.39)
|
||||
postcss-selector-parser: 6.1.0
|
||||
semver: 7.6.2
|
||||
svelte-eslint-parser: 0.39.2(svelte@5.0.0-next.175)
|
||||
svelte-eslint-parser: 0.40.0(svelte@5.0.0-next.175)
|
||||
optionalDependencies:
|
||||
svelte: 5.0.0-next.175
|
||||
transitivePeerDependencies:
|
||||
|
|
@ -6851,7 +6855,7 @@ snapshots:
|
|||
dependencies:
|
||||
oslo: 1.2.0
|
||||
|
||||
lucide-svelte@0.407.0(svelte@5.0.0-next.175):
|
||||
lucide-svelte@0.408.0(svelte@5.0.0-next.175):
|
||||
dependencies:
|
||||
svelte: 5.0.0-next.175
|
||||
|
||||
|
|
@ -6907,6 +6911,10 @@ snapshots:
|
|||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
minimatch@9.0.5:
|
||||
dependencies:
|
||||
brace-expansion: 2.0.1
|
||||
|
||||
minimist@1.2.8: {}
|
||||
|
||||
minipass@3.3.6:
|
||||
|
|
@ -7462,12 +7470,12 @@ snapshots:
|
|||
|
||||
prelude-ls@1.2.1: {}
|
||||
|
||||
prettier-plugin-svelte@3.2.5(prettier@3.3.2)(svelte@5.0.0-next.175):
|
||||
prettier-plugin-svelte@3.2.5(prettier@3.3.3)(svelte@5.0.0-next.175):
|
||||
dependencies:
|
||||
prettier: 3.3.2
|
||||
prettier: 3.3.3
|
||||
svelte: 5.0.0-next.175
|
||||
|
||||
prettier@3.3.2: {}
|
||||
prettier@3.3.3: {}
|
||||
|
||||
pretty-format@29.7.0:
|
||||
dependencies:
|
||||
|
|
@ -7614,7 +7622,7 @@ snapshots:
|
|||
dependencies:
|
||||
ultrahtml: 1.5.3
|
||||
|
||||
satori@0.10.13:
|
||||
satori@0.10.14:
|
||||
dependencies:
|
||||
'@shuding/opentype.js': 1.4.0-beta.0
|
||||
css-background-parser: 0.1.0
|
||||
|
|
@ -7803,7 +7811,7 @@ snapshots:
|
|||
- stylus
|
||||
- sugarss
|
||||
|
||||
svelte-eslint-parser@0.39.2(svelte@5.0.0-next.175):
|
||||
svelte-eslint-parser@0.40.0(svelte@5.0.0-next.175):
|
||||
dependencies:
|
||||
eslint-scope: 7.2.2
|
||||
eslint-visitor-keys: 3.4.3
|
||||
|
|
|
|||
|
|
@ -34,6 +34,7 @@ for (const table of [
|
|||
schema.sessions,
|
||||
schema.userRoles,
|
||||
schema.users,
|
||||
schema.twoFactor,
|
||||
schema.wishlists,
|
||||
schema.wishlist_items,
|
||||
]) {
|
||||
|
|
|
|||
|
|
@ -13,8 +13,7 @@ import { lucia } from '$lib/server/auth';
|
|||
// });
|
||||
|
||||
export const authentication: Handle = async function ({ event, resolve }) {
|
||||
const startTimer = Date.now();
|
||||
event.locals.startTimer = startTimer;
|
||||
event.locals.startTimer = Date.now();
|
||||
|
||||
const ip = event.request.headers.get('x-forwarded-for') as string;
|
||||
const country = event.request.headers.get('x-vercel-ip-country') as string;
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ export const lucia = new Lucia(adapter, {
|
|||
expires: false, // session cookies have very long lifespan (2 years)
|
||||
attributes: {
|
||||
// set to `true` when using HTTPS
|
||||
secure: process.env.NODE_ENV === 'production',
|
||||
secure: process.env.NODE_ENV === 'production' || process.env.VERCEL_ENV === 'production',
|
||||
sameSite: 'strict',
|
||||
domain,
|
||||
},
|
||||
|
|
|
|||
|
|
@ -25,5 +25,9 @@ export const signInSchema = z.object({
|
|||
});
|
||||
|
||||
export const totpSchema = z.object({
|
||||
totpToken: z.string().trim().min(6).max(10),
|
||||
totpToken: z.string().trim().min(6).max(6),
|
||||
});
|
||||
|
||||
export const recoveryCodeSchema = z.object({
|
||||
recoveryCode: z.string().trim().min(10).max(10),
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { fail, error, type Actions } from '@sveltejs/kit';
|
||||
import { eq } from 'drizzle-orm';
|
||||
import { eq, or } from 'drizzle-orm';
|
||||
import { Argon2id } from 'oslo/password';
|
||||
import { zod } from 'sveltekit-superforms/adapters';
|
||||
import { setError, superValidate } from 'sveltekit-superforms/server';
|
||||
|
|
@ -58,7 +58,7 @@ export const actions: Actions = {
|
|||
let session;
|
||||
let sessionCookie;
|
||||
const user: Users | undefined = await db.query.users.findFirst({
|
||||
where: eq(users.username, form.data.username),
|
||||
where: or(eq(users.username, form.data.username), eq(users.email, form.data.username)),
|
||||
});
|
||||
|
||||
if (!user) {
|
||||
|
|
|
|||
|
|
@ -41,15 +41,29 @@
|
|||
</svelte:head>
|
||||
|
||||
<div class="login">
|
||||
<form method="POST" use:enhance>
|
||||
<h2
|
||||
<h2
|
||||
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
||||
>
|
||||
Log into your account
|
||||
</h2>
|
||||
>
|
||||
Log into your account
|
||||
</h2>
|
||||
{@render usernamePasswordForm()}
|
||||
<p class="px-8 text-center text-sm text-muted-foreground">
|
||||
By clicking continue, you agree to our
|
||||
<a href="/terms" class="underline underline-offset-4 hover:text-primary">
|
||||
Terms of Use
|
||||
</a>
|
||||
and
|
||||
<a href="/privacy" class="underline underline-offset-4 hover:text-primary">
|
||||
Privacy Policy
|
||||
</a>.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
{#snippet usernamePasswordForm()}
|
||||
<form method="POST" use:enhance>
|
||||
<Form.Field form={superLoginForm} name="username">
|
||||
<Form.Control let:attrs>
|
||||
<Form.Label for="username">Username</Form.Label>
|
||||
<Form.Label for="username">Username/Email</Form.Label>
|
||||
<Input {...attrs} autocomplete="username" bind:value={$loginForm.username} />
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
|
|
@ -62,22 +76,13 @@
|
|||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Form.Button>Login</Form.Button>
|
||||
<p class="px-8 text-center text-sm text-muted-foreground">
|
||||
By clicking continue, you agree to our
|
||||
<a href="/terms" class="underline underline-offset-4 hover:text-primary">
|
||||
Terms of Use
|
||||
</a>
|
||||
and
|
||||
<a href="/privacy" class="underline underline-offset-4 hover:text-primary">
|
||||
Privacy Policy
|
||||
</a>.
|
||||
</p>
|
||||
</form>
|
||||
</div>
|
||||
{/snippet}
|
||||
|
||||
<style lang="postcss">
|
||||
.login {
|
||||
display: flex;
|
||||
gap: 1rem;
|
||||
margin-top: 1.5rem;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ import { add_user_to_role } from '$server/roles';
|
|||
import db from '../../../db';
|
||||
import { collections, users, wishlists } from '$db/schema';
|
||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||
import { userFullyAuthenticated, userNotFullyAuthenticated } from '$lib/server/auth-utils';
|
||||
|
||||
const limiter = new RateLimiter({
|
||||
// A rate is defined by [number, unit]
|
||||
|
|
@ -29,16 +30,23 @@ const signUpDefaults = {
|
|||
};
|
||||
|
||||
export const load: PageServerLoad = async (event) => {
|
||||
// redirect(
|
||||
// 302,
|
||||
// '/waitlist',
|
||||
// { type: 'error', message: 'Sign-up not yet available. Please add your email to the waitlist!' },
|
||||
// event
|
||||
// );
|
||||
const { locals, cookies } = event;
|
||||
const { user, session } = event.locals;
|
||||
|
||||
if (event.locals.user) {
|
||||
if (userFullyAuthenticated(user, session)) {
|
||||
const message = { type: 'success', message: 'You are already signed in' } as const;
|
||||
throw redirect('/', message, event);
|
||||
} else if (userNotFullyAuthenticated(user, session)) {
|
||||
try {
|
||||
await lucia.invalidateSession(locals.session!.id!);
|
||||
} catch (error) {
|
||||
console.log('Session already invalidated');
|
||||
}
|
||||
const sessionCookie = lucia.createBlankSessionCookie();
|
||||
cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||
path: '.',
|
||||
...sessionCookie.attributes,
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
|
|
@ -91,8 +99,6 @@ export const actions: Actions = {
|
|||
verified: false,
|
||||
receive_email: false,
|
||||
theme: 'system',
|
||||
two_factor_secret: '',
|
||||
two_factor_enabled: false,
|
||||
})
|
||||
.returning();
|
||||
console.log('signup user', user);
|
||||
|
|
@ -104,7 +110,7 @@ export const actions: Actions = {
|
|||
});
|
||||
}
|
||||
|
||||
add_user_to_role(user[0].id, 'user', true);
|
||||
await add_user_to_role(user[0].id, 'user', true);
|
||||
await db.insert(collections).values({
|
||||
user_id: user[0].id,
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { fail, error, type Actions, type Cookies, type RequestEvent } from '@sveltejs/kit';
|
||||
import { fail, error, type Actions } from '@sveltejs/kit';
|
||||
import { and, eq } from 'drizzle-orm';
|
||||
import { Argon2id } from 'oslo/password';
|
||||
import { decodeHex } from 'oslo/encoding';
|
||||
|
|
@ -9,7 +9,7 @@ import { redirect } from 'sveltekit-flash-message/server';
|
|||
import { RateLimiter } from 'sveltekit-rate-limiter/server';
|
||||
import db from '../../../db';
|
||||
import { lucia } from '$lib/server/auth';
|
||||
import { totpSchema } from '$lib/validations/auth';
|
||||
import { recoveryCodeSchema, totpSchema } from '$lib/validations/auth';
|
||||
import { users, twoFactor, recoveryCodes } from '$db/schema';
|
||||
import type { PageServerLoad } from './$types';
|
||||
import { notSignedInMessage } from '$lib/flashMessages';
|
||||
|
|
@ -33,7 +33,10 @@ export const load: PageServerLoad = async (event) => {
|
|||
});
|
||||
|
||||
if (!twoFactorDetails || !twoFactorDetails.enabled) {
|
||||
const message = { type: 'error', message: 'Two factor authentication is not enabled' } as const;
|
||||
const message = {
|
||||
type: 'error',
|
||||
message: 'Two factor authentication is not enabled',
|
||||
} as const;
|
||||
redirect(302, '/login', message, event);
|
||||
}
|
||||
|
||||
|
|
@ -49,10 +52,13 @@ export const load: PageServerLoad = async (event) => {
|
|||
}
|
||||
|
||||
// Check if two factor started less than TWO_FACTOR_TIMEOUT
|
||||
const timeElapsed = Date.now() - twoFactorInitiatedTime.getTime();
|
||||
console.log('Time elapsed', timeElapsed);
|
||||
if (timeElapsed > env.TWO_FACTOR_TIMEOUT) {
|
||||
console.log('Time elapsed was more than TWO_FACTOR_TIMEOUT', timeElapsed, env.TWO_FACTOR_TIMEOUT);
|
||||
const totpElapsed = totpTimeElapsed(twoFactorInitiatedTime);
|
||||
if (totpElapsed) {
|
||||
console.log(
|
||||
'Time elapsed was more than TWO_FACTOR_TIMEOUT',
|
||||
totpElapsed,
|
||||
env.TWO_FACTOR_TIMEOUT,
|
||||
);
|
||||
await lucia.invalidateSession(session!.id!);
|
||||
const sessionCookie = lucia.createBlankSessionCookie();
|
||||
cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||
|
|
@ -68,20 +74,15 @@ export const load: PageServerLoad = async (event) => {
|
|||
console.log('session', session);
|
||||
console.log('isTwoFactorAuthenticated', isTwoFactorAuthenticated);
|
||||
|
||||
if (
|
||||
isTwoFactorAuthenticated &&
|
||||
twoFactorDetails?.enabled &&
|
||||
twoFactorDetails?.secret !== ''
|
||||
) {
|
||||
if (isTwoFactorAuthenticated && twoFactorDetails?.enabled && twoFactorDetails?.secret !== '') {
|
||||
const message = { type: 'success', message: 'You are already signed in' } as const;
|
||||
throw redirect('/', message, event);
|
||||
}
|
||||
}
|
||||
|
||||
const form = await superValidate(event, zod(totpSchema));
|
||||
|
||||
return {
|
||||
form,
|
||||
totpForm: await superValidate(event, zod(totpSchema)),
|
||||
recoveryCodeForm: await superValidate(event, zod(recoveryCodeSchema)),
|
||||
};
|
||||
};
|
||||
|
||||
|
|
@ -115,13 +116,14 @@ export const actions: Actions = {
|
|||
const isTwoFactorAuthenticated = session?.isTwoFactorAuthenticated;
|
||||
const twoFactorDetails = await db.query.twoFactor.findFirst({
|
||||
where: eq(twoFactor.userId, dbUser!.id!),
|
||||
})
|
||||
});
|
||||
|
||||
if (
|
||||
isTwoFactorAuthenticated &&
|
||||
twoFactorDetails?.enabled &&
|
||||
twoFactorDetails?.secret !== ''
|
||||
) {
|
||||
if (!twoFactorDetails) {
|
||||
const message = { type: 'error', message: 'Unable to process request' } as const;
|
||||
throw redirect(302, '/login', message, event);
|
||||
}
|
||||
|
||||
if (isTwoFactorAuthenticated && twoFactorDetails.enabled && twoFactorDetails.secret !== '') {
|
||||
const message = { type: 'success', message: 'You are already signed in' } as const;
|
||||
throw redirect('/', message, event);
|
||||
}
|
||||
|
|
@ -140,19 +142,32 @@ export const actions: Actions = {
|
|||
const totpToken = form?.data?.totpToken;
|
||||
|
||||
const twoFactorSecretPopulated =
|
||||
twoFactorDetails?.secret !== '' && twoFactorDetails?.secret !== null;
|
||||
if (twoFactorDetails?.enabled && !twoFactorSecretPopulated && !totpToken) {
|
||||
twoFactorDetails.secret !== '' && twoFactorDetails.secret !== null;
|
||||
if (twoFactorDetails.enabled && !twoFactorSecretPopulated && !totpToken) {
|
||||
return fail(400, {
|
||||
form,
|
||||
});
|
||||
} else if (twoFactorSecretPopulated && totpToken) {
|
||||
// Check if two factor started less than TWO_FACTOR_TIMEOUT
|
||||
await checkTOTPExpiry(twoFactorDetails, session, cookies, event);
|
||||
const totpElapsed = totpTimeElapsed(twoFactorDetails.initiatedTime ?? new Date());
|
||||
if (totpElapsed) {
|
||||
await lucia.invalidateSession(session!.id!);
|
||||
const sessionCookie = lucia.createBlankSessionCookie();
|
||||
cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||
path: '.',
|
||||
...sessionCookie.attributes,
|
||||
});
|
||||
const message = {
|
||||
type: 'error',
|
||||
message: 'Two factor authentication has expired',
|
||||
} as const;
|
||||
redirect(302, '/login', message, event);
|
||||
}
|
||||
|
||||
console.log('totpToken', totpToken);
|
||||
const validOTP = await new TOTPController().verify(
|
||||
totpToken,
|
||||
decodeHex(twoFactorDetails?.secret ?? ''),
|
||||
decodeHex(twoFactorDetails.secret ?? ''),
|
||||
);
|
||||
console.log('validOTP', validOTP);
|
||||
|
||||
|
|
@ -161,6 +176,7 @@ export const actions: Actions = {
|
|||
const usedRecoveryCode = await checkRecoveryCode(totpToken, dbUser.id);
|
||||
if (!usedRecoveryCode) {
|
||||
console.log('invalid TOTP code');
|
||||
form.data.totpToken = '';
|
||||
return setError(form, 'totpToken', 'Invalid code.');
|
||||
}
|
||||
}
|
||||
|
|
@ -195,24 +211,22 @@ export const actions: Actions = {
|
|||
},
|
||||
};
|
||||
|
||||
async function checkTOTPExpiry(twoFactorDetails: { id: string; cuid: string | null; secret: string; enabled: boolean; initiatedTime: Date | null; createdAt: Date; updatedAt: Date; userId: string; } | undefined, session, cookies: Cookies, event: RequestEvent<Partial<Record<string, string>>, string | null>) {
|
||||
const twoFactorInitiatedTime = twoFactorDetails?.initiatedTime;
|
||||
if (twoFactorInitiatedTime === null || twoFactorInitiatedTime === undefined) {
|
||||
redirect(302, '/login');
|
||||
function totpTimeElapsed(initiatedTime: Date) {
|
||||
if (initiatedTime === null || initiatedTime === undefined) {
|
||||
return true;
|
||||
}
|
||||
const timeElapsed = Date.now() - twoFactorInitiatedTime.getTime();
|
||||
|
||||
const timeElapsed = Date.now() - initiatedTime.getTime();
|
||||
console.log('Time elapsed', timeElapsed);
|
||||
if (timeElapsed > env.TWO_FACTOR_TIMEOUT) {
|
||||
console.log('Time elapsed was more than TWO_FACTOR_TIMEOUT', timeElapsed, env.TWO_FACTOR_TIMEOUT);
|
||||
await lucia.invalidateSession(session!.id!);
|
||||
const sessionCookie = lucia.createBlankSessionCookie();
|
||||
cookies.set(sessionCookie.name, sessionCookie.value, {
|
||||
path: '.',
|
||||
...sessionCookie.attributes,
|
||||
});
|
||||
const message = { type: 'error', message: 'Two factor authentication has expired' } as const;
|
||||
redirect(302, '/login', message, event);
|
||||
console.log(
|
||||
'Time elapsed was more than TWO_FACTOR_TIMEOUT',
|
||||
timeElapsed,
|
||||
env.TWO_FACTOR_TIMEOUT,
|
||||
);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
async function checkRecoveryCode(recoveryCode: string, userId: string) {
|
||||
|
|
|
|||
|
|
@ -3,20 +3,17 @@
|
|||
import { superForm } from 'sveltekit-superforms/client';
|
||||
import * as flashModule from 'sveltekit-flash-message/client';
|
||||
import { AlertCircle } from "lucide-svelte";
|
||||
import { signInSchema, totpSchema } from '$lib/validations/auth';
|
||||
import { recoveryCodeSchema, totpSchema } from '$lib/validations/auth';
|
||||
import * as Form from '$lib/components/ui/form';
|
||||
import { Label } from '$components/ui/label';
|
||||
import { Input } from '$components/ui/input';
|
||||
import { Button } from '$components/ui/button';
|
||||
import * as Alert from "$components/ui/alert";
|
||||
import { boredState } from '$lib/stores/boredState.js';
|
||||
import PinInput from '$components/pin-input.svelte';
|
||||
|
||||
const { data } = $props();
|
||||
|
||||
const superTotpForm = superForm(data.form, {
|
||||
onSubmit: () => boredState.update((n) => ({ ...n, loading: true })),
|
||||
onResult: () => boredState.update((n) => ({ ...n, loading: false })),
|
||||
const superTotpForm = superForm(data.totpForm, {
|
||||
flashMessage: {
|
||||
module: flashModule,
|
||||
onError: ({ result, flashMessage }) => {
|
||||
|
|
@ -34,63 +31,81 @@
|
|||
delayMs: 0,
|
||||
});
|
||||
|
||||
const superRecoveryCodeForm = superForm(data.recoveryCodeForm, {
|
||||
validators: zodClient(recoveryCodeSchema),
|
||||
resetForm: false,
|
||||
flashMessage: {
|
||||
module: flashModule,
|
||||
onError: ({ result, flashMessage }) => {
|
||||
// Error handling for the flash message:
|
||||
// - result is the ActionResult
|
||||
// - message is the flash store (not the status message store)
|
||||
const errorMessage = result.error.message
|
||||
flashMessage.set({ type: 'error', message: errorMessage });
|
||||
}
|
||||
},
|
||||
syncFlashMessage: false,
|
||||
taintedMessage: null,
|
||||
validationMethod: 'oninput',
|
||||
delayMs: 0,
|
||||
});
|
||||
|
||||
let showRecoveryCode = $state(false);
|
||||
|
||||
const { form: totpForm, enhance } = superTotpForm;
|
||||
const { form: totpFormData, enhance: totpEnhance } = superTotpForm;
|
||||
const { form: recoveryCodeFormData, enhance: recoveryCodeEnhance } = superRecoveryCodeForm;
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<title>Bored Game | Login</title>
|
||||
</svelte:head>
|
||||
|
||||
<div class="login">
|
||||
<form method="POST" use:enhance>
|
||||
<h2
|
||||
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
||||
>
|
||||
Please enter your {showRecoveryCode ? 'recovery code' : 'TOTP code'}
|
||||
</h2>
|
||||
<Form.Field form={superTotpForm} name="totpToken">
|
||||
<Form.Control let:attrs>
|
||||
{#if showRecoveryCode}
|
||||
<Form.Label for="totpToken">Recovery Code</Form.Label>
|
||||
<Input {...attrs} autocomplete="one-time-code" bind:value={$totpForm.totpToken} />
|
||||
{:else}
|
||||
<Form.Label for="totpToken">TOTP Code</Form.Label>
|
||||
<PinInput {...attrs} bind:value={$totpForm.totpToken} />
|
||||
{/if}
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Form.Button>Submit</Form.Button>
|
||||
</form>
|
||||
<div class="totp">
|
||||
<h2
|
||||
class="scroll-m-20 border-b pb-2 text-3xl font-semibold tracking-tight transition-colors first:mt-0"
|
||||
>
|
||||
Please enter your {showRecoveryCode ? 'recovery code' : 'TOTP code'}
|
||||
</h2>
|
||||
{#if !showRecoveryCode}
|
||||
{@render totpForm()}
|
||||
<Button variant="link" class="text-secondary-foreground" on:click={() => showRecoveryCode = true}>Show Recovery Code</Button>
|
||||
{:else}
|
||||
{@render recoveryCodeForm()}
|
||||
<Button variant="link" class="text-secondary-foreground" on:click={() => showRecoveryCode = false}>Show TOTP Code</Button>
|
||||
{/if}
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.loading {
|
||||
position: fixed;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
z-index: 101;
|
||||
display: grid;
|
||||
place-items: center;
|
||||
gap: 1rem;
|
||||
{#snippet totpForm()}
|
||||
<form method="POST" use:totpEnhance>
|
||||
<Form.Field class="form-field-container" form={totpFormData} name="totpToken">
|
||||
<Form.Control let:attrs>
|
||||
<Form.Label for="totpToken">TOTP Code</Form.Label>
|
||||
<PinInput {...attrs} bind:value={$totpFormData.totpToken} />
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Form.Button class="w-full">Submit</Form.Button>
|
||||
</form>
|
||||
{/snippet}
|
||||
|
||||
h3 {
|
||||
color: white;
|
||||
}
|
||||
}
|
||||
.login {
|
||||
{#snippet recoveryCodeForm()}
|
||||
<form method="POST" use:recoveryCodeEnhance>
|
||||
<Form.Field form={recoveryCodeFormData} name="recoveryCode">
|
||||
<Form.Control let:attrs>
|
||||
<Form.Label for="totpToken">Recovery Code</Form.Label>
|
||||
<Input {...attrs} bind:value={$recoveryCodeFormData.recoveryCode} />
|
||||
</Form.Control>
|
||||
<Form.FieldErrors />
|
||||
</Form.Field>
|
||||
<Form.Button class="w-full">Submit</Form.Button>
|
||||
</form>
|
||||
{/snippet}
|
||||
|
||||
<style lang="postcss">
|
||||
.totp {
|
||||
display: flex;
|
||||
margin-top: 1.5rem;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
width: 100%;
|
||||
margin-right: auto;
|
||||
margin-left: auto;
|
||||
|
|
|
|||
|
|
@ -18,9 +18,6 @@ export default defineConfig({
|
|||
test: {
|
||||
include: ['src/**/*.{test,spec}.{js,ts}']
|
||||
},
|
||||
define: {
|
||||
SUPERFORMS_LEGACY: true
|
||||
},
|
||||
css: {
|
||||
devSourcemap: true,
|
||||
preprocessorOptions: {
|
||||
|
|
|
|||
Loading…
Reference in a new issue