From 3fae786eef538cb810d2da4d6128681ef0055d4f Mon Sep 17 00:00:00 2001 From: elianiva Date: Thu, 18 Jan 2024 22:21:31 +0700 Subject: [PATCH 1/4] refactor: schema are restructured --- .idea/codeStyles/Project.xml | 57 +++++++++++++++++++ .idea/codeStyles/codeStyleConfig.xml | 5 ++ .idea/dataSources.xml | 17 ++++++ .idea/misc.xml | 6 ++ .idea/modules.xml | 8 +++ .idea/onlyforms.iml | 9 +++ .idea/vcs.xml | 6 ++ src/hooks.server.ts | 0 src/lib/schema/{ => form}/blocks/checkbox.ts | 0 src/lib/schema/{ => form}/blocks/date.ts | 0 src/lib/schema/{ => form}/blocks/index.ts | 0 .../schema/{ => form}/blocks/linear-scale.ts | 0 src/lib/schema/{ => form}/blocks/paragraph.ts | 0 src/lib/schema/{ => form}/blocks/radio.ts | 0 src/lib/schema/{ => form}/blocks/select.ts | 0 src/lib/schema/{ => form}/blocks/text.ts | 0 src/lib/schema/{ => form}/blocks/time.ts | 0 src/lib/schema/{ => form}/form.ts | 2 +- src/lib/schema/form/index.ts | 2 + .../server/repositories/form-repository.ts | 2 +- .../repositories}/form-repository.test.ts | 3 +- 21 files changed, 113 insertions(+), 4 deletions(-) create mode 100644 .idea/codeStyles/Project.xml create mode 100644 .idea/codeStyles/codeStyleConfig.xml create mode 100644 .idea/dataSources.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/onlyforms.iml create mode 100644 .idea/vcs.xml create mode 100644 src/hooks.server.ts rename src/lib/schema/{ => form}/blocks/checkbox.ts (100%) rename src/lib/schema/{ => form}/blocks/date.ts (100%) rename src/lib/schema/{ => form}/blocks/index.ts (100%) rename src/lib/schema/{ => form}/blocks/linear-scale.ts (100%) rename src/lib/schema/{ => form}/blocks/paragraph.ts (100%) rename src/lib/schema/{ => form}/blocks/radio.ts (100%) rename src/lib/schema/{ => form}/blocks/select.ts (100%) rename src/lib/schema/{ => form}/blocks/text.ts (100%) rename src/lib/schema/{ => form}/blocks/time.ts (100%) rename src/lib/schema/{ => form}/form.ts (97%) create mode 100644 src/lib/schema/form/index.ts rename src/{ => tests/repositories}/form-repository.test.ts (96%) diff --git a/.idea/codeStyles/Project.xml b/.idea/codeStyles/Project.xml new file mode 100644 index 0000000..72cc81d --- /dev/null +++ b/.idea/codeStyles/Project.xml @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/codeStyles/codeStyleConfig.xml b/.idea/codeStyles/codeStyleConfig.xml new file mode 100644 index 0000000..79ee123 --- /dev/null +++ b/.idea/codeStyles/codeStyleConfig.xml @@ -0,0 +1,5 @@ + + + + \ No newline at end of file diff --git a/.idea/dataSources.xml b/.idea/dataSources.xml new file mode 100644 index 0000000..2a09600 --- /dev/null +++ b/.idea/dataSources.xml @@ -0,0 +1,17 @@ + + + + + mongo + true + com.dbschema.MongoJdbcDriver + mongodb://localhost:27017/onlyforms?authSource=admin + + + + + + $ProjectFileDir$ + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 0000000..172df7b --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..8fb5571 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/onlyforms.iml b/.idea/onlyforms.iml new file mode 100644 index 0000000..d6ebd48 --- /dev/null +++ b/.idea/onlyforms.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/src/hooks.server.ts b/src/hooks.server.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/lib/schema/blocks/checkbox.ts b/src/lib/schema/form/blocks/checkbox.ts similarity index 100% rename from src/lib/schema/blocks/checkbox.ts rename to src/lib/schema/form/blocks/checkbox.ts diff --git a/src/lib/schema/blocks/date.ts b/src/lib/schema/form/blocks/date.ts similarity index 100% rename from src/lib/schema/blocks/date.ts rename to src/lib/schema/form/blocks/date.ts diff --git a/src/lib/schema/blocks/index.ts b/src/lib/schema/form/blocks/index.ts similarity index 100% rename from src/lib/schema/blocks/index.ts rename to src/lib/schema/form/blocks/index.ts diff --git a/src/lib/schema/blocks/linear-scale.ts b/src/lib/schema/form/blocks/linear-scale.ts similarity index 100% rename from src/lib/schema/blocks/linear-scale.ts rename to src/lib/schema/form/blocks/linear-scale.ts diff --git a/src/lib/schema/blocks/paragraph.ts b/src/lib/schema/form/blocks/paragraph.ts similarity index 100% rename from src/lib/schema/blocks/paragraph.ts rename to src/lib/schema/form/blocks/paragraph.ts diff --git a/src/lib/schema/blocks/radio.ts b/src/lib/schema/form/blocks/radio.ts similarity index 100% rename from src/lib/schema/blocks/radio.ts rename to src/lib/schema/form/blocks/radio.ts diff --git a/src/lib/schema/blocks/select.ts b/src/lib/schema/form/blocks/select.ts similarity index 100% rename from src/lib/schema/blocks/select.ts rename to src/lib/schema/form/blocks/select.ts diff --git a/src/lib/schema/blocks/text.ts b/src/lib/schema/form/blocks/text.ts similarity index 100% rename from src/lib/schema/blocks/text.ts rename to src/lib/schema/form/blocks/text.ts diff --git a/src/lib/schema/blocks/time.ts b/src/lib/schema/form/blocks/time.ts similarity index 100% rename from src/lib/schema/blocks/time.ts rename to src/lib/schema/form/blocks/time.ts diff --git a/src/lib/schema/form.ts b/src/lib/schema/form/form.ts similarity index 97% rename from src/lib/schema/form.ts rename to src/lib/schema/form/form.ts index a1345fb..ce6e7be 100644 --- a/src/lib/schema/form.ts +++ b/src/lib/schema/form/form.ts @@ -6,7 +6,7 @@ import { linearScaleBlockSchema, paragraphBlockSchema, radioBlockSchema, selectBlockSchema, textBlockSchema, timeBlockSchema -} from "$lib/schema/blocks"; +} from "$lib/schema/form/blocks"; export const formSchema = z.object({ _id: z.instanceof(ObjectId), diff --git a/src/lib/schema/form/index.ts b/src/lib/schema/form/index.ts new file mode 100644 index 0000000..5b63a23 --- /dev/null +++ b/src/lib/schema/form/index.ts @@ -0,0 +1,2 @@ +export * from "./blocks"; +export * from "./form"; \ No newline at end of file diff --git a/src/lib/server/repositories/form-repository.ts b/src/lib/server/repositories/form-repository.ts index 5b218f8..64cc784 100644 --- a/src/lib/server/repositories/form-repository.ts +++ b/src/lib/server/repositories/form-repository.ts @@ -1,4 +1,4 @@ -import { formSchema, type FormSchema } from "$lib/schema/form"; +import { formSchema, type FormSchema } from "$lib/schema/form/form"; import { dbClient } from "$lib/server/repositories/db-client"; import { MONGO_DB } from "$env/static/private"; import { ObjectId } from "mongodb"; diff --git a/src/form-repository.test.ts b/src/tests/repositories/form-repository.test.ts similarity index 96% rename from src/form-repository.test.ts rename to src/tests/repositories/form-repository.test.ts index d2b374c..dc9cc9f 100644 --- a/src/form-repository.test.ts +++ b/src/tests/repositories/form-repository.test.ts @@ -1,9 +1,8 @@ import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; import { FORM_COLLECTION_NAME, getFormSchemaById } from "$lib/server/repositories/form-repository"; import { dbClient } from "$lib/server/repositories/db-client"; -import type { FormSchema } from "$lib/schema/form"; +import type { FormSchema, TextBlock } from "$lib/schema/form"; import { ObjectId } from "mongodb"; -import type { TextBlock } from "$lib/schema/blocks"; const DB_NAME = "onlyforms-form-test"; From 5803838eaafae4a5cdfbbfcc27a9bc72bfe42004 Mon Sep 17 00:00:00 2001 From: elianiva Date: Thu, 18 Jan 2024 22:55:08 +0700 Subject: [PATCH 2/4] feat: user repository, initial auth setup --- .env.example | 1 + package.json | 3 + pnpm-lock.yaml | 471 +++++++++++++++--- src/hooks.server.ts | 10 + src/lib/schema/user.ts | 18 + .../server/repositories/user-repository.ts | 16 + .../repositories/form-repository.test.ts | 2 +- .../repositories/user-repository.test.ts | 69 +++ 8 files changed, 526 insertions(+), 64 deletions(-) create mode 100644 src/lib/schema/user.ts create mode 100644 src/lib/server/repositories/user-repository.ts create mode 100644 src/tests/repositories/user-repository.test.ts diff --git a/.env.example b/.env.example index 276ff40..cd52cb9 100644 --- a/.env.example +++ b/.env.example @@ -3,3 +3,4 @@ MONGO_PASSWORD=password MONGO_HOST=localhost MONGO_PORT=27017 MONGO_DB=onlyforms +AUTH_SECRET=f75077df5ef454d38cd7f7851a8014b0f8df1160e034ec24a7eb0f8f63dc0cd1 diff --git a/package.json b/package.json index 9f60bec..27e622f 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,9 @@ }, "type": "module", "dependencies": { + "@auth/sveltekit": "^0.7.0", + "@types/node": "^20.11.5", + "argon2": "^0.31.2", "bits-ui": "^0.5.7", "clsx": "^2.0.0", "lucide-svelte": "^0.285.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 827bbc5..a81b8ba 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,6 +5,15 @@ settings: excludeLinksFromLockfile: false dependencies: + '@auth/sveltekit': + specifier: ^0.7.0 + version: 0.7.0(@sveltejs/kit@1.25.2)(svelte@4.2.1) + '@types/node': + specifier: ^20.11.5 + version: 20.11.5 + argon2: + specifier: ^0.31.2 + version: 0.31.2 bits-ui: specifier: ^0.5.7 version: 0.5.7(svelte@4.2.1) @@ -25,7 +34,7 @@ dependencies: version: 0.1.14(tailwindcss@3.3.3) vitest: specifier: ^1.2.0 - version: 1.2.0 + version: 1.2.0(@types/node@20.11.5) zod: specifier: ^3.22.4 version: 3.22.4 @@ -66,7 +75,7 @@ devDependencies: version: 5.2.2 vite: specifier: ^4.4.2 - version: 4.4.11 + version: 4.4.11(@types/node@20.11.5) packages: @@ -81,6 +90,36 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.19 + /@auth/core@0.21.0: + resolution: {integrity: sha512-jUWYs8gjy2GvtP9dd/4S9KcwZ660Cm/IkybiAq96/2Ooku9SKk5SUG+UTEwkyLuaQ38ZgfwggfpDOgzsXEcufA==} + peerDependencies: + nodemailer: ^6.8.0 + peerDependenciesMeta: + nodemailer: + optional: true + dependencies: + '@panva/hkdf': 1.1.1 + '@types/cookie': 0.6.0 + cookie: 0.6.0 + jose: 5.2.0 + oauth4webapi: 2.6.0 + preact: 10.11.3 + preact-render-to-string: 5.2.3(preact@10.11.3) + dev: false + + /@auth/sveltekit@0.7.0(@sveltejs/kit@1.25.2)(svelte@4.2.1): + resolution: {integrity: sha512-RZIRMU4rb9n7ltIlMEB4bAflBexPwu6jxGnY7Wcz31c7QMO1skASRQEThI/FUZIzFxQqYn1OvDF6yGz0hWrMKg==} + peerDependencies: + '@sveltejs/kit': ^1.0.0 || ^2.0.0 + svelte: ^3.54.0 || ^4.0.0 + dependencies: + '@auth/core': 0.21.0 + '@sveltejs/kit': 1.25.2(svelte@4.2.1)(vite@4.4.11) + svelte: 4.2.1 + transitivePeerDependencies: + - nodemailer + dev: false + /@esbuild/aix-ppc64@0.19.11: resolution: {integrity: sha512-FnzU0LyE3ySQk7UntJO4+qIiQgI7KoODnZg5xzXIrFJlKd2P2gwHsHY4927xj9y5PJmJSzULiUCWmv7iWnNa7g==} engines: {node: '>=12'} @@ -96,7 +135,6 @@ packages: cpu: [arm64] os: [android] requiresBuild: true - dev: true optional: true /@esbuild/android-arm64@0.19.11: @@ -114,7 +152,6 @@ packages: cpu: [arm] os: [android] requiresBuild: true - dev: true optional: true /@esbuild/android-arm@0.19.11: @@ -132,7 +169,6 @@ packages: cpu: [x64] os: [android] requiresBuild: true - dev: true optional: true /@esbuild/android-x64@0.19.11: @@ -150,7 +186,6 @@ packages: cpu: [arm64] os: [darwin] requiresBuild: true - dev: true optional: true /@esbuild/darwin-arm64@0.19.11: @@ -168,7 +203,6 @@ packages: cpu: [x64] os: [darwin] requiresBuild: true - dev: true optional: true /@esbuild/darwin-x64@0.19.11: @@ -186,7 +220,6 @@ packages: cpu: [arm64] os: [freebsd] requiresBuild: true - dev: true optional: true /@esbuild/freebsd-arm64@0.19.11: @@ -204,7 +237,6 @@ packages: cpu: [x64] os: [freebsd] requiresBuild: true - dev: true optional: true /@esbuild/freebsd-x64@0.19.11: @@ -222,7 +254,6 @@ packages: cpu: [arm64] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-arm64@0.19.11: @@ -240,7 +271,6 @@ packages: cpu: [arm] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-arm@0.19.11: @@ -258,7 +288,6 @@ packages: cpu: [ia32] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-ia32@0.19.11: @@ -276,7 +305,6 @@ packages: cpu: [loong64] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-loong64@0.19.11: @@ -294,7 +322,6 @@ packages: cpu: [mips64el] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-mips64el@0.19.11: @@ -312,7 +339,6 @@ packages: cpu: [ppc64] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-ppc64@0.19.11: @@ -330,7 +356,6 @@ packages: cpu: [riscv64] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-riscv64@0.19.11: @@ -348,7 +373,6 @@ packages: cpu: [s390x] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-s390x@0.19.11: @@ -366,7 +390,6 @@ packages: cpu: [x64] os: [linux] requiresBuild: true - dev: true optional: true /@esbuild/linux-x64@0.19.11: @@ -384,7 +407,6 @@ packages: cpu: [x64] os: [netbsd] requiresBuild: true - dev: true optional: true /@esbuild/netbsd-x64@0.19.11: @@ -402,7 +424,6 @@ packages: cpu: [x64] os: [openbsd] requiresBuild: true - dev: true optional: true /@esbuild/openbsd-x64@0.19.11: @@ -420,7 +441,6 @@ packages: cpu: [x64] os: [sunos] requiresBuild: true - dev: true optional: true /@esbuild/sunos-x64@0.19.11: @@ -438,7 +458,6 @@ packages: cpu: [arm64] os: [win32] requiresBuild: true - dev: true optional: true /@esbuild/win32-arm64@0.19.11: @@ -456,7 +475,6 @@ packages: cpu: [ia32] os: [win32] requiresBuild: true - dev: true optional: true /@esbuild/win32-ia32@0.19.11: @@ -474,7 +492,6 @@ packages: cpu: [x64] os: [win32] requiresBuild: true - dev: true optional: true /@esbuild/win32-x64@0.19.11: @@ -489,7 +506,6 @@ packages: /@fastify/busboy@2.0.0: resolution: {integrity: sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==} engines: {node: '>=14'} - dev: true /@floating-ui/core@1.5.0: resolution: {integrity: sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==} @@ -540,6 +556,24 @@ packages: '@jridgewell/resolve-uri': 3.1.1 '@jridgewell/sourcemap-codec': 1.4.15 + /@mapbox/node-pre-gyp@1.0.11: + resolution: {integrity: sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==} + hasBin: true + dependencies: + detect-libc: 2.0.2 + https-proxy-agent: 5.0.1 + make-dir: 3.1.0 + node-fetch: 2.7.0 + nopt: 5.0.0 + npmlog: 5.0.1 + rimraf: 3.0.2 + semver: 7.5.4 + tar: 6.2.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /@melt-ui/svelte@0.41.3(svelte@4.2.1): resolution: {integrity: sha512-zNd7Bogh9Bm0CdrjU0hAak26SVV5VSxJoaJEtJnV1ZR3KxVPDekVoG1hnin7AG0VYWPm1gKXA1uXTOi5M8XJYw==} peerDependencies: @@ -577,9 +611,17 @@ packages: '@nodelib/fs.scandir': 2.1.5 fastq: 1.15.0 + /@panva/hkdf@1.1.1: + resolution: {integrity: sha512-dhPeilub1NuIG0X5Kvhh9lH4iW3ZsHlnzwgwbOlgwQ2wG1IqFzsgHqmKPk3WzsdWAeaxKJxgM0+W433RmN45GA==} + dev: false + + /@phc/format@1.0.0: + resolution: {integrity: sha512-m7X9U6BG2+J+R1lSOdCiITLLrxm+cWlNI3HUFA92oLO77ObGNzaKdh8pMLqdZcshtkKuV84olNNXDfMc4FezBQ==} + engines: {node: '>=10'} + dev: false + /@polka/url@1.0.0-next.23: resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==} - dev: true /@rollup/rollup-android-arm-eabi@4.9.5: resolution: {integrity: sha512-idWaG8xeSRCfRq9KpRysDHJ/rEHBEXcHuJ82XY0yYFIWnLMjZv9vF/7DOq8djQ2n3Lk6+3qfSH8AqlmHlmi1MA==} @@ -721,10 +763,9 @@ packages: svelte: 4.2.1 tiny-glob: 0.2.9 undici: 5.25.4 - vite: 4.4.11 + vite: 4.4.11(@types/node@20.11.5) transitivePeerDependencies: - supports-color - dev: true /@sveltejs/vite-plugin-svelte-inspector@1.0.4(@sveltejs/vite-plugin-svelte@2.4.6)(svelte@4.2.1)(vite@4.4.11): resolution: {integrity: sha512-zjiuZ3yydBtwpF3bj0kQNV0YXe+iKE545QGZVTaylW3eAzFr+pJ/cwK8lZEaRp4JtaJXhD5DyWAV4AxLh6DgaQ==} @@ -737,10 +778,9 @@ packages: '@sveltejs/vite-plugin-svelte': 2.4.6(svelte@4.2.1)(vite@4.4.11) debug: 4.3.4 svelte: 4.2.1 - vite: 4.4.11 + vite: 4.4.11(@types/node@20.11.5) transitivePeerDependencies: - supports-color - dev: true /@sveltejs/vite-plugin-svelte@2.4.6(svelte@4.2.1)(vite@4.4.11): resolution: {integrity: sha512-zO79p0+DZnXPnF0ltIigWDx/ux7Ni+HRaFOw720Qeivc1azFUrJxTl0OryXVibYNx1hCboGia1NRV3x8RNv4cA==} @@ -756,15 +796,17 @@ packages: magic-string: 0.30.4 svelte: 4.2.1 svelte-hmr: 0.15.3(svelte@4.2.1) - vite: 4.4.11 + vite: 4.4.11(@types/node@20.11.5) vitefu: 0.2.4(vite@4.4.11) transitivePeerDependencies: - supports-color - dev: true /@types/cookie@0.5.2: resolution: {integrity: sha512-DBpRoJGKJZn7RY92dPrgoMew8xCWc2P71beqsjyhEI/Ds9mOyVmBwtekyfhpwFIVt1WrxTonFifiOZ62V8CnNA==} - dev: true + + /@types/cookie@0.6.0: + resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} + dev: false /@types/estree@1.0.2: resolution: {integrity: sha512-VeiPZ9MMwXjO32/Xu7+OwflfmeoRwkE/qzndw42gGtgJwZopBnzy2gD//NN1+go1mADzkDcqf/KnFRSjTJ8xJA==} @@ -773,6 +815,11 @@ packages: resolution: {integrity: sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==} dev: false + /@types/node@20.11.5: + resolution: {integrity: sha512-g557vgQjUUfN76MZAN/dt1z3dzcUsimuysco0KeluHgrPdJXkP/XdAURgyO2W9fZWHRtRBiVKzKn8vyOAwlG+w==} + dependencies: + undici-types: 5.26.5 + /@types/pug@2.0.7: resolution: {integrity: sha512-I469DU0UXNC1aHepwirWhu9YKg5fkxohZD95Ey/5A7lovC+Siu+MCLffva87lnfThaOrw9Vb1DUN5t55oULAAw==} dev: true @@ -826,6 +873,10 @@ packages: pretty-format: 29.7.0 dev: false + /abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + dev: false + /acorn-walk@8.3.2: resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} engines: {node: '>=0.4.0'} @@ -842,6 +893,20 @@ packages: hasBin: true dev: false + /agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + dependencies: + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + + /ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + dev: false + /ansi-styles@5.2.0: resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} engines: {node: '>=10'} @@ -857,9 +922,34 @@ packages: normalize-path: 3.0.0 picomatch: 2.3.1 + /aproba@2.0.0: + resolution: {integrity: sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ==} + dev: false + + /are-we-there-yet@2.0.0: + resolution: {integrity: sha512-Ci/qENmwHnsYo9xKIcUJN5LeDKdJ6R1Z1j9V/J5wyq8nh/mYPEpIKJbBZXtZjG04HiK7zV/p6Vs9952MrMeUIw==} + engines: {node: '>=10'} + dependencies: + delegates: 1.0.0 + readable-stream: 3.6.2 + dev: false + /arg@5.0.2: resolution: {integrity: sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==} + /argon2@0.31.2: + resolution: {integrity: sha512-QSnJ8By5Mth60IEte45w9Y7v6bWcQw3YhRtJKKN8oNCxnTLDiv/AXXkDPf2srTMfxFVn3QJdVv2nhXESsUa+Yg==} + engines: {node: '>=14.0.0'} + requiresBuild: true + dependencies: + '@mapbox/node-pre-gyp': 1.0.11 + '@phc/format': 1.0.0 + node-addon-api: 7.0.0 + transitivePeerDependencies: + - encoding + - supports-color + dev: false + /aria-query@5.3.0: resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} dependencies: @@ -990,6 +1080,11 @@ packages: optionalDependencies: fsevents: 2.3.3 + /chownr@2.0.0: + resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} + engines: {node: '>=10'} + dev: false + /clsx@2.0.0: resolution: {integrity: sha512-rQ1+kcj+ttHG0MKVGBUXwayCCF1oh39BF5COIpRzuCEv8Mwjv0XucrI2ExNTOn9IlLifGClWQcU9BrZORvtw6Q==} engines: {node: '>=6'} @@ -1004,6 +1099,11 @@ packages: estree-walker: 3.0.3 periscopic: 3.1.0 + /color-support@1.1.3: + resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==} + hasBin: true + dev: false + /commander@4.1.1: resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} engines: {node: '>= 6'} @@ -1011,10 +1111,18 @@ packages: /concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + /console-control-strings@1.1.0: + resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} + dev: false + /cookie@0.5.0: resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} engines: {node: '>= 0.6'} - dev: true + + /cookie@0.6.0: + resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} + engines: {node: '>= 0.6'} + dev: false /cross-spawn@7.0.3: resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==} @@ -1058,7 +1166,10 @@ packages: /deepmerge@4.3.1: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} - dev: true + + /delegates@1.0.0: + resolution: {integrity: sha512-bd2L678uiWATM6m5Z1VzNCErI3jiGzt6HGY8OVICs40JQq/HALfbyNJmp0UDakEY4pMMaN0Ly5om/B1VI/+xfQ==} + dev: false /dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} @@ -1069,9 +1180,13 @@ packages: engines: {node: '>=8'} dev: true + /detect-libc@2.0.2: + resolution: {integrity: sha512-UX6sGumvvqSaXgdKGUsgZWqcUyIXZ/vZTrlRT/iobiKhGL0zL4d3osHj3uqllWJK+i+sixDS/3COVEOFbupFyw==} + engines: {node: '>=8'} + dev: false + /devalue@4.3.2: resolution: {integrity: sha512-KqFl6pOgOW+Y6wJgu80rHpo2/3H07vr8ntR9rkkFIRETewbf5GaYYcakYfiKz89K+sLsuPkQIZaXDMjUObZwWg==} - dev: true /didyoumean@1.2.2: resolution: {integrity: sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==} @@ -1088,6 +1203,10 @@ packages: resolution: {integrity: sha512-/Ng/W/kFv7wdEHYzxdK7Cv0BHEGSkSB3M0Ssl8Ndr1eMiYeas/+Mv4cNaDqamqWx6nd2uQZfPz6g25z25M/sdw==} dev: true + /emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + dev: false + /es6-promise@3.3.1: resolution: {integrity: sha512-SOp9Phqvqn7jtEUxPWdWfWoLmyt2VaJ6MpvP9Comy1MceMXqE6bxvaTu4iaxpYYPzhny28Lc+M87/c2cPK6lDg==} dev: true @@ -1120,7 +1239,6 @@ packages: '@esbuild/win32-arm64': 0.18.20 '@esbuild/win32-ia32': 0.18.20 '@esbuild/win32-x64': 0.18.20 - dev: true /esbuild@0.19.11: resolution: {integrity: sha512-HJ96Hev2hX/6i5cDVwcqiJBBtuo9+FeIJOtZ9W1kA5M6AMJRHUZlpYZ1/SbEwtO0ioNAW8rUooVpC/WehY2SfA==} @@ -1160,7 +1278,6 @@ packages: /esm-env@1.0.0: resolution: {integrity: sha512-Cf6VksWPsTuW01vU9Mk/3vRue91Zevka5SjyNf3nEpokFRuqt/KjUQoGAwq9qMmhpLTHmXzSIrFRw8zxWzmFBA==} - dev: true /estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} @@ -1213,6 +1330,13 @@ packages: resolution: {integrity: sha512-n2aZ9tNfYDwaHhvFTkhFErqOMIb8uyzSQ+vGJBjZyanAKZVbGUQ1sngfk9FdkBw7G26O7AgNjLcecLffD1c7eg==} dev: true + /fs-minipass@2.1.0: + resolution: {integrity: sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + dev: false + /fs.realpath@1.0.0: resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} @@ -1223,6 +1347,21 @@ packages: requiresBuild: true optional: true + /gauge@3.0.2: + resolution: {integrity: sha512-+5J6MS/5XksCuXq++uFRsnUd7Ovu1XenbeuIuNRJxYWjgQbPuFhT14lAvsWfqfAmnwluf1OwMjz39HjfLPci0Q==} + engines: {node: '>=10'} + dependencies: + aproba: 2.0.0 + color-support: 1.1.3 + console-control-strings: 1.1.0 + has-unicode: 2.0.1 + object-assign: 4.1.1 + signal-exit: 3.0.7 + string-width: 4.2.3 + strip-ansi: 6.0.1 + wide-align: 1.1.5 + dev: false + /get-func-name@2.0.2: resolution: {integrity: sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==} dev: false @@ -1263,24 +1402,35 @@ packages: minimatch: 3.1.2 once: 1.4.0 path-is-absolute: 1.0.1 - dev: true /globalyzer@0.1.0: resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} - dev: true /globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - dev: true /graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} dev: true + /has-unicode@2.0.1: + resolution: {integrity: sha512-8Rf9Y83NBReMnx0gFzA8JImQACstCYWUplepDa9xprwwtmgEZUF0h/i5xSA625zB/I37EtrswSST6OXxwaaIJQ==} + dev: false + /has@1.0.4: resolution: {integrity: sha512-qdSAmqLF6209RFj4VVItywPMbm3vWylknmB3nvNiUIs72xAimcM8nVYxYr7ncvZq5qzk9MKIZR8ijqD/1QuYjQ==} engines: {node: '>= 0.4.0'} + /https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + dependencies: + agent-base: 6.0.2 + debug: 4.3.4 + transitivePeerDependencies: + - supports-color + dev: false + /human-signals@5.0.0: resolution: {integrity: sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==} engines: {node: '>=16.17.0'} @@ -1322,6 +1472,11 @@ packages: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} + /is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + dev: false + /is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} @@ -1350,6 +1505,10 @@ packages: resolution: {integrity: sha512-3TV69ZbrvV6U5DfQimop50jE9Dl6J8O1ja1dvBbMba/sZ3YBEQqJ2VZRoQPVnhlzjNtU1vaXRZVrVjU4qtm8yA==} hasBin: true + /jose@5.2.0: + resolution: {integrity: sha512-oW3PCnvyrcm1HMvGTzqjxxfnEs9EoFOFWi2HsEGhlFVOXxTE3K9GKWVMFoFw06yPUqwpvEWic1BmtUZBI/tIjw==} + dev: false + /jsonc-parser@3.2.0: resolution: {integrity: sha512-gfFQZrcTc8CnKXp6Y4/CBT3fTc0OVuDofpre4aEeEpSBPV5X5v4+Vmx+8snU7RLPrNHPKSgLxGo9YuQzz20o+w==} dev: false @@ -1357,7 +1516,6 @@ packages: /kleur@4.1.5: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - dev: true /lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} @@ -1383,6 +1541,13 @@ packages: get-func-name: 2.0.2 dev: false + /lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + dependencies: + yallist: 4.0.0 + dev: false + /lucide-svelte@0.285.0(svelte@4.2.1): resolution: {integrity: sha512-GAvdcTWsgE58IbB7yKM9Y3bEwLpI76VICb6c3FXeaCnSJHFtZDOXysnr71wvjNVZYNLXCv1b7oNLN6o5nMt0sA==} peerDependencies: @@ -1411,6 +1576,13 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: false + /make-dir@3.1.0: + resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} + engines: {node: '>=8'} + dependencies: + semver: 6.3.1 + dev: false + /mdn-data@2.0.30: resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==} @@ -1437,7 +1609,6 @@ packages: resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} engines: {node: '>=10.0.0'} hasBin: true - dev: true /mimic-fn@4.0.0: resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==} @@ -1458,6 +1629,26 @@ packages: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} dev: true + /minipass@3.3.6: + resolution: {integrity: sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==} + engines: {node: '>=8'} + dependencies: + yallist: 4.0.0 + dev: false + + /minipass@5.0.0: + resolution: {integrity: sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==} + engines: {node: '>=8'} + dev: false + + /minizlib@2.1.2: + resolution: {integrity: sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==} + engines: {node: '>= 8'} + dependencies: + minipass: 3.3.6 + yallist: 4.0.0 + dev: false + /mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -1465,6 +1656,12 @@ packages: minimist: 1.2.8 dev: true + /mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + dev: false + /mlly@1.5.0: resolution: {integrity: sha512-NPVQvAY1xr1QoVeG0cy8yUYC7FQcOx6evl/RjT1wL5FvzPnzOysoqB/jmx/DhssT2dYa8nxECLAaFI/+gVLhDQ==} dependencies: @@ -1516,12 +1713,10 @@ packages: /mri@1.2.0: resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} engines: {node: '>=4'} - dev: true /mrmime@1.0.1: resolution: {integrity: sha512-hzzEagAgDyoU1Q6yg5uI+AorQgdvMCur3FcKf7NhMKWsaYg+RnbTyHRa/9IlLF9rf455MOCtcqqrQQ83pPP7Uw==} engines: {node: '>=10'} - dev: true /ms@2.1.2: resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} @@ -1550,10 +1745,34 @@ packages: hasBin: true dev: false + /node-addon-api@7.0.0: + resolution: {integrity: sha512-vgbBJTS4m5/KkE16t5Ly0WW9hz46swAstv0hYYwMtbG7AznRhNyfLRe8HZAiWIpcHzoO7HxhLuBQj9rJ/Ho0ZA==} + dev: false + + /node-fetch@2.7.0: + resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} + engines: {node: 4.x || >=6.0.0} + peerDependencies: + encoding: ^0.1.0 + peerDependenciesMeta: + encoding: + optional: true + dependencies: + whatwg-url: 5.0.0 + dev: false + /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} dev: true + /nopt@5.0.0: + resolution: {integrity: sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ==} + engines: {node: '>=6'} + hasBin: true + dependencies: + abbrev: 1.1.1 + dev: false + /normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} engines: {node: '>=0.10.0'} @@ -1570,6 +1789,19 @@ packages: path-key: 4.0.0 dev: false + /npmlog@5.0.1: + resolution: {integrity: sha512-AqZtDUWOMKs1G/8lwylVjrdYgqA4d9nu8hc+0gzRxlDb1I10+FHBGMXs6aiQHFdCUUlqH99MUMuLfzWDNDtfxw==} + dependencies: + are-we-there-yet: 2.0.0 + console-control-strings: 1.1.0 + gauge: 3.0.2 + set-blocking: 2.0.0 + dev: false + + /oauth4webapi@2.6.0: + resolution: {integrity: sha512-4P43og0d8fQ61RMQEl9L7zwGVduuYbLED7uP99MkFSGuOUvJL1Fs52/D3tRtKoFtiSwKblScTYJI+utQn3SUDg==} + dev: false + /object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -1731,6 +1963,19 @@ packages: source-map-js: 1.0.2 dev: false + /preact-render-to-string@5.2.3(preact@10.11.3): + resolution: {integrity: sha512-aPDxUn5o3GhWdtJtW0svRC2SS/l8D9MAgo2+AWml+BhDImb27ALf04Q2d+AHqUUOc6RdSXFIBVa2gxzgMKgtZA==} + peerDependencies: + preact: '>=10' + dependencies: + preact: 10.11.3 + pretty-format: 3.8.0 + dev: false + + /preact@10.11.3: + resolution: {integrity: sha512-eY93IVpod/zG3uMF22Unl8h9KkrcKIRs2EGar8hwLZZDU1lkjph303V9HZBwufh2s736U6VXuhD109LYqPoffg==} + dev: false + /prettier@3.0.3: resolution: {integrity: sha512-L/4pUDMxcNa8R/EthV08Zt42WBO4h1rarVtK0K+QJG0X187OLo7l699jWw0GKuwzkPQ//jMFA/8Xm6Fh3J/DAg==} engines: {node: '>=14'} @@ -1746,6 +1991,10 @@ packages: react-is: 18.2.0 dev: false + /pretty-format@3.8.0: + resolution: {integrity: sha512-WuxUnVtlWL1OfZFQFuqvnvs6MiAGk9UNsBostyBOB0Is9wb5uRESevA6rnl/rkksXaGX3GzZhPup5d6Vp1nFew==} + dev: false + /punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -1763,6 +2012,15 @@ packages: dependencies: pify: 2.3.0 + /readable-stream@3.6.2: + resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} + engines: {node: '>= 6'} + dependencies: + inherits: 2.0.4 + string_decoder: 1.3.0 + util-deprecate: 1.0.2 + dev: false + /readdirp@3.6.0: resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} engines: {node: '>=8.10.0'} @@ -1793,13 +2051,19 @@ packages: glob: 7.2.3 dev: true + /rimraf@3.0.2: + resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} + hasBin: true + dependencies: + glob: 7.2.3 + dev: false + /rollup@3.29.4: resolution: {integrity: sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==} engines: {node: '>=14.18.0', npm: '>=8.0.0'} hasBin: true optionalDependencies: fsevents: 2.3.3 - dev: true /rollup@4.9.5: resolution: {integrity: sha512-E4vQW0H/mbNMw2yLSqJyjtkHY9dslf/p0zuT1xehNRqUTBOFMqEjguDvqhXr7N7r/4ttb2jr4T41d3dncmIgbQ==} @@ -1834,7 +2098,10 @@ packages: engines: {node: '>=6'} dependencies: mri: 1.2.0 - dev: true + + /safe-buffer@5.2.1: + resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} + dev: false /sander@0.5.1: resolution: {integrity: sha512-3lVqBir7WuKDHGrKRDn/1Ye3kwpXaDOMsiRP1wd6wpZW56gJhsbp5RqQpA6JG/P+pkXizygnr1dKR8vzWaVsfA==} @@ -1845,9 +2112,25 @@ packages: rimraf: 2.7.1 dev: true + /semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + dev: false + + /semver@7.5.4: + resolution: {integrity: sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==} + engines: {node: '>=10'} + hasBin: true + dependencies: + lru-cache: 6.0.0 + dev: false + + /set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + dev: false + /set-cookie-parser@2.6.0: resolution: {integrity: sha512-RVnVQxTXuerk653XfuliOxBP81Sf0+qfQE73LIYKcyMYHG94AuH0kgrQpRDuTZnSmjpysHmzxJXKNfa6PjFhyQ==} - dev: true /shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -1865,6 +2148,10 @@ packages: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} dev: false + /signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + dev: false + /signal-exit@4.1.0: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} @@ -1877,7 +2164,6 @@ packages: '@polka/url': 1.0.0-next.23 mrmime: 1.0.1 totalist: 3.0.1 - dev: true /sorcery@0.11.0: resolution: {integrity: sha512-J69LQ22xrQB1cIFJhPfgtLuI6BpWRiWu1Y3vSsIwK/eAScqJxd/+CJlUuHQRdX2C9NGFamq+KqNywGgaThwfHw==} @@ -1907,6 +2193,28 @@ packages: resolution: {integrity: sha512-JPbdCEQLj1w5GilpiHAx3qJvFndqybBysA3qUOnznweH4QbNYUsW/ea8QzSrnh0vNsezMMw5bcVool8lM0gwzg==} dev: false + /string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + dev: false + + /string_decoder@1.3.0: + resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} + dependencies: + safe-buffer: 5.2.1 + dev: false + + /strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + dependencies: + ansi-regex: 5.0.1 + dev: false + /strip-final-newline@3.0.0: resolution: {integrity: sha512-dOESqjYr96iWYylGObzd39EuNTa5VJxyvVAEm5Jnh7KGo75V43Hk1odPQkNDyXNmUR6k+gEiDVXnjB8HJ3crXw==} engines: {node: '>=12'} @@ -1976,7 +2284,6 @@ packages: svelte: ^3.19.0 || ^4.0.0 dependencies: svelte: 4.2.1 - dev: true /svelte-preprocess@5.0.4(postcss-load-config@4.0.1)(postcss@8.4.31)(svelte@4.2.1)(typescript@5.2.2): resolution: {integrity: sha512-ABia2QegosxOGsVlsSBJvoWeXy1wUKSfF7SWJdTjLAbx/Y3SrVevvvbFNQqrSJw89+lNSsM58SipmZJ5SRi5iw==} @@ -2093,6 +2400,18 @@ packages: transitivePeerDependencies: - ts-node + /tar@6.2.0: + resolution: {integrity: sha512-/Wo7DcT0u5HUV486xg675HtjNd3BXZ6xDbzsCUZPt5iw8bTQ63bP0Raut3mvro9u+CUyq7YQd8Cx55fsZXxqLQ==} + engines: {node: '>=10'} + dependencies: + chownr: 2.0.0 + fs-minipass: 2.1.0 + minipass: 5.0.0 + minizlib: 2.1.2 + mkdirp: 1.0.4 + yallist: 4.0.0 + dev: false + /thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} engines: {node: '>=0.8'} @@ -2109,7 +2428,6 @@ packages: dependencies: globalyzer: 0.1.0 globrex: 0.1.2 - dev: true /tinybench@2.6.0: resolution: {integrity: sha512-N8hW3PG/3aOoZAN5V/NSAEDz0ZixDSSt5b/a05iqtpgfLWMSVuCo7w0k2vVvEjdrIoeGqZzweX2WlyioNIHchA==} @@ -2134,7 +2452,10 @@ packages: /totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - dev: true + + /tr46@0.0.3: + resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} + dev: false /tr46@4.1.1: resolution: {integrity: sha512-2lv/66T7e5yNyhAAC4NaKe5nVavzuGJQVVtRYLyQ2OI8tsJ61PMLlelehb0wi2Hx6+hT/OJUWZcw8MjlSRnxvw==} @@ -2165,12 +2486,14 @@ packages: resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} dev: false + /undici-types@5.26.5: + resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + /undici@5.25.4: resolution: {integrity: sha512-450yJxT29qKMf3aoudzFpIciqpx6Pji3hEWaXqXmanbXF58LTAGCKxcJjxMXWu3iG+Mudgo3ZUfDB6YDFd/dAw==} engines: {node: '>=14.0'} dependencies: '@fastify/busboy': 2.0.0 - dev: true /update-browserslist-db@1.0.13(browserslist@4.22.1): resolution: {integrity: sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==} @@ -2186,7 +2509,7 @@ packages: /util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - /vite-node@1.2.0: + /vite-node@1.2.0(@types/node@20.11.5): resolution: {integrity: sha512-ETnQTHeAbbOxl7/pyBck9oAPZZZo+kYnFt1uQDD+hPReOc+wCjXw4r4jHriBRuVDB5isHmPXxrfc1yJnfBERqg==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -2195,7 +2518,7 @@ packages: debug: 4.3.4 pathe: 1.1.2 picocolors: 1.0.0 - vite: 5.0.11 + vite: 5.0.11(@types/node@20.11.5) transitivePeerDependencies: - '@types/node' - less @@ -2207,7 +2530,7 @@ packages: - terser dev: false - /vite@4.4.11: + /vite@4.4.11(@types/node@20.11.5): resolution: {integrity: sha512-ksNZJlkcU9b0lBwAGZGGaZHCMqHsc8OpgtoYhsQ4/I2v5cnpmmmqe5pM4nv/4Hn6G/2GhTdj0DhZh2e+Er1q5A==} engines: {node: ^14.18.0 || >=16.0.0} hasBin: true @@ -2235,14 +2558,14 @@ packages: terser: optional: true dependencies: + '@types/node': 20.11.5 esbuild: 0.18.20 postcss: 8.4.31 rollup: 3.29.4 optionalDependencies: fsevents: 2.3.3 - dev: true - /vite@5.0.11: + /vite@5.0.11(@types/node@20.11.5): resolution: {integrity: sha512-XBMnDjZcNAw/G1gEiskiM1v6yzM4GE5aMGvhWTlHAYYhxb7S3/V1s3m2LDHa8Vh6yIWYYB0iJwsEaS523c4oYA==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -2270,6 +2593,7 @@ packages: terser: optional: true dependencies: + '@types/node': 20.11.5 esbuild: 0.19.11 postcss: 8.4.33 rollup: 4.9.5 @@ -2285,10 +2609,9 @@ packages: vite: optional: true dependencies: - vite: 4.4.11 - dev: true + vite: 4.4.11(@types/node@20.11.5) - /vitest@1.2.0: + /vitest@1.2.0(@types/node@20.11.5): resolution: {integrity: sha512-Ixs5m7BjqvLHXcibkzKRQUvD/XLw0E3rvqaCMlrm/0LMsA0309ZqYvTlPzkhh81VlEyVZXFlwWnkhb6/UMtcaQ==} engines: {node: ^18.0.0 || >=20.0.0} hasBin: true @@ -2313,6 +2636,7 @@ packages: jsdom: optional: true dependencies: + '@types/node': 20.11.5 '@vitest/expect': 1.2.0 '@vitest/runner': 1.2.0 '@vitest/snapshot': 1.2.0 @@ -2331,8 +2655,8 @@ packages: strip-literal: 1.3.0 tinybench: 2.6.0 tinypool: 0.8.1 - vite: 5.0.11 - vite-node: 1.2.0 + vite: 5.0.11(@types/node@20.11.5) + vite-node: 1.2.0(@types/node@20.11.5) why-is-node-running: 2.2.2 transitivePeerDependencies: - less @@ -2344,6 +2668,10 @@ packages: - terser dev: false + /webidl-conversions@3.0.1: + resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} + dev: false + /webidl-conversions@7.0.0: resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} engines: {node: '>=12'} @@ -2357,6 +2685,13 @@ packages: webidl-conversions: 7.0.0 dev: false + /whatwg-url@5.0.0: + resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} + dependencies: + tr46: 0.0.3 + webidl-conversions: 3.0.1 + dev: false + /which@2.0.2: resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} engines: {node: '>= 8'} @@ -2374,9 +2709,19 @@ packages: stackback: 0.0.2 dev: false + /wide-align@1.1.5: + resolution: {integrity: sha512-eDMORYaPNZ4sQIuuYPDHdQvf4gyCF9rEEV/yPxGfwPkRodwEgiMUUXTx/dex+Me0wxx53S+NgUHaP7y3MGlDmg==} + dependencies: + string-width: 4.2.3 + dev: false + /wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + /yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: false + /yaml@2.3.2: resolution: {integrity: sha512-N/lyzTPaJasoDmfV7YTrYCI0G/3ivm/9wdG0aHuheKowWQwGTsK0Eoiw6utmzAnI6pkJa0DUVygvp3spqqEKXg==} engines: {node: '>= 14'} diff --git a/src/hooks.server.ts b/src/hooks.server.ts index e69de29..9923eee 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -0,0 +1,10 @@ +import { SvelteKitAuth } from "@auth/sveltekit"; +import CredentialsProvider from "@auth/sveltekit/providers/credentials"; + +export const handle = SvelteKitAuth({ + providers: [CredentialsProvider({ + authorize: async (credentials) => { + + } + })], +}); \ No newline at end of file diff --git a/src/lib/schema/user.ts b/src/lib/schema/user.ts new file mode 100644 index 0000000..345be4c --- /dev/null +++ b/src/lib/schema/user.ts @@ -0,0 +1,18 @@ +import * as argon2 from "argon2"; +import { z } from "zod"; +import { ObjectId } from "mongodb"; + +export const roleSchema = z.enum(["admin", "user"] as const); +export type RoleSchema = z.infer; + +export const userSchema = z.object({ + _id: z.instanceof(ObjectId), + fullname: z.string().min(4).max(255).trim(), + username: z.string().min(4).max(255).trim(), + password: z.string().min(8), + email: z.string().email(), + role: roleSchema, + createdAt: z.date(), + updatedAt: z.date() +}); +export type UserSchema = z.infer; \ No newline at end of file diff --git a/src/lib/server/repositories/user-repository.ts b/src/lib/server/repositories/user-repository.ts new file mode 100644 index 0000000..b7cca9d --- /dev/null +++ b/src/lib/server/repositories/user-repository.ts @@ -0,0 +1,16 @@ +import { userSchema, type UserSchema } from "$lib/schema/user"; +import { dbClient } from "$lib/server/repositories/db-client"; +import { MONGO_DB } from "$env/static/private"; + +export const USER_COLLECTION_NAME = "users"; + +export async function getUserByEmailOrUsername(emailOrUsername: string): Promise { + const user = await dbClient.db(MONGO_DB).collection(USER_COLLECTION_NAME).findOne({ + $or: [ + { email: emailOrUsername }, + { username: emailOrUsername } + ] + }); + if (user === null) return null; + return userSchema.parse(user); +} \ No newline at end of file diff --git a/src/tests/repositories/form-repository.test.ts b/src/tests/repositories/form-repository.test.ts index dc9cc9f..f71783a 100644 --- a/src/tests/repositories/form-repository.test.ts +++ b/src/tests/repositories/form-repository.test.ts @@ -4,7 +4,7 @@ import { dbClient } from "$lib/server/repositories/db-client"; import type { FormSchema, TextBlock } from "$lib/schema/form"; import { ObjectId } from "mongodb"; -const DB_NAME = "onlyforms-form-test"; +const DB_NAME = "onlyforms-test"; describe("form-repository", () => { const objectId = ObjectId.createFromHexString("fb57f193091e6e59c462741d"); diff --git a/src/tests/repositories/user-repository.test.ts b/src/tests/repositories/user-repository.test.ts new file mode 100644 index 0000000..405367d --- /dev/null +++ b/src/tests/repositories/user-repository.test.ts @@ -0,0 +1,69 @@ +import { afterAll, beforeAll, describe, expect, it, vi } from "vitest"; +import * as argon2 from "argon2"; +import { ObjectId } from "mongodb"; +import type { UserSchema } from "$lib/schema/user"; +import { USER_COLLECTION_NAME, getUserByEmailOrUsername } from "$lib/server/repositories/user-repository"; +import { dbClient } from "$lib/server/repositories/db-client"; + +const DB_NAME = "onlyforms-test"; + +describe("user-repository", () => { + const objectId = ObjectId.createFromHexString("fb57f193091e6e59c462741d"); + beforeAll(async () => { + vi.mock("$env/static/private", async (importOriginal) => { + const original = await importOriginal() as Record; + return { + ...original, + MONGO_DB: "onlyforms-test" + }; + }); + + const hashedPassword = await argon2.hash("password", { type: argon2.argon2i }); + // insert data into database + await dbClient.db(DB_NAME).collection(USER_COLLECTION_NAME).insertMany([ + { + _id: objectId, + fullname: "John Doe", + username: "johndoe", + email: "john.doe@gmail.com", + password: hashedPassword, + role: "admin", + createdAt: new Date(), + updatedAt: new Date() + } + ] satisfies UserSchema[]); + }); + + afterAll(async () => { + await dbClient.db(DB_NAME).dropDatabase(); + }); + + it("should return null when user is not found", async () => { + const user = await getUserByEmailOrUsername("notfound"); + expect(user).toBeNull(); + }); + + it("should get a user by their username", async () => { + const user = await getUserByEmailOrUsername("johndoe"); + expect(user).toBeDefined(); + expect(user?.username).toBe("johndoe"); + expect(user?.email).toBe("john.doe@gmail.com"); + expect(user?.fullname).toBe("John Doe"); + expect(user?.role).toBe("admin"); + expect(user?.password).toBeDefined(); + expect(user?.createdAt).toBeInstanceOf(Date); + expect(user?.updatedAt).toBeInstanceOf(Date); + }); + + it("should get a user by their email", async () => { + const user = await getUserByEmailOrUsername("john.doe@gmail.com"); + expect(user).toBeDefined(); + expect(user?.username).toBe("johndoe"); + expect(user?.email).toBe("john.doe@gmail.com"); + expect(user?.fullname).toBe("John Doe"); + expect(user?.role).toBe("admin"); + expect(user?.password).toBeDefined(); + expect(user?.createdAt).toBeInstanceOf(Date); + expect(user?.updatedAt).toBeInstanceOf(Date); + }); +}); \ No newline at end of file From 681aac333fd8e2159953fff766cc5057000e2b0c Mon Sep 17 00:00:00 2001 From: elianiva Date: Fri, 19 Jan 2024 03:41:12 +0700 Subject: [PATCH 3/4] feat: authentication, form validation --- package.json | 4 + pnpm-lock.yaml | 61 ++++++++++ src/app.d.ts | 13 ++ src/app.html | 2 +- src/app.postcss | 4 + src/hooks.server.ts | 115 +++++++++++++++++- .../ui/alert/alert-description.svelte | 13 ++ .../components/ui/alert/alert-title.svelte | 21 ++++ src/lib/components/ui/alert/alert.svelte | 17 +++ src/lib/components/ui/alert/index.ts | 33 +++++ src/lib/components/ui/label/index.ts | 7 ++ src/lib/components/ui/label/label.svelte | 21 ++++ src/lib/schema/auth.ts | 7 ++ src/lib/utils.ts | 13 ++ src/routes/(auth)/+layout.svelte | 7 ++ src/routes/(auth)/sign-in/+page.svelte | 93 ++++++++++++++ src/routes/+layout.svelte | 3 + src/routes/app/+layout.server.ts | 7 ++ src/routes/app/+layout.svelte | 5 + src/routes/app/+page.svelte | 12 ++ 20 files changed, 452 insertions(+), 6 deletions(-) create mode 100644 src/lib/components/ui/alert/alert-description.svelte create mode 100644 src/lib/components/ui/alert/alert-title.svelte create mode 100644 src/lib/components/ui/alert/alert.svelte create mode 100644 src/lib/components/ui/alert/index.ts create mode 100644 src/lib/components/ui/label/index.ts create mode 100644 src/lib/components/ui/label/label.svelte create mode 100644 src/lib/schema/auth.ts create mode 100644 src/routes/(auth)/+layout.svelte create mode 100644 src/routes/(auth)/sign-in/+page.svelte create mode 100644 src/routes/app/+layout.server.ts create mode 100644 src/routes/app/+layout.svelte create mode 100644 src/routes/app/+page.svelte diff --git a/package.json b/package.json index 27e622f..3bfc330 100644 --- a/package.json +++ b/package.json @@ -28,13 +28,17 @@ }, "type": "module", "dependencies": { + "@auth/core": "^0.21.0", "@auth/sveltekit": "^0.7.0", + "@felte/validator-zod": "^1.0.17", "@types/node": "^20.11.5", "argon2": "^0.31.2", "bits-ui": "^0.5.7", "clsx": "^2.0.0", + "felte": "^1.2.12", "lucide-svelte": "^0.285.0", "mongodb": "^6.3.0", + "svelte-french-toast": "^1.2.0", "tailwind-merge": "^1.14.0", "tailwind-variants": "^0.1.14", "vitest": "^1.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a81b8ba..b306b2d 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -5,9 +5,15 @@ settings: excludeLinksFromLockfile: false dependencies: + '@auth/core': + specifier: ^0.21.0 + version: 0.21.0 '@auth/sveltekit': specifier: ^0.7.0 version: 0.7.0(@sveltejs/kit@1.25.2)(svelte@4.2.1) + '@felte/validator-zod': + specifier: ^1.0.17 + version: 1.0.17(zod@3.22.4) '@types/node': specifier: ^20.11.5 version: 20.11.5 @@ -20,12 +26,18 @@ dependencies: clsx: specifier: ^2.0.0 version: 2.0.0 + felte: + specifier: ^1.2.12 + version: 1.2.12(svelte@4.2.1) lucide-svelte: specifier: ^0.285.0 version: 0.285.0(svelte@4.2.1) mongodb: specifier: ^6.3.0 version: 6.3.0 + svelte-french-toast: + specifier: ^1.2.0 + version: 1.2.0(svelte@4.2.1) tailwind-merge: specifier: ^1.14.0 version: 1.14.0 @@ -507,6 +519,28 @@ packages: resolution: {integrity: sha512-JUFJad5lv7jxj926GPgymrWQxxjPYuJNiNjNMzqT+HiuP6Vl3dk5xzG+8sTX96np0ZAluvaMzPsjhHZ5rNuNQQ==} engines: {node: '>=14'} + /@felte/common@1.1.8: + resolution: {integrity: sha512-VbEOfNLWfDx0SpCfeE+fNWDpvcntND4MFs7Lxd18RIjrZYH82D0wWe9th2oVF9QT5XzgBEdMF5NGIttcwU4sjg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + + /@felte/core@1.4.1: + resolution: {integrity: sha512-dUzfzug5cK93kBjG0u9F3zDM781qCJP4QwYPOpJsXbydwVseDM5BXpDqvZUFhqJsd0x1GKftkX69+iWafyASjw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dependencies: + '@felte/common': 1.1.8 + dev: false + + /@felte/validator-zod@1.0.17(zod@3.22.4): + resolution: {integrity: sha512-rOX1chLfTcixKMPEdrMSi8zsCM685Dsoy1a5qN1G6Fyh7HYK1vSmI6SfJ7m92DOt6kV+vAP4m5rk94Y8UFIeVw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + zod: ^3.2.0 + dependencies: + '@felte/common': 1.1.8 + zod: 3.22.4 + dev: false + /@floating-ui/core@1.5.0: resolution: {integrity: sha512-kK1h4m36DQ0UHGj5Ah4db7R0rHemTqqO0QLvUqi1/mUUp3LuAWbWxdxSIf/XsnH9VS6rRVPLJCncjRzUvyCLXg==} dependencies: @@ -1314,6 +1348,16 @@ packages: dependencies: reusify: 1.0.4 + /felte@1.2.12(svelte@4.2.1): + resolution: {integrity: sha512-llg9ywCgIso48NnO6jZUy8D9vWuKE90dfIFUZPLyNKqbH1WJ0brNU6C4DkdfXtpRKlzWWHvaQkgMIezKoWlzvA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + svelte: ^3.31.0 || ^4.0.0 + dependencies: + '@felte/core': 1.4.1 + svelte: 4.2.1 + dev: false + /fill-range@7.0.1: resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} engines: {node: '>=8'} @@ -2277,6 +2321,15 @@ packages: - sugarss dev: true + /svelte-french-toast@1.2.0(svelte@4.2.1): + resolution: {integrity: sha512-5PW+6RFX3xQPbR44CngYAP1Sd9oCq9P2FOox4FZffzJuZI2mHOB7q5gJBVnOiLF5y3moVGZ7u2bYt7+yPAgcEQ==} + peerDependencies: + svelte: ^3.57.0 || ^4.0.0 + dependencies: + svelte: 4.2.1 + svelte-writable-derived: 3.1.0(svelte@4.2.1) + dev: false + /svelte-hmr@0.15.3(svelte@4.2.1): resolution: {integrity: sha512-41snaPswvSf8TJUhlkoJBekRrABDXDMdpNpT2tfHIv4JuhgvHqLMhEPGtaQn0BmbNSTkuz2Ed20DF2eHw0SmBQ==} engines: {node: ^12.20 || ^14.13.1 || >= 16} @@ -2334,6 +2387,14 @@ packages: typescript: 5.2.2 dev: true + /svelte-writable-derived@3.1.0(svelte@4.2.1): + resolution: {integrity: sha512-cTvaVFNIJ036vSDIyPxJYivKC7ZLtcFOPm1Iq6qWBDo1fOHzfk6ZSbwaKrxhjgy52Rbl5IHzRcWgos6Zqn9/rg==} + peerDependencies: + svelte: ^3.2.1 || ^4.0.0-next.1 + dependencies: + svelte: 4.2.1 + dev: false + /svelte@4.2.1: resolution: {integrity: sha512-LpLqY2Jr7cRxkrTc796/AaaoMLF/1ax7cto8Ot76wrvKQhrPmZ0JgajiWPmg9mTSDqO16SSLiD17r9MsvAPTmw==} engines: {node: '>=16'} diff --git a/src/app.d.ts b/src/app.d.ts index f59b884..8724db3 100644 --- a/src/app.d.ts +++ b/src/app.d.ts @@ -1,3 +1,15 @@ +import "@auth/sveltekit"; + +declare module "@auth/sveltekit" { + interface User { + id: string; + fullname: string; + email: string; + username: string; + role: string; + } +} + // See https://kit.svelte.dev/docs/types#app // for information about these interfaces declare global { @@ -9,4 +21,5 @@ declare global { } } + export {}; diff --git a/src/app.html b/src/app.html index 77a5ff5..fda3997 100644 --- a/src/app.html +++ b/src/app.html @@ -7,6 +7,6 @@ %sveltekit.head% -
%sveltekit.body%
+
%sveltekit.body% diff --git a/src/app.postcss b/src/app.postcss index 76f978c..b025f0a 100644 --- a/src/app.postcss +++ b/src/app.postcss @@ -75,4 +75,8 @@ body { @apply bg-background text-foreground; } + html, + body { + @apply h-full; + } } diff --git a/src/hooks.server.ts b/src/hooks.server.ts index 9923eee..68033d1 100644 --- a/src/hooks.server.ts +++ b/src/hooks.server.ts @@ -1,10 +1,115 @@ +import * as argon2 from "argon2"; import { SvelteKitAuth } from "@auth/sveltekit"; import CredentialsProvider from "@auth/sveltekit/providers/credentials"; +import { getUserByEmailOrUsername } from "$lib/server/repositories/user-repository"; +import { type Handle, redirect } from "@sveltejs/kit"; +import { sequence } from "@sveltejs/kit/hooks"; +import { wrapResult } from "$lib/utils"; +import { authSchema } from "$lib/schema/auth"; +import { dev } from "$app/environment"; -export const handle = SvelteKitAuth({ - providers: [CredentialsProvider({ - authorize: async (credentials) => { +const authorization: Handle = async ({ event, resolve }) => { + const pathname = event.url.pathname; + // redirect for index path + if (pathname === "/") { + throw redirect(303, "/app"); + } + const session = await event.locals.getSession(); + + if (!session) { + if (pathname.startsWith("/app")) { + throw redirect(303, "/sign-in"); + } + } + + if (session) { + if (pathname.startsWith("/sign-in")) { + throw redirect(303, "/app"); } - })], -}); \ No newline at end of file + } + + return resolve(event); +}; + +export const handle = sequence( + SvelteKitAuth({ + providers: [ + CredentialsProvider({ + id: "credentials", + authorize: async (credentials) => { + const validatedCredentials = authSchema.safeParse(credentials); + if (!validatedCredentials.success) { + return null; + } + + // TODO(elianiva): only for temporary development purpose, please remove later + if (dev) { + if ( + validatedCredentials.data.username === "admin" && + validatedCredentials.data.password === "password" + ) { + return { + id: "admin", + username: "admin", + fullname: "Administrator", + email: "admin@localhost", + role: "admin", + }; + } + } + + const [user, userError] = await wrapResult( + getUserByEmailOrUsername(validatedCredentials.data.username as string), + ); + if (user === null || userError !== null) { + return null; + } + + const [isPasswordMatch, verifyError] = await wrapResult( + argon2.verify(user.password, validatedCredentials.data.password as string, { + type: argon2.argon2i, + }), + ); + if (!isPasswordMatch || verifyError !== null) { + return null; + } + + return { + id: user._id.toHexString(), + username: user.username, + fullname: user.fullname, + email: user.email, + role: user.role, + }; + }, + }), + ], + session: { + strategy: "jwt", + }, + callbacks: { + async jwt({ token, user }) { + if (user) { + token.sub = user.id; + token.user = { + id: user.id, + username: user.username, + fullname: user.fullname, + email: user.email, + role: user.role, + }; + } + return token; + }, + async session({ session, token }) { + session.user = token.user; + return session; + }, + }, + pages: { + signIn: "/sign-in", + }, + }), + authorization, +); diff --git a/src/lib/components/ui/alert/alert-description.svelte b/src/lib/components/ui/alert/alert-description.svelte new file mode 100644 index 0000000..42a9133 --- /dev/null +++ b/src/lib/components/ui/alert/alert-description.svelte @@ -0,0 +1,13 @@ + + +
+ +
diff --git a/src/lib/components/ui/alert/alert-title.svelte b/src/lib/components/ui/alert/alert-title.svelte new file mode 100644 index 0000000..72d0138 --- /dev/null +++ b/src/lib/components/ui/alert/alert-title.svelte @@ -0,0 +1,21 @@ + + + + + diff --git a/src/lib/components/ui/alert/alert.svelte b/src/lib/components/ui/alert/alert.svelte new file mode 100644 index 0000000..8c6790f --- /dev/null +++ b/src/lib/components/ui/alert/alert.svelte @@ -0,0 +1,17 @@ + + + diff --git a/src/lib/components/ui/alert/index.ts b/src/lib/components/ui/alert/index.ts new file mode 100644 index 0000000..cde7987 --- /dev/null +++ b/src/lib/components/ui/alert/index.ts @@ -0,0 +1,33 @@ +import { tv, type VariantProps } from "tailwind-variants"; + +import Root from "./alert.svelte"; +import Description from "./alert-description.svelte"; +import Title from "./alert-title.svelte"; + +export const alertVariants = tv({ + base: "relative w-full rounded-lg border p-4 [&>svg]:absolute [&>svg]:text-foreground [&>svg]:left-4 [&>svg]:top-4 [&>svg+div]:translate-y-[-3px] [&:has(svg)]:pl-11", + + variants: { + variant: { + default: "bg-background text-foreground", + destructive: + "text-destructive border-destructive/50 dark:border-destructive [&>svg]:text-destructive text-destructive" + } + }, + defaultVariants: { + variant: "default" + } +}); + +export type Variant = VariantProps["variant"]; +export type HeadingLevel = "h1" | "h2" | "h3" | "h4" | "h5" | "h6"; + +export { + Root, + Description, + Title, + // + Root as Alert, + Description as AlertDescription, + Title as AlertTitle +}; diff --git a/src/lib/components/ui/label/index.ts b/src/lib/components/ui/label/index.ts new file mode 100644 index 0000000..2c3128c --- /dev/null +++ b/src/lib/components/ui/label/index.ts @@ -0,0 +1,7 @@ +import Root from "./label.svelte"; + +export { + Root, + // + Root as Label +}; diff --git a/src/lib/components/ui/label/label.svelte b/src/lib/components/ui/label/label.svelte new file mode 100644 index 0000000..264c8fd --- /dev/null +++ b/src/lib/components/ui/label/label.svelte @@ -0,0 +1,21 @@ + + + + + diff --git a/src/lib/schema/auth.ts b/src/lib/schema/auth.ts new file mode 100644 index 0000000..87df3c3 --- /dev/null +++ b/src/lib/schema/auth.ts @@ -0,0 +1,7 @@ +import { z } from "zod"; + +export const authSchema = z.object({ + username: z.string().trim(), + password: z.string().min(8).max(32), +}); +export type AuthSchema = z.infer; diff --git a/src/lib/utils.ts b/src/lib/utils.ts index ccaec55..8610b3e 100644 --- a/src/lib/utils.ts +++ b/src/lib/utils.ts @@ -54,3 +54,16 @@ export const flyAndScale = ( easing: cubicOut, }; }; + +export async function wrapResult(promise: Promise): Promise<[TResult | null, Error | null]> { + try { + const result = await promise; + return [result, null]; + } catch (error) { + if (error instanceof Error) { + return [null, error]; + } + const wrappedError = new Error(error as string); + return [null, wrappedError]; + } +} diff --git a/src/routes/(auth)/+layout.svelte b/src/routes/(auth)/+layout.svelte new file mode 100644 index 0000000..f0266b3 --- /dev/null +++ b/src/routes/(auth)/+layout.svelte @@ -0,0 +1,7 @@ + + Sign In | OnlyForms + + +
+ +
\ No newline at end of file diff --git a/src/routes/(auth)/sign-in/+page.svelte b/src/routes/(auth)/sign-in/+page.svelte new file mode 100644 index 0000000..3a557cb --- /dev/null +++ b/src/routes/(auth)/sign-in/+page.svelte @@ -0,0 +1,93 @@ + + +
+ + + Sign In to OnlyForms + Sign In to access your OnlyForms account + + +
+
+ + + {#if $errors.username} +

{$errors.username}

+ {/if} +
+
+ + + {#if $errors.password} +

{$errors.password}

+ {/if} +
+
+
+ + + +
+
diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 2816bcf..348d8dd 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -1,5 +1,8 @@ + + diff --git a/src/routes/app/+layout.server.ts b/src/routes/app/+layout.server.ts new file mode 100644 index 0000000..6b8848e --- /dev/null +++ b/src/routes/app/+layout.server.ts @@ -0,0 +1,7 @@ +import type { LayoutServerLoad } from "./$types"; + +export const load: LayoutServerLoad = async (event) => { + return { + session: await event.locals.getSession(), + }; +}; diff --git a/src/routes/app/+layout.svelte b/src/routes/app/+layout.svelte new file mode 100644 index 0000000..6e5e5bd --- /dev/null +++ b/src/routes/app/+layout.svelte @@ -0,0 +1,5 @@ + + Dashboard | OnlyForms + + + diff --git a/src/routes/app/+page.svelte b/src/routes/app/+page.svelte new file mode 100644 index 0000000..29fd106 --- /dev/null +++ b/src/routes/app/+page.svelte @@ -0,0 +1,12 @@ + + +
+

+ Hello there, you're authenticated as {$page.data.session?.user?.email} +

+ +
From 7c5097ce4cbc0b67d92f0b203315e017ab33804e Mon Sep 17 00:00:00 2001 From: elianiva Date: Sat, 20 Jan 2024 12:50:57 +0700 Subject: [PATCH 4/4] fix: div tag was closed twice --- src/app.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/app.html b/src/app.html index fda3997..699fded 100644 --- a/src/app.html +++ b/src/app.html @@ -7,6 +7,6 @@ %sveltekit.head% -
%sveltekit.body% +
%sveltekit.body%