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",
|
||||
"just-clone": "^6.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-import": "^16.1.0",
|
||||
"postcss-load-config": "^5.1.0",
|
||||
|
|
@ -71,10 +75,6 @@
|
|||
"zod": "^3.23.8"
|
||||
},
|
||||
"type": "module",
|
||||
"engines": {
|
||||
"node": ">=18.0.0 <19.0.0 || >=20.0.0 <21.0.0",
|
||||
"pnpm": ">=8"
|
||||
},
|
||||
"dependencies": {
|
||||
"@fontsource/fira-mono": "^5.0.13",
|
||||
"@hono/zod-validator": "^0.2.2",
|
||||
|
|
@ -91,6 +91,7 @@
|
|||
"arctic": "^1.9.2",
|
||||
"bits-ui": "^0.21.12",
|
||||
"boardgamegeekclient": "^1.9.1",
|
||||
"bullmq": "^5.11.0",
|
||||
"class-variance-authority": "^0.7.0",
|
||||
"clsx": "^2.1.1",
|
||||
"cookie": "^0.6.0",
|
||||
|
|
@ -99,6 +100,7 @@
|
|||
"drizzle-orm": "^0.32.1",
|
||||
"feather-icons": "^4.29.2",
|
||||
"formsnap": "^1.0.1",
|
||||
"handlebars": "^4.7.8",
|
||||
"hono": "^4.5.2",
|
||||
"hono-rate-limiter": "^0.4.0",
|
||||
"html-entities": "^2.5.2",
|
||||
|
|
@ -107,10 +109,7 @@
|
|||
"just-capitalize": "^3.2.0",
|
||||
"just-kebab-case": "^4.2.0",
|
||||
"loader": "^2.1.1",
|
||||
"lucia": "3.2.0",
|
||||
"lucide-svelte": "^0.408.0",
|
||||
"open-props": "^1.7.5",
|
||||
"oslo": "^1.2.1",
|
||||
"pg": "^8.12.0",
|
||||
"postgres": "^3.4.4",
|
||||
"qrcode": "^1.5.3",
|
||||
|
|
|
|||
185
pnpm-lock.yaml
185
pnpm-lock.yaml
|
|
@ -53,6 +53,9 @@ importers:
|
|||
boardgamegeekclient:
|
||||
specifier: ^1.9.1
|
||||
version: 1.9.1
|
||||
bullmq:
|
||||
specifier: ^5.11.0
|
||||
version: 5.11.0
|
||||
class-variance-authority:
|
||||
specifier: ^0.7.0
|
||||
version: 0.7.0
|
||||
|
|
@ -77,6 +80,9 @@ importers:
|
|||
formsnap:
|
||||
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))
|
||||
handlebars:
|
||||
specifier: ^4.7.8
|
||||
version: 4.7.8
|
||||
hono:
|
||||
specifier: ^4.5.2
|
||||
version: 4.5.2
|
||||
|
|
@ -101,18 +107,9 @@ importers:
|
|||
loader:
|
||||
specifier: ^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:
|
||||
specifier: ^1.7.5
|
||||
version: 1.7.5
|
||||
oslo:
|
||||
specifier: ^1.2.1
|
||||
version: 1.2.1
|
||||
pg:
|
||||
specifier: ^8.12.0
|
||||
version: 8.12.0
|
||||
|
|
@ -210,6 +207,18 @@ importers:
|
|||
just-debounce-it:
|
||||
specifier: ^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:
|
||||
specifier: ^8.4.40
|
||||
version: 8.4.40
|
||||
|
|
@ -1386,6 +1395,36 @@ packages:
|
|||
peerDependencies:
|
||||
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':
|
||||
resolution: {integrity: sha512-D0AXgJh6xkf+XTlsO7iwE2Q1w8981E1cLCPAALMU2YKtkF/1SF6BiAzYARZFYo175ON+b1RNIy9TdSFHm5nteg==}
|
||||
|
||||
|
|
@ -2225,6 +2264,9 @@ packages:
|
|||
buffer-from@1.1.2:
|
||||
resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==}
|
||||
|
||||
bullmq@5.11.0:
|
||||
resolution: {integrity: sha512-qVzyWGZqie3VHaYEgRXhId/j8ebfmj6MExEJyUByMsUJA5pVciVle3hKLer5fyMwtQ8lTMP7GwhXV/NZ+HzlRA==}
|
||||
|
||||
bytes@3.1.2:
|
||||
resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==}
|
||||
engines: {node: '>= 0.8'}
|
||||
|
|
@ -2357,6 +2399,10 @@ packages:
|
|||
create-require@1.1.1:
|
||||
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:
|
||||
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
|
||||
engines: {node: '>= 8'}
|
||||
|
|
@ -2943,6 +2989,11 @@ packages:
|
|||
graphemer@1.4.0:
|
||||
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:
|
||||
resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -3205,6 +3256,10 @@ packages:
|
|||
peerDependencies:
|
||||
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:
|
||||
resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==}
|
||||
|
||||
|
|
@ -3338,6 +3393,13 @@ packages:
|
|||
ms@2.1.3:
|
||||
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:
|
||||
resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==}
|
||||
|
||||
|
|
@ -3358,6 +3420,12 @@ packages:
|
|||
resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==}
|
||||
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:
|
||||
resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==}
|
||||
engines: {node: 4.x || >=6.0.0}
|
||||
|
|
@ -3367,6 +3435,10 @@ packages:
|
|||
encoding:
|
||||
optional: true
|
||||
|
||||
node-gyp-build-optional-packages@5.2.2:
|
||||
resolution: {integrity: sha512-s+w+rBWnpTMwSFbaE0UXsRlg7hU4FjekKU4eyAih5T8nJuNZT1nNsskXpxmeqSK9UzkBl6UgRlnKc8hz8IEqOw==}
|
||||
hasBin: true
|
||||
|
||||
node-gyp-build@4.8.1:
|
||||
resolution: {integrity: sha512-OSs33Z9yWr148JZcbZd5WiAXhh/n9z8TxQcdMhIOlpN9AhWpLfvVFO73+m77bBABQMaY9XSvIa+qk0jlI7Gcaw==}
|
||||
hasBin: true
|
||||
|
|
@ -3374,6 +3446,10 @@ packages:
|
|||
node-releases@2.0.14:
|
||||
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:
|
||||
resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
|
@ -4519,6 +4595,11 @@ packages:
|
|||
ufo@1.5.3:
|
||||
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:
|
||||
resolution: {integrity: sha512-GykOvZwgDWZlTQMtp5jrD4BVL+gNn2NVlVafjcFUJ7taY20tqYdwdoWBFy6GBJsNTZe1GkGPkSl5knQAjtgceg==}
|
||||
|
||||
|
|
@ -4557,6 +4638,10 @@ packages:
|
|||
resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==}
|
||||
engines: {node: '>= 0.4.0'}
|
||||
|
||||
uuid@9.0.1:
|
||||
resolution: {integrity: sha512-b+1eJOlsR9K8HJpow9Ok3fiWOWSIcIzXodvv0rQjVoOVNpWMpxf1wZNpt4y9h10odCNrqnYp1OBzRktckBe3sA==}
|
||||
hasBin: true
|
||||
|
||||
v8-compile-cache-lib@3.0.1:
|
||||
resolution: {integrity: sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==}
|
||||
|
||||
|
|
@ -4670,6 +4755,9 @@ packages:
|
|||
resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
||||
wordwrap@1.0.0:
|
||||
resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==}
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==}
|
||||
engines: {node: '>=8'}
|
||||
|
|
@ -5579,6 +5667,24 @@ snapshots:
|
|||
nanoid: 5.0.7
|
||||
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':
|
||||
dependencies:
|
||||
'@types/pg': 8.11.6
|
||||
|
|
@ -6367,6 +6473,18 @@ snapshots:
|
|||
|
||||
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: {}
|
||||
|
||||
cac@6.7.14: {}
|
||||
|
|
@ -6493,6 +6611,10 @@ snapshots:
|
|||
|
||||
create-require@1.1.1: {}
|
||||
|
||||
cron-parser@4.9.0:
|
||||
dependencies:
|
||||
luxon: 3.4.4
|
||||
|
||||
cross-spawn@7.0.3:
|
||||
dependencies:
|
||||
path-key: 3.1.1
|
||||
|
|
@ -7127,6 +7249,15 @@ snapshots:
|
|||
|
||||
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-property-descriptors@1.0.2:
|
||||
|
|
@ -7373,6 +7504,8 @@ snapshots:
|
|||
dependencies:
|
||||
svelte: 5.0.0-next.175
|
||||
|
||||
luxon@3.4.4: {}
|
||||
|
||||
magic-string@0.30.10:
|
||||
dependencies:
|
||||
'@jridgewell/sourcemap-codec': 1.4.15
|
||||
|
|
@ -7481,6 +7614,22 @@ snapshots:
|
|||
|
||||
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:
|
||||
dependencies:
|
||||
any-promise: 1.3.0
|
||||
|
|
@ -7495,14 +7644,25 @@ snapshots:
|
|||
|
||||
negotiator@0.6.3: {}
|
||||
|
||||
neo-async@2.6.2: {}
|
||||
|
||||
node-abort-controller@3.1.1: {}
|
||||
|
||||
node-fetch@2.7.0:
|
||||
dependencies:
|
||||
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-releases@2.0.14: {}
|
||||
|
||||
nodemailer@6.9.14: {}
|
||||
|
||||
nopt@5.0.0:
|
||||
dependencies:
|
||||
abbrev: 1.1.1
|
||||
|
|
@ -8737,6 +8897,9 @@ snapshots:
|
|||
|
||||
ufo@1.5.3: {}
|
||||
|
||||
uglify-js@3.19.1:
|
||||
optional: true
|
||||
|
||||
ultrahtml@1.5.3: {}
|
||||
|
||||
undici-types@5.26.5: {}
|
||||
|
|
@ -8770,6 +8933,8 @@ snapshots:
|
|||
|
||||
utils-merge@1.0.1: {}
|
||||
|
||||
uuid@9.0.1: {}
|
||||
|
||||
v8-compile-cache-lib@3.0.1: {}
|
||||
|
||||
valibot@0.31.1:
|
||||
|
|
@ -8878,6 +9043,8 @@ snapshots:
|
|||
|
||||
word-wrap@1.2.5: {}
|
||||
|
||||
wordwrap@1.0.0: {}
|
||||
|
||||
wrap-ansi@6.2.0:
|
||||
dependencies:
|
||||
ansi-styles: 4.3.0
|
||||
|
|
|
|||
|
|
@ -1,22 +1,21 @@
|
|||
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 { registerEmailPasswordDto } from '$lib/dtos/register-emailpassword.dto';
|
||||
import { limiter } from '../middleware/rate-limiter.middleware';
|
||||
import type { Controller } from '../interfaces/controller.interface';
|
||||
|
||||
const app = new Hono()
|
||||
@injectable()
|
||||
export class IamController implements Controller {
|
||||
controller = new Hono<HonoTypes>();
|
||||
|
||||
constructor(
|
||||
) { }
|
||||
|
||||
routes() {
|
||||
return this.controller
|
||||
.get('/me', requireAuth, async (c) => {
|
||||
const user = c.var.user;
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,13 +1,26 @@
|
|||
import { Hono } from 'hono';
|
||||
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 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()
|
||||
.post('/', zValidator('json', registerEmailPasswordDto), limiter({ limit: 10, minutes: 60 }), async (c) => {
|
||||
const { email } = c.req.valid('json');
|
||||
await loginRequestsService.create({ email });
|
||||
@injectable()
|
||||
export class LoginController implements Controller {
|
||||
controller = new Hono<HonoTypes>();
|
||||
|
||||
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' });
|
||||
});
|
||||
|
||||
export default app;
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 { type InferSelectModel, relations } from 'drizzle-orm';
|
||||
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';
|
||||
|
||||
// Symbol
|
||||
|
|
|
|||
|
|
@ -1,10 +1,11 @@
|
|||
// import { lucia } from '../infrastructure/auth/lucia';
|
||||
import { container } from 'tsyringe';
|
||||
import { lucia } from '../infrastructure/auth/lucia';
|
||||
|
||||
// // Symbol
|
||||
// export const LuciaProvider = Symbol('LUCIA_PROVIDER');
|
||||
// Symbol
|
||||
export const LuciaProvider = Symbol('LUCIA_PROVIDER');
|
||||
|
||||
// // Type
|
||||
// export type LuciaProvider = typeof lucia;
|
||||
// Type
|
||||
export type LuciaProvider = typeof lucia;
|
||||
|
||||
// // Register
|
||||
// container.register<LuciaProvider>(LuciaProvider, { useValue: lucia });
|
||||
// Register
|
||||
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;
|
||||
}
|
||||
|
||||
async findOneByUsername(username: string) {
|
||||
return db.query.usersTable.findFirst({
|
||||
where: eq(usersTable.username, username)
|
||||
});
|
||||
}
|
||||
|
||||
async findOneByEmail(email: string) {
|
||||
return db.query.usersTable.findFirst({
|
||||
where: eq(usersTable.email, email)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { injectable } from "tsyringe";
|
||||
import { Argon2id } from "oslo/password";
|
||||
|
||||
/* ---------------------------------- 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,
|
||||
// ensure that you configure them properly.
|
||||
@injectable()
|
||||
export class HashingService {
|
||||
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 */
|
||||
|
|
@ -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.
|
||||
*/
|
||||
/* -------------------------------------------------------------------------- */
|
||||
@injectable()
|
||||
export class IamService {
|
||||
constructor(
|
||||
@inject(LuciaProvider) private readonly lucia: LuciaProvider,
|
||||
) { }
|
||||
|
||||
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 { TimeSpan, createDate, type TimeSpanUnit } from 'oslo';
|
||||
import { HashingService } from "./hashing.service";
|
||||
|
||||
@injectable()
|
||||
export class TokensService {
|
||||
private readonly hashingService = new HashingService();
|
||||
constructor(@inject(HashingService) private readonly hashingService: HashingService) { }
|
||||
|
||||
generateToken() {
|
||||
const alphabet = '23456789ACDEFGHJKLMNPQRSTUVWXYZ'; // alphabet with removed look-alike characters (0, 1, O, I)
|
||||
|
|
|
|||
Loading…
Reference in a new issue