Adding timespan, token service, fixing ui for password form.

This commit is contained in:
Bradley Shellnut 2024-12-28 23:45:43 -08:00
parent 744e5dad89
commit 5497fb75a7
8 changed files with 220 additions and 66 deletions

View file

@ -38,7 +38,7 @@
"@storybook/test": "^8.4.7",
"@sveltejs/adapter-node": "^5.2.9",
"@sveltejs/enhanced-img": "^0.4.4",
"@sveltejs/kit": "^2.9.0",
"@sveltejs/kit": "^2.15.1",
"@sveltejs/vite-plugin-svelte": "^5.0.3",
"@tanstack/svelte-query": "^5.62.9",
"@tanstack/svelte-query-devtools": "^5.62.9",
@ -95,7 +95,7 @@
"dotenv": "^16.4.7",
"drizzle-orm": "^0.38.3",
"drizzle-zod": "^0.6.1",
"hono": "^4.6.14",
"hono": "^4.6.15",
"hono-pino": "^0.7.0",
"hono-rate-limiter": "^0.4.2",
"hono-zod-openapi": "^0.5.0",

View file

@ -10,16 +10,16 @@ importers:
dependencies:
'@hono/swagger-ui':
specifier: ^0.5.0
version: 0.5.0(hono@4.6.14)
version: 0.5.0(hono@4.6.15)
'@hono/zod-openapi':
specifier: ^0.18.3
version: 0.18.3(hono@4.6.14)(zod@3.24.1)
version: 0.18.3(hono@4.6.15)(zod@3.24.1)
'@hono/zod-validator':
specifier: ^0.4.2
version: 0.4.2(hono@4.6.14)(zod@3.24.1)
version: 0.4.2(hono@4.6.15)(zod@3.24.1)
'@inlang/paraglide-sveltekit':
specifier: ^0.15.0
version: 0.15.0(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))
version: 0.15.0(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))
'@needle-di/core':
specifier: ^0.8.4
version: 0.8.4
@ -46,7 +46,7 @@ importers:
version: 1.0.0
'@scalar/hono-api-reference':
specifier: ^0.5.162
version: 0.5.165(hono@4.6.14)
version: 0.5.165(hono@4.6.15)
'@tailwindcss/container-queries':
specifier: ^0.1.1
version: 0.1.1(tailwindcss@3.4.17)
@ -75,17 +75,17 @@ importers:
specifier: ^0.6.1
version: 0.6.1(drizzle-orm@0.38.3(@types/pg@8.11.10)(@types/react@19.0.2)(pg@8.13.1)(postgres@3.4.5)(react@18.3.1))(zod@3.24.1)
hono:
specifier: ^4.6.14
version: 4.6.14
specifier: ^4.6.15
version: 4.6.15
hono-pino:
specifier: ^0.7.0
version: 0.7.0(hono@4.6.14)(pino@9.6.0)
version: 0.7.0(hono@4.6.15)(pino@9.6.0)
hono-rate-limiter:
specifier: ^0.4.2
version: 0.4.2(hono@4.6.14)
version: 0.4.2(hono@4.6.15)
hono-zod-openapi:
specifier: ^0.5.0
version: 0.5.0(hono@4.6.14)(zod@3.24.1)
version: 0.5.0(hono@4.6.15)(zod@3.24.1)
ioredis:
specifier: ^5.4.2
version: 5.4.2
@ -121,7 +121,7 @@ importers:
version: 0.33.5
stoker:
specifier: ^1.4.2
version: 1.4.2(@asteasolutions/zod-to-openapi@7.3.0(zod@3.24.1))(@hono/zod-openapi@0.18.3(hono@4.6.14)(zod@3.24.1))(hono@4.6.14)(openapi3-ts@4.4.0)
version: 1.4.2(@asteasolutions/zod-to-openapi@7.3.0(zod@3.24.1))(@hono/zod-openapi@0.18.3(hono@4.6.15)(zod@3.24.1))(hono@4.6.15)(openapi3-ts@4.4.0)
devDependencies:
'@biomejs/biome':
specifier: ^1.9.4
@ -167,13 +167,13 @@ importers:
version: 8.4.7(storybook@8.4.7)
'@sveltejs/adapter-node':
specifier: ^5.2.9
version: 5.2.11(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))
version: 5.2.11(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))
'@sveltejs/enhanced-img':
specifier: ^0.4.4
version: 0.4.4(rollup@4.29.1)(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
'@sveltejs/kit':
specifier: ^2.9.0
version: 2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
specifier: ^2.15.1
version: 2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
'@sveltejs/vite-plugin-svelte':
specifier: ^5.0.3
version: 5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
@ -212,7 +212,7 @@ importers:
version: 0.30.1
formsnap:
specifier: ^2.0.0
version: 2.0.0(svelte@5.16.0)(sveltekit-superforms@2.22.1(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.0)(typescript@5.7.2))
version: 2.0.0(svelte@5.16.0)(sveltekit-superforms@2.22.1(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.0)(typescript@5.7.2))
lucide-svelte:
specifier: ^0.469.0
version: 0.469.0(svelte@5.16.0)
@ -239,10 +239,10 @@ importers:
version: 0.3.28(svelte@5.16.0)
sveltekit-flash-message:
specifier: ^2.4.4
version: 2.4.4(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)
version: 2.4.4(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)
sveltekit-superforms:
specifier: ^2.22.1
version: 2.22.1(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.0)(typescript@5.7.2)
version: 2.22.1(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.0)(typescript@5.7.2)
tailwind-merge:
specifier: ^2.6.0
version: 2.6.0
@ -2160,8 +2160,8 @@ packages:
svelte: ^5.0.0
vite: '>= 5.0.0'
'@sveltejs/kit@2.15.0':
resolution: {integrity: sha512-FI1bhfhFNGI2sKg+BhiRyM4eaOvX+KZqRYSQqL5PK3ZZREX2xufZ6MzZAw79N846OnIxYNqcz/3VOUq+FPDd3w==}
'@sveltejs/kit@2.15.1':
resolution: {integrity: sha512-8t7D3hQHbUDMiaQ2RVnjJJ/+Ur4Fn/tkeySJCsHtX346Q9cp3LAnav8xXdfuqYNJwpUGX0x3BqF1uvbmXQw93A==}
engines: {node: '>=18.13'}
hasBin: true
peerDependencies:
@ -3411,8 +3411,8 @@ packages:
hono: ^4.6.10
zod: ^3.21.4
hono@4.6.14:
resolution: {integrity: sha512-j4VkyUp2xazGJ8eCCLN1Vm/bxdvm/j5ZuU9AIjLu9vapn2M44p9L3Ktr9Vnb2RN2QtcR/wVjZVMlT5k7GJQgPw==}
hono@4.6.15:
resolution: {integrity: sha512-OiQwvAOAaI2JrABBH69z5rsctHDzFzIKJge0nYXgtzGJ0KftwLWcBXm1upJC23/omNRtnqM0gjRMbtXshPdqhQ==}
engines: {node: '>=16.9.0'}
hookable@5.5.3:
@ -5724,20 +5724,20 @@ snapshots:
'@hapi/hoek': 9.3.0
optional: true
'@hono/swagger-ui@0.5.0(hono@4.6.14)':
'@hono/swagger-ui@0.5.0(hono@4.6.15)':
dependencies:
hono: 4.6.14
hono: 4.6.15
'@hono/zod-openapi@0.18.3(hono@4.6.14)(zod@3.24.1)':
'@hono/zod-openapi@0.18.3(hono@4.6.15)(zod@3.24.1)':
dependencies:
'@asteasolutions/zod-to-openapi': 7.3.0(zod@3.24.1)
'@hono/zod-validator': 0.4.2(hono@4.6.14)(zod@3.24.1)
hono: 4.6.14
'@hono/zod-validator': 0.4.2(hono@4.6.15)(zod@3.24.1)
hono: 4.6.15
zod: 3.24.1
'@hono/zod-validator@0.4.2(hono@4.6.14)(zod@3.24.1)':
'@hono/zod-validator@0.4.2(hono@4.6.15)(zod@3.24.1)':
dependencies:
hono: 4.6.14
hono: 4.6.15
zod: 3.24.1
'@humanwhocodes/config-array@0.9.5':
@ -5869,12 +5869,12 @@ snapshots:
- babel-plugin-macros
- debug
'@inlang/paraglide-sveltekit@0.15.0(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))':
'@inlang/paraglide-sveltekit@0.15.0(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))':
dependencies:
'@inlang/paraglide-js': 1.11.3
'@inlang/paraglide-vite': 1.3.0
'@lix-js/client': 2.2.1
'@sveltejs/kit': 2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
'@sveltejs/kit': 2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
commander: 12.1.0
dedent: 1.5.1
devalue: 4.3.3
@ -6388,10 +6388,10 @@ snapshots:
'@rollup/rollup-win32-x64-msvc@4.29.1':
optional: true
'@scalar/hono-api-reference@0.5.165(hono@4.6.14)':
'@scalar/hono-api-reference@0.5.165(hono@4.6.15)':
dependencies:
'@scalar/types': 0.0.25
hono: 4.6.14
hono: 4.6.15
'@scalar/openapi-types@0.1.5': {}
@ -6690,12 +6690,12 @@ snapshots:
dependencies:
storybook: 8.4.7
'@sveltejs/adapter-node@5.2.11(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))':
'@sveltejs/adapter-node@5.2.11(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))':
dependencies:
'@rollup/plugin-commonjs': 28.0.2(rollup@4.29.1)
'@rollup/plugin-json': 6.1.0(rollup@4.29.1)
'@rollup/plugin-node-resolve': 16.0.0(rollup@4.29.1)
'@sveltejs/kit': 2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
'@sveltejs/kit': 2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
rollup: 4.29.1
'@sveltejs/enhanced-img@0.4.4(rollup@4.29.1)(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))':
@ -6710,7 +6710,7 @@ snapshots:
transitivePeerDependencies:
- rollup
'@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))':
'@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))':
dependencies:
'@sveltejs/vite-plugin-svelte': 5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
'@types/cookie': 0.6.0
@ -7897,11 +7897,11 @@ snapshots:
combined-stream: 1.0.8
mime-types: 2.1.35
formsnap@2.0.0(svelte@5.16.0)(sveltekit-superforms@2.22.1(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.0)(typescript@5.7.2)):
formsnap@2.0.0(svelte@5.16.0)(sveltekit-superforms@2.22.1(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.0)(typescript@5.7.2)):
dependencies:
svelte: 5.16.0
svelte-toolbelt: 0.5.0(svelte@5.16.0)
sveltekit-superforms: 2.22.1(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.0)(typescript@5.7.2)
sveltekit-superforms: 2.22.1(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.0)(typescript@5.7.2)
forwarded@0.2.0: {}
@ -7998,24 +7998,24 @@ snapshots:
help-me@5.0.0: {}
hono-pino@0.7.0(hono@4.6.14)(pino@9.6.0):
hono-pino@0.7.0(hono@4.6.15)(pino@9.6.0):
dependencies:
defu: 6.1.4
hono: 4.6.14
hono: 4.6.15
pino: 9.6.0
hono-rate-limiter@0.4.2(hono@4.6.14):
hono-rate-limiter@0.4.2(hono@4.6.15):
dependencies:
hono: 4.6.14
hono: 4.6.15
hono-zod-openapi@0.5.0(hono@4.6.14)(zod@3.24.1):
hono-zod-openapi@0.5.0(hono@4.6.15)(zod@3.24.1):
dependencies:
'@hono/zod-validator': 0.4.2(hono@4.6.14)(zod@3.24.1)
hono: 4.6.14
'@hono/zod-validator': 0.4.2(hono@4.6.15)(zod@3.24.1)
hono: 4.6.15
zod: 3.24.1
zod-openapi: 4.2.1(zod@3.24.1)
hono@4.6.14: {}
hono@4.6.15: {}
hookable@5.5.3: {}
@ -9024,13 +9024,13 @@ snapshots:
std-env@3.8.0: {}
stoker@1.4.2(@asteasolutions/zod-to-openapi@7.3.0(zod@3.24.1))(@hono/zod-openapi@0.18.3(hono@4.6.14)(zod@3.24.1))(hono@4.6.14)(openapi3-ts@4.4.0):
stoker@1.4.2(@asteasolutions/zod-to-openapi@7.3.0(zod@3.24.1))(@hono/zod-openapi@0.18.3(hono@4.6.15)(zod@3.24.1))(hono@4.6.15)(openapi3-ts@4.4.0):
dependencies:
'@asteasolutions/zod-to-openapi': 7.3.0(zod@3.24.1)
hono: 4.6.14
hono: 4.6.15
openapi3-ts: 4.4.0
optionalDependencies:
'@hono/zod-openapi': 0.18.3(hono@4.6.14)(zod@3.24.1)
'@hono/zod-openapi': 0.18.3(hono@4.6.15)(zod@3.24.1)
storybook@8.4.7:
dependencies:
@ -9223,14 +9223,14 @@ snapshots:
transitivePeerDependencies:
- supports-color
sveltekit-flash-message@2.4.4(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0):
sveltekit-flash-message@2.4.4(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0):
dependencies:
'@sveltejs/kit': 2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
'@sveltejs/kit': 2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
svelte: 5.16.0
sveltekit-superforms@2.22.1(@sveltejs/kit@2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.0)(typescript@5.7.2):
sveltekit-superforms@2.22.1(@sveltejs/kit@2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(@types/json-schema@7.0.15)(svelte@5.16.0)(typescript@5.7.2):
dependencies:
'@sveltejs/kit': 2.15.0(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
'@sveltejs/kit': 2.15.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1)))(svelte@5.16.0)(vite@6.0.6(@types/node@22.10.2)(jiti@1.21.7)(tsx@4.19.2)(yaml@2.6.1))
devalue: 5.1.1
memoize-weak: 1.0.2
svelte: 5.16.0

View file

@ -0,0 +1,7 @@
import Root from "./separator.svelte";
export {
Root,
//
Root as Separator,
};

View file

@ -0,0 +1,22 @@
<script lang="ts">
import { Separator as SeparatorPrimitive } from "bits-ui";
import { cn } from "$lib/utils.js";
let {
ref = $bindable(null),
class: className,
orientation = "horizontal",
...restProps
}: SeparatorPrimitive.RootProps = $props();
</script>
<SeparatorPrimitive.Root
bind:ref
class={cn(
"bg-border shrink-0",
orientation === "horizontal" ? "h-[1px] w-full" : "min-h-full w-[1px]",
className
)}
{orientation}
{...restProps}
/>

View file

@ -0,0 +1,44 @@
import { inject, injectable } from '@needle-di/core';
import { generateRandomString, type RandomReader } from "@oslojs/crypto/random";
import { HashingService } from './hashing.service';
import { createDate, TimeSpan, type TimeSpanUnit } from '@/utils/timespan';
@injectable()
export class TokensService {
constructor(private hashingService = inject(HashingService)) {}
generateToken() {
const alphabet = '23456789ACDEFGHJKLMNPQRSTUVWXYZ'; // alphabet with removed look-alike characters (0, 1, O, I)
const random: RandomReader = {
read(bytes) {
crypto.getRandomValues(bytes);
}
}
return generateRandomString(random, alphabet, 10);
}
generateTokenWithExpiry(number: number, lifespan: TimeSpanUnit) {
return {
token: this.generateToken(),
expiry: createDate(new TimeSpan(number, lifespan)),
};
}
async generateTokenWithExpiryAndHash(number: number, lifespan: TimeSpanUnit) {
const token = this.generateToken();
const hashedToken = await this.hashingService.hash(token);
return {
token,
hashedToken,
expiry: createDate(new TimeSpan(number, lifespan)),
};
}
async createHashedToken(token: string) {
return this.hashingService.hash(token);
}
async verifyHashedToken(hashedToken: string, token: string) {
return this.hashingService.compare(hashedToken, token);
}
}

