mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Updating env, adding pino logger and providing to Hono, fixing biome formatting, and starting to maybe add some OpenAPI middleware.
This commit is contained in:
parent
27e17933af
commit
47ae91e015
19 changed files with 526 additions and 407 deletions
|
|
@ -2,7 +2,8 @@
|
|||
DOMAIN=localhost
|
||||
ORIGIN=http://$DOMAIN:5173
|
||||
|
||||
NODE_ENV=development
|
||||
NODE_ENV=
|
||||
LOG_LEVEL=
|
||||
|
||||
DATABASE_USER='postgres'
|
||||
DATABASE_PASSWORD='postgres'
|
||||
|
|
@ -32,7 +33,6 @@ PUBLIC_SITE_URL='http://$DOMAIN:5173'
|
|||
PUBLIC_UMAMI_DO_NOT_TRACK=true
|
||||
PUBLIC_UMAMI_URL=
|
||||
PUBLIC_UMAMI_ID=
|
||||
PUBLIC_PLAUSIBLE_URL=
|
||||
|
||||
# quick setting for key-combo only
|
||||
SVELTE_INSPECTOR_TOGGLE=control-shift-i
|
||||
|
|
|
|||
12
package.json
12
package.json
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "boredgame",
|
||||
"version": "0.0.2",
|
||||
"version": "0.0.5",
|
||||
"private": "true",
|
||||
"scripts": {
|
||||
"db:push": "drizzle-kit push",
|
||||
|
|
@ -30,10 +30,10 @@
|
|||
"@playwright/test": "^1.47.1",
|
||||
"@sveltejs/adapter-auto": "^3.2.5",
|
||||
"@sveltejs/enhanced-img": "^0.3.8",
|
||||
"@sveltejs/kit": "^2.6.2",
|
||||
"@sveltejs/kit": "^2.6.3",
|
||||
"@sveltejs/vite-plugin-svelte": "4.0.0-next.7",
|
||||
"@types/cookie": "^0.6.0",
|
||||
"@types/node": "^20.16.10",
|
||||
"@types/node": "^20.16.11",
|
||||
"@types/pg": "^8.11.10",
|
||||
"@types/qrcode": "^1.5.5",
|
||||
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
||||
|
|
@ -92,12 +92,13 @@
|
|||
"@oslojs/otp": "^1.0.0",
|
||||
"@oslojs/webauthn": "^1.0.0",
|
||||
"@paralleldrive/cuid2": "^2.2.2",
|
||||
"@scalar/hono-api-reference": "^0.5.152",
|
||||
"@sveltejs/adapter-node": "^5.2.5",
|
||||
"@sveltejs/adapter-vercel": "^5.4.4",
|
||||
"@sveltejs/adapter-vercel": "^5.4.5",
|
||||
"@types/feather-icons": "^4.29.4",
|
||||
"bits-ui": "^0.21.16",
|
||||
"boardgamegeekclient": "^1.9.1",
|
||||
"bullmq": "^5.16.0",
|
||||
"bullmq": "^5.17.1",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cookie": "^0.6.0",
|
||||
|
|
@ -111,6 +112,7 @@
|
|||
"hono": "^4.6.3",
|
||||
"hono-pino": "^0.3.0",
|
||||
"hono-rate-limiter": "^0.4.0",
|
||||
"hono-zod-openapi": "^0.2.0",
|
||||
"html-entities": "^2.5.2",
|
||||
"iconify-icon": "^2.1.0",
|
||||
"ioredis": "^5.4.1",
|
||||
|
|
|
|||
258
pnpm-lock.yaml
258
pnpm-lock.yaml
|
|
@ -62,12 +62,15 @@ importers:
|
|||
'@paralleldrive/cuid2':
|
||||
specifier: ^2.2.2
|
||||
version: 2.2.2
|
||||
'@scalar/hono-api-reference':
|
||||
specifier: ^0.5.152
|
||||
version: 0.5.152(hono@4.6.3)
|
||||
'@sveltejs/adapter-node':
|
||||
specifier: ^5.2.5
|
||||
version: 5.2.5(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))
|
||||
version: 5.2.5(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))
|
||||
'@sveltejs/adapter-vercel':
|
||||
specifier: ^5.4.4
|
||||
version: 5.4.4(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))
|
||||
specifier: ^5.4.5
|
||||
version: 5.4.5(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))
|
||||
'@types/feather-icons':
|
||||
specifier: ^4.29.4
|
||||
version: 4.29.4
|
||||
|
|
@ -78,8 +81,8 @@ importers:
|
|||
specifier: ^1.9.1
|
||||
version: 1.9.1
|
||||
bullmq:
|
||||
specifier: ^5.16.0
|
||||
version: 5.16.0
|
||||
specifier: ^5.17.1
|
||||
version: 5.17.1
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.0
|
||||
version: 0.7.0
|
||||
|
|
@ -106,7 +109,7 @@ importers:
|
|||
version: 4.29.2
|
||||
formsnap:
|
||||
specifier: ^1.0.1
|
||||
version: 1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.19.1(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175))
|
||||
version: 1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.19.1(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175))
|
||||
handlebars:
|
||||
specifier: ^4.7.8
|
||||
version: 4.7.8
|
||||
|
|
@ -119,6 +122,9 @@ importers:
|
|||
hono-rate-limiter:
|
||||
specifier: ^0.4.0
|
||||
version: 0.4.0(hono@4.6.3)
|
||||
hono-zod-openapi:
|
||||
specifier: ^0.2.0
|
||||
version: 0.2.0(hono@4.6.3)(zod@3.23.8)
|
||||
html-entities:
|
||||
specifier: ^2.5.2
|
||||
version: 2.5.2
|
||||
|
|
@ -184,10 +190,10 @@ importers:
|
|||
version: 2.5.3
|
||||
tailwind-variants:
|
||||
specifier: ^0.2.1
|
||||
version: 0.2.1(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2)))
|
||||
version: 0.2.1(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2)))
|
||||
tailwindcss-animate:
|
||||
specifier: ^1.0.7
|
||||
version: 1.0.7(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2)))
|
||||
version: 1.0.7(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2)))
|
||||
tsyringe:
|
||||
specifier: ^4.8.0
|
||||
version: 4.8.0
|
||||
|
|
@ -212,22 +218,22 @@ importers:
|
|||
version: 1.47.2
|
||||
'@sveltejs/adapter-auto':
|
||||
specifier: ^3.2.5
|
||||
version: 3.2.5(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))
|
||||
version: 3.2.5(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))
|
||||
'@sveltejs/enhanced-img':
|
||||
specifier: ^0.3.8
|
||||
version: 0.3.8(rollup@4.24.0)(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
version: 0.3.8(rollup@4.24.0)(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
'@sveltejs/kit':
|
||||
specifier: ^2.6.2
|
||||
version: 2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
specifier: ^2.6.3
|
||||
version: 2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
'@sveltejs/vite-plugin-svelte':
|
||||
specifier: 4.0.0-next.7
|
||||
version: 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
version: 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
'@types/cookie':
|
||||
specifier: ^0.6.0
|
||||
version: 0.6.0
|
||||
'@types/node':
|
||||
specifier: ^20.16.10
|
||||
version: 20.16.10
|
||||
specifier: ^20.16.11
|
||||
version: 20.16.11
|
||||
'@types/pg':
|
||||
specifier: ^8.11.10
|
||||
version: 8.11.10
|
||||
|
|
@ -257,7 +263,7 @@ importers:
|
|||
version: 9.1.0(eslint@8.57.1)
|
||||
eslint-plugin-svelte:
|
||||
specifier: 2.36.0-next.13
|
||||
version: 2.36.0-next.13(eslint@8.57.1)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2))
|
||||
version: 2.36.0-next.13(eslint@8.57.1)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2))
|
||||
just-clone:
|
||||
specifier: ^6.2.0
|
||||
version: 6.2.0
|
||||
|
|
@ -311,16 +317,16 @@ importers:
|
|||
version: 2.0.2
|
||||
sveltekit-flash-message:
|
||||
specifier: ^2.4.4
|
||||
version: 2.4.4(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)
|
||||
version: 2.4.4(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)
|
||||
sveltekit-superforms:
|
||||
specifier: ^2.19.1
|
||||
version: 2.19.1(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175)
|
||||
version: 2.19.1(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175)
|
||||
tailwindcss:
|
||||
specifier: ^3.4.13
|
||||
version: 3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2))
|
||||
version: 3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2))
|
||||
ts-node:
|
||||
specifier: ^10.9.2
|
||||
version: 10.9.2(@types/node@20.16.10)(typescript@5.6.2)
|
||||
version: 10.9.2(@types/node@20.16.11)(typescript@5.6.2)
|
||||
tslib:
|
||||
specifier: ^2.7.0
|
||||
version: 2.7.0
|
||||
|
|
@ -332,10 +338,10 @@ importers:
|
|||
version: 5.6.2
|
||||
vite:
|
||||
specifier: ^5.4.8
|
||||
version: 5.4.8(@types/node@20.16.10)
|
||||
version: 5.4.8(@types/node@20.16.11)
|
||||
vitest:
|
||||
specifier: ^1.6.0
|
||||
version: 1.6.0(@types/node@20.16.10)
|
||||
version: 1.6.0(@types/node@20.16.11)
|
||||
zod:
|
||||
specifier: ^3.23.8
|
||||
version: 3.23.8
|
||||
|
|
@ -1447,6 +1453,12 @@ packages:
|
|||
hono: '>=3.9.0'
|
||||
zod: ^3.19.1
|
||||
|
||||
'@hono/zod-validator@0.4.1':
|
||||
resolution: {integrity: sha512-I8LyfeJfvVmC5hPjZ2Iij7RjexlgSBT7QJudZ4JvNPLxn0JQ3sqclz2zydlwISAnw21D2n4LQ0nfZdoiv9fQQA==}
|
||||
peerDependencies:
|
||||
hono: '>=3.9.0'
|
||||
zod: ^3.19.1
|
||||
|
||||
'@humanwhocodes/config-array@0.13.0':
|
||||
resolution: {integrity: sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==}
|
||||
engines: {node: '>=10.10.0'}
|
||||
|
|
@ -2131,6 +2143,20 @@ packages:
|
|||
cpu: [x64]
|
||||
os: [win32]
|
||||
|
||||
'@scalar/hono-api-reference@0.5.152':
|
||||
resolution: {integrity: sha512-mSRpicEjr3q3ulXHV9fpPKgq+Mju0/A9jyB4NvvZ9GitunTm6P4urr/RKzgESDTqYK3zK/VGahZWeQFLi6PSKQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
hono: ^4.0.0
|
||||
|
||||
'@scalar/openapi-types@0.1.1':
|
||||
resolution: {integrity: sha512-NMy3QNk6ytcCoPUGJH0t4NNr36OWXgZhA3ormr3TvhX1NDgoF95wFyodGVH8xiHeUyn2/FxtETm8UBLbB5xEmg==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@scalar/types@0.0.13':
|
||||
resolution: {integrity: sha512-4baCQ3uXTQsT/da5X3+yO34VEu057Jjw0SJFkaaFmXTqHXVZM+SaDHSyTvT6tyKvgDpPpn6iD22uiFCdldEzRQ==}
|
||||
engines: {node: '>=18'}
|
||||
|
||||
'@sideway/address@4.1.5':
|
||||
resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==}
|
||||
|
||||
|
|
@ -2156,8 +2182,8 @@ packages:
|
|||
peerDependencies:
|
||||
'@sveltejs/kit': ^2.4.0
|
||||
|
||||
'@sveltejs/adapter-vercel@5.4.4':
|
||||
resolution: {integrity: sha512-KORoxxqB2H5DrxpCHc9Yfijcgvmoaaz6G6eKHEg9fRlTsujJkxN26C0x4YlcgxqDU4dLIi1wfSLHpuZD0E4Irg==}
|
||||
'@sveltejs/adapter-vercel@5.4.5':
|
||||
resolution: {integrity: sha512-SROpUbjSZ1Xni4xuS22dunXFLjYzvTZwppqixIQFzTrf9oWcZEm2OfO+VgnrOT67LOcWQefJp7VSrpmjV691yQ==}
|
||||
peerDependencies:
|
||||
'@sveltejs/kit': ^2.4.0
|
||||
|
||||
|
|
@ -2167,8 +2193,8 @@ packages:
|
|||
svelte: ^4.0.0 || ^5.0.0-next.0
|
||||
vite: '>= 5.0.0'
|
||||
|
||||
'@sveltejs/kit@2.6.2':
|
||||
resolution: {integrity: sha512-ruogrSPXjckn5poUiZU8VYNCSPHq66SFR1AATvOikQxtP6LNI4niAZVX/AWZRe/EPDG3oY2DNJ9c5z7u0t2NAQ==}
|
||||
'@sveltejs/kit@2.6.3':
|
||||
resolution: {integrity: sha512-baIAnmfMqAISrPtTC/22w6ay5kTEIQ/vq9bctiaQgRIoLCPBNhb6LEidTuWQS7OzPYCDBMuMX1t/fMvi4r3q/g==}
|
||||
engines: {node: '>=18.13'}
|
||||
hasBin: true
|
||||
peerDependencies:
|
||||
|
|
@ -2224,8 +2250,8 @@ packages:
|
|||
'@types/json-schema@7.0.15':
|
||||
resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==}
|
||||
|
||||
'@types/node@20.16.10':
|
||||
resolution: {integrity: sha512-vQUKgWTjEIRFCvK6CyriPH3MZYiYlNy0fKiEYHWbcoWLEgs4opurGGKlebrTLqdSMIbXImH6XExNiIyNUv3WpA==}
|
||||
'@types/node@20.16.11':
|
||||
resolution: {integrity: sha512-y+cTCACu92FyA5fgQSAI8A1H429g7aSK2HsO7K4XYUWc4dY5IUz55JSDIYT6/VsOLfGy8vmvQYC2hfb0iF16Uw==}
|
||||
|
||||
'@types/pg@8.11.10':
|
||||
resolution: {integrity: sha512-LczQUW4dbOQzsH2RQ5qoeJ6qJPdrcM/DcMLoqWQkMLMsq83J5lAX3LXjdkWdpscFy67JSOWDnh7Ny/sPFykmkg==}
|
||||
|
|
@ -2322,6 +2348,9 @@ packages:
|
|||
'@ungap/structured-clone@1.2.0':
|
||||
resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==}
|
||||
|
||||
'@unhead/schema@1.11.7':
|
||||
resolution: {integrity: sha512-j9uN7T63aUXrZ6yx2CfjVT7xZHjn0PZO7TPMaWqMFjneIH/NONKvDVCMEqDlXeqdSIERIYtk/xTHgCUMer5eyw==}
|
||||
|
||||
'@vercel/nft@0.27.4':
|
||||
resolution: {integrity: sha512-Rioz3LJkEKicKCi9BSyc1RXZ5R6GmXosFMeBSThh6msWSOiArKhb7c75MiWwZEgPL7x0/l3TAfH/l0cxKNuUFA==}
|
||||
engines: {node: '>=16'}
|
||||
|
|
@ -2525,8 +2554,8 @@ packages:
|
|||
buffer@6.0.3:
|
||||
resolution: {integrity: sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==}
|
||||
|
||||
bullmq@5.16.0:
|
||||
resolution: {integrity: sha512-7FaZzHsRXFOxrxCQTNKowuo9PPRwnAOpYXB5tcfk8vg0IbuVQ/je1Bf228Zy29gCS/5ytIEJNVB/DDGwZM0wbA==}
|
||||
bullmq@5.17.1:
|
||||
resolution: {integrity: sha512-wqjhdJptb3KLeuUO+ZfsjVHqHuPtHhhoAE2XM8zvnidk6uU/ELo16uU6CVTBhliAupgvPE9jWE7tchR0GCtsdA==}
|
||||
|
||||
bytes@3.1.2:
|
||||
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||
|
|
@ -2657,10 +2686,6 @@ packages:
|
|||
resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
cookie@0.7.2:
|
||||
resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==}
|
||||
engines: {node: '>= 0.6'}
|
||||
|
||||
core-js@3.38.1:
|
||||
resolution: {integrity: sha512-OP35aUorbU3Zvlx7pjsFdu1rGNnD4pgw/CWoYzRY3t2EzoVT7shKHY1dlAy3f41cGIO7ZDPQimhGFTlEYkG/Hw==}
|
||||
|
||||
|
|
@ -3312,10 +3337,19 @@ packages:
|
|||
peerDependencies:
|
||||
hono: ^4.1.1
|
||||
|
||||
hono-zod-openapi@0.2.0:
|
||||
resolution: {integrity: sha512-LYQXLb+shxIdS5PLFAaeelQg5BQ3rph5kB1rpUbqRW4Pr4JxHA8u7sjNNs0g7H/sXOiFLNAZRhF3yFsgBEoybA==}
|
||||
peerDependencies:
|
||||
hono: ^4.6.3
|
||||
zod: ^3.21.4
|
||||
|
||||
hono@4.6.3:
|
||||
resolution: {integrity: sha512-0LeEuBNFeSHGqZ9sNVVgZjB1V5fmhkBSB0hZrpqStSMLOWgfLy0dHOvrjbJh0H2khsjet6rbHfWTHY0kpYThKQ==}
|
||||
engines: {node: '>=16.9.0'}
|
||||
|
||||
hookable@5.5.3:
|
||||
resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==}
|
||||
|
||||
html-entities@2.5.2:
|
||||
resolution: {integrity: sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==}
|
||||
|
||||
|
|
@ -5110,9 +5144,18 @@ packages:
|
|||
yup@1.4.0:
|
||||
resolution: {integrity: sha512-wPbgkJRCqIf+OHyiTBQoJiP5PFuAXaWiJK6AmYkzQAh5/c2K9hzSApBZG5wV9KoKSePF7sAxmNSvh/13YHkFDg==}
|
||||
|
||||
zhead@2.2.4:
|
||||
resolution: {integrity: sha512-8F0OI5dpWIA5IGG5NHUg9staDwz/ZPxZtvGVf01j7vHqSyZ0raHY+78atOVxRqb73AotX22uV1pXt3gYSstGag==}
|
||||
|
||||
zimmerframe@1.1.2:
|
||||
resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==}
|
||||
|
||||
zod-openapi@3.1.1:
|
||||
resolution: {integrity: sha512-jn5udnrGTAmTY7nj/E6ggKBsqIi9Vzj5u0RQpDyOOpzmz2ijcBssSeEjnQFbriqG2PY2JJBP5Gi4umRrhVxghQ==}
|
||||
engines: {node: '>=18'}
|
||||
peerDependencies:
|
||||
zod: ^3.21.4
|
||||
|
||||
zod-to-json-schema@3.23.3:
|
||||
resolution: {integrity: sha512-TYWChTxKQbRJp5ST22o/Irt9KC5nj7CdBKYB/AosCRdj/wxEMvv4NNaj9XVUHDOIp53ZxArGhnw5HMZziPFjog==}
|
||||
peerDependencies:
|
||||
|
|
@ -5885,6 +5928,11 @@ snapshots:
|
|||
hono: 4.6.3
|
||||
zod: 3.23.8
|
||||
|
||||
'@hono/zod-validator@0.4.1(hono@4.6.3)(zod@3.23.8)':
|
||||
dependencies:
|
||||
hono: 4.6.3
|
||||
zod: 3.23.8
|
||||
|
||||
'@humanwhocodes/config-array@0.13.0':
|
||||
dependencies:
|
||||
'@humanwhocodes/object-schema': 2.0.3
|
||||
|
|
@ -6459,6 +6507,18 @@ snapshots:
|
|||
'@rollup/rollup-win32-x64-msvc@4.24.0':
|
||||
optional: true
|
||||
|
||||
'@scalar/hono-api-reference@0.5.152(hono@4.6.3)':
|
||||
dependencies:
|
||||
'@scalar/types': 0.0.13
|
||||
hono: 4.6.3
|
||||
|
||||
'@scalar/openapi-types@0.1.1': {}
|
||||
|
||||
'@scalar/types@0.0.13':
|
||||
dependencies:
|
||||
'@scalar/openapi-types': 0.1.1
|
||||
'@unhead/schema': 1.11.7
|
||||
|
||||
'@sideway/address@4.1.5':
|
||||
dependencies:
|
||||
'@hapi/hoek': 9.3.0
|
||||
|
|
@ -6475,43 +6535,43 @@ snapshots:
|
|||
'@sinclair/typebox@0.32.35':
|
||||
optional: true
|
||||
|
||||
'@sveltejs/adapter-auto@3.2.5(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))':
|
||||
'@sveltejs/adapter-auto@3.2.5(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))':
|
||||
dependencies:
|
||||
'@sveltejs/kit': 2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
'@sveltejs/kit': 2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
import-meta-resolve: 4.1.0
|
||||
|
||||
'@sveltejs/adapter-node@5.2.5(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))':
|
||||
'@sveltejs/adapter-node@5.2.5(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))':
|
||||
dependencies:
|
||||
'@rollup/plugin-commonjs': 28.0.0(rollup@4.24.0)
|
||||
'@rollup/plugin-json': 6.1.0(rollup@4.24.0)
|
||||
'@rollup/plugin-node-resolve': 15.3.0(rollup@4.24.0)
|
||||
'@sveltejs/kit': 2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
'@sveltejs/kit': 2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
rollup: 4.24.0
|
||||
|
||||
'@sveltejs/adapter-vercel@5.4.4(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))':
|
||||
'@sveltejs/adapter-vercel@5.4.5(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))':
|
||||
dependencies:
|
||||
'@sveltejs/kit': 2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
'@sveltejs/kit': 2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
'@vercel/nft': 0.27.4
|
||||
esbuild: 0.21.5
|
||||
transitivePeerDependencies:
|
||||
- encoding
|
||||
- supports-color
|
||||
|
||||
'@sveltejs/enhanced-img@0.3.8(rollup@4.24.0)(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))':
|
||||
'@sveltejs/enhanced-img@0.3.8(rollup@4.24.0)(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))':
|
||||
dependencies:
|
||||
magic-string: 0.30.11
|
||||
svelte: 5.0.0-next.175
|
||||
svelte-parse-markup: 0.1.5(svelte@5.0.0-next.175)
|
||||
vite: 5.4.8(@types/node@20.16.10)
|
||||
vite: 5.4.8(@types/node@20.16.11)
|
||||
vite-imagetools: 7.0.4(rollup@4.24.0)
|
||||
transitivePeerDependencies:
|
||||
- rollup
|
||||
|
||||
'@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))':
|
||||
'@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))':
|
||||
dependencies:
|
||||
'@sveltejs/vite-plugin-svelte': 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
'@sveltejs/vite-plugin-svelte': 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
'@types/cookie': 0.6.0
|
||||
cookie: 0.7.2
|
||||
cookie: 0.6.0
|
||||
devalue: 5.1.1
|
||||
esm-env: 1.0.0
|
||||
import-meta-resolve: 4.1.0
|
||||
|
|
@ -6523,27 +6583,27 @@ snapshots:
|
|||
sirv: 2.0.4
|
||||
svelte: 5.0.0-next.175
|
||||
tiny-glob: 0.2.9
|
||||
vite: 5.4.8(@types/node@20.16.10)
|
||||
vite: 5.4.8(@types/node@20.16.11)
|
||||
|
||||
'@sveltejs/vite-plugin-svelte-inspector@3.0.0-next.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))':
|
||||
'@sveltejs/vite-plugin-svelte-inspector@3.0.0-next.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))':
|
||||
dependencies:
|
||||
'@sveltejs/vite-plugin-svelte': 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
'@sveltejs/vite-plugin-svelte': 4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
debug: 4.3.7
|
||||
svelte: 5.0.0-next.175
|
||||
vite: 5.4.8(@types/node@20.16.10)
|
||||
vite: 5.4.8(@types/node@20.16.11)
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
'@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))':
|
||||
'@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))':
|
||||
dependencies:
|
||||
'@sveltejs/vite-plugin-svelte-inspector': 3.0.0-next.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
'@sveltejs/vite-plugin-svelte-inspector': 3.0.0-next.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
debug: 4.3.7
|
||||
deepmerge: 4.3.1
|
||||
kleur: 4.1.5
|
||||
magic-string: 0.30.11
|
||||
svelte: 5.0.0-next.175
|
||||
vite: 5.4.8(@types/node@20.16.10)
|
||||
vitefu: 1.0.2(vite@5.4.8(@types/node@20.16.10))
|
||||
vite: 5.4.8(@types/node@20.16.11)
|
||||
vitefu: 1.0.2(vite@5.4.8(@types/node@20.16.11))
|
||||
transitivePeerDependencies:
|
||||
- supports-color
|
||||
|
||||
|
|
@ -6578,19 +6638,19 @@ snapshots:
|
|||
'@types/json-schema@7.0.15':
|
||||
optional: true
|
||||
|
||||
'@types/node@20.16.10':
|
||||
'@types/node@20.16.11':
|
||||
dependencies:
|
||||
undici-types: 6.19.8
|
||||
|
||||
'@types/pg@8.11.10':
|
||||
dependencies:
|
||||
'@types/node': 20.16.10
|
||||
'@types/node': 20.16.11
|
||||
pg-protocol: 1.7.0
|
||||
pg-types: 4.0.2
|
||||
|
||||
'@types/pg@8.11.6':
|
||||
dependencies:
|
||||
'@types/node': 20.16.10
|
||||
'@types/node': 20.16.11
|
||||
pg-protocol: 1.7.0
|
||||
pg-types: 4.0.2
|
||||
|
||||
|
|
@ -6598,7 +6658,7 @@ snapshots:
|
|||
|
||||
'@types/qrcode@1.5.5':
|
||||
dependencies:
|
||||
'@types/node': 20.16.10
|
||||
'@types/node': 20.16.11
|
||||
|
||||
'@types/resolve@1.20.2': {}
|
||||
|
||||
|
|
@ -6702,6 +6762,11 @@ snapshots:
|
|||
|
||||
'@ungap/structured-clone@1.2.0': {}
|
||||
|
||||
'@unhead/schema@1.11.7':
|
||||
dependencies:
|
||||
hookable: 5.5.3
|
||||
zhead: 2.2.4
|
||||
|
||||
'@vercel/nft@0.27.4':
|
||||
dependencies:
|
||||
'@mapbox/node-pre-gyp': 1.0.11
|
||||
|
|
@ -6943,7 +7008,7 @@ snapshots:
|
|||
base64-js: 1.5.1
|
||||
ieee754: 1.2.1
|
||||
|
||||
bullmq@5.16.0:
|
||||
bullmq@5.17.1:
|
||||
dependencies:
|
||||
cron-parser: 4.9.0
|
||||
ioredis: 5.4.1
|
||||
|
|
@ -7084,8 +7149,6 @@ snapshots:
|
|||
|
||||
cookie@0.6.0: {}
|
||||
|
||||
cookie@0.7.2: {}
|
||||
|
||||
core-js@3.38.1: {}
|
||||
|
||||
create-require@1.1.1: {}
|
||||
|
|
@ -7404,7 +7467,7 @@ snapshots:
|
|||
dependencies:
|
||||
eslint: 8.57.1
|
||||
|
||||
eslint-plugin-svelte@2.36.0-next.13(eslint@8.57.1)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2)):
|
||||
eslint-plugin-svelte@2.36.0-next.13(eslint@8.57.1)(svelte@5.0.0-next.175)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2)):
|
||||
dependencies:
|
||||
'@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1)
|
||||
'@jridgewell/sourcemap-codec': 1.5.0
|
||||
|
|
@ -7414,7 +7477,7 @@ snapshots:
|
|||
esutils: 2.0.3
|
||||
known-css-properties: 0.30.0
|
||||
postcss: 8.4.47
|
||||
postcss-load-config: 3.1.4(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2))
|
||||
postcss-load-config: 3.1.4(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2))
|
||||
postcss-safe-parser: 6.0.0(postcss@8.4.47)
|
||||
postcss-selector-parser: 6.1.2
|
||||
semver: 7.6.3
|
||||
|
|
@ -7650,11 +7713,11 @@ snapshots:
|
|||
cross-spawn: 7.0.3
|
||||
signal-exit: 4.1.0
|
||||
|
||||
formsnap@1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.19.1(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175)):
|
||||
formsnap@1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.19.1(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175)):
|
||||
dependencies:
|
||||
nanoid: 5.0.7
|
||||
svelte: 5.0.0-next.175
|
||||
sveltekit-superforms: 2.19.1(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175)
|
||||
sveltekit-superforms: 2.19.1(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175)
|
||||
|
||||
forwarded@0.2.0: {}
|
||||
|
||||
|
|
@ -7797,8 +7860,17 @@ snapshots:
|
|||
dependencies:
|
||||
hono: 4.6.3
|
||||
|
||||
hono-zod-openapi@0.2.0(hono@4.6.3)(zod@3.23.8):
|
||||
dependencies:
|
||||
'@hono/zod-validator': 0.4.1(hono@4.6.3)(zod@3.23.8)
|
||||
hono: 4.6.3
|
||||
zod: 3.23.8
|
||||
zod-openapi: 3.1.1(zod@3.23.8)
|
||||
|
||||
hono@4.6.3: {}
|
||||
|
||||
hookable@5.5.3: {}
|
||||
|
||||
html-entities@2.5.2: {}
|
||||
|
||||
http-errors@2.0.0:
|
||||
|
|
@ -8531,21 +8603,21 @@ snapshots:
|
|||
'@csstools/utilities': 1.0.0(postcss@8.4.47)
|
||||
postcss: 8.4.47
|
||||
|
||||
postcss-load-config@3.1.4(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2)):
|
||||
postcss-load-config@3.1.4(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2)):
|
||||
dependencies:
|
||||
lilconfig: 2.1.0
|
||||
yaml: 1.10.2
|
||||
optionalDependencies:
|
||||
postcss: 8.4.47
|
||||
ts-node: 10.9.2(@types/node@20.16.10)(typescript@5.6.2)
|
||||
ts-node: 10.9.2(@types/node@20.16.11)(typescript@5.6.2)
|
||||
|
||||
postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2)):
|
||||
postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2)):
|
||||
dependencies:
|
||||
lilconfig: 3.1.2
|
||||
yaml: 2.5.1
|
||||
optionalDependencies:
|
||||
postcss: 8.4.47
|
||||
ts-node: 10.9.2(@types/node@20.16.10)(typescript@5.6.2)
|
||||
ts-node: 10.9.2(@types/node@20.16.11)(typescript@5.6.2)
|
||||
|
||||
postcss-load-config@5.1.0(jiti@1.21.6)(postcss@8.4.47)(tsx@4.19.1):
|
||||
dependencies:
|
||||
|
|
@ -9220,14 +9292,14 @@ snapshots:
|
|||
magic-string: 0.30.11
|
||||
zimmerframe: 1.1.2
|
||||
|
||||
sveltekit-flash-message@2.4.4(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175):
|
||||
sveltekit-flash-message@2.4.4(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175):
|
||||
dependencies:
|
||||
'@sveltejs/kit': 2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
'@sveltejs/kit': 2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
svelte: 5.0.0-next.175
|
||||
|
||||
sveltekit-superforms@2.19.1(@sveltejs/kit@2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175):
|
||||
sveltekit-superforms@2.19.1(@sveltejs/kit@2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(@types/json-schema@7.0.15)(svelte@5.0.0-next.175):
|
||||
dependencies:
|
||||
'@sveltejs/kit': 2.6.2(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.10))
|
||||
'@sveltejs/kit': 2.6.3(@sveltejs/vite-plugin-svelte@4.0.0-next.7(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11)))(svelte@5.0.0-next.175)(vite@5.4.8(@types/node@20.16.11))
|
||||
devalue: 5.1.1
|
||||
just-clone: 6.2.0
|
||||
memoize-weak: 1.0.2
|
||||
|
|
@ -9255,16 +9327,16 @@ snapshots:
|
|||
|
||||
tailwind-merge@2.5.3: {}
|
||||
|
||||
tailwind-variants@0.2.1(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2))):
|
||||
tailwind-variants@0.2.1(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2))):
|
||||
dependencies:
|
||||
tailwind-merge: 2.5.3
|
||||
tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2))
|
||||
tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2))
|
||||
|
||||
tailwindcss-animate@1.0.7(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2))):
|
||||
tailwindcss-animate@1.0.7(tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2))):
|
||||
dependencies:
|
||||
tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2))
|
||||
tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2))
|
||||
|
||||
tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2)):
|
||||
tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2)):
|
||||
dependencies:
|
||||
'@alloc/quick-lru': 5.2.0
|
||||
arg: 5.0.2
|
||||
|
|
@ -9283,7 +9355,7 @@ snapshots:
|
|||
postcss: 8.4.47
|
||||
postcss-import: 15.1.0(postcss@8.4.47)
|
||||
postcss-js: 4.0.1(postcss@8.4.47)
|
||||
postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2))
|
||||
postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2))
|
||||
postcss-nested: 6.2.0(postcss@8.4.47)
|
||||
postcss-selector-parser: 6.1.2
|
||||
resolve: 1.22.8
|
||||
|
|
@ -9352,14 +9424,14 @@ snapshots:
|
|||
|
||||
ts-interface-checker@0.1.13: {}
|
||||
|
||||
ts-node@10.9.2(@types/node@20.16.10)(typescript@5.6.2):
|
||||
ts-node@10.9.2(@types/node@20.16.11)(typescript@5.6.2):
|
||||
dependencies:
|
||||
'@cspotcode/source-map-support': 0.8.1
|
||||
'@tsconfig/node10': 1.0.11
|
||||
'@tsconfig/node12': 1.0.11
|
||||
'@tsconfig/node14': 1.0.3
|
||||
'@tsconfig/node16': 1.0.4
|
||||
'@types/node': 20.16.10
|
||||
'@types/node': 20.16.11
|
||||
acorn: 8.12.1
|
||||
acorn-walk: 8.3.4
|
||||
arg: 4.1.3
|
||||
|
|
@ -9454,13 +9526,13 @@ snapshots:
|
|||
transitivePeerDependencies:
|
||||
- rollup
|
||||
|
||||
vite-node@1.6.0(@types/node@20.16.10):
|
||||
vite-node@1.6.0(@types/node@20.16.11):
|
||||
dependencies:
|
||||
cac: 6.7.14
|
||||
debug: 4.3.7
|
||||
pathe: 1.1.2
|
||||
picocolors: 1.1.0
|
||||
vite: 5.4.8(@types/node@20.16.10)
|
||||
vite: 5.4.8(@types/node@20.16.11)
|
||||
transitivePeerDependencies:
|
||||
- '@types/node'
|
||||
- less
|
||||
|
|
@ -9472,20 +9544,20 @@ snapshots:
|
|||
- supports-color
|
||||
- terser
|
||||
|
||||
vite@5.4.8(@types/node@20.16.10):
|
||||
vite@5.4.8(@types/node@20.16.11):
|
||||
dependencies:
|
||||
esbuild: 0.21.5
|
||||
postcss: 8.4.47
|
||||
rollup: 4.24.0
|
||||
optionalDependencies:
|
||||
'@types/node': 20.16.10
|
||||
'@types/node': 20.16.11
|
||||
fsevents: 2.3.3
|
||||
|
||||
vitefu@1.0.2(vite@5.4.8(@types/node@20.16.10)):
|
||||
vitefu@1.0.2(vite@5.4.8(@types/node@20.16.11)):
|
||||
optionalDependencies:
|
||||
vite: 5.4.8(@types/node@20.16.10)
|
||||
vite: 5.4.8(@types/node@20.16.11)
|
||||
|
||||
vitest@1.6.0(@types/node@20.16.10):
|
||||
vitest@1.6.0(@types/node@20.16.11):
|
||||
dependencies:
|
||||
'@vitest/expect': 1.6.0
|
||||
'@vitest/runner': 1.6.0
|
||||
|
|
@ -9504,11 +9576,11 @@ snapshots:
|
|||
strip-literal: 2.1.0
|
||||
tinybench: 2.9.0
|
||||
tinypool: 0.8.4
|
||||
vite: 5.4.8(@types/node@20.16.10)
|
||||
vite-node: 1.6.0(@types/node@20.16.10)
|
||||
vite: 5.4.8(@types/node@20.16.11)
|
||||
vite-node: 1.6.0(@types/node@20.16.11)
|
||||
why-is-node-running: 2.3.0
|
||||
optionalDependencies:
|
||||
'@types/node': 20.16.10
|
||||
'@types/node': 20.16.11
|
||||
transitivePeerDependencies:
|
||||
- less
|
||||
- lightningcss
|
||||
|
|
@ -9608,8 +9680,14 @@ snapshots:
|
|||
type-fest: 2.19.0
|
||||
optional: true
|
||||
|
||||
zhead@2.2.4: {}
|
||||
|
||||
zimmerframe@1.1.2: {}
|
||||
|
||||
zod-openapi@3.1.1(zod@3.23.8):
|
||||
dependencies:
|
||||
zod: 3.23.8
|
||||
|
||||
zod-to-json-schema@3.23.3(zod@3.23.8):
|
||||
dependencies:
|
||||
zod: 3.23.8
|
||||
|
|
|
|||
|
|
@ -1,13 +0,0 @@
|
|||
<script lang="ts">
|
||||
import { PUBLIC_PLAUSIBLE_URL, PUBLIC_SITE_URL } from '$env/static/public'
|
||||
const src = `${PUBLIC_PLAUSIBLE_URL}/js/script.js`
|
||||
const dataDomain = PUBLIC_SITE_URL.replace('https://', '').replace('http://', '')
|
||||
</script>
|
||||
|
||||
<svelte:head>
|
||||
<script
|
||||
defer
|
||||
data-domain={dataDomain}
|
||||
{src}
|
||||
></script>
|
||||
</svelte:head>
|
||||
|
|
@ -1,8 +1,8 @@
|
|||
import env from './env'
|
||||
import type { Config } from './types/config'
|
||||
import env from './env';
|
||||
import type { Config } from './types/config';
|
||||
|
||||
export const config: Config = {
|
||||
isProduction: process.env.NODE_ENV === 'production',
|
||||
isProduction: env.NODE_ENV === 'production',
|
||||
domain: env.DOMAIN,
|
||||
api: {
|
||||
origin: env.ORIGIN,
|
||||
|
|
@ -19,4 +19,4 @@ export const config: Config = {
|
|||
ssl: false, // env.DATABASE_HOST !== 'localhost',
|
||||
max: env.DB_MIGRATING || env.DB_SEEDING ? 1 : undefined,
|
||||
},
|
||||
}
|
||||
};
|
||||
|
|
|
|||
37
src/lib/server/api/common/create-app.ts
Normal file
37
src/lib/server/api/common/create-app.ts
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
import env from '$lib/server/api/common/env';
|
||||
import type { AppBindings } from '$lib/server/api/common/types/hono';
|
||||
import { validateAuthSession, verifyOrigin } from '$lib/server/api/middleware/auth.middleware';
|
||||
import { pinoLogger } from '$lib/server/api/middleware/pino-logger.middleware';
|
||||
import { Hono } from 'hono';
|
||||
import { cors } from 'hono/cors';
|
||||
import { notFound, onError, serveEmojiFavicon } from 'stoker/middlewares';
|
||||
|
||||
export function createRouter() {
|
||||
return new Hono<AppBindings>({
|
||||
strict: false,
|
||||
}).basePath('/api');
|
||||
}
|
||||
|
||||
export default function createApp() {
|
||||
const app = createRouter();
|
||||
|
||||
app.use(verifyOrigin).use(validateAuthSession);
|
||||
app.use(serveEmojiFavicon('📝'));
|
||||
app.use(pinoLogger());
|
||||
|
||||
app.notFound(notFound);
|
||||
app.onError(onError);
|
||||
|
||||
app.use(
|
||||
'/*',
|
||||
cors({
|
||||
origin: [env.ORIGIN],
|
||||
|
||||
allowMethods: ['POST'],
|
||||
allowHeaders: ['Content-Type'],
|
||||
// credentials: true, // If you need to send cookies or HTTP authentication
|
||||
}),
|
||||
);
|
||||
|
||||
return app;
|
||||
}
|
||||
|
|
@ -1,13 +1,15 @@
|
|||
import { config } from 'dotenv'
|
||||
import { expand } from 'dotenv-expand'
|
||||
import { ZodError, z } from 'zod'
|
||||
import { config } from 'dotenv';
|
||||
import { expand } from 'dotenv-expand';
|
||||
import { type ZodError, z } from 'zod';
|
||||
|
||||
expand(config());
|
||||
|
||||
const stringBoolean = z.coerce
|
||||
.string()
|
||||
.transform((val) => {
|
||||
return val === 'true'
|
||||
return val === 'true';
|
||||
})
|
||||
.default('false')
|
||||
.default('false');
|
||||
|
||||
const EnvSchema = z.object({
|
||||
DATABASE_USER: z.string(),
|
||||
|
|
@ -22,34 +24,29 @@ const EnvSchema = z.object({
|
|||
GITHUB_CLIENT_SECRET: z.string(),
|
||||
GOOGLE_CLIENT_ID: z.string(),
|
||||
GOOGLE_CLIENT_SECRET: z.string(),
|
||||
LOG_LEVEL: z.enum(['fatal', 'error', 'warn', 'info', 'debug', 'trace']).default('info'),
|
||||
NODE_ENV: z.string().default('development'),
|
||||
ORIGIN: z.string(),
|
||||
PUBLIC_SITE_NAME: z.string(),
|
||||
PUBLIC_SITE_URL: z.string(),
|
||||
PUBLIC_UMAMI_DO_NOT_TRACK: z.string(),
|
||||
PUBLIC_UMAMI_DO_NOT_TRACK: z.string().default('true'),
|
||||
PUBLIC_UMAMI_ID: z.string(),
|
||||
PUBLIC_UMAMI_URL: z.string(),
|
||||
REDIS_URL: z.string(),
|
||||
TWO_FACTOR_TIMEOUT: z.coerce.number().default(300000),
|
||||
})
|
||||
});
|
||||
|
||||
export type EnvSchema = z.infer<typeof EnvSchema>
|
||||
export type env = z.infer<typeof EnvSchema>;
|
||||
|
||||
expand(config())
|
||||
let env: env;
|
||||
|
||||
try {
|
||||
EnvSchema.parse(process.env)
|
||||
} catch (error) {
|
||||
if (error instanceof ZodError) {
|
||||
let message = 'Missing required values in .env:\n'
|
||||
for (const issue of error.issues) {
|
||||
message += `${issue.path[0]}\n`
|
||||
}
|
||||
const e = new Error(message)
|
||||
e.stack = ''
|
||||
throw e
|
||||
}
|
||||
console.error(error)
|
||||
env = EnvSchema.parse(process.env);
|
||||
} catch (e) {
|
||||
const error = e as ZodError;
|
||||
console.error('❌ Missing required values in .env:\n');
|
||||
console.error(error.flatten().fieldErrors);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
export default EnvSchema.parse(process.env)
|
||||
export default env;
|
||||
|
|
|
|||
|
|
@ -1,14 +1,29 @@
|
|||
import type { PinoLogger } from 'hono-pino';
|
||||
import type { Promisify, RateLimitInfo } from 'hono-rate-limiter';
|
||||
import type { Session, User } from 'lucia';
|
||||
|
||||
export type HonoTypes = {
|
||||
export type AppBindings = {
|
||||
Variables: {
|
||||
logger: PinoLogger;
|
||||
session: Session | null;
|
||||
user: User | null;
|
||||
rateLimit: RateLimitInfo;
|
||||
rateLimitStore: {
|
||||
getKey?: (key: string) => Promisify<RateLimitInfo | undefined>;
|
||||
resetKey: (key: string) => Promisify<void>;
|
||||
};
|
||||
rateLimitStore: {
|
||||
getKey?: (key: string) => Promisify<RateLimitInfo | undefined>;
|
||||
resetKey: (key: string) => Promisify<void>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
export type HonoTypes = {
|
||||
Variables: {
|
||||
logger: PinoLogger;
|
||||
session: Session | null;
|
||||
user: User | null;
|
||||
rateLimit: RateLimitInfo;
|
||||
rateLimitStore: {
|
||||
getKey?: (key: string) => Promisify<RateLimitInfo | undefined>;
|
||||
resetKey: (key: string) => Promisify<void>;
|
||||
};
|
||||
};
|
||||
};
|
||||
|
|
|
|||
42
src/lib/server/api/configure-open-api.ts
Normal file
42
src/lib/server/api/configure-open-api.ts
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
// // import type { AppOpenAPI } from '$lib/server/api/common/types/hono';
|
||||
// import { apiReference } from '@scalar/hono-api-reference';
|
||||
// import { Hono } from 'hono';
|
||||
//
|
||||
// import type { AppBindings } from '$lib/server/api/common/types/hono';
|
||||
// import { createOpenApiDocument } from 'hono-zod-openapi';
|
||||
// import packageJSON from '../../../../package.json';
|
||||
//
|
||||
// // export default function configureOpenAPI(app: AppOpenAPI) {
|
||||
// // app.doc('/doc', {
|
||||
// // openapi: '3.0.0',
|
||||
// // info: {
|
||||
// // title: 'Bored Game API',
|
||||
// // description: 'Bored Game API',
|
||||
// // version: packageJSON.version,
|
||||
// // },
|
||||
// // });
|
||||
// //
|
||||
// // app.get(
|
||||
// // '/reference',
|
||||
// // apiReference({
|
||||
// // theme: 'kepler',
|
||||
// // layout: 'classic',
|
||||
// // defaultHttpClient: {
|
||||
// // targetKey: 'javascript',
|
||||
// // clientKey: 'fetch',
|
||||
// // },
|
||||
// // spec: {
|
||||
// // url: '/api/doc',
|
||||
// // },
|
||||
// // }),
|
||||
// // );
|
||||
// // }
|
||||
//
|
||||
// export default function configureOpenAPI(app: Hono<AppBindings>) {
|
||||
// createOpenApiDocument(app, {
|
||||
// info: {
|
||||
// title: 'Example API',
|
||||
// version: '1.0.0',
|
||||
// },
|
||||
// });
|
||||
// }
|
||||
|
|
@ -1,17 +1,17 @@
|
|||
import { StatusCodes } from '$lib/constants/status-codes'
|
||||
import { Controller } from '$lib/server/api/common/types/controller'
|
||||
import { changePasswordDto } from '$lib/server/api/dtos/change-password.dto'
|
||||
import { updateEmailDto } from '$lib/server/api/dtos/update-email.dto'
|
||||
import { updateProfileDto } from '$lib/server/api/dtos/update-profile.dto'
|
||||
import { verifyPasswordDto } from '$lib/server/api/dtos/verify-password.dto'
|
||||
import { limiter } from '$lib/server/api/middleware/rate-limiter.middleware'
|
||||
import { IamService } from '$lib/server/api/services/iam.service'
|
||||
import { LoginRequestsService } from '$lib/server/api/services/loginrequest.service'
|
||||
import { LuciaService } from '$lib/server/api/services/lucia.service'
|
||||
import { zValidator } from '@hono/zod-validator'
|
||||
import { setCookie } from 'hono/cookie'
|
||||
import { inject, injectable } from 'tsyringe'
|
||||
import { requireAuth } from '../middleware/require-auth.middleware'
|
||||
import { StatusCodes } from '$lib/constants/status-codes';
|
||||
import { Controller } from '$lib/server/api/common/types/controller';
|
||||
import { changePasswordDto } from '$lib/server/api/dtos/change-password.dto';
|
||||
import { updateEmailDto } from '$lib/server/api/dtos/update-email.dto';
|
||||
import { updateProfileDto } from '$lib/server/api/dtos/update-profile.dto';
|
||||
import { verifyPasswordDto } from '$lib/server/api/dtos/verify-password.dto';
|
||||
import { limiter } from '$lib/server/api/middleware/rate-limiter.middleware';
|
||||
import { IamService } from '$lib/server/api/services/iam.service';
|
||||
import { LoginRequestsService } from '$lib/server/api/services/loginrequest.service';
|
||||
import { LuciaService } from '$lib/server/api/services/lucia.service';
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
import { setCookie } from 'hono/cookie';
|
||||
import { inject, injectable } from 'tsyringe';
|
||||
import { requireAuth } from '../middleware/require-auth.middleware';
|
||||
|
||||
@injectable()
|
||||
export class IamController extends Controller {
|
||||
|
|
@ -20,45 +20,47 @@ export class IamController extends Controller {
|
|||
@inject(LoginRequestsService) private readonly loginRequestService: LoginRequestsService,
|
||||
@inject(LuciaService) private luciaService: LuciaService,
|
||||
) {
|
||||
super()
|
||||
super();
|
||||
}
|
||||
|
||||
routes() {
|
||||
const tags = ['IAM'];
|
||||
|
||||
return this.controller
|
||||
.get('/', requireAuth, async (c) => {
|
||||
const user = c.var.user
|
||||
return c.json({ user })
|
||||
const user = c.var.user;
|
||||
return c.json({ user });
|
||||
})
|
||||
.put('/update/profile', requireAuth, zValidator('json', updateProfileDto), limiter({ limit: 30, minutes: 60 }), async (c) => {
|
||||
const user = c.var.user
|
||||
const { firstName, lastName, username } = c.req.valid('json')
|
||||
const updatedUser = await this.iamService.updateProfile(user.id, { firstName, lastName, username })
|
||||
const user = c.var.user;
|
||||
const { firstName, lastName, username } = c.req.valid('json');
|
||||
const updatedUser = await this.iamService.updateProfile(user.id, { firstName, lastName, username });
|
||||
if (!updatedUser) {
|
||||
return c.json('Username already in use', StatusCodes.BAD_REQUEST)
|
||||
return c.json('Username already in use', StatusCodes.BAD_REQUEST);
|
||||
}
|
||||
return c.json({ user: updatedUser }, StatusCodes.OK)
|
||||
return c.json({ user: updatedUser }, StatusCodes.OK);
|
||||
})
|
||||
.post('/verify/password', requireAuth, zValidator('json', verifyPasswordDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
|
||||
const user = c.var.user
|
||||
const { password } = c.req.valid('json')
|
||||
const passwordVerified = await this.iamService.verifyPassword(user.id, { password })
|
||||
const user = c.var.user;
|
||||
const { password } = c.req.valid('json');
|
||||
const passwordVerified = await this.iamService.verifyPassword(user.id, { password });
|
||||
if (!passwordVerified) {
|
||||
console.log('Incorrect password')
|
||||
return c.json('Incorrect password', StatusCodes.BAD_REQUEST)
|
||||
console.log('Incorrect password');
|
||||
return c.json('Incorrect password', StatusCodes.BAD_REQUEST);
|
||||
}
|
||||
return c.json({}, StatusCodes.OK)
|
||||
return c.json({}, StatusCodes.OK);
|
||||
})
|
||||
.put('/update/password', requireAuth, zValidator('json', changePasswordDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
|
||||
const user = c.var.user
|
||||
const { password, confirm_password } = c.req.valid('json')
|
||||
const user = c.var.user;
|
||||
const { password, confirm_password } = c.req.valid('json');
|
||||
if (password !== confirm_password) {
|
||||
return c.json('Passwords do not match', StatusCodes.BAD_REQUEST)
|
||||
return c.json('Passwords do not match', StatusCodes.BAD_REQUEST);
|
||||
}
|
||||
try {
|
||||
await this.iamService.updatePassword(user.id, { password, confirm_password })
|
||||
await this.luciaService.lucia.invalidateUserSessions(user.id)
|
||||
await this.loginRequestService.createUserSession(user.id, c.req, undefined)
|
||||
const sessionCookie = this.luciaService.lucia.createBlankSessionCookie()
|
||||
await this.iamService.updatePassword(user.id, { password, confirm_password });
|
||||
await this.luciaService.lucia.invalidateUserSessions(user.id);
|
||||
await this.loginRequestService.createUserSession(user.id, c.req, undefined);
|
||||
const sessionCookie = this.luciaService.lucia.createBlankSessionCookie();
|
||||
setCookie(c, sessionCookie.name, sessionCookie.value, {
|
||||
path: sessionCookie.attributes.path,
|
||||
maxAge: sessionCookie.attributes.maxAge,
|
||||
|
|
@ -67,26 +69,26 @@ export class IamController extends Controller {
|
|||
secure: sessionCookie.attributes.secure,
|
||||
httpOnly: sessionCookie.attributes.httpOnly,
|
||||
expires: sessionCookie.attributes.expires,
|
||||
})
|
||||
return c.json({ status: 'success' })
|
||||
});
|
||||
return c.json({ status: 'success' });
|
||||
} catch (error) {
|
||||
console.error('Error updating password', error)
|
||||
return c.json('Error updating password', StatusCodes.BAD_REQUEST)
|
||||
console.error('Error updating password', error);
|
||||
return c.json('Error updating password', StatusCodes.BAD_REQUEST);
|
||||
}
|
||||
})
|
||||
.post('/update/email', requireAuth, zValidator('json', updateEmailDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
|
||||
const user = c.var.user
|
||||
const { email } = c.req.valid('json')
|
||||
const updatedUser = await this.iamService.updateEmail(user.id, { email })
|
||||
const user = c.var.user;
|
||||
const { email } = c.req.valid('json');
|
||||
const updatedUser = await this.iamService.updateEmail(user.id, { email });
|
||||
if (!updatedUser) {
|
||||
return c.json('Email already in use', StatusCodes.BAD_REQUEST)
|
||||
return c.json('Email already in use', StatusCodes.BAD_REQUEST);
|
||||
}
|
||||
return c.json({ user: updatedUser }, StatusCodes.OK)
|
||||
return c.json({ user: updatedUser }, StatusCodes.OK);
|
||||
})
|
||||
.post('/logout', requireAuth, async (c) => {
|
||||
const sessionId = c.var.session.id
|
||||
await this.iamService.logout(sessionId)
|
||||
const sessionCookie = this.luciaService.lucia.createBlankSessionCookie()
|
||||
const sessionId = c.var.session.id;
|
||||
await this.iamService.logout(sessionId);
|
||||
const sessionCookie = this.luciaService.lucia.createBlankSessionCookie();
|
||||
setCookie(c, sessionCookie.name, sessionCookie.value, {
|
||||
path: sessionCookie.attributes.path,
|
||||
maxAge: sessionCookie.attributes.maxAge,
|
||||
|
|
@ -95,8 +97,8 @@ export class IamController extends Controller {
|
|||
secure: sessionCookie.attributes.secure,
|
||||
httpOnly: sessionCookie.attributes.httpOnly,
|
||||
expires: sessionCookie.attributes.expires,
|
||||
})
|
||||
return c.json({ status: 'success' })
|
||||
})
|
||||
});
|
||||
return c.json({ status: 'success' });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,30 +1,30 @@
|
|||
import 'reflect-metadata'
|
||||
import { Controller } from '$lib/server/api/common/types/controller'
|
||||
import { UsersService } from '$lib/server/api/services/users.service'
|
||||
import { inject, injectable } from 'tsyringe'
|
||||
import { requireAuth } from '../middleware/require-auth.middleware'
|
||||
import 'reflect-metadata';
|
||||
import { Controller } from '$lib/server/api/common/types/controller';
|
||||
import { UsersService } from '$lib/server/api/services/users.service';
|
||||
import { inject, injectable } from 'tsyringe';
|
||||
import { requireAuth } from '../middleware/require-auth.middleware';
|
||||
|
||||
@injectable()
|
||||
export class UserController extends Controller {
|
||||
constructor(@inject(UsersService) private readonly usersService: UsersService) {
|
||||
super()
|
||||
super();
|
||||
}
|
||||
|
||||
routes() {
|
||||
return this.controller
|
||||
.get('/', async (c) => {
|
||||
const user = c.var.user
|
||||
return c.json({ user })
|
||||
const user = c.var.user;
|
||||
return c.json({ user });
|
||||
})
|
||||
.get('/:id', requireAuth, async (c) => {
|
||||
const id = c.req.param('id')
|
||||
const user = await this.usersService.findOneById(id)
|
||||
return c.json({ user })
|
||||
const id = c.req.param('id');
|
||||
const user = await this.usersService.findOneById(id);
|
||||
return c.json({ user });
|
||||
})
|
||||
.get('/username/:userName', requireAuth, async (c) => {
|
||||
const userName = c.req.param('userName')
|
||||
const user = await this.usersService.findOneByUsername(userName)
|
||||
return c.json({ user })
|
||||
})
|
||||
const userName = c.req.param('userName');
|
||||
const user = await this.usersService.findOneByUsername(userName);
|
||||
return c.json({ user });
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,20 +1,19 @@
|
|||
import { eq } from 'drizzle-orm'
|
||||
import type { db } from '../../packages/drizzle'
|
||||
import { HashingService } from '../../services/hashing.service'
|
||||
import * as schema from '../tables'
|
||||
import users from './data/users.json'
|
||||
import { eq } from 'drizzle-orm';
|
||||
import type { db } from '../../packages/drizzle';
|
||||
import { HashingService } from '../../services/hashing.service';
|
||||
import * as schema from '../tables';
|
||||
import users from './data/users.json';
|
||||
|
||||
type JsonRole = {
|
||||
name: string
|
||||
primary: boolean
|
||||
}
|
||||
name: string;
|
||||
primary: boolean;
|
||||
};
|
||||
|
||||
export default async function seed(db: db) {
|
||||
const hashingService = new HashingService()
|
||||
const adminRole = await db.select().from(schema.rolesTable).where(eq(schema.rolesTable.name, 'admin'))
|
||||
const userRole = await db.select().from(schema.rolesTable).where(eq(schema.rolesTable.name, 'user'))
|
||||
const hashingService = new HashingService();
|
||||
const adminRole = await db.select().from(schema.rolesTable).where(eq(schema.rolesTable.name, 'admin'));
|
||||
const userRole = await db.select().from(schema.rolesTable).where(eq(schema.rolesTable.name, 'user'));
|
||||
|
||||
console.log('Admin Role: ', adminRole)
|
||||
const adminUser = await db
|
||||
.insert(schema.usersTable)
|
||||
.values({
|
||||
|
|
@ -25,19 +24,17 @@ export default async function seed(db: db) {
|
|||
verified: true,
|
||||
})
|
||||
.returning()
|
||||
.onConflictDoNothing()
|
||||
|
||||
console.log('Admin user created.', adminUser)
|
||||
.onConflictDoNothing();
|
||||
|
||||
await db.insert(schema.credentialsTable).values({
|
||||
user_id: adminUser[0].id,
|
||||
type: schema.CredentialsType.PASSWORD,
|
||||
secret_data: await hashingService.hash(`${process.env.ADMIN_PASSWORD}`),
|
||||
})
|
||||
});
|
||||
|
||||
await db.insert(schema.collections).values({ user_id: adminUser[0].id }).onConflictDoNothing()
|
||||
await db.insert(schema.collections).values({ user_id: adminUser[0].id }).onConflictDoNothing();
|
||||
|
||||
await db.insert(schema.wishlistsTable).values({ user_id: adminUser[0].id }).onConflictDoNothing()
|
||||
await db.insert(schema.wishlistsTable).values({ user_id: adminUser[0].id }).onConflictDoNothing();
|
||||
|
||||
await db
|
||||
.insert(schema.user_roles)
|
||||
|
|
@ -46,9 +43,7 @@ export default async function seed(db: db) {
|
|||
role_id: adminRole[0].id,
|
||||
primary: true,
|
||||
})
|
||||
.onConflictDoNothing()
|
||||
|
||||
console.log('Admin user given admin role.')
|
||||
.onConflictDoNothing();
|
||||
|
||||
await db
|
||||
.insert(schema.user_roles)
|
||||
|
|
@ -57,10 +52,8 @@ export default async function seed(db: db) {
|
|||
role_id: userRole[0].id,
|
||||
primary: false,
|
||||
})
|
||||
.onConflictDoNothing()
|
||||
.onConflictDoNothing();
|
||||
|
||||
console.log('Admin user given user role.')
|
||||
const hasingService = new HashingService()
|
||||
await Promise.all(
|
||||
users.map(async (user) => {
|
||||
const [insertedUser] = await db
|
||||
|
|
@ -68,29 +61,29 @@ export default async function seed(db: db) {
|
|||
.values({
|
||||
...user,
|
||||
})
|
||||
.returning()
|
||||
.returning();
|
||||
await db.insert(schema.credentialsTable).values({
|
||||
user_id: insertedUser?.id,
|
||||
type: schema.CredentialsType.PASSWORD,
|
||||
secret_data: await hasingService.hash(user.password),
|
||||
})
|
||||
await db.insert(schema.collections).values({ user_id: insertedUser?.id })
|
||||
await db.insert(schema.wishlistsTable).values({ user_id: insertedUser?.id })
|
||||
secret_data: await hashingService.hash(user.password),
|
||||
});
|
||||
await db.insert(schema.collections).values({ user_id: insertedUser?.id });
|
||||
await db.insert(schema.wishlistsTable).values({ user_id: insertedUser?.id });
|
||||
await Promise.all(
|
||||
user.roles.map(async (role: JsonRole) => {
|
||||
const foundRole = await db.query.rolesTable.findFirst({
|
||||
where: eq(schema.rolesTable.name, role.name),
|
||||
})
|
||||
});
|
||||
if (!foundRole) {
|
||||
throw new Error('Role not found')
|
||||
throw new Error('Role not found');
|
||||
}
|
||||
await db.insert(schema.user_roles).values({
|
||||
user_id: insertedUser?.id,
|
||||
role_id: foundRole?.id,
|
||||
primary: role?.primary,
|
||||
})
|
||||
});
|
||||
}),
|
||||
)
|
||||
);
|
||||
}),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,53 +1,21 @@
|
|||
import 'reflect-metadata'
|
||||
import { CollectionController } from '$lib/server/api/controllers/collection.controller'
|
||||
import { MfaController } from '$lib/server/api/controllers/mfa.controller'
|
||||
import { OAuthController } from '$lib/server/api/controllers/oauth.controller'
|
||||
import { SignupController } from '$lib/server/api/controllers/signup.controller'
|
||||
import { UserController } from '$lib/server/api/controllers/user.controller'
|
||||
import { WishlistController } from '$lib/server/api/controllers/wishlist.controller'
|
||||
import { AuthCleanupJobs } from '$lib/server/api/jobs/auth-cleanup.job'
|
||||
import { OpenAPIHono } from '@hono/zod-openapi'
|
||||
import type { PinoLogger } from 'hono-pino'
|
||||
import { hc } from 'hono/client'
|
||||
import { cors } from 'hono/cors'
|
||||
import { notFound, onError } from 'stoker/middlewares';
|
||||
import { container } from 'tsyringe'
|
||||
import { config } from './common/config'
|
||||
import { IamController } from './controllers/iam.controller'
|
||||
import { LoginController } from './controllers/login.controller'
|
||||
import { validateAuthSession, verifyOrigin } from './middleware/auth.middleware'
|
||||
import { pinoLogger } from './middleware/pino-logger.middleware'
|
||||
import 'reflect-metadata';
|
||||
import createApp from '$lib/server/api/common/create-app';
|
||||
import { CollectionController } from '$lib/server/api/controllers/collection.controller';
|
||||
import { MfaController } from '$lib/server/api/controllers/mfa.controller';
|
||||
import { OAuthController } from '$lib/server/api/controllers/oauth.controller';
|
||||
import { SignupController } from '$lib/server/api/controllers/signup.controller';
|
||||
import { UserController } from '$lib/server/api/controllers/user.controller';
|
||||
import { WishlistController } from '$lib/server/api/controllers/wishlist.controller';
|
||||
import { AuthCleanupJobs } from '$lib/server/api/jobs/auth-cleanup.job';
|
||||
import { hc } from 'hono/client';
|
||||
import { container } from 'tsyringe';
|
||||
import { config } from './common/config';
|
||||
import { IamController } from './controllers/iam.controller';
|
||||
import { LoginController } from './controllers/login.controller';
|
||||
|
||||
type AppBindings = {
|
||||
Variables: {
|
||||
logger: PinoLogger
|
||||
}
|
||||
}
|
||||
export const app = createApp();
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* App */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
export const app = new OpenAPIHono<AppBindings>().basePath('/api')
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Global Middlewares */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
app.use(verifyOrigin).use(validateAuthSession)
|
||||
app.use(pinoLogger())
|
||||
|
||||
app.notFound(notFound)
|
||||
app.onError(onError)
|
||||
|
||||
app.use(
|
||||
'/*',
|
||||
cors({
|
||||
origin: ['http://localhost:5173', 'http://localhost:80', 'http://host.docker.internal:80', 'http://host.docker.internal:5173'], // Replace with your allowed domains
|
||||
|
||||
allowMethods: ['POST'],
|
||||
allowHeaders: ['Content-Type'],
|
||||
// credentials: true, // If you need to send cookies or HTTP authentication
|
||||
}),
|
||||
)
|
||||
// configureOpenAPI(app);
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Routes */
|
||||
|
|
@ -61,22 +29,17 @@ const routes = app
|
|||
.route('/wishlists', container.resolve(WishlistController).routes())
|
||||
.route('/collections', container.resolve(CollectionController).routes())
|
||||
.route('/mfa', container.resolve(MfaController).routes())
|
||||
.get('/', (c) => c.json({ message: 'Server is healthy' }))
|
||||
.get('/error', (c) => {
|
||||
c.status(422);
|
||||
c.var.logger.info('Logged here');
|
||||
throw new Error('Test error')
|
||||
})
|
||||
.get('/', (c) => c.json({ message: 'Server is healthy' }));
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Cron Jobs */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
container.resolve(AuthCleanupJobs).deleteStaleEmailVerificationRequests()
|
||||
container.resolve(AuthCleanupJobs).deleteStaleLoginRequests()
|
||||
container.resolve(AuthCleanupJobs).deleteStaleEmailVerificationRequests();
|
||||
container.resolve(AuthCleanupJobs).deleteStaleLoginRequests();
|
||||
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* Exports */
|
||||
/* -------------------------------------------------------------------------- */
|
||||
export const rpc = hc<typeof routes>(config.api.origin)
|
||||
export type ApiClient = typeof rpc
|
||||
export type ApiRoutes = typeof routes
|
||||
export const rpc = hc<typeof routes>(config.api.origin);
|
||||
export type ApiClient = typeof rpc;
|
||||
export type ApiRoutes = typeof routes;
|
||||
|
|
|
|||
|
|
@ -1,41 +1,41 @@
|
|||
import { LuciaService } from '$lib/server/api/services/lucia.service'
|
||||
import type { MiddlewareHandler } from 'hono'
|
||||
import { createMiddleware } from 'hono/factory'
|
||||
import { verifyRequestOrigin } from 'oslo/request'
|
||||
import { container } from 'tsyringe'
|
||||
import type { HonoTypes } from '../common/types/hono'
|
||||
import { LuciaService } from '$lib/server/api/services/lucia.service';
|
||||
import type { MiddlewareHandler } from 'hono';
|
||||
import { createMiddleware } from 'hono/factory';
|
||||
import { verifyRequestOrigin } from 'oslo/request';
|
||||
import { container } from 'tsyringe';
|
||||
import type { AppBindings } from '../common/types/hono';
|
||||
|
||||
// resolve dependencies from the container
|
||||
const { lucia } = container.resolve(LuciaService)
|
||||
const { lucia } = container.resolve(LuciaService);
|
||||
|
||||
export const verifyOrigin: MiddlewareHandler<HonoTypes> = createMiddleware(async (c, next) => {
|
||||
export const verifyOrigin: MiddlewareHandler<AppBindings> = createMiddleware(async (c, next) => {
|
||||
if (c.req.method === 'GET') {
|
||||
return next()
|
||||
return next();
|
||||
}
|
||||
const originHeader = c.req.header('Origin') ?? null
|
||||
const hostHeader = c.req.header('Host') ?? null
|
||||
const originHeader = c.req.header('Origin') ?? null;
|
||||
const hostHeader = c.req.header('Host') ?? null;
|
||||
if (!originHeader || !hostHeader || !verifyRequestOrigin(originHeader, [hostHeader])) {
|
||||
return c.body(null, 403)
|
||||
return c.body(null, 403);
|
||||
}
|
||||
return next()
|
||||
})
|
||||
return next();
|
||||
});
|
||||
|
||||
export const validateAuthSession: MiddlewareHandler<HonoTypes> = createMiddleware(async (c, next) => {
|
||||
const sessionId = lucia.readSessionCookie(c.req.header('Cookie') ?? '')
|
||||
export const validateAuthSession: MiddlewareHandler<AppBindings> = createMiddleware(async (c, next) => {
|
||||
const sessionId = lucia.readSessionCookie(c.req.header('Cookie') ?? '');
|
||||
if (!sessionId) {
|
||||
c.set('user', null)
|
||||
c.set('session', null)
|
||||
return next()
|
||||
c.set('user', null);
|
||||
c.set('session', null);
|
||||
return next();
|
||||
}
|
||||
|
||||
const { session, user } = await lucia.validateSession(sessionId)
|
||||
const { session, user } = await lucia.validateSession(sessionId);
|
||||
if (session?.fresh) {
|
||||
c.header('Set-Cookie', lucia.createSessionCookie(session.id).serialize(), { append: true })
|
||||
c.header('Set-Cookie', lucia.createSessionCookie(session.id).serialize(), { append: true });
|
||||
}
|
||||
if (!session) {
|
||||
c.header('Set-Cookie', lucia.createBlankSessionCookie().serialize(), { append: true })
|
||||
c.header('Set-Cookie', lucia.createBlankSessionCookie().serialize(), { append: true });
|
||||
}
|
||||
c.set('session', session)
|
||||
c.set('user', user)
|
||||
return next()
|
||||
})
|
||||
c.set('session', session);
|
||||
c.set('user', user);
|
||||
return next();
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,14 +1,18 @@
|
|||
import env from '$lib/server/api/common/env';
|
||||
import { logger } from 'hono-pino';
|
||||
import pino from 'pino';
|
||||
import pretty from 'pino-pretty';
|
||||
|
||||
export function pinoLogger() {
|
||||
return logger({
|
||||
pino: pino({
|
||||
level: process.env.LOG_LEVEL || 'info',
|
||||
}, process.env.NODE_ENV === 'production' ? undefined : pretty()),
|
||||
pino: pino(
|
||||
{
|
||||
level: env.LOG_LEVEL || 'info',
|
||||
},
|
||||
env.NODE_ENV === 'production' ? undefined : pretty(),
|
||||
),
|
||||
http: {
|
||||
reqId: () => crypto.randomUUID(),
|
||||
}
|
||||
},
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,35 +1,35 @@
|
|||
import { rateLimiter } from 'hono-rate-limiter'
|
||||
import { RedisStore } from 'rate-limit-redis'
|
||||
import { container } from 'tsyringe'
|
||||
import type { HonoTypes } from '../common/types/hono'
|
||||
import { RedisService } from '../services/redis.service'
|
||||
import { rateLimiter } from 'hono-rate-limiter';
|
||||
import { RedisStore } from 'rate-limit-redis';
|
||||
import { container } from 'tsyringe';
|
||||
import type { AppBindings } from '../common/types/hono';
|
||||
import { RedisService } from '../services/redis.service';
|
||||
|
||||
// resolve dependencies from the container
|
||||
const { client } = container.resolve(RedisService)
|
||||
const { client } = container.resolve(RedisService);
|
||||
|
||||
export function limiter({
|
||||
limit,
|
||||
minutes,
|
||||
key = '',
|
||||
}: {
|
||||
limit: number
|
||||
minutes: number
|
||||
key?: string
|
||||
limit: number;
|
||||
minutes: number;
|
||||
key?: string;
|
||||
}) {
|
||||
return rateLimiter({
|
||||
windowMs: minutes * 60 * 1000, // every x minutes
|
||||
limit, // Limit each IP to 100 requests per `window` (here, per 15 minutes).
|
||||
standardHeaders: 'draft-6', // draft-6: `RateLimit-*` headers; draft-7: combined `RateLimit` header
|
||||
keyGenerator: (c) => {
|
||||
const vars = c.var as HonoTypes['Variables']
|
||||
const clientKey = vars.user?.id || c.req.header('x-forwarded-for')
|
||||
const pathKey = key || c.req.routePath
|
||||
return `${clientKey}_${pathKey}`
|
||||
const vars = c.var as AppBindings['Variables'];
|
||||
const clientKey = vars.user?.id || c.req.header('x-forwarded-for');
|
||||
const pathKey = key || c.req.routePath;
|
||||
return `${clientKey}_${pathKey}`;
|
||||
}, // Method to generate custom identifiers for clients.
|
||||
// Redis store configuration
|
||||
store: new RedisStore({
|
||||
// @ts-expect-error - Known issue: the `call` function is not present in @types/ioredis
|
||||
sendCommand: (...args: string[]) => client.call(...args),
|
||||
}) as any,
|
||||
})
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,14 +1,15 @@
|
|||
import { type NodePgDatabase, drizzle } from 'drizzle-orm/node-postgres'
|
||||
import pg from 'pg'
|
||||
import { type Disposable, injectable } from 'tsyringe'
|
||||
import { config } from '../common/config'
|
||||
import * as schema from '../databases/tables'
|
||||
import env from '$lib/server/api/common/env';
|
||||
import { type NodePgDatabase, drizzle } from 'drizzle-orm/node-postgres';
|
||||
import pg from 'pg';
|
||||
import { type Disposable, injectable } from 'tsyringe';
|
||||
import { config } from '../common/config';
|
||||
import * as schema from '../databases/tables';
|
||||
|
||||
@injectable()
|
||||
export class DrizzleService implements Disposable {
|
||||
protected readonly pool: pg.Pool
|
||||
db: NodePgDatabase<typeof schema>
|
||||
readonly schema: typeof schema = schema
|
||||
protected readonly pool: pg.Pool;
|
||||
db: NodePgDatabase<typeof schema>;
|
||||
readonly schema: typeof schema = schema;
|
||||
|
||||
constructor() {
|
||||
const pool = new pg.Pool({
|
||||
|
|
@ -19,15 +20,15 @@ export class DrizzleService implements Disposable {
|
|||
database: config.postgres.database,
|
||||
ssl: config.postgres.ssl,
|
||||
max: config.postgres.max,
|
||||
})
|
||||
this.pool = pool
|
||||
});
|
||||
this.pool = pool;
|
||||
this.db = drizzle(pool, {
|
||||
schema,
|
||||
logger: process.env.NODE_ENV === 'development',
|
||||
})
|
||||
logger: env.NODE_ENV === 'development',
|
||||
});
|
||||
}
|
||||
|
||||
dispose(): Promise<void> | void {
|
||||
this.pool.end()
|
||||
this.pool.end();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,52 +1,52 @@
|
|||
import { CredentialsRepository } from '$lib/server/api/repositories/credentials.repository'
|
||||
import { decodeHex, encodeHexLowerCase } from '@oslojs/encoding'
|
||||
import { verifyTOTP } from '@oslojs/otp'
|
||||
import { inject, injectable } from 'tsyringe'
|
||||
import type { CredentialsType } from '../databases/tables'
|
||||
import { CredentialsRepository } from '$lib/server/api/repositories/credentials.repository';
|
||||
import { decodeHex, encodeHexLowerCase } from '@oslojs/encoding';
|
||||
import { verifyTOTP } from '@oslojs/otp';
|
||||
import { inject, injectable } from 'tsyringe';
|
||||
import type { CredentialsType } from '../databases/tables';
|
||||
|
||||
@injectable()
|
||||
export class TotpService {
|
||||
constructor(@inject(CredentialsRepository) private readonly credentialsRepository: CredentialsRepository) {}
|
||||
|
||||
async findOneByUserId(userId: string) {
|
||||
return this.credentialsRepository.findTOTPCredentialsByUserId(userId)
|
||||
return this.credentialsRepository.findTOTPCredentialsByUserId(userId);
|
||||
}
|
||||
|
||||
async findOneByUserIdOrThrow(userId: string) {
|
||||
const credential = await this.findOneByUserId(userId)
|
||||
const credential = await this.findOneByUserId(userId);
|
||||
if (!credential) {
|
||||
throw new Error('TOTP credential not found')
|
||||
throw new Error('TOTP credential not found');
|
||||
}
|
||||
return credential
|
||||
return credential;
|
||||
}
|
||||
|
||||
async create(userId: string) {
|
||||
const secret = new Uint8Array(20)
|
||||
const secret = new Uint8Array(20);
|
||||
try {
|
||||
return await this.credentialsRepository.create({
|
||||
user_id: userId,
|
||||
secret_data: encodeHexLowerCase(crypto.getRandomValues(secret)),
|
||||
type: 'totp',
|
||||
})
|
||||
});
|
||||
} catch (e) {
|
||||
console.error(e)
|
||||
return null
|
||||
console.error(e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
async deleteOneByUserId(userId: string) {
|
||||
return this.credentialsRepository.deleteByUserId(userId)
|
||||
return this.credentialsRepository.deleteByUserId(userId);
|
||||
}
|
||||
|
||||
async deleteOneByUserIdAndType(userId: string, type: CredentialsType) {
|
||||
return this.credentialsRepository.deleteByUserIdAndType(userId, type)
|
||||
return this.credentialsRepository.deleteByUserIdAndType(userId, type);
|
||||
}
|
||||
|
||||
async verify(userId: string, code: string) {
|
||||
const credential = await this.credentialsRepository.findTOTPCredentialsByUserId(userId)
|
||||
const credential = await this.credentialsRepository.findTOTPCredentialsByUserId(userId);
|
||||
if (!credential) {
|
||||
throw new Error('TOTP credential not found')
|
||||
throw new Error('TOTP credential not found');
|
||||
}
|
||||
return verifyTOTP(decodeHex(credential.secret_data), 30, 6, code)
|
||||
return verifyTOTP(decodeHex(credential.secret_data), 30, 6, code);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,23 +1,22 @@
|
|||
<script lang="ts">
|
||||
import '$lib/styles/app.pcss'
|
||||
import { onMount } from 'svelte'
|
||||
import { MetaTags } from 'svelte-meta-tags'
|
||||
import { getFlash } from 'sveltekit-flash-message/client'
|
||||
import 'iconify-icon'
|
||||
import { onNavigate } from '$app/navigation'
|
||||
import { page } from '$app/stores'
|
||||
import Analytics from '$components/Analytics.svelte'
|
||||
import PlausibleAnalytics from '$components/PlausibleAnalytics.svelte'
|
||||
import { Toaster } from '$lib/components/ui/sonner'
|
||||
import PageLoadingIndicator from '$lib/page_loading_indicator.svelte'
|
||||
import { toastMessage } from '$lib/utils/superforms.js'
|
||||
import { theme } from '$state/theme'
|
||||
import '$lib/styles/app.pcss';
|
||||
import { onMount } from 'svelte';
|
||||
import { MetaTags } from 'svelte-meta-tags';
|
||||
import { getFlash } from 'sveltekit-flash-message/client';
|
||||
import 'iconify-icon';
|
||||
import { onNavigate } from '$app/navigation';
|
||||
import { page } from '$app/stores';
|
||||
import Analytics from '$components/Analytics.svelte';
|
||||
import { Toaster } from '$lib/components/ui/sonner';
|
||||
import PageLoadingIndicator from '$lib/page_loading_indicator.svelte';
|
||||
import { toastMessage } from '$lib/utils/superforms.js';
|
||||
import { theme } from '$state/theme';
|
||||
// import { ModeWatcher } from 'mode-watcher'
|
||||
|
||||
const dev = process.env.NODE_ENV !== 'production'
|
||||
const dev = process.env.NODE_ENV !== 'production';
|
||||
|
||||
const { data, children } = $props()
|
||||
const { user } = data
|
||||
const { data, children } = $props();
|
||||
const { user } = data;
|
||||
|
||||
const metaTags = $derived({
|
||||
titleTemplate: '%s | Bored Game',
|
||||
|
|
@ -29,45 +28,44 @@ const metaTags = $derived({
|
|||
description: 'Bored Game, keep track of your games',
|
||||
},
|
||||
...$page.data.metaTagsChild,
|
||||
})
|
||||
});
|
||||
|
||||
const flash = getFlash(page, {
|
||||
clearOnNavigate: true,
|
||||
clearAfterMs: 3000,
|
||||
clearArray: true,
|
||||
})
|
||||
});
|
||||
|
||||
onMount(() => {
|
||||
// set the theme to the user's active theme
|
||||
$theme = user?.theme || 'system'
|
||||
document.querySelector('html')?.setAttribute('data-theme', $theme)
|
||||
})
|
||||
$theme = user?.theme || 'system';
|
||||
document.querySelector('html')?.setAttribute('data-theme', $theme);
|
||||
});
|
||||
|
||||
$effect(() => {
|
||||
console.log('flash', $flash)
|
||||
console.log('flash', $flash);
|
||||
if ($flash) {
|
||||
toastMessage({ type: $flash.type, text: $flash.message })
|
||||
toastMessage({ type: $flash.type, text: $flash.message });
|
||||
// Clearing the flash message could sometimes
|
||||
// be required here to avoid double-toasting.
|
||||
flash.set(undefined)
|
||||
flash.set(undefined);
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
onNavigate(async (navigation) => {
|
||||
if (!document.startViewTransition) return
|
||||
if (!document.startViewTransition) return;
|
||||
|
||||
return new Promise((oldStateCaptureResolve) => {
|
||||
document.startViewTransition(async () => {
|
||||
oldStateCaptureResolve()
|
||||
await navigation.complete
|
||||
})
|
||||
})
|
||||
})
|
||||
oldStateCaptureResolve();
|
||||
await navigation.complete;
|
||||
});
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{#if !dev}
|
||||
<Analytics />
|
||||
<PlausibleAnalytics />
|
||||
{/if}
|
||||
|
||||
<MetaTags {...metaTags} />
|
||||
|
|
|
|||
Loading…
Reference in a new issue