From 1674cdd72614e1f44f5cf474e5144edf632bbda5 Mon Sep 17 00:00:00 2001 From: Mihkel Martin Kasterpalu Date: Tue, 11 Feb 2025 14:46:14 +0200 Subject: [PATCH] WIP rahvatarkus, working CRUD demo --- package.json | 10 +- pnpm-lock.yaml | 465 +++++++++++++++++- src/lib/server/db/schema.ts | 27 +- src/lib/types.ts | 4 + src/routes/api/rahvatarkus/answer/+server.ts | 72 +++ .../archive/[limit]/[[offset]]/+server.ts | 52 ++ .../api/rahvatarkus/question/+server.ts | 67 +++ src/routes/vinge/+layout.svelte | 4 + src/routes/vinge/rahvatarkus/+page.server.ts | 162 ++++++ src/routes/vinge/rahvatarkus/+page.svelte | 63 +++ .../vinge/rahvatarkus/answer-form.svelte | 50 ++ src/routes/vinge/rahvatarkus/answer-schema.ts | 8 + .../vinge/rahvatarkus/question-form.svelte | 39 ++ .../vinge/rahvatarkus/question-schema.ts | 7 + 14 files changed, 1015 insertions(+), 15 deletions(-) create mode 100644 src/routes/api/rahvatarkus/answer/+server.ts create mode 100644 src/routes/api/rahvatarkus/archive/[limit]/[[offset]]/+server.ts create mode 100644 src/routes/api/rahvatarkus/question/+server.ts create mode 100644 src/routes/vinge/rahvatarkus/+page.server.ts create mode 100644 src/routes/vinge/rahvatarkus/+page.svelte create mode 100644 src/routes/vinge/rahvatarkus/answer-form.svelte create mode 100644 src/routes/vinge/rahvatarkus/answer-schema.ts create mode 100644 src/routes/vinge/rahvatarkus/question-form.svelte create mode 100644 src/routes/vinge/rahvatarkus/question-schema.ts diff --git a/package.json b/package.json index 2c9a28c..a8a76ad 100644 --- a/package.json +++ b/package.json @@ -27,34 +27,38 @@ "@types/better-sqlite3": "^7.6.12", "@types/spotify-web-api-node": "^5.0.11", "autoprefixer": "^10.4.20", - "bits-ui": "1.0.0-next.86", + "bits-ui": "1.0.0-next.94", "clsx": "^2.1.1", "drizzle-kit": "^0.30.2", "eslint": "^9.19.0", "eslint-config-prettier": "^10.0.1", "eslint-plugin-svelte": "^2.46.1", + "formsnap": "^2.0.0", "globals": "^15.14.0", "lucide-svelte": "^0.474.0", + "mode-watcher": "^0.5.1", "prettier": "^3.4.2", "prettier-plugin-svelte": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.10", "svelte": "^5.19.1", "svelte-check": "^4.1.4", "svelte-dnd-action": "^0.9.55", + "svelte-sonner": "^0.3.28", + "sveltekit-superforms": "^2.23.1", "tailwind-merge": "^2.6.0", "tailwind-variants": "^0.3.1", "tailwindcss": "^3.4.17", "tailwindcss-animate": "^1.0.7", "typescript": "^5.7.3", "typescript-eslint": "^8.22.0", - "vite": "^6.0.11" + "vite": "^6.0.11", + "zod": "^3.24.1" }, "dependencies": { "@fontsource-variable/kode-mono": "^5.1.1", "@fontsource-variable/smooch-sans": "^5.1.1", "better-sqlite3": "^11.8.0", "drizzle-orm": "^0.38.4", - "mode-watcher": "^0.5.1", "nanoid": "^5.0.9", "spotify-web-api-node": "^5.0.2", "svelte-kit-sessions": "^0.4.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 14e94fe..dbbfd30 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,9 +20,6 @@ importers: drizzle-orm: specifier: ^0.38.4 version: 0.38.4(@types/better-sqlite3@7.6.12)(better-sqlite3@11.8.1) - mode-watcher: - specifier: ^0.5.1 - version: 0.5.1(svelte@5.19.1) nanoid: specifier: ^5.0.9 version: 5.0.9 @@ -67,8 +64,8 @@ importers: specifier: ^10.4.20 version: 10.4.20(postcss@8.5.1) bits-ui: - specifier: 1.0.0-next.86 - version: 1.0.0-next.86(svelte@5.19.1) + specifier: 1.0.0-next.94 + version: 1.0.0-next.94(svelte@5.19.1) clsx: specifier: ^2.1.1 version: 2.1.1 @@ -84,12 +81,18 @@ importers: eslint-plugin-svelte: specifier: ^2.46.1 version: 2.46.1(eslint@9.19.0(jiti@1.21.7))(svelte@5.19.1) + formsnap: + specifier: ^2.0.0 + version: 2.0.0(svelte@5.19.1)(sveltekit-superforms@2.23.1(@sveltejs/kit@2.16.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(@types/json-schema@7.0.15)(svelte@5.19.1)(typescript@5.7.3)) globals: specifier: ^15.14.0 version: 15.14.0 lucide-svelte: specifier: ^0.474.0 version: 0.474.0(svelte@5.19.1) + mode-watcher: + specifier: ^0.5.1 + version: 0.5.1(svelte@5.19.1) prettier: specifier: ^3.4.2 version: 3.4.2 @@ -108,6 +111,12 @@ importers: svelte-dnd-action: specifier: ^0.9.55 version: 0.9.55(svelte@5.19.1) + svelte-sonner: + specifier: ^0.3.28 + version: 0.3.28(svelte@5.19.1) + sveltekit-superforms: + specifier: ^2.23.1 + version: 2.23.1(@sveltejs/kit@2.16.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(@types/json-schema@7.0.15)(svelte@5.19.1)(typescript@5.7.3) tailwind-merge: specifier: ^2.6.0 version: 2.6.0 @@ -129,6 +138,9 @@ importers: vite: specifier: ^6.0.11 version: 6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0) + zod: + specifier: ^3.24.1 + version: 3.24.1 packages: @@ -140,6 +152,16 @@ packages: resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} engines: {node: '>=6.0.0'} + '@ark/schema@0.39.0': + resolution: {integrity: sha512-LQbQUb3Sj461LgklXObAyUJNtsUUCBxZlO2HqRLYvRSqpStm0xTMrXn51DwBNNxeSULvKVpXFwoxiSec9kwKww==} + + '@ark/util@0.39.0': + resolution: {integrity: sha512-90APHVklk8BP4kku7hIh1BgrhuyKYqoZ4O7EybtFRo7cDl9mIyc/QUbGvYDg//73s0J2H0I/gW9pzroA1R4IBQ==} + + '@babel/runtime@7.26.7': + resolution: {integrity: sha512-AOPI3D+a8dXnja+iwsUqGRjr1BbZIe771sXdapOtYI531gSqpi92vXivKcq2asu/DFpdl1ceFAKZyRzK2PCVcQ==} + engines: {node: '>=6.9.0'} + '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} @@ -617,6 +639,9 @@ packages: resolution: {integrity: sha512-lB05FkqEdUg2AA0xEbUz0SnkXT1LcCTa438W4IWTUh4hdOnVbQyOJ81OrDXsJk/LSiJHubgGEFoR5EHq1NsH1A==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@exodus/schemasafe@1.3.0': + resolution: {integrity: sha512-5Aap/GaRupgNx/feGBwLLTVv8OQFfv3pq2lPRzPg9R+IOBnDgghTGW7l7EuVXOvg5cc/xSAlRW8rBrjIC3Nvqw==} + '@floating-ui/core@1.6.9': resolution: {integrity: sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==} @@ -632,6 +657,16 @@ packages: '@fontsource-variable/smooch-sans@5.1.1': resolution: {integrity: sha512-ADcY3Pjkvu74x4T+p2gNIo8Ba7DGrX1IhQgJFefztWB8Tf5nX7Qb+tqAbtW7O/KYWJi4EjzrxCefHBM1PfOOsg==} + '@gcornut/valibot-json-schema@0.31.0': + resolution: {integrity: sha512-3xGptCurm23e7nuPQkdrE5rEs1FeTPHhAUsBuwwqG4/YeZLwJOoYZv+fmsppUEfo5y9lzUwNQrNqLS/q7HMc7g==} + hasBin: true + + '@hapi/hoek@9.3.0': + resolution: {integrity: sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==} + + '@hapi/topo@5.1.0': + resolution: {integrity: sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==} + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} @@ -805,6 +840,10 @@ packages: '@polka/url@1.0.0-next.28': resolution: {integrity: sha512-8LduaNlMZGwdZ6qWrKlfa+2M4gahzFkprZiAt2TF8uS0qQgBizKXpXURqvTJ4WtmupWxaLqjRb2UCTe72mu+Aw==} + '@poppinss/macroable@1.0.4': + resolution: {integrity: sha512-ct43jurbe7lsUX5eIrj4ijO3j/6zIPp7CDnFWXDs7UPAbw1Pu1iH3oAmFdP4jcskKJBURH5M9oTtyeiUXyHX8Q==} + engines: {node: '>=18.16.0'} + '@rollup/plugin-commonjs@28.0.2': resolution: {integrity: sha512-BEFI2EDqzl+vA1rl97IDRZ61AIwGH093d9nz8+dThxJNH8oSoB7MjWvPCX3dkaK1/RCJ/1v/R1XB15FuSs0fQw==} engines: {node: '>=16.0.0 || 14 >= 14.17'} @@ -936,6 +975,18 @@ packages: cpu: [x64] os: [win32] + '@sideway/address@4.1.5': + resolution: {integrity: sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==} + + '@sideway/formula@3.0.1': + resolution: {integrity: sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==} + + '@sideway/pinpoint@2.0.0': + resolution: {integrity: sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==} + + '@sinclair/typebox@0.34.16': + resolution: {integrity: sha512-rIljj8VPYAfn26ANY+5pCNVBPiv6hSufuKGe46y65cJZpvx8vHvPXlU0Q/Le4OGtlNaL8Jg2FuhtvQX18lSIqA==} + '@sveltejs/adapter-node@5.2.12': resolution: {integrity: sha512-0bp4Yb3jKIEcZWVcJC/L1xXp9zzJS4hDwfb4VITAkfT4OVdkspSHsx7YhqJDbb2hgLl6R9Vs7VQR+fqIVOxPUQ==} peerDependencies: @@ -1008,6 +1059,25 @@ packages: '@types/spotify-web-api-node@5.0.11': resolution: {integrity: sha512-RS3IkSqH9geC61e8qd+Oy7giOTtiY7ywm0Z4bu5uYuc7XuOcLfDwKjmle85IbpTEdazeCgmIbo8nMLg7WDVvgw==} + '@types/validator@13.12.2': + resolution: {integrity: sha512-6SlHBzUW8Jhf3liqrGGXyTJSIFe4nqlJ5A5KaMZ2l/vbM3Wh3KSybots/wfWVzNLK4D1NZluDlSQIbIEPx6oyA==} + + '@typeschema/class-validator@0.3.0': + resolution: {integrity: sha512-OJSFeZDIQ8EK1HTljKLT5CItM2wsbgczLN8tMEfz3I1Lmhc5TBfkZ0eikFzUC16tI3d1Nag7um6TfCgp2I2Bww==} + peerDependencies: + class-validator: ^0.14.1 + peerDependenciesMeta: + class-validator: + optional: true + + '@typeschema/core@0.14.0': + resolution: {integrity: sha512-Ia6PtZHcL3KqsAWXjMi5xIyZ7XMH4aSnOQes8mfMLx+wGFGtGRNlwe6Y7cYvX+WfNK67OL0/HSe9t8QDygV0/w==} + peerDependencies: + '@types/json-schema': ^7.0.15 + peerDependenciesMeta: + '@types/json-schema': + optional: true + '@typescript-eslint/eslint-plugin@8.22.0': resolution: {integrity: sha512-4Uta6REnz/xEJMvwf72wdUnC3rr4jAQf5jnTkeRQ9b6soxLxhDEbS/pfMPoJLDfFPNVRdryqWUIV/2GZzDJFZw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -1055,6 +1125,14 @@ packages: resolution: {integrity: sha512-AWpYAXnUgvLNabGTy3uBylkgZoosva/miNd1I8Bz3SjotmQPbVqhO4Cczo8AsZ44XVErEBPr/CRSgaj8sG7g0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@vinejs/compiler@3.0.0': + resolution: {integrity: sha512-v9Lsv59nR56+bmy2p0+czjZxsLHwaibJ+SV5iK9JJfehlJMa501jUJQqqz4X/OqKXrxtE3uTQmSqjUqzF3B2mw==} + engines: {node: '>=18.0.0'} + + '@vinejs/vine@3.0.0': + resolution: {integrity: sha512-GeCAHLzKkL2kMFqatgqyiiNh+FILOSAV8x8imBDo6AWQ91w30Kaxw4FnzUDqgcd9z8aCYOBQ7RJxBBGfyr+USQ==} + engines: {node: '>=18.16.0'} + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: @@ -1106,6 +1184,9 @@ packages: resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} engines: {node: '>= 0.4'} + arktype@2.0.4: + resolution: {integrity: sha512-S68rWVDnJauwH7/QCm8zCUM3aTe9Xk6oRihdcc3FSUAtxCo/q1Fwq46JhcwB5Ufv1YStwdQRz+00Y/URlvbhAQ==} + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} @@ -1136,8 +1217,8 @@ packages: bindings@1.5.0: resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} - bits-ui@1.0.0-next.86: - resolution: {integrity: sha512-C2sTO3sasGoRhoMG2CUUsGfOhAoRL5Jc4pVB6AxoKQ+FBmX/uG9K1tW44eT/801iMoH+QeaH6fNCnoshpZtS8A==} + bits-ui@1.0.0-next.94: + resolution: {integrity: sha512-aGr6iMg16olEVFDYOUDfMB/uvExdmFuNLeILxv3MkwD3plTIbBBanA5/KLVfEnzT0uFgoEIrDV/unLfLG/BmEQ==} engines: {node: '>=18', pnpm: '>=8.7.0'} peerDependencies: svelte: ^5.11.0 @@ -1182,6 +1263,10 @@ packages: resolution: {integrity: sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==} engines: {node: '>= 6'} + camelcase@8.0.0: + resolution: {integrity: sha512-8WB3Jcas3swSvjIeA2yvCJ+Miyz5l1ZmB6HFb9R1317dt9LCQoswg/BGrmAmkWVEszSrrg4RwmO46qIm2OEnSA==} + engines: {node: '>=16'} + caniuse-lite@1.0.30001695: resolution: {integrity: sha512-vHyLade6wTgI2u1ec3WQBxv+2BrTERV28UXQu9LO6lZ9pYeMk34vjXFLOxo1A4UBA8XTL4njRQZdno/yYaSmWw==} @@ -1200,6 +1285,9 @@ packages: chownr@1.1.4: resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + class-validator@0.14.1: + resolution: {integrity: sha512-2VEG9JICxIqTpoK1eMzZqaV+u/EiwEJkMGzTrZf6sU/fwsnOITVgYJ8yojSy6CaXtO9V0Cc6ZQZ8h8m4UBuLwQ==} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -1251,6 +1339,9 @@ packages: engines: {node: '>=4'} hasBin: true + dayjs@1.11.13: + resolution: {integrity: sha512-oaMBel6gjolK862uaPQOVTA7q3TZhuSvuMQAAglQDOWYO9A91IrAOUJEyKVlqJlHE0vq5p5UXxzdPfMH/x6xNg==} + debug@4.4.0: resolution: {integrity: sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==} engines: {node: '>=6.0'} @@ -1395,6 +1486,9 @@ packages: eastasianwidth@0.2.0: resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + effect@3.12.10: + resolution: {integrity: sha512-fGg3sEN+l1rffWJvXICBTqyyzpa4y1uNo3aI/JLezJDmDk0Qj/WHiy6wVe0cecdr0eFU0XkZcFu2TWpgV8kBiw==} + electron-to-chromium@1.5.84: resolution: {integrity: sha512-I+DQ8xgafao9Ha6y0qjHHvpZ9OfyA1qKlkHkjywxzniORU2awxyz7f/iVJcULmrF2yrM3nHQf+iDjJtbbexd/g==} @@ -1424,6 +1518,12 @@ packages: peerDependencies: esbuild: '>=0.12 <1' + esbuild-runner@2.2.2: + resolution: {integrity: sha512-fRFVXcmYVmSmtYm2mL8RlUASt2TDkGh3uRcvHFOKNr/T58VrfVeKD9uT9nlgxk96u0LS0ehS/GY7Da/bXWKkhw==} + hasBin: true + peerDependencies: + esbuild: '*' + esbuild@0.18.20: resolution: {integrity: sha512-ceqxoedUrcayh7Y7ZX6NdbbDzGROiyVBgC4PriJThBKSVPWnnFHZAkfI1lJT8QFkOwH4qOS2SJkS4wvpGl8BpA==} engines: {node: '>=12'} @@ -1532,6 +1632,10 @@ packages: resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} engines: {node: '>=6'} + fast-check@3.23.2: + resolution: {integrity: sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==} + engines: {node: '>=8.0.0'} + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -1593,6 +1697,13 @@ packages: resolution: {integrity: sha512-KcpbcpuLNOwrEjnbpMC0gS+X8ciDoZE1kkqzat4a8vrprf+s9pKNQ/QIwWfbfs4ltgmFl3MD177SNTkve3BwGQ==} deprecated: 'Please upgrade to latest, formidable@v2 or formidable@v3! Check these notes: https://bit.ly/2ZEqIau' + formsnap@2.0.0: + resolution: {integrity: sha512-W61elddvdzeBEs10nNvwxQnx/FctJFHBXPk9uluNQAckHo1nuSUvSQGIjtLjTKIbQdQnwEOoxqWrk9tuv0U7hA==} + engines: {node: '>=18', pnpm: '>=8.7.0'} + peerDependencies: + svelte: ^5.0.0 + sveltekit-superforms: ^2.19.0 + fraction.js@4.3.7: resolution: {integrity: sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==} @@ -1737,6 +1848,9 @@ packages: resolution: {integrity: sha512-/imKNG4EbWNrVjoNC/1H5/9GFy+tqjGBHCaSsN+P2RnPqjsLmv6UD3Ej+Kj8nBWaRAwyk7kK5ZUc+OEatnTR3A==} hasBin: true + joi@17.13.3: + resolution: {integrity: sha512-otDA4ldcIx+ZXsKHWmp0YizCweVRZG96J10b0FevjfuncLO1oX59THoAmHkNubYJ+9gWsYsp5k8v4ib6oDv1fA==} + js-yaml@4.1.0: resolution: {integrity: sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==} hasBin: true @@ -1744,6 +1858,10 @@ packages: json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + json-schema-to-ts@3.1.1: + resolution: {integrity: sha512-+DWg8jCJG2TEnpy7kOm/7/AxaYoaRbjVB4LFZLySZlWn8exGs3A4OLJR966cVvU26N7X9TWxl+Jsw7dzAqKT6g==} + engines: {node: '>=16'} + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} @@ -1764,6 +1882,9 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} + libphonenumber-js@1.11.19: + resolution: {integrity: sha512-bW/Yp/9dod6fmyR+XqSUL1N5JE7QRxQ3KrBIbYS1FTv32e5i3SEtQVX+71CYNv8maWNSOgnlCoNp9X78f/cKiA==} + lilconfig@2.1.0: resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} engines: {node: '>=10'} @@ -1800,6 +1921,9 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} + memoize-weak@1.0.2: + resolution: {integrity: sha512-gj39xkrjEw7nCn4nJ1M5ms6+MyMlyiGmttzsqAUsAKn6bYKwuTHh/AO3cKPF8IBrTIYTxb0wWXFs3E//Y8VoWQ==} + merge2@1.4.1: resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} engines: {node: '>= 8'} @@ -1900,6 +2024,10 @@ packages: resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} engines: {node: '>=0.10.0'} + normalize-url@8.0.1: + resolution: {integrity: sha512-IO9QvjUMWxPQQhs60oOu10CRkWCiZzSUkzbXGGV9pviYl1fXYcvkzQ5jV9z8Y6un8ARoVRl4EtC6v6jNqbaJ/w==} + engines: {node: '>=14.16'} + object-assign@4.1.1: resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} engines: {node: '>=0.10.0'} @@ -2108,6 +2236,9 @@ packages: engines: {node: '>=14'} hasBin: true + property-expr@2.0.6: + resolution: {integrity: sha512-SVtmxhRE/CGkn3eZY1T6pC8Nln6Fr/lu1mKSgRud0eC73whjGfoAogbn78LkD8aFL0zz3bAFerKSnOl7NlErBA==} + pump@3.0.2: resolution: {integrity: sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==} @@ -2115,6 +2246,9 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + pure-rand@6.1.0: + resolution: {integrity: sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==} + qs@6.14.0: resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} engines: {node: '>=0.6'} @@ -2141,6 +2275,9 @@ packages: resolution: {integrity: sha512-h80JrZu/MHUZCyHu5ciuoI0+WxsCxzxJTILn6Fs8rxSnFPh+UVHYfeIxK1nVGugMqkfC4vJcBOYbkfkwYK0+gw==} engines: {node: '>= 14.18.0'} + regenerator-runtime@0.14.1: + resolution: {integrity: sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==} + resolve-from@4.0.0: resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} engines: {node: '>=4'} @@ -2284,6 +2421,10 @@ packages: engines: {node: '>= 7.0.0'} deprecated: Please upgrade to v9.0.0+ as we have fixed a public vulnerability with formidable dependency. Note that v9.0.0+ requires Node.js v14.18.0+. See https://github.com/ladjs/superagent/pull/1800 for insight. This project is supported and maintained by the team at Forward Email @ https://forwardemail.net + superstruct@2.0.2: + resolution: {integrity: sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==} + engines: {node: '>=14.0.0'} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -2325,6 +2466,17 @@ packages: peerDependencies: svelte: ^3.0.0 || ^4.0.0 || ^5.0.0-next.1 + svelte-sonner@0.3.28: + resolution: {integrity: sha512-K3AmlySeFifF/cKgsYNv5uXqMVNln0NBAacOYgmkQStLa/UoU0LhfAACU6Gr+YYC8bOCHdVmFNoKuDbMEsppJg==} + peerDependencies: + svelte: ^3.0.0 || ^4.0.0 || ^5.0.0-next.1 + + svelte-toolbelt@0.5.0: + resolution: {integrity: sha512-t3tenZcnfQoIeRuQf/jBU7bvTeT3TGkcEE+1EUr5orp0lR7NEpprflpuie3x9Dn0W9nOKqs3HwKGJeeN5Ok1sQ==} + engines: {node: '>=18', pnpm: '>=8.7.0'} + peerDependencies: + svelte: ^5.0.0-next.126 + svelte-toolbelt@0.7.1: resolution: {integrity: sha512-HcBOcR17Vx9bjaOceUvxkY3nGmbBmCBBbuWLLEWO6jtmWH8f/QoWmbyUfQZrpDINH39en1b8mptfPQT9VKQ1xQ==} engines: {node: '>=18', pnpm: '>=8.7.0'} @@ -2335,6 +2487,15 @@ packages: resolution: {integrity: sha512-H/Vs2O51bwILZbaNUSdr4P1NbLpOGsxl4jJAjd88ELjzRgeRi1BHqexcVGannDr7D1pmTYWWajzHOM7bMbtB9Q==} engines: {node: '>=18'} + sveltekit-superforms@2.23.1: + resolution: {integrity: sha512-SPj5ac4SMg8SPyP0Zi3ynwXJa7r9U1CTyn+YSyck67zLsjt367Sro4SZnl3yASrLd5kJ6Y57cgIdYJ2aWNArXw==} + peerDependencies: + '@sveltejs/kit': 1.x || 2.x + svelte: 3.x || 4.x || >=5.0.0-next.51 + + tabbable@6.2.0: + resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + tailwind-merge@2.5.4: resolution: {integrity: sha512-0q8cfZHMu9nuYP/b5Shb7Y7Sh1B7Nnl5GqNr1U+n2p6+mybvRtayrQ+0042Z5byvTA8ihjlP8Odo8/VnHbZu4Q==} @@ -2371,23 +2532,39 @@ packages: thenify@3.3.1: resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + tiny-case@1.0.3: + resolution: {integrity: sha512-Eet/eeMhkO6TX8mnUteS9zgPbUMQa4I6Kkp5ORiBD5476/m+PIRiumP5tmh5ioJpH7k51Kehawy2UDfsnxxY8Q==} + to-regex-range@5.0.1: resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} engines: {node: '>=8.0'} + toposort@2.0.2: + resolution: {integrity: sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg==} + totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} + ts-algebra@2.0.0: + resolution: {integrity: sha512-FPAhNPFMrkwz76P7cdjdmiShwMynZYN6SgOujD1urY4oNm80Ou9oMdmbR45LotcKOXoy7wSmHkRFE6Mxbrhefw==} + ts-api-utils@2.0.0: resolution: {integrity: sha512-xCt/TOAc+EOHS1XPnijD3/yzpH6qg2xppZO1YDqGoVsNXfQfzHpOdNuXwrwOU8u4ITXJyDCTyt8w5g1sZv9ynQ==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' + ts-deepmerge@7.0.2: + resolution: {integrity: sha512-akcpDTPuez4xzULo5NwuoKwYRtjQJ9eoNfBACiBMaXwNAx7B1PKfe5wqUFJuW5uKzQ68YjDFwPaWHDG1KnFGsA==} + engines: {node: '>=14.13.1'} + ts-interface-checker@0.1.13: resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + tslib@2.4.0: + resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} + tslib@2.8.1: resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} @@ -2398,6 +2575,10 @@ packages: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} + type-fest@2.19.0: + resolution: {integrity: sha512-RAH822pAdBgcNMAfWnCBU3CFZcfZ/i1eZjwFU/dsLKumyuuP3niueg2UAukXYF0E2AAoc82ZSSf9J0WQBinzHA==} + engines: {node: '>=12.20'} + typescript-eslint@8.22.0: resolution: {integrity: sha512-Y2rj210FW1Wb6TWXzQc5+P+EWI9/zdS57hLEc0gnyuvdzWo8+Y8brKlbj0muejonhMI/xAZCnZZwjbIfv1CkOw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} @@ -2425,6 +2606,21 @@ packages: util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} + valibot@0.31.1: + resolution: {integrity: sha512-2YYIhPrnVSz/gfT2/iXVTrSj92HwchCt9Cga/6hX4B26iCz9zkIsGTS0HjDYTZfTi1Un0X6aRvhBi1cfqs/i0Q==} + + valibot@1.0.0-beta.11: + resolution: {integrity: sha512-Ztl5Iks1Ql7Z6CwkS5oyqguN3G8tmUiNlsHpqbDt6DLMpm+eu+n8Q7f921gI3uHvNZ8xDVkd4cEJP5t+lELOfw==} + peerDependencies: + typescript: '>=5' + peerDependenciesMeta: + typescript: + optional: true + + validator@13.12.0: + resolution: {integrity: sha512-c1Q0mCiPlgdTVVVIJIrBuxNicYE+t/7oKeI9MWLj3fh/uq2Pxh/3eeWbVZ4OcGW1TUf53At0njHw5SMdA3tmMg==} + engines: {node: '>= 0.10'} + vite-imagetools@7.0.5: resolution: {integrity: sha512-OOvVnaBTqJJ2J7X1cM1qpH4pj9jsfTxia1VSuWeyXtf+OnP8d0YI1LHpv8y2NT47wg+n7XiTgh3BvcSffuBWrw==} engines: {node: '>=18.0.0'} @@ -2510,9 +2706,20 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yup@1.6.1: + resolution: {integrity: sha512-JED8pB50qbA4FOkDol0bYF/p60qSEDQqBD0/qeIrUCG1KbPBIQ776fCUNb9ldbPcSTxA69g/47XTo4TqWiuXOA==} + zimmerframe@1.1.2: resolution: {integrity: sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==} + zod-to-json-schema@3.24.1: + resolution: {integrity: sha512-3h08nf3Vw3Wl3PK+q3ow/lIil81IT2Oa7YpQyUUDsEWbXveMesdfK1xBd2RhCkynwZndAxixji/7SYJJowr62w==} + peerDependencies: + zod: ^3.24.1 + + zod@3.24.1: + resolution: {integrity: sha512-muH7gBL9sI1nciMZV67X5fTKKBLtwpZ5VBp1vsOQzj1MhrBZ4wlVCm3gedKZWLp0Oyel8sIGfeiz54Su+OVT+A==} + snapshots: '@alloc/quick-lru@5.2.0': {} @@ -2522,6 +2729,19 @@ snapshots: '@jridgewell/gen-mapping': 0.3.8 '@jridgewell/trace-mapping': 0.3.25 + '@ark/schema@0.39.0': + dependencies: + '@ark/util': 0.39.0 + optional: true + + '@ark/util@0.39.0': + optional: true + + '@babel/runtime@7.26.7': + dependencies: + regenerator-runtime: 0.14.1 + optional: true + '@drizzle-team/brocli@0.10.2': {} '@emnapi/runtime@1.3.1': @@ -2795,6 +3015,9 @@ snapshots: '@eslint/core': 0.10.0 levn: 0.4.1 + '@exodus/schemasafe@1.3.0': + optional: true + '@floating-ui/core@1.6.9': dependencies: '@floating-ui/utils': 0.2.9 @@ -2810,6 +3033,23 @@ snapshots: '@fontsource-variable/smooch-sans@5.1.1': {} + '@gcornut/valibot-json-schema@0.31.0': + dependencies: + valibot: 0.31.1 + optionalDependencies: + '@types/json-schema': 7.0.15 + esbuild: 0.24.2 + esbuild-runner: 2.2.2(esbuild@0.24.2) + optional: true + + '@hapi/hoek@9.3.0': + optional: true + + '@hapi/topo@5.1.0': + dependencies: + '@hapi/hoek': 9.3.0 + optional: true + '@humanfs/core@0.19.1': {} '@humanfs/node@0.16.6': @@ -2947,6 +3187,9 @@ snapshots: '@polka/url@1.0.0-next.28': {} + '@poppinss/macroable@1.0.4': + optional: true + '@rollup/plugin-commonjs@28.0.2(rollup@4.31.0)': dependencies: '@rollup/pluginutils': 5.1.4(rollup@4.31.0) @@ -3040,6 +3283,20 @@ snapshots: '@rollup/rollup-win32-x64-msvc@4.31.0': optional: true + '@sideway/address@4.1.5': + dependencies: + '@hapi/hoek': 9.3.0 + optional: true + + '@sideway/formula@3.0.1': + optional: true + + '@sideway/pinpoint@2.0.0': + optional: true + + '@sinclair/typebox@0.34.16': + optional: true + '@sveltejs/adapter-node@5.2.12(@sveltejs/kit@2.16.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))': dependencies: '@rollup/plugin-commonjs': 28.0.2(rollup@4.31.0) @@ -3134,6 +3391,23 @@ snapshots: dependencies: '@types/spotify-api': 0.0.25 + '@types/validator@13.12.2': + optional: true + + '@typeschema/class-validator@0.3.0(@types/json-schema@7.0.15)(class-validator@0.14.1)': + dependencies: + '@typeschema/core': 0.14.0(@types/json-schema@7.0.15) + optionalDependencies: + class-validator: 0.14.1 + transitivePeerDependencies: + - '@types/json-schema' + optional: true + + '@typeschema/core@0.14.0(@types/json-schema@7.0.15)': + optionalDependencies: + '@types/json-schema': 7.0.15 + optional: true + '@typescript-eslint/eslint-plugin@8.22.0(@typescript-eslint/parser@8.22.0(eslint@9.19.0(jiti@1.21.7))(typescript@5.7.3))(eslint@9.19.0(jiti@1.21.7))(typescript@5.7.3)': dependencies: '@eslint-community/regexpp': 4.12.1 @@ -3211,6 +3485,21 @@ snapshots: '@typescript-eslint/types': 8.22.0 eslint-visitor-keys: 4.2.0 + '@vinejs/compiler@3.0.0': + optional: true + + '@vinejs/vine@3.0.0': + dependencies: + '@poppinss/macroable': 1.0.4 + '@types/validator': 13.12.2 + '@vinejs/compiler': 3.0.0 + camelcase: 8.0.0 + dayjs: 1.11.13 + dlv: 1.1.3 + normalize-url: 8.0.1 + validator: 13.12.0 + optional: true + acorn-jsx@5.3.2(acorn@8.14.0): dependencies: acorn: 8.14.0 @@ -3251,6 +3540,12 @@ snapshots: aria-query@5.3.2: {} + arktype@2.0.4: + dependencies: + '@ark/schema': 0.39.0 + '@ark/util': 0.39.0 + optional: true + asynckit@0.4.0: {} autoprefixer@10.4.20(postcss@8.5.1): @@ -3280,7 +3575,7 @@ snapshots: dependencies: file-uri-to-path: 1.0.0 - bits-ui@1.0.0-next.86(svelte@5.19.1): + bits-ui@1.0.0-next.94(svelte@5.19.1): dependencies: '@floating-ui/core': 1.6.9 '@floating-ui/dom': 1.6.13 @@ -3289,6 +3584,7 @@ snapshots: runed: 0.23.2(svelte@5.19.1) svelte: 5.19.1 svelte-toolbelt: 0.7.1(svelte@5.19.1) + tabbable: 6.2.0 bl@4.1.0: dependencies: @@ -3337,6 +3633,9 @@ snapshots: camelcase-css@2.0.1: {} + camelcase@8.0.0: + optional: true + caniuse-lite@1.0.30001695: {} chalk@4.1.2: @@ -3362,6 +3661,13 @@ snapshots: chownr@1.1.4: {} + class-validator@0.14.1: + dependencies: + '@types/validator': 13.12.2 + libphonenumber-js: 1.11.19 + validator: 13.12.0 + optional: true + clsx@2.1.1: {} color-convert@2.0.1: @@ -3404,6 +3710,9 @@ snapshots: cssesc@3.0.0: {} + dayjs@1.11.13: + optional: true + debug@4.4.0: dependencies: ms: 2.1.3 @@ -3450,6 +3759,11 @@ snapshots: eastasianwidth@0.2.0: {} + effect@3.12.10: + dependencies: + fast-check: 3.23.2 + optional: true + electron-to-chromium@1.5.84: {} emoji-regex@8.0.0: {} @@ -3475,6 +3789,13 @@ snapshots: transitivePeerDependencies: - supports-color + esbuild-runner@2.2.2(esbuild@0.24.2): + dependencies: + esbuild: 0.24.2 + source-map-support: 0.5.21 + tslib: 2.4.0 + optional: true + esbuild@0.18.20: optionalDependencies: '@esbuild/android-arm': 0.18.20 @@ -3675,6 +3996,11 @@ snapshots: expand-template@2.0.3: {} + fast-check@3.23.2: + dependencies: + pure-rand: 6.1.0 + optional: true + fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -3734,6 +4060,12 @@ snapshots: formidable@1.2.6: {} + formsnap@2.0.0(svelte@5.19.1)(sveltekit-superforms@2.23.1(@sveltejs/kit@2.16.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(@types/json-schema@7.0.15)(svelte@5.19.1)(typescript@5.7.3)): + dependencies: + svelte: 5.19.1 + svelte-toolbelt: 0.5.0(svelte@5.19.1) + sveltekit-superforms: 2.23.1(@sveltejs/kit@2.16.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(@types/json-schema@7.0.15)(svelte@5.19.1)(typescript@5.7.3) + fraction.js@4.3.7: {} fs-constants@1.0.0: {} @@ -3861,12 +4193,27 @@ snapshots: jiti@1.21.7: {} + joi@17.13.3: + dependencies: + '@hapi/hoek': 9.3.0 + '@hapi/topo': 5.1.0 + '@sideway/address': 4.1.5 + '@sideway/formula': 3.0.1 + '@sideway/pinpoint': 2.0.0 + optional: true + js-yaml@4.1.0: dependencies: argparse: 2.0.1 json-buffer@3.0.1: {} + json-schema-to-ts@3.1.1: + dependencies: + '@babel/runtime': 7.26.7 + ts-algebra: 2.0.0 + optional: true + json-schema-traverse@0.4.1: {} json-stable-stringify-without-jsonify@1.0.1: {} @@ -3884,6 +4231,9 @@ snapshots: prelude-ls: 1.2.1 type-check: 0.4.0 + libphonenumber-js@1.11.19: + optional: true + lilconfig@2.1.0: {} lilconfig@3.1.3: {} @@ -3910,6 +4260,8 @@ snapshots: math-intrinsics@1.1.0: {} + memoize-weak@1.0.2: {} + merge2@1.4.1: {} methods@1.1.2: {} @@ -3979,6 +4331,9 @@ snapshots: normalize-range@0.1.2: {} + normalize-url@8.0.1: + optional: true + object-assign@4.1.1: {} object-hash@3.0.0: {} @@ -4115,6 +4470,9 @@ snapshots: prettier@3.4.2: {} + property-expr@2.0.6: + optional: true + pump@3.0.2: dependencies: end-of-stream: 1.4.4 @@ -4122,6 +4480,9 @@ snapshots: punycode@2.3.1: {} + pure-rand@6.1.0: + optional: true + qs@6.14.0: dependencies: side-channel: 1.1.0 @@ -4151,6 +4512,9 @@ snapshots: readdirp@4.1.1: {} + regenerator-runtime@0.14.1: + optional: true + resolve-from@4.0.0: {} resolve-pkg-maps@1.0.0: {} @@ -4360,6 +4724,9 @@ snapshots: transitivePeerDependencies: - supports-color + superstruct@2.0.2: + optional: true + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -4402,6 +4769,16 @@ snapshots: dependencies: svelte: 5.19.1 + svelte-sonner@0.3.28(svelte@5.19.1): + dependencies: + svelte: 5.19.1 + + svelte-toolbelt@0.5.0(svelte@5.19.1): + dependencies: + clsx: 2.1.1 + style-to-object: 1.0.8 + svelte: 5.19.1 + svelte-toolbelt@0.7.1(svelte@5.19.1): dependencies: clsx: 2.1.1 @@ -4426,6 +4803,35 @@ snapshots: magic-string: 0.30.17 zimmerframe: 1.1.2 + sveltekit-superforms@2.23.1(@sveltejs/kit@2.16.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(@types/json-schema@7.0.15)(svelte@5.19.1)(typescript@5.7.3): + dependencies: + '@sveltejs/kit': 2.16.1(@sveltejs/vite-plugin-svelte@5.0.3(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)))(svelte@5.19.1)(vite@6.0.11(@types/node@22.13.1)(jiti@1.21.7)(yaml@2.7.0)) + devalue: 5.1.1 + memoize-weak: 1.0.2 + svelte: 5.19.1 + ts-deepmerge: 7.0.2 + optionalDependencies: + '@exodus/schemasafe': 1.3.0 + '@gcornut/valibot-json-schema': 0.31.0 + '@sinclair/typebox': 0.34.16 + '@typeschema/class-validator': 0.3.0(@types/json-schema@7.0.15)(class-validator@0.14.1) + '@vinejs/vine': 3.0.0 + arktype: 2.0.4 + class-validator: 0.14.1 + effect: 3.12.10 + joi: 17.13.3 + json-schema-to-ts: 3.1.1 + superstruct: 2.0.2 + valibot: 1.0.0-beta.11(typescript@5.7.3) + yup: 1.6.1 + zod: 3.24.1 + zod-to-json-schema: 3.24.1(zod@3.24.1) + transitivePeerDependencies: + - '@types/json-schema' + - typescript + + tabbable@6.2.0: {} + tailwind-merge@2.5.4: {} tailwind-merge@2.6.0: {} @@ -4489,18 +4895,32 @@ snapshots: dependencies: any-promise: 1.3.0 + tiny-case@1.0.3: + optional: true + to-regex-range@5.0.1: dependencies: is-number: 7.0.0 + toposort@2.0.2: + optional: true + totalist@3.0.1: {} + ts-algebra@2.0.0: + optional: true + ts-api-utils@2.0.0(typescript@5.7.3): dependencies: typescript: 5.7.3 + ts-deepmerge@7.0.2: {} + ts-interface-checker@0.1.13: {} + tslib@2.4.0: + optional: true + tslib@2.8.1: {} tunnel-agent@0.6.0: @@ -4511,6 +4931,9 @@ snapshots: dependencies: prelude-ls: 1.2.1 + type-fest@2.19.0: + optional: true + typescript-eslint@8.22.0(eslint@9.19.0(jiti@1.21.7))(typescript@5.7.3): dependencies: '@typescript-eslint/eslint-plugin': 8.22.0(@typescript-eslint/parser@8.22.0(eslint@9.19.0(jiti@1.21.7))(typescript@5.7.3))(eslint@9.19.0(jiti@1.21.7))(typescript@5.7.3) @@ -4537,6 +4960,17 @@ snapshots: util-deprecate@1.0.2: {} + valibot@0.31.1: + optional: true + + valibot@1.0.0-beta.11(typescript@5.7.3): + optionalDependencies: + typescript: 5.7.3 + optional: true + + validator@13.12.0: + optional: true + vite-imagetools@7.0.5(rollup@4.31.0): dependencies: '@rollup/pluginutils': 5.1.4(rollup@4.31.0) @@ -4586,4 +5020,19 @@ snapshots: yocto-queue@0.1.0: {} + yup@1.6.1: + dependencies: + property-expr: 2.0.6 + tiny-case: 1.0.3 + toposort: 2.0.2 + type-fest: 2.19.0 + optional: true + zimmerframe@1.1.2: {} + + zod-to-json-schema@3.24.1(zod@3.24.1): + dependencies: + zod: 3.24.1 + optional: true + + zod@3.24.1: {} diff --git a/src/lib/server/db/schema.ts b/src/lib/server/db/schema.ts index 01ed1b3..0da2640 100644 --- a/src/lib/server/db/schema.ts +++ b/src/lib/server/db/schema.ts @@ -1,6 +1,25 @@ -import { sqliteTable, text, integer } from 'drizzle-orm/sqlite-core'; +import { relations } from 'drizzle-orm/relations'; +import { sqliteTable, text } from 'drizzle-orm/sqlite-core'; +import { nanoid } from 'nanoid'; -export const user = sqliteTable('user', { - id: integer('id').primaryKey(), - age: integer('age') +export const questions = sqliteTable('questions', { + id: text('id') + .primaryKey() + .$defaultFn(() => nanoid()), + creator: text('creator').notNull(), // session token + content: text('content').notNull().unique() }); + +export const answers = sqliteTable('answers', { + id: text('id') + .primaryKey() + .$defaultFn(() => nanoid()), + creator: text('creator').notNull(), // session token + content: text('content').notNull(), + questionId: text('question_id').references(() => questions.id) +}); + +// Relations +export const questionsRelations = relations(questions, ({ many }) => ({ + answers: many(answers) +})); diff --git a/src/lib/types.ts b/src/lib/types.ts index 32a2578..29e7df1 100644 --- a/src/lib/types.ts +++ b/src/lib/types.ts @@ -1,4 +1,5 @@ import type { Picture } from 'vite-imagetools'; +import type { answers, questions } from './server/db/schema'; export type EnhancedImage = { src: string | Picture; @@ -75,3 +76,6 @@ export type Tag = { }; export type TagsObj = Record; + +export type Answer = typeof answers.$inferSelect; +export type Question = typeof questions.$inferSelect & { answers: Answer[] }; diff --git a/src/routes/api/rahvatarkus/answer/+server.ts b/src/routes/api/rahvatarkus/answer/+server.ts new file mode 100644 index 0000000..6e1d684 --- /dev/null +++ b/src/routes/api/rahvatarkus/answer/+server.ts @@ -0,0 +1,72 @@ +import { json } from '@sveltejs/kit'; +import { db } from '$lib/server/db'; +import { questions, answers } from '$lib/server/db/schema'; +import { eq } from 'drizzle-orm'; + +const maxAnswers = 5; + +export async function POST({ locals, request }) { + const { userId, questionId, content }: { userId: string; questionId: string; content: string } = + await request.json(); + const { session } = locals; + + if (!session?.data?.userId) { + return; + } + + const user = session.data.userId; + + if (!user || !userId || user !== userId) { + return json({ error: 'Unauthorized' }, { status: 401 }); + } + + if (!content) { + return json({ error: 'Answer is required' }, { status: 400 }); + } + + if (!questionId) { + return json({ error: 'No question specified' }, { status: 400 }); + } + + const question = await db + .select({ + question: questions + }) + .from(questions) + .where(eq(questions.id, questionId)) + .limit(1); + + if (!question) { + return json({ error: 'Question not found' }, { status: 400 }); + } + + if (question[0].question.creator === user) { + return json({ error: 'Not allowed to answer your own question' }, { status: 400 }); + } + + const currentAnswers = await db + .select({ + answer: answers + }) + .from(answers) + .where(eq(answers.questionId, questionId)); + + if (currentAnswers.length >= maxAnswers) { + return json({ error: 'No more answers needed for this question' }, { status: 400 }); + } + + try { + const [newAnswer] = await db + .insert(answers) + .values({ + content: content, + creator: userId, + questionId: questionId + }) + .returning(); + + return json(newAnswer); + } catch (e) { + return json({ error: e }, { status: 400 }); + } +} diff --git a/src/routes/api/rahvatarkus/archive/[limit]/[[offset]]/+server.ts b/src/routes/api/rahvatarkus/archive/[limit]/[[offset]]/+server.ts new file mode 100644 index 0000000..e30a027 --- /dev/null +++ b/src/routes/api/rahvatarkus/archive/[limit]/[[offset]]/+server.ts @@ -0,0 +1,52 @@ +import { json } from '@sveltejs/kit'; +import { db } from '$lib/server/db'; +import { questions, answers } from '$lib/server/db/schema'; +import { eq, sql } from 'drizzle-orm'; +import type { Question } from '$lib/types'; + +export async function GET({ params }) { + const limit = parseInt(params.limit) || 10; + const offset = parseInt(params.offset) || 0; + + // Get total count + const [{ total }] = await db + .select({ + total: sql`count(DISTINCT ${questions.id})` + }) + .from(questions) + .innerJoin(answers, eq(questions.id, answers.questionId)); + + const results = await db + .select({ + question: questions, + answers: answers + }) + .from(questions) + .innerJoin(answers, eq(questions.id, answers.questionId)) + .limit(limit) + .offset(offset); + + // Group answers by question + type QuestionMap = { + [key: string]: Question; + }; + + const questionsWithAnswers = results.reduce((acc, row) => { + const questionId = row.question.id; + + if (!acc[questionId]) { + acc[questionId] = { + ...row.question, + answers: [] + }; + } + + if (row.answers) { + acc[questionId].answers.push(row.answers); + } + + return acc; + }, {}); + + return json({ data: Object.values(questionsWithAnswers), meta: { limit, offset, total } }); +} diff --git a/src/routes/api/rahvatarkus/question/+server.ts b/src/routes/api/rahvatarkus/question/+server.ts new file mode 100644 index 0000000..f9b69a9 --- /dev/null +++ b/src/routes/api/rahvatarkus/question/+server.ts @@ -0,0 +1,67 @@ +import { json } from '@sveltejs/kit'; +import { db } from '$lib/server/db'; +import { questions, answers } from '$lib/server/db/schema'; +import { eq, count, and, not, sql } from 'drizzle-orm'; + +export async function GET({ locals }) { + const { session } = locals; + + if (!session?.data?.userId) { + return; + } + + const user = session.data.userId; + + const questionWithAnswerCount = await db + .select({ + id: questions.id, + content: questions.content, + answerCount: count(answers.id) + }) + .from(questions) + .leftJoin(answers, eq(questions.id, answers.questionId)) + .groupBy(questions.id) + .having(and(sql`${count(answers.id)} < 5`, not(eq(questions.creator, user)))) + .orderBy(sql`RANDOM()`) + .limit(1); + + if (!questionWithAnswerCount.length) { + return json({ error: 'No questions available' }, { status: 404 }); + } + + return json(questionWithAnswerCount[0]); +} + +export async function POST({ locals, request }) { + const { userId, content }: { userId: string; content: string } = await request.json(); + const { session } = locals; + + if (!session?.data?.userId) { + return; + } + + const user = session.data.userId; + + if (!user || !userId || user !== userId) { + console.log(user, userId); + return json({ error: 'Unauthorized' }, { status: 401 }); + } + + if (!content) { + return json({ error: 'Content is required' }, { status: 400 }); + } + + try { + const [newQuestion] = await db + .insert(questions) + .values({ + content: content.at(-1) === '?' ? content.slice(0, -1) : content, + creator: userId + }) + .returning(); + + return json(newQuestion); + } catch (e) { + return json({ error: e }, { status: 400 }); + } +} diff --git a/src/routes/vinge/+layout.svelte b/src/routes/vinge/+layout.svelte index 8608759..42c4473 100644 --- a/src/routes/vinge/+layout.svelte +++ b/src/routes/vinge/+layout.svelte @@ -1,6 +1,8 @@ + + + + +{#await data.streamed.archive} +

loading

+{:then archive} + + {#each archive.data as question} + 0)} value={question.id}> + {question.content}? + +
    + {#each question.answers as answer} +
  1. + {answer.content} +
  2. + {/each} +
+
+
+ {/each} +
+ + {#snippet children({ pages, currentPage })} + + + + + {#each pages as page (page.key)} + {#if page.type === 'ellipsis'} + + + + {:else} + + + {page.value} + + + {/if} + {/each} + + + + + {/snippet} + +{/await} diff --git a/src/routes/vinge/rahvatarkus/answer-form.svelte b/src/routes/vinge/rahvatarkus/answer-form.svelte new file mode 100644 index 0000000..b0d5195 --- /dev/null +++ b/src/routes/vinge/rahvatarkus/answer-form.svelte @@ -0,0 +1,50 @@ + + +{#if data.question} +
+ + + {#snippet children({ props })} + {data.question.content}? + + {/snippet} + + + + + + {#snippet children({ props })} + + {/snippet} + + + + Vasta +
+{/if} diff --git a/src/routes/vinge/rahvatarkus/answer-schema.ts b/src/routes/vinge/rahvatarkus/answer-schema.ts new file mode 100644 index 0000000..59fbad8 --- /dev/null +++ b/src/routes/vinge/rahvatarkus/answer-schema.ts @@ -0,0 +1,8 @@ +import { z } from 'zod'; + +export const formSchema = z.object({ + questionId: z.string().length(21), + answer: z.string().min(2).max(250) +}); + +export type FormSchema = typeof formSchema; diff --git a/src/routes/vinge/rahvatarkus/question-form.svelte b/src/routes/vinge/rahvatarkus/question-form.svelte new file mode 100644 index 0000000..3c2c25c --- /dev/null +++ b/src/routes/vinge/rahvatarkus/question-form.svelte @@ -0,0 +1,39 @@ + + +
+ + + {#snippet children({ props })} + Uus küsimus + + {/snippet} + + Küsi ükskõik mida sellelt kollektiiv intelektilt. + + + Küsi +
diff --git a/src/routes/vinge/rahvatarkus/question-schema.ts b/src/routes/vinge/rahvatarkus/question-schema.ts new file mode 100644 index 0000000..6d7d365 --- /dev/null +++ b/src/routes/vinge/rahvatarkus/question-schema.ts @@ -0,0 +1,7 @@ +import { z } from 'zod'; + +export const formSchema = z.object({ + question: z.string().min(2).max(50) +}); + +export type FormSchema = typeof formSchema;