View file

@ -12,6 +12,7 @@ import { UsersRepository } from '../../users/users.repository';
import { VerificationCodesService } from '../../common/services/verification-codes.service';
import type { LoginRequestDto } from './dtos/login-request.dto';
import { CredentialsRepository } from '../../users/credentials.repository';
import { TokensService } from '../../common/services/tokens.service';
@injectable()
export class LoginRequestsService {
@ -22,6 +23,7 @@ export class LoginRequestsService {
private verificationCodesService = inject(VerificationCodesService),
private usersService = inject(UsersService),
private sessionsService = inject(SessionsService),
private tokensService = inject(TokensService),
private mailer = inject(MailerService),
) {}
@ -38,7 +40,7 @@ export class LoginRequestsService {
throw BadRequest('Invalid credentials');
}
if (!(await this.tokensService.verifyHashedToken(credential.secret_data, data.password))) {
if (!(await this.tokensService.verifyHashedToken(credential.secret_data, password))) {
throw BadRequest('Invalid credentials');
}

58
src/lib/utils/timespan.ts Normal file
View file

@ -0,0 +1,58 @@
export type TimeSpanUnit = "ms" | "s" | "m" | "h" | "d" | "w";
export class TimeSpan {
constructor(value: number, unit: TimeSpanUnit) {
this.value = value;
this.unit = unit;
}
public value: number;
public unit: TimeSpanUnit;
public milliseconds(): number {
if (this.unit === "ms") {
return this.value;
}
if (this.unit === "s") {
return this.value * 1000;
}
if (this.unit === "m") {
return this.value * 1000 * 60;
}
if (this.unit === "h") {
return this.value * 1000 * 60 * 60;
}
if (this.unit === "d") {
return this.value * 1000 * 60 * 60 * 24;
}
return this.value * 1000 * 60 * 60 * 24 * 7;
}
public seconds(): number {
return this.milliseconds() / 1000;
}
public transform(x: number): TimeSpan {
return new TimeSpan(Math.round(this.milliseconds() * x), "ms");
}
}
export function isWithinExpirationDate(date: Date): boolean {
return Date.now() < date.getTime();
}
export function createDate(timeSpan: TimeSpan): Date {
return new Date(Date.now() + timeSpan.milliseconds());
}
export type TypedArray =
| Uint8Array
| Int8Array
| Uint16Array
| Int16Array
| Uint32Array
| Int32Array
| Float32Array
| Float64Array
| BigInt64Array
| BigUint64Array;

View file

@ -28,11 +28,12 @@
import ChevronLeftIcon from 'lucide-svelte/icons/chevron-left';
import { queryHandler } from '$lib/tanstack-query';
import * as InputOTP from '$lib/components/ui/input-otp/index.js';
import Separator from '@/components/ui/separator/separator.svelte';
const RESEND_VERIFICATION_CODE_COOLDOWN = 60;
let queryClient = useQueryClient();
let step = $state<'login' | 'request' | 'verify'>('request');
let step = $state<'login' | 'totp' | 'request' | 'verify'>('request');
let countdownTimer = $state(RESEND_VERIFICATION_CODE_COOLDOWN);
let resendVerificationCodeOnCooldown = $derived(
countdownTimer != RESEND_VERIFICATION_CODE_COOLDOWN
@ -42,9 +43,12 @@
const requestUsernamePasswordLoginMutation = createMutation({
...queryHandler().iam.requestUsernamePasswordLogin(),
onSuccess(_data, variables, _context) {
step = 'verify';
$verifyForm.email = variables.json.email;
$verifyForm.
step = 'totp';
$loginPasswordForm.email = variables.json.email;
$loginPasswordForm.password = variables.json.password;
},
onError(error) {
loginPasswordErrors.set({ email: [error.message] });
}
})
@ -71,17 +75,30 @@
}
});
/* ------------------------------- Login Form ------------------------------- */
/* ------------------------------- Login Password Form ------------------------------- */
const sf_login_username_password = superForm(defaults(zod(loginPasswordSchema)), {
resetForm: false,
SPA: true,
validators: zod(loginPasswordSchema),
async onUpdated(event) {
if (!event.form.valid) return;
await $requestUsernamePasswordLogin.mutateAsync({ json: event.form.data });
if (!event.form.valid) {
return;
}
await $requestUsernamePasswordLoginMutation.mutateAsync({ json: event.form.data });
if ($requestUsernamePasswordLoginMutation.error) {
return setError(event.form, 'email', $requestUsernamePasswordLoginMutation.error.message);
}
step = 'totp';
$loginPasswordForm.email = event.form.data.email;
}
})
const { form: loginPasswordForm, enhance: loginPasswordEnhance, errors: loginPasswordErrors } = sf_login_username_password;
/* ------------------------------- Login Form ------------------------------- */
const sf_login = superForm(defaults(zod(loginSchema)), {
resetForm: false,
SPA: true,
@ -95,14 +112,14 @@
}
});
if ($requestMutation.error)
if ($requestMutation.error) {
return setError(event.form, 'email', $requestMutation.error.message);
}
step = 'verify';
$verifyForm.email = event.form.data.email;
}
});
const { form: loginPasswordForm, enhance: loginPasswordEnhance, errors: loginPasswordErrors } = sf_login_username_password;
const { form: loginForm, enhance: loginEnhance, errors: requestErrors } = sf_login;
@ -161,7 +178,7 @@
<Card.Description>Enter your email below to login to your account</Card.Description>
</Card.Header>
<Card.Content>
<form use:loginEnhance method="POST" class="grid gap-4">
<form use:loginPasswordEnhance method="POST" class="grid gap-4">
<Form.Field form={sf_login_username_password} name="email">
<Form.Control>
{#snippet children({ props })}
@ -182,7 +199,9 @@
<Form.Description />
<Form.FieldErrors />
</Form.Field>
<Button type="submit" class="w-full">Continue with Email</Button>
<Button type="submit" class="w-full">Submit</Button>
<Separator class="my-4" />
<Button type="button" onclick={() => (step = 'request')}>Login with Email</Button>
</form>
</Card.Content>
</Card.Root>
@ -207,6 +226,8 @@
<Form.FieldErrors />
</Form.Field>
<Button type="submit" class="w-full">Continue with Email</Button>
<Separator class="my-4" />
<Button type="button" onclick={() => (step = 'login')}>Login with Username & Password</Button>
</form>
</Card.Content>
</Card.Root>