mirror of
https://github.com/BradNut/boredgame
synced 2025-09-08 17:40:22 +00:00
Converting everything to the tsyringe IoC pattern.
This commit is contained in:
parent
3190e9601e
commit
bf55b04de6
19 changed files with 415 additions and 57 deletions
|
|
@ -1 +1 @@
|
||||||
20.15.1
|
22.1.0
|
||||||
13
package.json
13
package.json
|
|
@ -43,6 +43,10 @@
|
||||||
"eslint-plugin-svelte": "^2.43.0",
|
"eslint-plugin-svelte": "^2.43.0",
|
||||||
"just-clone": "^6.2.0",
|
"just-clone": "^6.2.0",
|
||||||
"just-debounce-it": "^3.2.0",
|
"just-debounce-it": "^3.2.0",
|
||||||
|
"lucia": "3.2.0",
|
||||||
|
"lucide-svelte": "^0.408.0",
|
||||||
|
"nodemailer": "^6.9.14",
|
||||||
|
"oslo": "^1.2.1",
|
||||||
"postcss": "^8.4.40",
|
"postcss": "^8.4.40",
|
||||||
"postcss-import": "^16.1.0",
|
"postcss-import": "^16.1.0",
|
||||||
"postcss-load-config": "^5.1.0",
|
"postcss-load-config": "^5.1.0",
|
||||||
|
|
@ -71,10 +75,6 @@
|
||||||
"zod": "^3.23.8"
|
"zod": "^3.23.8"
|
||||||
},
|
},
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
|
||||||
"node": ">=18.0.0 <19.0.0 || >=20.0.0 <21.0.0",
|
|
||||||
"pnpm": ">=8"
|
|
||||||
},
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/fira-mono": "^5.0.13",
|
"@fontsource/fira-mono": "^5.0.13",
|
||||||
"@hono/zod-validator": "^0.2.2",
|
"@hono/zod-validator": "^0.2.2",
|
||||||
|
|
@ -91,6 +91,7 @@
|
||||||
"arctic": "^1.9.2",
|
"arctic": "^1.9.2",
|
||||||
"bits-ui": "^0.21.12",
|
"bits-ui": "^0.21.12",
|
||||||
"boardgamegeekclient": "^1.9.1",
|
"boardgamegeekclient": "^1.9.1",
|
||||||
|
"bullmq": "^5.11.0",
|
||||||
"class-variance-authority": "^0.7.0",
|
"class-variance-authority": "^0.7.0",
|
||||||
"clsx": "^2.1.1",
|
"clsx": "^2.1.1",
|
||||||
"cookie": "^0.6.0",
|
"cookie": "^0.6.0",
|
||||||
|
|
@ -99,6 +100,7 @@
|
||||||
"drizzle-orm": "^0.32.1",
|
"drizzle-orm": "^0.32.1",
|
||||||
"feather-icons": "^4.29.2",
|
"feather-icons": "^4.29.2",
|
||||||
"formsnap": "^1.0.1",
|
"formsnap": "^1.0.1",
|
||||||
|
"handlebars": "^4.7.8",
|
||||||
"hono": "^4.5.2",
|
"hono": "^4.5.2",
|
||||||
"hono-rate-limiter": "^0.4.0",
|
"hono-rate-limiter": "^0.4.0",
|
||||||
"html-entities": "^2.5.2",
|
"html-entities": "^2.5.2",
|
||||||
|
|
@ -107,10 +109,7 @@
|
||||||
"just-capitalize": "^3.2.0",
|
"just-capitalize": "^3.2.0",
|
||||||
"just-kebab-case": "^4.2.0",
|
"just-kebab-case": "^4.2.0",
|
||||||
"loader": "^2.1.1",
|
"loader": "^2.1.1",
|
||||||
"lucia": "3.2.0",
|
|
||||||
"lucide-svelte": "^0.408.0",
|
|
||||||
"open-props": "^1.7.5",
|
"open-props": "^1.7.5",
|
||||||
"oslo": "^1.2.1",
|
|
||||||
"pg": "^8.12.0",
|
"pg": "^8.12.0",
|
||||||
"postgres": "^3.4.4",
|
"postgres": "^3.4.4",
|
||||||
"qrcode": "^1.5.3",
|
"qrcode": "^1.5.3",
|
||||||
|
|
|
||||||
185
pnpm-lock.yaml
185
pnpm-lock.yaml
|
|
@ -53,6 +53,9 @@ importers:
|
||||||
boardgamegeekclient:
|
boardgamegeekclient:
|
||||||
specifier: ^1.9.1
|
specifier: ^1.9.1
|
||||||
version: 1.9.1
|
version: 1.9.1
|
||||||
|
bullmq:
|
||||||
|
specifier: ^5.11.0
|
||||||
|
version: 5.11.0
|
||||||
class-variance-authority:
|
class-variance-authority:
|
||||||
specifier: ^0.7.0
|
specifier: ^0.7.0
|
||||||
version: 0.7.0
|
version: 0.7.0
|
||||||
|
|
@ -77,6 +80,9 @@ importers:
|
||||||
formsnap:
|
formsnap:
|
||||||
specifier: ^1.0.1
|
specifier: ^1.0.1
|
||||||
version: 1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.16.1(@sveltejs/kit@2.5.18(@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.175)(vite@5.3.5(@types/node@20.14.13)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.3.5(@types/node@20.14.13)(sass@1.77.8)))(svelte@5.0.0-next.175))
|
version: 1.0.1(svelte@5.0.0-next.175)(sveltekit-superforms@2.16.1(@sveltejs/kit@2.5.18(@sveltejs/vite-plugin-svelte@3.1.1(svelte@5.0.0-next.175)(vite@5.3.5(@types/node@20.14.13)(sass@1.77.8)))(svelte@5.0.0-next.175)(vite@5.3.5(@types/node@20.14.13)(sass@1.77.8)))(svelte@5.0.0-next.175))
|
||||||
|
handlebars:
|
||||||
|
specifier: ^4.7.8
|
||||||
|
version: 4.7.8
|
||||||
hono:
|
hono:
|
||||||
specifier: ^4.5.2
|
specifier: ^4.5.2
|
||||||
version: 4.5.2
|
version: 4.5.2
|
||||||
|
|
@ -101,18 +107,9 @@ importers:
|
||||||
loader:
|
loader:
|
||||||
specifier: ^2.1.1
|
specifier: ^2.1.1
|
||||||
version: 2.1.1
|
version: 2.1.1
|
||||||
lucia:
|
|
||||||
specifier: 3.2.0
|
|
||||||
version: 3.2.0
|
|
||||||
lucide-svelte:
|
|
||||||
specifier: ^0.408.0
|
|
||||||
version: 0.408.0(svelte@5.0.0-next.175)
|
|
||||||
open-props:
|
open-props:
|
||||||
specifier: ^1.7.5
|
specifier: ^1.7.5
|
||||||
version: 1.7.5
|
version: 1.7.5
|
||||||
oslo:
|
|
||||||
specifier: ^1.2.1
|
|
||||||
version: 1.2.1
|
|
||||||
pg:
|
pg:
|
||||||
specifier: ^8.12.0
|
specifier: ^8.12.0
|
||||||
version: 8.12.0
|
version: 8.12.0
|
||||||
|
|
@ -210,6 +207,18 @@ importers:
|
||||||
just-debounce-it:
|
just-debounce-it:
|
||||||
specifier: ^3.2.0
|
specifier: ^3.2.0
|
||||||
version: 3.2.0
|
version: 3.2.0
|
||||||
|
lucia:
|
||||||
|
specifier: 3.2.0
|
||||||
|
version: 3.2.0
|
||||||
|
lucide-svelte:
|
||||||
|
specifier: ^0.408.0
|
||||||
|
version: 0.408.0(svelte@5.0.0-next.175)
|
||||||
|
nodemailer:
|
||||||
|
specifier: ^6.9.14
|
||||||
|
version: 6.9.14
|
||||||
|
oslo:
|
||||||
|
specifier: ^1.2.1
|
||||||
|
version: 1.2.1
|
||||||
postcss:
|
postcss:
|
||||||
specifier: ^8.4.40
|
specifier: ^8.4.40
|
||||||
version: 8.4.40
|
version: 8.4.40
|
||||||
|
|
@ -1386,6 +1395,36 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
svelte: ^3.0.0 || ^4.0.0 || ^5.0.0-next.118
|
svelte: ^3.0.0 || ^4.0.0 || ^5.0.0-next.118
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
|
||||||
|
resolution: {integrity: sha512-QZHtlVgbAdy2zAqNA9Gu1UpIuI8Xvsd1v8ic6B2pZmeFnFcMWiPLfWXh7TVw4eGEZ/C9TH281KwhVoeQUKbyjw==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3':
|
||||||
|
resolution: {integrity: sha512-mdzd3AVzYKuUmiWOQ8GNhl64/IoFGol569zNRdkLReh6LRLHOXxU4U8eq0JwaD8iFHdVGqSy4IjFL4reoWCDFw==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [darwin]
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3':
|
||||||
|
resolution: {integrity: sha512-YxQL+ax0XqBJDZiKimS2XQaf+2wDGVa1enVRGzEvLLVFeqa5kx2bWbtcSXgsxjQB7nRqqIGFIcLteF/sHeVtQg==}
|
||||||
|
cpu: [arm64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3':
|
||||||
|
resolution: {integrity: sha512-fg0uy/dG/nZEXfYilKoRe7yALaNmHoYeIoJuJ7KJ+YyU2bvY8vPv27f7UKhGRpY6euFYqEVhxCFZgAUNQBM3nw==}
|
||||||
|
cpu: [arm]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3':
|
||||||
|
resolution: {integrity: sha512-cvwNfbP07pKUfq1uH+S6KJ7dT9K8WOE4ZiAcsrSes+UY55E/0jLYc+vq+DO7jlmqRb5zAggExKm0H7O/CBaesg==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [linux]
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
|
||||||
|
resolution: {integrity: sha512-x0fWaQtYp4E6sktbsdAqnehxDgEc/VwM7uLsRCYWaiGu0ykYdZPiS8zCWdnjHwyiumousxfBm4SO31eXqwEZhQ==}
|
||||||
|
cpu: [x64]
|
||||||
|
os: [win32]
|
||||||
|
|
||||||
'@neondatabase/serverless@0.9.4':
|
'@neondatabase/serverless@0.9.4':
|
||||||
resolution: {integrity: sha512-D0AXgJh6xkf+XTlsO7iwE2Q1w8981E1cLCPAALMU2YKtkF/1SF6BiAzYARZFYo175ON+b1RNIy9TdSFHm5nteg==}
|
resolution: {integrity: sha512-D0AXgJh6xkf+XTlsO7iwE2Q1w8981E1cLCPAALMU2YKtkF/1SF6BiAzYARZFYo175ON+b1RNIy9TdSFHm5nteg==}
|
||||||
|
|
||||||
|
|
@ -2225,6 +2264,9 @@ packages:
|
||||||
buffer-from@1.1.2:
|
buffer-from@1.1.2:
|
||||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||||
|
|
||||||
|
bullmq@5.11.0:
|
||||||
|
resolution: {integrity: sha512-qVzyWGZqie3VHaYEgRXhId/j8ebfmj6MExEJyUByMsUJA5pVciVle3hKLer5fyMwtQ8lTMP7GwhXV/NZ+HzlRA==}
|
||||||
|
|
||||||
bytes@3.1.2:
|
bytes@3.1.2:
|
||||||
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||||
engines: {node: '>= 0.8'}
|
engines: {node: '>= 0.8'}
|
||||||
|
|
@ -2357,6 +2399,10 @@ packages:
|
||||||
create-require@1.1.1:
|
create-require@1.1.1:
|
||||||
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
resolution: {integrity: sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==}
|
||||||
|
|
||||||
|
cron-parser@4.9.0:
|
||||||
|
resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==}
|
||||||
|
engines: {node: '>=12.0.0'}
|
||||||
|
|
||||||
cross-spawn@7.0.3:
|
cross-spawn@7.0.3:
|
||||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||||
engines: {node: '>= 8'}
|
engines: {node: '>= 8'}
|
||||||
|
|
@ -2943,6 +2989,11 @@ packages:
|
||||||
graphemer@1.4.0:
|
graphemer@1.4.0:
|
||||||
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==}
|
||||||
|
|
||||||
|
handlebars@4.7.8:
|
||||||
|
resolution: {integrity: sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ==}
|
||||||
|
engines: {node: '>=0.4.7'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
has-flag@4.0.0:
|
has-flag@4.0.0:
|
||||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -3205,6 +3256,10 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
svelte: ^3 || ^4 || ^5.0.0-next.42
|
svelte: ^3 || ^4 || ^5.0.0-next.42
|
||||||
|
|
||||||
|
luxon@3.4.4:
|
||||||
|
resolution: {integrity: sha512-zobTr7akeGHnv7eBOXcRgMeCP6+uyYsczwmeRCauvpvaAltgNyTbLH/+VaEAPUeWBT+1GuNmz4wC/6jtQzbbVA==}
|
||||||
|
engines: {node: '>=12'}
|
||||||
|
|
||||||
magic-string@0.30.10:
|
magic-string@0.30.10:
|
||||||
resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
|
resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
|
||||||
|
|
||||||
|
|
@ -3338,6 +3393,13 @@ packages:
|
||||||
ms@2.1.3:
|
ms@2.1.3:
|
||||||
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==}
|
||||||
|
|
||||||
|
msgpackr-extract@3.0.3:
|
||||||
|
resolution: {integrity: sha512-P0efT1C9jIdVRefqjzOQ9Xml57zpOXnIuS+csaB4MdZbTdmGDLo8XhzBG1N7aO11gKDDkJvBLULeFTo46wwreA==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
|
msgpackr@1.11.0:
|
||||||
|
resolution: {integrity: sha512-I8qXuuALqJe5laEBYoFykChhSXLikZmUhccjGsPuSJ/7uPip2TJ7lwdIQwWSAi0jGZDXv4WOP8Qg65QZRuXxXw==}
|
||||||
|
|
||||||
mz@2.7.0:
|
mz@2.7.0:
|
||||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||||
|
|
||||||
|
|
@ -3358,6 +3420,12 @@ packages:
|
||||||
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
||||||
engines: {node: '>= 0.6'}
|
engines: {node: '>= 0.6'}
|
||||||
|
|
||||||
|
neo-async@2.6.2:
|
||||||
|
resolution: {integrity: sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==}
|
||||||
|
|
||||||
|
node-abort-controller@3.1.1:
|
||||||
|
resolution: {integrity: sha512-AGK2yQKIjRuqnc6VkX2Xj5d+QW8xZ87pa1UK6yA6ouUyuxfHuMP6umE5QK7UmTeOAymo+Zx1Fxiuw9rVx8taHQ==}
|
||||||
|
|
||||||
node-fetch@2.7.0:
|
node-fetch@2.7.0:
|
||||||
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
|
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
|
||||||
engines: {node: 4.x || >=6.0.0}
|
engines: {node: 4.x || >=6.0.0}
|
||||||
|
|
@ -3367,6 +3435,10 @@ packages:
|
||||||
encoding:
|
encoding:
|
||||||
optional: true
|
optional: true
|
||||||
|
|
||||||
|
node-gyp-build-optional-packages@5.2.2:
|
||||||
|
resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
node-gyp-build@4.8.1:
|
node-gyp-build@4.8.1:
|
||||||
resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==}
|
resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==}
|
||||||
hasBin: true
|
hasBin: true
|
||||||
|
|
@ -3374,6 +3446,10 @@ packages:
|
||||||
node-releases@2.0.14:
|
node-releases@2.0.14:
|
||||||
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
|
resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==}
|
||||||
|
|
||||||
|
nodemailer@6.9.14:
|
||||||
|
resolution: {integrity: sha512-Dobp/ebDKBvz91sbtRKhcznLThrKxKt97GI2FAlAyy+fk19j73Uz3sBXolVtmcXjaorivqsbbbjDY+Jkt4/bQA==}
|
||||||
|
engines: {node: '>=6.0.0'}
|
||||||
|
|
||||||
nopt@5.0.0:
|
nopt@5.0.0:
|
||||||
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
|
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
|
||||||
engines: {node: '>=6'}
|
engines: {node: '>=6'}
|
||||||
|
|
@ -4519,6 +4595,11 @@ packages:
|
||||||
ufo@1.5.3:
|
ufo@1.5.3:
|
||||||
resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==}
|
resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==}
|
||||||
|
|
||||||
|
uglify-js@3.19.1:
|
||||||
|
resolution: {integrity: sha512-y/2wiW+ceTYR2TSSptAhfnEtpLaQ4Ups5zrjB2d3kuVxHj16j/QJwPl5PvuGy9uARb39J0+iKxcRPvtpsx4A4A==}
|
||||||
|
engines: {node: '>=0.8.0'}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
ultrahtml@1.5.3:
|
ultrahtml@1.5.3:
|
||||||
resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==}
|
resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==}
|
||||||
|
|
||||||
|
|
@ -4557,6 +4638,10 @@ packages:
|
||||||
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
||||||
engines: {node: '>= 0.4.0'}
|
engines: {node: '>= 0.4.0'}
|
||||||
|
|
||||||
|
uuid@9.0.1:
|
||||||
|
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
|
||||||
|
hasBin: true
|
||||||
|
|
||||||
v8-compile-cache-lib@3.0.1:
|
v8-compile-cache-lib@3.0.1:
|
||||||
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
|
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
|
||||||
|
|
||||||
|
|
@ -4670,6 +4755,9 @@ packages:
|
||||||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||||
engines: {node: '>=0.10.0'}
|
engines: {node: '>=0.10.0'}
|
||||||
|
|
||||||
|
wordwrap@1.0.0:
|
||||||
|
resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
|
||||||
|
|
||||||
wrap-ansi@6.2.0:
|
wrap-ansi@6.2.0:
|
||||||
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||||
engines: {node: '>=8'}
|
engines: {node: '>=8'}
|
||||||
|
|
@ -5579,6 +5667,24 @@ snapshots:
|
||||||
nanoid: 5.0.7
|
nanoid: 5.0.7
|
||||||
svelte: 5.0.0-next.175
|
svelte: 5.0.0-next.175
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-darwin-x64@3.0.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-linux-arm64@3.0.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-linux-arm@3.0.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-linux-x64@3.0.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
'@msgpackr-extract/msgpackr-extract-win32-x64@3.0.3':
|
||||||
|
optional: true
|
||||||
|
|
||||||
'@neondatabase/serverless@0.9.4':
|
'@neondatabase/serverless@0.9.4':
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/pg': 8.11.6
|
'@types/pg': 8.11.6
|
||||||
|
|
@ -6367,6 +6473,18 @@ snapshots:
|
||||||
|
|
||||||
buffer-from@1.1.2: {}
|
buffer-from@1.1.2: {}
|
||||||
|
|
||||||
|
bullmq@5.11.0:
|
||||||
|
dependencies:
|
||||||
|
cron-parser: 4.9.0
|
||||||
|
ioredis: 5.4.1
|
||||||
|
msgpackr: 1.11.0
|
||||||
|
node-abort-controller: 3.1.1
|
||||||
|
semver: 7.6.3
|
||||||
|
tslib: 2.6.3
|
||||||
|
uuid: 9.0.1
|
||||||
|
transitivePeerDependencies:
|
||||||
|
- supports-color
|
||||||
|
|
||||||
bytes@3.1.2: {}
|
bytes@3.1.2: {}
|
||||||
|
|
||||||
cac@6.7.14: {}
|
cac@6.7.14: {}
|
||||||
|
|
@ -6493,6 +6611,10 @@ snapshots:
|
||||||
|
|
||||||
create-require@1.1.1: {}
|
create-require@1.1.1: {}
|
||||||
|
|
||||||
|
cron-parser@4.9.0:
|
||||||
|
dependencies:
|
||||||
|
luxon: 3.4.4
|
||||||
|
|
||||||
cross-spawn@7.0.3:
|
cross-spawn@7.0.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
path-key: 3.1.1
|
path-key: 3.1.1
|
||||||
|
|
@ -7127,6 +7249,15 @@ snapshots:
|
||||||
|
|
||||||
graphemer@1.4.0: {}
|
graphemer@1.4.0: {}
|
||||||
|
|
||||||
|
handlebars@4.7.8:
|
||||||
|
dependencies:
|
||||||
|
minimist: 1.2.8
|
||||||
|
neo-async: 2.6.2
|
||||||
|
source-map: 0.6.1
|
||||||
|
wordwrap: 1.0.0
|
||||||
|
optionalDependencies:
|
||||||
|
uglify-js: 3.19.1
|
||||||
|
|
||||||
has-flag@4.0.0: {}
|
has-flag@4.0.0: {}
|
||||||
|
|
||||||
has-property-descriptors@1.0.2:
|
has-property-descriptors@1.0.2:
|
||||||
|
|
@ -7373,6 +7504,8 @@ snapshots:
|
||||||
dependencies:
|
dependencies:
|
||||||
svelte: 5.0.0-next.175
|
svelte: 5.0.0-next.175
|
||||||
|
|
||||||
|
luxon@3.4.4: {}
|
||||||
|
|
||||||
magic-string@0.30.10:
|
magic-string@0.30.10:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jridgewell/sourcemap-codec': 1.4.15
|
'@jridgewell/sourcemap-codec': 1.4.15
|
||||||
|
|
@ -7481,6 +7614,22 @@ snapshots:
|
||||||
|
|
||||||
ms@2.1.3: {}
|
ms@2.1.3: {}
|
||||||
|
|
||||||
|
msgpackr-extract@3.0.3:
|
||||||
|
dependencies:
|
||||||
|
node-gyp-build-optional-packages: 5.2.2
|
||||||
|
optionalDependencies:
|
||||||
|
'@msgpackr-extract/msgpackr-extract-darwin-arm64': 3.0.3
|
||||||
|
'@msgpackr-extract/msgpackr-extract-darwin-x64': 3.0.3
|
||||||
|
'@msgpackr-extract/msgpackr-extract-linux-arm': 3.0.3
|
||||||
|
'@msgpackr-extract/msgpackr-extract-linux-arm64': 3.0.3
|
||||||
|
'@msgpackr-extract/msgpackr-extract-linux-x64': 3.0.3
|
||||||
|
'@msgpackr-extract/msgpackr-extract-win32-x64': 3.0.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
|
msgpackr@1.11.0:
|
||||||
|
optionalDependencies:
|
||||||
|
msgpackr-extract: 3.0.3
|
||||||
|
|
||||||
mz@2.7.0:
|
mz@2.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
any-promise: 1.3.0
|
any-promise: 1.3.0
|
||||||
|
|
@ -7495,14 +7644,25 @@ snapshots:
|
||||||
|
|
||||||
negotiator@0.6.3: {}
|
negotiator@0.6.3: {}
|
||||||
|
|
||||||
|
neo-async@2.6.2: {}
|
||||||
|
|
||||||
|
node-abort-controller@3.1.1: {}
|
||||||
|
|
||||||
node-fetch@2.7.0:
|
node-fetch@2.7.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
whatwg-url: 5.0.0
|
whatwg-url: 5.0.0
|
||||||
|
|
||||||
|
node-gyp-build-optional-packages@5.2.2:
|
||||||
|
dependencies:
|
||||||
|
detect-libc: 2.0.3
|
||||||
|
optional: true
|
||||||
|
|
||||||
node-gyp-build@4.8.1: {}
|
node-gyp-build@4.8.1: {}
|
||||||
|
|
||||||
node-releases@2.0.14: {}
|
node-releases@2.0.14: {}
|
||||||
|
|
||||||
|
nodemailer@6.9.14: {}
|
||||||
|
|
||||||
nopt@5.0.0:
|
nopt@5.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
abbrev: 1.1.1
|
abbrev: 1.1.1
|
||||||
|
|
@ -8737,6 +8897,9 @@ snapshots:
|
||||||
|
|
||||||
ufo@1.5.3: {}
|
ufo@1.5.3: {}
|
||||||
|
|
||||||
|
uglify-js@3.19.1:
|
||||||
|
optional: true
|
||||||
|
|
||||||
ultrahtml@1.5.3: {}
|
ultrahtml@1.5.3: {}
|
||||||
|
|
||||||
undici-types@5.26.5: {}
|
undici-types@5.26.5: {}
|
||||||
|
|
@ -8770,6 +8933,8 @@ snapshots:
|
||||||
|
|
||||||
utils-merge@1.0.1: {}
|
utils-merge@1.0.1: {}
|
||||||
|
|
||||||
|
uuid@9.0.1: {}
|
||||||
|
|
||||||
v8-compile-cache-lib@3.0.1: {}
|
v8-compile-cache-lib@3.0.1: {}
|
||||||
|
|
||||||
valibot@0.31.1:
|
valibot@0.31.1:
|
||||||
|
|
@ -8878,6 +9043,8 @@ snapshots:
|
||||||
|
|
||||||
word-wrap@1.2.5: {}
|
word-wrap@1.2.5: {}
|
||||||
|
|
||||||
|
wordwrap@1.0.0: {}
|
||||||
|
|
||||||
wrap-ansi@6.2.0:
|
wrap-ansi@6.2.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-styles: 4.3.0
|
ansi-styles: 4.3.0
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,21 @@
|
||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { zValidator } from '@hono/zod-validator';
|
import { injectable } from 'tsyringe';
|
||||||
|
import type { HonoTypes } from '../types';
|
||||||
import { requireAuth } from "../middleware/auth.middleware";
|
import { requireAuth } from "../middleware/auth.middleware";
|
||||||
import { registerEmailPasswordDto } from '$lib/dtos/register-emailpassword.dto';
|
import type { Controller } from '../interfaces/controller.interface';
|
||||||
import { limiter } from '../middleware/rate-limiter.middleware';
|
|
||||||
|
|
||||||
const app = new Hono()
|
@injectable()
|
||||||
.get('/me', requireAuth, async (c) => {
|
export class IamController implements Controller {
|
||||||
const user = c.var.user;
|
controller = new Hono<HonoTypes>();
|
||||||
return c.json({ user });
|
|
||||||
})
|
|
||||||
.get('/user', requireAuth, async (c) => {
|
|
||||||
const user = c.var.user;
|
|
||||||
return c.json({ user });
|
|
||||||
})
|
|
||||||
.post('/login/request', zValidator('json', registerEmailPasswordDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
|
|
||||||
const { email } = c.req.valid('json');
|
|
||||||
await this.loginRequestsService.create({ email });
|
|
||||||
return c.json({ message: 'Verification email sent' });
|
|
||||||
});
|
|
||||||
|
|
||||||
export default app;
|
constructor(
|
||||||
|
) { }
|
||||||
|
|
||||||
|
routes() {
|
||||||
|
return this.controller
|
||||||
|
.get('/me', requireAuth, async (c) => {
|
||||||
|
const user = c.var.user;
|
||||||
|
return c.json({ user });
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,26 @@
|
||||||
import { Hono } from 'hono';
|
import { Hono } from 'hono';
|
||||||
import { zValidator } from '@hono/zod-validator';
|
import { zValidator } from '@hono/zod-validator';
|
||||||
import { registerEmailPasswordDto } from '$lib/dtos/register-emailpassword.dto';
|
import { inject, injectable } from 'tsyringe';
|
||||||
|
import type { HonoTypes } from '../types';
|
||||||
import { limiter } from '../middleware/rate-limiter.middleware';
|
import { limiter } from '../middleware/rate-limiter.middleware';
|
||||||
|
import type { Controller } from '../interfaces/controller.interface';
|
||||||
|
import { signInEmailDto } from '$lib/dtos/signin-email.dto';
|
||||||
|
import type { LoginRequestsService } from '../services/loginrequest.service';
|
||||||
|
|
||||||
const app = new Hono()
|
@injectable()
|
||||||
.post('/', zValidator('json', registerEmailPasswordDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
|
export class LoginController implements Controller {
|
||||||
const { email } = c.req.valid('json');
|
controller = new Hono<HonoTypes>();
|
||||||
await loginRequestsService.create({ email });
|
|
||||||
return c.json({ message: 'Verification email sent' });
|
|
||||||
});
|
|
||||||
|
|
||||||
export default app;
|
constructor(
|
||||||
|
@inject('LoginRequestsService') private readonly loginRequestsService: LoginRequestsService
|
||||||
|
) { }
|
||||||
|
|
||||||
|
routes() {
|
||||||
|
return this.controller
|
||||||
|
.post('/', zValidator('json', signInEmailDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
|
||||||
|
const { username, password } = c.req.valid('json');
|
||||||
|
await this.loginRequestsService.verify({ username, password });
|
||||||
|
return c.json({ message: 'Verification email sent' });
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,20 @@
|
||||||
|
import { pgTable, text, uuid } from "drizzle-orm/pg-core";
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
import { usersTable } from "./users.table";
|
||||||
|
|
||||||
|
enum CredentialsType {
|
||||||
|
SECRET = 'secret',
|
||||||
|
PASSWORD = 'password',
|
||||||
|
TOTP = 'totp',
|
||||||
|
HOTP = 'hotp'
|
||||||
|
}
|
||||||
|
|
||||||
|
export const credentialsTable = pgTable('credentials', {
|
||||||
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
user_id: uuid('user_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => usersTable.id, { onDelete: 'cascade' }),
|
||||||
|
type: text('type').notNull().default(CredentialsType.PASSWORD),
|
||||||
|
secret_data: text('secret_data').notNull(),
|
||||||
|
...timestamps
|
||||||
|
});
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
import { pgTable, text, timestamp, uuid } from 'drizzle-orm/pg-core';
|
import { pgTable, text, uuid } from 'drizzle-orm/pg-core';
|
||||||
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
import { createId as cuid2 } from '@paralleldrive/cuid2';
|
||||||
import { type InferSelectModel, relations } from 'drizzle-orm';
|
import { type InferSelectModel, relations } from 'drizzle-orm';
|
||||||
import games from './games';
|
import games from './games';
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,14 @@
|
||||||
|
import { pgTable, text, uuid } from "drizzle-orm/pg-core";
|
||||||
|
import { usersTable } from "./users.table";
|
||||||
|
import { timestamps } from '../utils';
|
||||||
|
|
||||||
|
export const federatedIdentityTable = pgTable('federated_identity', {
|
||||||
|
id: uuid('id').primaryKey().defaultRandom(),
|
||||||
|
user_id: uuid('user_id')
|
||||||
|
.notNull()
|
||||||
|
.references(() => usersTable.id, { onDelete: 'cascade' }),
|
||||||
|
idenitity_provider: text('idenitity_provider').notNull(),
|
||||||
|
federated_user_id: text('federated_user_id').notNull(),
|
||||||
|
federated_username: text('federated_username').notNull(),
|
||||||
|
...timestamps
|
||||||
|
});
|
||||||
8
src/lib/server/api/interfaces/controller.interface.ts
Normal file
8
src/lib/server/api/interfaces/controller.interface.ts
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
import { Hono } from 'hono';
|
||||||
|
import type { HonoTypes } from '../types';
|
||||||
|
import type { BlankSchema } from 'hono/types';
|
||||||
|
|
||||||
|
export interface Controller {
|
||||||
|
controller: Hono<HonoTypes, BlankSchema, '/'>;
|
||||||
|
routes(): any;
|
||||||
|
}
|
||||||
10
src/lib/server/api/mockTest.ts
Normal file
10
src/lib/server/api/mockTest.ts
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
import { Argon2id } from "oslo/password";
|
||||||
|
|
||||||
|
export async function hash(value: string) {
|
||||||
|
const argon2 = new Argon2id()
|
||||||
|
return argon2.hash(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function verify(hashedValue: string, value: string) {
|
||||||
|
return new Argon2id().verify(hashedValue, value);
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { container } from 'tsyringe';
|
||||||
import { db } from '../infrastructure/database';
|
import { db } from '../infrastructure/database';
|
||||||
|
|
||||||
// Symbol
|
// Symbol
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
// import { lucia } from '../infrastructure/auth/lucia';
|
import { container } from 'tsyringe';
|
||||||
|
import { lucia } from '../infrastructure/auth/lucia';
|
||||||
|
|
||||||
// // Symbol
|
// Symbol
|
||||||
// export const LuciaProvider = Symbol('LUCIA_PROVIDER');
|
export const LuciaProvider = Symbol('LUCIA_PROVIDER');
|
||||||
|
|
||||||
// // Type
|
// Type
|
||||||
// export type LuciaProvider = typeof lucia;
|
export type LuciaProvider = typeof lucia;
|
||||||
|
|
||||||
// // Register
|
// Register
|
||||||
// container.register<LuciaProvider>(LuciaProvider, { useValue: lucia });
|
container.register<LuciaProvider>(LuciaProvider, { useValue: lucia });
|
||||||
|
|
|
||||||
35
src/lib/server/api/repositories/credentials.repository.ts
Normal file
35
src/lib/server/api/repositories/credentials.repository.ts
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
import { eq, type InferInsertModel } from "drizzle-orm";
|
||||||
|
import { credentialsTable } from "../infrastructure/database/tables/credentials.table";
|
||||||
|
import { db } from "../infrastructure/database";
|
||||||
|
import { takeFirstOrThrow } from "../infrastructure/database/utils";
|
||||||
|
|
||||||
|
export type CreateCredentials = InferInsertModel<typeof credentialsTable>;
|
||||||
|
export type UpdateCredentials = Partial<CreateCredentials>;
|
||||||
|
|
||||||
|
export class CredentialsRepository {
|
||||||
|
|
||||||
|
async findOneById(id: string) {
|
||||||
|
return db.query.credentialsTable.findFirst({
|
||||||
|
where: eq(credentialsTable.id, id)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async findOneByIdOrThrow(id: string) {
|
||||||
|
const credentials = await this.findOneById(id);
|
||||||
|
if (!credentials) throw Error('Credentials not found');
|
||||||
|
return credentials;
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(data: CreateCredentials) {
|
||||||
|
return db.insert(credentialsTable).values(data).returning().then(takeFirstOrThrow);
|
||||||
|
}
|
||||||
|
|
||||||
|
async update(id: string, data: UpdateCredentials) {
|
||||||
|
return db
|
||||||
|
.update(credentialsTable)
|
||||||
|
.set(data)
|
||||||
|
.where(eq(credentialsTable.id, id))
|
||||||
|
.returning()
|
||||||
|
.then(takeFirstOrThrow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -35,6 +35,12 @@ export class UsersRepository {
|
||||||
return user;
|
return user;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findOneByUsername(username: string) {
|
||||||
|
return db.query.usersTable.findFirst({
|
||||||
|
where: eq(usersTable.username, username)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async findOneByEmail(email: string) {
|
async findOneByEmail(email: string) {
|
||||||
return db.query.usersTable.findFirst({
|
return db.query.usersTable.findFirst({
|
||||||
where: eq(usersTable.email, email)
|
where: eq(usersTable.email, email)
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import { injectable } from "tsyringe";
|
||||||
import { Argon2id } from "oslo/password";
|
import { Argon2id } from "oslo/password";
|
||||||
|
|
||||||
/* ---------------------------------- Note ---------------------------------- */
|
/* ---------------------------------- Note ---------------------------------- */
|
||||||
|
|
@ -19,6 +20,7 @@ node_modules/.pnpm/@node-rs+argon2@1.7.0/node_modules/@node-rs/argon2/index.js:1
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
// If you don't use a hasher from oslo, which are preconfigured with recommended parameters from OWASP,
|
// If you don't use a hasher from oslo, which are preconfigured with recommended parameters from OWASP,
|
||||||
// ensure that you configure them properly.
|
// ensure that you configure them properly.
|
||||||
|
@injectable()
|
||||||
export class HashingService {
|
export class HashingService {
|
||||||
private readonly hasher = new Argon2id();
|
private readonly hasher = new Argon2id();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
import { lucia } from '../infrastructure/auth/lucia';
|
import { inject, injectable } from 'tsyringe';
|
||||||
|
import { LuciaProvider } from '../providers/lucia.provider';
|
||||||
|
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
/* Service */
|
/* Service */
|
||||||
|
|
@ -17,8 +18,13 @@ Create private functions to handle complex logic and keep the public methods as
|
||||||
simple as possible. This makes the service easier to read, test and understand.
|
simple as possible. This makes the service easier to read, test and understand.
|
||||||
*/
|
*/
|
||||||
/* -------------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------------- */
|
||||||
|
@injectable()
|
||||||
export class IamService {
|
export class IamService {
|
||||||
|
constructor(
|
||||||
|
@inject(LuciaProvider) private readonly lucia: LuciaProvider,
|
||||||
|
) { }
|
||||||
|
|
||||||
async logout(sessionId: string) {
|
async logout(sessionId: string) {
|
||||||
return lucia.invalidateSession(sessionId);
|
return this.lucia.invalidateSession(sessionId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
75
src/lib/server/api/services/loginrequest.service.ts
Normal file
75
src/lib/server/api/services/loginrequest.service.ts
Normal file
|
|
@ -0,0 +1,75 @@
|
||||||
|
import { inject, injectable } from 'tsyringe';
|
||||||
|
import { BadRequest } from '../common/errors';
|
||||||
|
import { DatabaseProvider } from '../providers';
|
||||||
|
import { MailerService } from './mailer.service';
|
||||||
|
import { TokensService } from './tokens.service';
|
||||||
|
import { LuciaProvider } from '../providers/lucia.provider';
|
||||||
|
import { UsersRepository } from '../repositories/users.repository';
|
||||||
|
import type { SignInEmailDto } from '../../../dtos/signin-email.dto';
|
||||||
|
import type { RegisterEmailDto } from '../../../dtos/register-email.dto';
|
||||||
|
import { LoginRequestsRepository } from '../repositories/login-requests.repository';
|
||||||
|
|
||||||
|
@injectable()
|
||||||
|
export class LoginRequestsService {
|
||||||
|
constructor(
|
||||||
|
@inject(LuciaProvider) private readonly lucia: LuciaProvider,
|
||||||
|
@inject(DatabaseProvider) private readonly db: DatabaseProvider,
|
||||||
|
@inject(TokensService) private readonly tokensService: TokensService,
|
||||||
|
@inject(MailerService) private readonly mailerService: MailerService,
|
||||||
|
@inject(UsersRepository) private readonly usersRepository: UsersRepository,
|
||||||
|
@inject(LoginRequestsRepository) private readonly loginRequestsRepository: LoginRequestsRepository,
|
||||||
|
) { }
|
||||||
|
|
||||||
|
async validate(data: SignInEmailDto) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async create(data: RegisterEmailDto) {
|
||||||
|
// generate a token, expiry date, and hash
|
||||||
|
const { token, expiry, hashedToken } = await this.tokensService.generateTokenWithExpiryAndHash(15, 'm');
|
||||||
|
// save the login request to the database - ensuring we save the hashedToken
|
||||||
|
await this.loginRequestsRepository.create({ email: data.email, hashedToken, expiresAt: expiry });
|
||||||
|
// send the login request email
|
||||||
|
await this.mailerService.sendLoginRequest({
|
||||||
|
to: data.email,
|
||||||
|
props: { token: token }
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async verify(data: SignInEmailDto) {
|
||||||
|
let existingUser = await this.usersRepository.findOneByUsername(data.username);
|
||||||
|
|
||||||
|
if (!existingUser) {
|
||||||
|
throw BadRequest('User not found');
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
return this.lucia.createSession(existingUser.id, {});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a new user and send a welcome email - or other onboarding process
|
||||||
|
private async handleNewUserRegistration(email: string) {
|
||||||
|
const newUser = await this.usersRepository.create({ email, verified: true, avatar: null })
|
||||||
|
this.mailerService.sendWelcome({ to: email, props: null });
|
||||||
|
// TODO: add whatever onboarding process or extra data you need here
|
||||||
|
return newUser
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fetch a valid request from the database, verify the token and burn the request if it is valid
|
||||||
|
private async fetchValidRequest(email: string, token: string) {
|
||||||
|
return await this.db.transaction(async (trx) => {
|
||||||
|
// fetch the login request
|
||||||
|
const loginRequest = await this.loginRequestsRepository.trxHost(trx).findOneByEmail(email)
|
||||||
|
if (!loginRequest) return null;
|
||||||
|
|
||||||
|
// check if the token is valid
|
||||||
|
const isValidRequest = await this.tokensService.verifyHashedToken(loginRequest.hashedToken, token);
|
||||||
|
if (!isValidRequest) return null
|
||||||
|
|
||||||
|
// if the token is valid, burn the request
|
||||||
|
await this.loginRequestsRepository.trxHost(trx).deleteById(loginRequest.id);
|
||||||
|
return loginRequest
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,11 @@
|
||||||
|
import { inject, injectable } from "tsyringe";
|
||||||
import { generateRandomString } from "oslo/crypto";
|
import { generateRandomString } from "oslo/crypto";
|
||||||
import { TimeSpan, createDate, type TimeSpanUnit } from 'oslo';
|
import { TimeSpan, createDate, type TimeSpanUnit } from 'oslo';
|
||||||
import { HashingService } from "./hashing.service";
|
import { HashingService } from "./hashing.service";
|
||||||
|
|
||||||
|
@injectable()
|
||||||
export class TokensService {
|
export class TokensService {
|
||||||
private readonly hashingService = new HashingService();
|
constructor(@inject(HashingService) private readonly hashingService: HashingService) { }
|
||||||
|
|
||||||
generateToken() {
|
generateToken() {
|
||||||
const alphabet = '23456789ACDEFGHJKLMNPQRSTUVWXYZ'; // alphabet with removed look-alike characters (0, 1, O, I)
|
const alphabet = '23456789ACDEFGHJKLMNPQRSTUVWXYZ'; // alphabet with removed look-alike characters (0, 1, O, I)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue