From f0d045bba988aae9a740b7042bf50604bcfbd90e Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Mon, 14 Apr 2025 10:45:13 +0200 Subject: [PATCH 01/88] Add svelte test project --- package-lock.json | 1363 ++++- package.json | 5 + test-sveltekit/.gitignore | 24 + test-sveltekit/.npmrc | 1 + test-sveltekit/.prettierignore | 6 + test-sveltekit/.prettierrc | 15 + test-sveltekit/README.md | 38 + test-sveltekit/e2e/demo.test.ts | 6 + test-sveltekit/eslint.config.js | 36 + test-sveltekit/package-lock.json | 5210 +++++++++++++++++ test-sveltekit/package.json | 45 + test-sveltekit/playwright.config.ts | 9 + test-sveltekit/src/app.css | 1 + test-sveltekit/src/app.d.ts | 13 + test-sveltekit/src/app.html | 12 + test-sveltekit/src/demo.spec.ts | 7 + test-sveltekit/src/lib/index.ts | 1 + test-sveltekit/src/routes/+layout.svelte | 7 + test-sveltekit/src/routes/+page.svelte | 2 + test-sveltekit/src/routes/page.svelte.test.ts | 11 + test-sveltekit/static/favicon.png | Bin 0 -> 1571 bytes test-sveltekit/svelte.config.js | 18 + test-sveltekit/tsconfig.json | 19 + test-sveltekit/vite.config.ts | 33 + test-sveltekit/vitest-setup-client.ts | 18 + tsconfig.json | 6 +- 26 files changed, 6697 insertions(+), 209 deletions(-) create mode 100644 test-sveltekit/.gitignore create mode 100644 test-sveltekit/.npmrc create mode 100644 test-sveltekit/.prettierignore create mode 100644 test-sveltekit/.prettierrc create mode 100644 test-sveltekit/README.md create mode 100644 test-sveltekit/e2e/demo.test.ts create mode 100644 test-sveltekit/eslint.config.js create mode 100644 test-sveltekit/package-lock.json create mode 100644 test-sveltekit/package.json create mode 100644 test-sveltekit/playwright.config.ts create mode 100644 test-sveltekit/src/app.css create mode 100644 test-sveltekit/src/app.d.ts create mode 100644 test-sveltekit/src/app.html create mode 100644 test-sveltekit/src/demo.spec.ts create mode 100644 test-sveltekit/src/lib/index.ts create mode 100644 test-sveltekit/src/routes/+layout.svelte create mode 100644 test-sveltekit/src/routes/+page.svelte create mode 100644 test-sveltekit/src/routes/page.svelte.test.ts create mode 100644 test-sveltekit/static/favicon.png create mode 100644 test-sveltekit/svelte.config.js create mode 100644 test-sveltekit/tsconfig.json create mode 100644 test-sveltekit/vite.config.ts create mode 100644 test-sveltekit/vitest-setup-client.ts diff --git a/package-lock.json b/package-lock.json index 8e201cfd..ee0e6e66 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,8 @@ "devDependencies": { "@commander-js/extra-typings": "^12.1.0", "@edge-runtime/vm": "^3.2.0", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", "@types/inquirer": "^9.0.7", "@types/node": "20.6.0", "@types/react": "^18.3.12", @@ -40,6 +42,8 @@ "npm-run-all": "^4.1.5", "react-dom": "^18.3.1", "shelljs": "^0.8.5", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", "tsup": "^8.0.1", "typescript": "^5.5.2", "valibot": "^0.35.0", @@ -48,6 +52,7 @@ "peerDependencies": { "@auth/core": "^0.37.0", "convex": "^1.17.0", + "convex-svelte": "^0.0.11", "react": "^18.2.0 || ^19.0.0-0" }, "peerDependenciesMeta": { @@ -56,14 +61,27 @@ } } }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/@auth/core": { - "version": "0.37.3", - "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.37.3.tgz", - "integrity": "sha512-qcffDLwxB9iUYH8GHq68w/KU8jtjAbjjk9xnpoKhjX3+QcntaQ2MKVSkTTocmA6ElpL5vK2xR9CXfQ98dvGnyg==", + "version": "0.37.4", + "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.37.4.tgz", + "integrity": "sha512-HOXJwXWXQRhbBDHlMU0K/6FT1v+wjtzdKhsNg0ZN7/gne6XPsIrjZ4daMcFnbq0Z/vsAbYBinQhhua0d77v7qw==", + "license": "ISC", "peer": true, "dependencies": { "@panva/hkdf": "^1.2.1", - "cookie": "1.0.1", "jose": "^5.9.6", "oauth4webapi": "^3.1.1", "preact": "10.24.3", @@ -603,12 +621,14 @@ } }, "node_modules/@esbuild/android-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", - "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", + "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", "cpu": [ "arm" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -619,12 +639,14 @@ } }, "node_modules/@esbuild/android-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", - "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", + "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -635,12 +657,14 @@ } }, "node_modules/@esbuild/android-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", - "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", + "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", "cpu": [ "x64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -651,12 +675,14 @@ } }, "node_modules/@esbuild/darwin-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", - "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", + "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -667,12 +693,14 @@ } }, "node_modules/@esbuild/darwin-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", - "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", + "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", "cpu": [ "x64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -683,12 +711,14 @@ } }, "node_modules/@esbuild/freebsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", - "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", + "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -699,12 +729,14 @@ } }, "node_modules/@esbuild/freebsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", - "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", + "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", "cpu": [ "x64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -715,12 +747,14 @@ } }, "node_modules/@esbuild/linux-arm": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", - "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", + "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", "cpu": [ "arm" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -731,12 +765,14 @@ } }, "node_modules/@esbuild/linux-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", - "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", + "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -747,12 +783,14 @@ } }, "node_modules/@esbuild/linux-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", - "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", + "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", "cpu": [ "ia32" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -763,12 +801,14 @@ } }, "node_modules/@esbuild/linux-loong64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", - "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", + "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", "cpu": [ "loong64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -779,12 +819,14 @@ } }, "node_modules/@esbuild/linux-mips64el": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", - "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", + "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", "cpu": [ "mips64el" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -795,12 +837,14 @@ } }, "node_modules/@esbuild/linux-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", - "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", + "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", "cpu": [ "ppc64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -811,12 +855,14 @@ } }, "node_modules/@esbuild/linux-riscv64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", - "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", + "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", "cpu": [ "riscv64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -827,12 +873,14 @@ } }, "node_modules/@esbuild/linux-s390x": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", - "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", + "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", "cpu": [ "s390x" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -843,12 +891,14 @@ } }, "node_modules/@esbuild/linux-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", - "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", + "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", "cpu": [ "x64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -858,13 +908,33 @@ "node": ">=18" } }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", + "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, "node_modules/@esbuild/netbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", - "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", + "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", "cpu": [ "x64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -875,12 +945,14 @@ } }, "node_modules/@esbuild/openbsd-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", - "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", + "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -891,12 +963,14 @@ } }, "node_modules/@esbuild/openbsd-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", - "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", + "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", "cpu": [ "x64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -907,12 +981,14 @@ } }, "node_modules/@esbuild/sunos-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", - "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", + "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", "cpu": [ "x64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -923,12 +999,14 @@ } }, "node_modules/@esbuild/win32-arm64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", - "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", + "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", "cpu": [ "arm64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -939,12 +1017,14 @@ } }, "node_modules/@esbuild/win32-ia32": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", - "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", + "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", "cpu": [ "ia32" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -955,12 +1035,14 @@ } }, "node_modules/@esbuild/win32-x64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", - "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", + "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", "cpu": [ "x64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -1615,7 +1697,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1629,7 +1710,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1638,22 +1718,20 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } }, "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "license": "MIT" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -2331,6 +2409,7 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz", "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==", + "license": "MIT", "peer": true, "funding": { "url": "https://github.com/sponsors/panva" @@ -2346,6 +2425,13 @@ "node": ">=14" } }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.29.1", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz", @@ -2599,6 +2685,96 @@ "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", "dev": true }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", + "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.20.5", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.20.5.tgz", + "integrity": "sha512-zT/97KvVUo19jEGZa972ls7KICjPCB53j54TVxnEFT5VEwL16G+YFqRVwJbfxh7AmS7/Ptr1rKF7Qt4FBMDNlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^0.6.0", + "devalue": "^5.1.0", + "esm-env": "^1.2.2", + "import-meta-resolve": "^4.1.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.6.0", + "sirv": "^3.0.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.3 || ^6.0.0" + } + }, + "node_modules/@sveltejs/kit/node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.0.3.tgz", + "integrity": "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", + "debug": "^4.4.0", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.15", + "vitefu": "^1.0.4" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte/node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", + "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.7" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, "node_modules/@swc/counter": { "version": "0.1.3", "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", @@ -2625,11 +2801,17 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", - "dev": true + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" }, "node_modules/@types/inquirer": { "version": "9.0.7", @@ -2725,6 +2907,7 @@ "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.21.0.tgz", "integrity": "sha512-tbsV1jPne5CkFQCgPBcDOt30ItF7aJoZL997JSF7MhGQqOeT3svWRYxiqlfA5RUdlHN6Fi+EI9bxqbdyAUZjYQ==", "dev": true, + "license": "BSD-2-Clause", "peer": true, "dependencies": { "@typescript-eslint/scope-manager": "6.21.0", @@ -3025,10 +3208,10 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", - "dev": true, + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "license": "MIT", "bin": { "acorn": "bin/acorn" }, @@ -3137,6 +3320,19 @@ "node": ">= 8" } }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/arctic": { "version": "1.9.0", "resolved": "https://registry.npmjs.org/arctic/-/arctic-1.9.0.tgz", @@ -3151,6 +3347,15 @@ "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", "dev": true }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/array-buffer-byte-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", @@ -3227,6 +3432,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -3583,6 +3797,15 @@ "node": ">=0.8" } }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/color": { "version": "4.2.3", "resolved": "https://registry.npmjs.org/color/-/color-4.2.3.tgz", @@ -3652,6 +3875,7 @@ "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", "dev": true, + "license": "MIT", "peer": true, "engines": { "node": ">=18" @@ -3684,59 +3908,531 @@ "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", "dev": true }, - "node_modules/convex": { - "version": "1.17.3", - "resolved": "https://registry.npmjs.org/convex/-/convex-1.17.3.tgz", - "integrity": "sha512-VrfxylZN8frti/2dNGvFpo1M+yIZxB+ibrGFfNk/5gBOUDQ471xxjVIRZW80oS7spRX4+1fS2YV1q3iVRmEOkw==", + "node_modules/convex": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/convex/-/convex-1.23.0.tgz", + "integrity": "sha512-Mz2GpCrw3wXR+TWQgUjQPLkZ5ZhnSSJbvZ/+GUdBY4yMwPpoPw5T6DszAFUB2o1SKyhmyes1iYGijueNsZb/Xw==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "esbuild": "0.25.1", + "jwt-decode": "^4.0.0", + "prettier": "3.5.2" + }, + "bin": { + "convex": "bin/main.js" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=7.0.0" + }, + "peerDependencies": { + "@auth0/auth0-react": "^2.0.1", + "@clerk/clerk-react": "^4.12.8 || ^5.0.0", + "react": "^17.0.2 || ^18.0.0 || ^19.0.0-0 || ^19.0.0", + "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0-0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@auth0/auth0-react": { + "optional": true + }, + "@clerk/clerk-react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/convex-svelte": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/convex-svelte/-/convex-svelte-0.0.11.tgz", + "integrity": "sha512-N/29gg5Zqy72vKL4xHSLk3jGwXVKIWXPs6xzq6KxGL84y/D6hG85pG2CPOzn08EzMmByts5FTkJ5p3var6yDng==", + "license": "Apache-2.0", + "peer": true, + "peerDependencies": { + "convex": "^1.10.0", + "svelte": "^5.0.0" + } + }, + "node_modules/convex-test": { + "version": "0.0.20", + "resolved": "https://registry.npmjs.org/convex-test/-/convex-test-0.0.20.tgz", + "integrity": "sha512-sCNGl/fh4AUFkAKepRbIOA6GNbO5DSPuL5yBbbuOWamXXdzfftAzjrxchJ8226GK5QEJxwSrK4tSl1eSW7sgyQ==", + "dev": true, + "peerDependencies": { + "convex": "^1.10.0" + } + }, + "node_modules/convex/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/android-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/android-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/android-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/darwin-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-loong64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-s390x": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/sunos-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/win32-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/win32-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/win32-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/esbuild": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "hasInstallScript": true, + "license": "MIT", "peer": true, - "dependencies": { - "esbuild": "0.23.0", - "jwt-decode": "^3.1.2", - "prettier": "3.2.5" - }, "bin": { - "convex": "bin/main.js" + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=18.0.0", - "npm": ">=7.0.0" - }, - "peerDependencies": { - "@auth0/auth0-react": "^2.0.1", - "@clerk/clerk-react": "^4.12.8 || ^5.0.0", - "react": "^17.0.2 || ^18.0.0 || ^19.0.0-0", - "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0-0" + "node": ">=18" }, - "peerDependenciesMeta": { - "@auth0/auth0-react": { - "optional": true - }, - "@clerk/clerk-react": { - "optional": true - }, - "react": { - "optional": true - }, - "react-dom": { - "optional": true - } - } - }, - "node_modules/convex-test": { - "version": "0.0.20", - "resolved": "https://registry.npmjs.org/convex-test/-/convex-test-0.0.20.tgz", - "integrity": "sha512-sCNGl/fh4AUFkAKepRbIOA6GNbO5DSPuL5yBbbuOWamXXdzfftAzjrxchJ8226GK5QEJxwSrK4tSl1eSW7sgyQ==", - "dev": true, - "peerDependencies": { - "convex": "^1.10.0" + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.1", + "@esbuild/android-arm": "0.25.1", + "@esbuild/android-arm64": "0.25.1", + "@esbuild/android-x64": "0.25.1", + "@esbuild/darwin-arm64": "0.25.1", + "@esbuild/darwin-x64": "0.25.1", + "@esbuild/freebsd-arm64": "0.25.1", + "@esbuild/freebsd-x64": "0.25.1", + "@esbuild/linux-arm": "0.25.1", + "@esbuild/linux-arm64": "0.25.1", + "@esbuild/linux-ia32": "0.25.1", + "@esbuild/linux-loong64": "0.25.1", + "@esbuild/linux-mips64el": "0.25.1", + "@esbuild/linux-ppc64": "0.25.1", + "@esbuild/linux-riscv64": "0.25.1", + "@esbuild/linux-s390x": "0.25.1", + "@esbuild/linux-x64": "0.25.1", + "@esbuild/netbsd-arm64": "0.25.1", + "@esbuild/netbsd-x64": "0.25.1", + "@esbuild/openbsd-arm64": "0.25.1", + "@esbuild/openbsd-x64": "0.25.1", + "@esbuild/sunos-x64": "0.25.1", + "@esbuild/win32-arm64": "0.25.1", + "@esbuild/win32-ia32": "0.25.1", + "@esbuild/win32-x64": "0.25.1" } }, - "node_modules/convex/node_modules/jwt-decode": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-3.1.2.tgz", - "integrity": "sha512-UfpWE/VZn0iP50d8cz9NrZLM9lSWhcJ+0Gt/nm4by88UL+J1SiKN8/5dkjMmbEzwL2CAe+67GsegCbIKtbp75A==", - "peer": true - }, "node_modules/cookie": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.1.tgz", @@ -4026,12 +4722,13 @@ } }, "node_modules/debug": { - "version": "4.3.4", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", - "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", "dev": true, + "license": "MIT", "dependencies": { - "ms": "2.1.2" + "ms": "^2.1.3" }, "engines": { "node": ">=6.0" @@ -4060,6 +4757,16 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/defaults": { "version": "1.0.4", "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.4.tgz", @@ -4117,6 +4824,13 @@ "node": ">=8" } }, + "node_modules/devalue": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", + "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", + "dev": true, + "license": "MIT" + }, "node_modules/diff-sequences": { "version": "29.6.3", "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", @@ -4319,10 +5033,12 @@ } }, "node_modules/esbuild": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", - "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "dev": true, "hasInstallScript": true, + "license": "MIT", "peer": true, "bin": { "esbuild": "bin/esbuild" @@ -4331,39 +5047,42 @@ "node": ">=18" }, "optionalDependencies": { - "@esbuild/aix-ppc64": "0.23.0", - "@esbuild/android-arm": "0.23.0", - "@esbuild/android-arm64": "0.23.0", - "@esbuild/android-x64": "0.23.0", - "@esbuild/darwin-arm64": "0.23.0", - "@esbuild/darwin-x64": "0.23.0", - "@esbuild/freebsd-arm64": "0.23.0", - "@esbuild/freebsd-x64": "0.23.0", - "@esbuild/linux-arm": "0.23.0", - "@esbuild/linux-arm64": "0.23.0", - "@esbuild/linux-ia32": "0.23.0", - "@esbuild/linux-loong64": "0.23.0", - "@esbuild/linux-mips64el": "0.23.0", - "@esbuild/linux-ppc64": "0.23.0", - "@esbuild/linux-riscv64": "0.23.0", - "@esbuild/linux-s390x": "0.23.0", - "@esbuild/linux-x64": "0.23.0", - "@esbuild/netbsd-x64": "0.23.0", - "@esbuild/openbsd-arm64": "0.23.0", - "@esbuild/openbsd-x64": "0.23.0", - "@esbuild/sunos-x64": "0.23.0", - "@esbuild/win32-arm64": "0.23.0", - "@esbuild/win32-ia32": "0.23.0", - "@esbuild/win32-x64": "0.23.0" + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" } }, "node_modules/esbuild/node_modules/@esbuild/aix-ppc64": { - "version": "0.23.0", - "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", - "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", + "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", "cpu": [ "ppc64" ], + "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -4538,6 +5257,12 @@ "node": "*" } }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "license": "MIT" + }, "node_modules/espree": { "version": "9.6.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", @@ -4579,6 +5304,15 @@ "node": ">=0.10" } }, + "node_modules/esrap": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.6.tgz", + "integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -4717,6 +5451,20 @@ "reusify": "^1.0.4" } }, + "node_modules/fdir": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", + "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, "node_modules/file-entry-cache": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", @@ -5568,6 +6316,15 @@ "node": ">=8" } }, + "node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6" + } + }, "node_modules/is-regex": { "version": "1.1.4", "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", @@ -5784,6 +6541,16 @@ "json-buffer": "3.0.1" } }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -5855,6 +6622,12 @@ "url": "https://github.com/sponsors/antfu" } }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "license": "MIT" + }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -5992,12 +6765,12 @@ } }, "node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "@jridgewell/sourcemap-codec": "^1.5.0" } }, "node_modules/memfs": { @@ -6057,6 +6830,18 @@ "node": ">=8.6" } }, + "node_modules/micromatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/mimic-fn": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", @@ -6102,11 +6887,32 @@ "ufo": "^1.5.3" } }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" }, "node_modules/mute-stream": { "version": "1.0.0", @@ -6766,11 +7572,12 @@ "dev": true }, "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "license": "MIT", "engines": { - "node": ">=8.6" + "node": ">=12" }, "funding": { "url": "https://github.com/sponsors/jonschlinkert" @@ -6893,6 +7700,7 @@ "version": "10.24.3", "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz", "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==", + "license": "MIT", "peer": true, "funding": { "type": "opencollective", @@ -6903,6 +7711,7 @@ "version": "6.5.11", "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz", "integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==", + "license": "MIT", "peer": true, "peerDependencies": { "preact": ">=10" @@ -6918,9 +7727,10 @@ } }, "node_modules/prettier": { - "version": "3.2.5", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", - "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.2.tgz", + "integrity": "sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==", + "license": "MIT", "peer": true, "bin": { "prettier": "bin/prettier.cjs" @@ -6966,6 +7776,7 @@ "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", "integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==", "devOptional": true, + "license": "MIT", "peer": true, "dependencies": { "loose-envify": "^1.1.0" @@ -7045,6 +7856,19 @@ "node": ">=8.10.0" } }, + "node_modules/readdirp/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/rechoir": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", @@ -7226,6 +8050,19 @@ "tslib": "^2.1.0" } }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/safe-array-concat": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", @@ -7313,6 +8150,13 @@ "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==" }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "dev": true, + "license": "MIT" + }, "node_modules/set-function-length": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", @@ -7482,6 +8326,21 @@ "license": "MIT", "optional": true }, + "node_modules/sirv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", + "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -7885,6 +8744,85 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/svelte": { + "version": "5.26.2", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.26.2.tgz", + "integrity": "sha512-e2TEcGK2YKVwDWYy5OsptVclYgDvfY1E/8IzPiOq63uG/GDo/j5VUYTC9EinQNraoZalbMWN+5f5TYC1QlAqOw==", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "acorn": "^8.12.1", + "aria-query": "^5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "esm-env": "^1.2.1", + "esrap": "^1.4.6", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/svelte-check": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.1.6.tgz", + "integrity": "sha512-P7w/6tdSfk3zEVvfsgrp3h3DFC75jCdZjTQvgGJtjPORs1n7/v2VMPIoty3PWv7jnfEm3x0G/p9wH4pecTb0Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" + } + }, + "node_modules/svelte-check/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/svelte-check/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", @@ -7930,30 +8868,6 @@ "node": ">=12.0.0" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" - } - }, "node_modules/tinypool": { "version": "0.8.4", "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-0.8.4.tgz", @@ -7995,6 +8909,16 @@ "node": ">=8.0" } }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/tree-kill": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", @@ -9134,6 +10058,25 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/vitefu": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.6.tgz", + "integrity": "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, "node_modules/vitest": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", @@ -9564,6 +10507,12 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/zimmerframe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", + "license": "MIT" } } } diff --git a/package.json b/package.json index e11dcd2c..4438eb79 100644 --- a/package.json +++ b/package.json @@ -78,6 +78,7 @@ "peerDependencies": { "@auth/core": "^0.37.0", "convex": "^1.17.0", + "convex-svelte": "^0.0.11", "react": "^18.2.0 || ^19.0.0-0" }, "peerDependenciesMeta": { @@ -102,6 +103,10 @@ "eslint": "8.49.0", "inquirer": "^9.2.22", "next": "^15.0.3", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", "npm-run-all": "^4.1.5", "react-dom": "^18.3.1", "shelljs": "^0.8.5", diff --git a/test-sveltekit/.gitignore b/test-sveltekit/.gitignore new file mode 100644 index 00000000..bff793d5 --- /dev/null +++ b/test-sveltekit/.gitignore @@ -0,0 +1,24 @@ +test-results +node_modules + +# Output +.output +.vercel +.netlify +.wrangler +/.svelte-kit +/build + +# OS +.DS_Store +Thumbs.db + +# Env +.env +.env.* +!.env.example +!.env.test + +# Vite +vite.config.js.timestamp-* +vite.config.ts.timestamp-* diff --git a/test-sveltekit/.npmrc b/test-sveltekit/.npmrc new file mode 100644 index 00000000..b6f27f13 --- /dev/null +++ b/test-sveltekit/.npmrc @@ -0,0 +1 @@ +engine-strict=true diff --git a/test-sveltekit/.prettierignore b/test-sveltekit/.prettierignore new file mode 100644 index 00000000..6562bcbb --- /dev/null +++ b/test-sveltekit/.prettierignore @@ -0,0 +1,6 @@ +# Package Managers +package-lock.json +pnpm-lock.yaml +yarn.lock +bun.lock +bun.lockb diff --git a/test-sveltekit/.prettierrc b/test-sveltekit/.prettierrc new file mode 100644 index 00000000..7ebb855b --- /dev/null +++ b/test-sveltekit/.prettierrc @@ -0,0 +1,15 @@ +{ + "useTabs": true, + "singleQuote": true, + "trailingComma": "none", + "printWidth": 100, + "plugins": ["prettier-plugin-svelte", "prettier-plugin-tailwindcss"], + "overrides": [ + { + "files": "*.svelte", + "options": { + "parser": "svelte" + } + } + ] +} diff --git a/test-sveltekit/README.md b/test-sveltekit/README.md new file mode 100644 index 00000000..b5b29507 --- /dev/null +++ b/test-sveltekit/README.md @@ -0,0 +1,38 @@ +# sv + +Everything you need to build a Svelte project, powered by [`sv`](https://github.com/sveltejs/cli). + +## Creating a project + +If you're seeing this, you've probably already done this step. Congrats! + +```bash +# create a new project in the current directory +npx sv create + +# create a new project in my-app +npx sv create my-app +``` + +## Developing + +Once you've created a project and installed dependencies with `npm install` (or `pnpm install` or `yarn`), start a development server: + +```bash +npm run dev + +# or start the server and open the app in a new browser tab +npm run dev -- --open +``` + +## Building + +To create a production version of your app: + +```bash +npm run build +``` + +You can preview the production build with `npm run preview`. + +> To deploy your app, you may need to install an [adapter](https://svelte.dev/docs/kit/adapters) for your target environment. diff --git a/test-sveltekit/e2e/demo.test.ts b/test-sveltekit/e2e/demo.test.ts new file mode 100644 index 00000000..9985ce11 --- /dev/null +++ b/test-sveltekit/e2e/demo.test.ts @@ -0,0 +1,6 @@ +import { expect, test } from '@playwright/test'; + +test('home page has expected h1', async ({ page }) => { + await page.goto('/'); + await expect(page.locator('h1')).toBeVisible(); +}); diff --git a/test-sveltekit/eslint.config.js b/test-sveltekit/eslint.config.js new file mode 100644 index 00000000..ef07d322 --- /dev/null +++ b/test-sveltekit/eslint.config.js @@ -0,0 +1,36 @@ +import prettier from 'eslint-config-prettier'; +import js from '@eslint/js'; +import { includeIgnoreFile } from '@eslint/compat'; +import svelte from 'eslint-plugin-svelte'; +import globals from 'globals'; +import { fileURLToPath } from 'node:url'; +import ts from 'typescript-eslint'; +import svelteConfig from './svelte.config.js'; + +const gitignorePath = fileURLToPath(new URL('./.gitignore', import.meta.url)); + +export default ts.config( + includeIgnoreFile(gitignorePath), + js.configs.recommended, + ...ts.configs.recommended, + ...svelte.configs.recommended, + prettier, + ...svelte.configs.prettier, + { + languageOptions: { + globals: { ...globals.browser, ...globals.node } + }, + rules: { 'no-undef': 'off' } + }, + { + files: ['**/*.svelte', '**/*.svelte.ts', '**/*.svelte.js'], + languageOptions: { + parserOptions: { + projectService: true, + extraFileExtensions: ['.svelte'], + parser: ts.parser, + svelteConfig + } + } + } +); diff --git a/test-sveltekit/package-lock.json b/test-sveltekit/package-lock.json new file mode 100644 index 00000000..5ca7246d --- /dev/null +++ b/test-sveltekit/package-lock.json @@ -0,0 +1,5210 @@ +{ + "name": "test-sveltekit", + "version": "0.0.1", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "test-sveltekit", + "version": "0.0.1", + "devDependencies": { + "@eslint/compat": "^1.2.5", + "@eslint/js": "^9.18.0", + "@playwright/test": "^1.49.1", + "@sveltejs/adapter-auto": "^4.0.0", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@tailwindcss/vite": "^4.0.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/svelte": "^5.2.4", + "eslint": "^9.18.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-svelte": "^3.0.0", + "globals": "^16.0.0", + "jsdom": "^26.0.0", + "prettier": "^3.4.2", + "prettier-plugin-svelte": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.6.11", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", + "tailwindcss": "^4.0.0", + "typescript": "^5.0.0", + "typescript-eslint": "^8.20.0", + "vite": "^6.2.5", + "vitest": "^3.0.0" + } + }, + "node_modules/@adobe/css-tools": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz", + "integrity": "sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.1.1.tgz", + "integrity": "sha512-hpRD68SV2OMcZCsrbdkccTw5FXjNDLo5OuqSHyHZfwweGsDWZwDJ2+gONyNAbazZclobMirACLw0lk8WVxIqxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@csstools/css-calc": "^2.1.2", + "@csstools/css-color-parser": "^3.0.8", + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3", + "lru-cache": "^10.4.3" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.25.9", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.25.9.tgz", + "integrity": "sha512-Ed61U6XJc3CVRfkERJWDz4dJwKe7iLmmJsbOGu9wSloNSFttHV0I8g6UAgb7qnK5ly5bGLPd4oXZlxCdANBOWQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.27.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz", + "integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-5.0.2.tgz", + "integrity": "sha512-JqWH1vsgdGcw2RR6VliXXdA0/59LttzlU8UlRT/iUUsEeWfYq8I+K0yhihEUTTHLRm1EXvpsCx3083EU15ecsA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=18" + } + }, + "node_modules/@csstools/css-calc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-2.1.2.tgz", + "integrity": "sha512-TklMyb3uBB28b5uQdxjReG4L80NxAqgrECqLZFQbyLekwwlcDDS8r3f07DKqeo8C4926Br0gf/ZDe17Zv4wIuw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "3.0.8", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-3.0.8.tgz", + "integrity": "sha512-pdwotQjCCnRPuNi06jFuP68cykU1f3ZWExLe/8MQ1LOs8Xq+fTkYgd+2V8mWUWMrOn9iS2HftPVaMZDaXzGbhQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^5.0.2", + "@csstools/css-calc": "^2.1.2" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^3.0.4", + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-3.0.4.tgz", + "integrity": "sha512-Up7rBoV77rv29d3uKHUIVubz1BTcgyUK72IvCQAbfbMv584xHcGKCKbWh7i8hPrRJ7qU4Y8IO3IY9m+iTB7P3A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^3.0.3" + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-3.0.3.tgz", + "integrity": "sha512-UJnjoFsmxfKUdNYdWgOB0mWUypuLvAfQPH1+pyvRJs6euowbFkFC6P13w1l8mJyi3vxYMxc9kld5jZEGRQs6bw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.2.tgz", + "integrity": "sha512-wCIboOL2yXZym2cgm6mlA742s9QeJ8DjGVaL39dLN4rRwrOgOyYSnOaFPhKZGLb2ngj4EyfAFjsNJwPXZvseag==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.2.tgz", + "integrity": "sha512-NQhH7jFstVY5x8CKbcfa166GoV0EFkaPkCKBQkdPJFvo5u+nGXLEH/ooniLb3QI8Fk58YAx7nsPLozUWfCBOJA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.2.tgz", + "integrity": "sha512-5ZAX5xOmTligeBaeNEPnPaeEuah53Id2tX4c2CVP3JaROTH+j4fnfHCkr1PjXMd78hMst+TlkfKcW/DlTq0i4w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.2.tgz", + "integrity": "sha512-Ffcx+nnma8Sge4jzddPHCZVRvIfQ0kMsUsCMcJRHkGJ1cDmhe4SsrYIjLUKn1xpHZybmOqCWwB0zQvsjdEHtkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.2.tgz", + "integrity": "sha512-MpM6LUVTXAzOvN4KbjzU/q5smzryuoNjlriAIx+06RpecwCkL9JpenNzpKd2YMzLJFOdPqBpuub6eVRP5IgiSA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.2.tgz", + "integrity": "sha512-5eRPrTX7wFyuWe8FqEFPG2cU0+butQQVNcT4sVipqjLYQjjh8a8+vUTfgBKM88ObB85ahsnTwF7PSIt6PG+QkA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.2.tgz", + "integrity": "sha512-mLwm4vXKiQ2UTSX4+ImyiPdiHjiZhIaE9QvC7sw0tZ6HoNMjYAqQpGyui5VRIi5sGd+uWq940gdCbY3VLvsO1w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.2.tgz", + "integrity": "sha512-6qyyn6TjayJSwGpm8J9QYYGQcRgc90nmfdUb0O7pp1s4lTY+9D0H9O02v5JqGApUyiHOtkz6+1hZNvNtEhbwRQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.2.tgz", + "integrity": "sha512-UHBRgJcmjJv5oeQF8EpTRZs/1knq6loLxTsjc3nxO9eXAPDLcWW55flrMVc97qFPbmZP31ta1AZVUKQzKTzb0g==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.2.tgz", + "integrity": "sha512-gq/sjLsOyMT19I8obBISvhoYiZIAaGF8JpeXu1u8yPv8BE5HlWYobmlsfijFIZ9hIVGYkbdFhEqC0NvM4kNO0g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.2.tgz", + "integrity": "sha512-bBYCv9obgW2cBP+2ZWfjYTU+f5cxRoGGQ5SeDbYdFCAZpYWrfjjfYwvUpP8MlKbP0nwZ5gyOU/0aUzZ5HWPuvQ==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.2.tgz", + "integrity": "sha512-SHNGiKtvnU2dBlM5D8CXRFdd+6etgZ9dXfaPCeJtz+37PIUlixvlIhI23L5khKXs3DIzAn9V8v+qb1TRKrgT5w==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.2.tgz", + "integrity": "sha512-hDDRlzE6rPeoj+5fsADqdUZl1OzqDYow4TB4Y/3PlKBD0ph1e6uPHzIQcv2Z65u2K0kpeByIyAjCmjn1hJgG0Q==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.2.tgz", + "integrity": "sha512-tsHu2RRSWzipmUi9UBDEzc0nLc4HtpZEI5Ba+Omms5456x5WaNuiG3u7xh5AO6sipnJ9r4cRWQB2tUjPyIkc6g==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.2.tgz", + "integrity": "sha512-k4LtpgV7NJQOml/10uPU0s4SAXGnowi5qBSjaLWMojNCUICNu7TshqHLAEbkBdAszL5TabfvQ48kK84hyFzjnw==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.2.tgz", + "integrity": "sha512-GRa4IshOdvKY7M/rDpRR3gkiTNp34M0eLTaC1a08gNrh4u488aPhuZOCpkF6+2wl3zAN7L7XIpOFBhnaE3/Q8Q==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.2.tgz", + "integrity": "sha512-QInHERlqpTTZ4FRB0fROQWXcYRD64lAoiegezDunLpalZMjcUcld3YzZmVJ2H/Cp0wJRZ8Xtjtj0cEHhYc/uUg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.2.tgz", + "integrity": "sha512-talAIBoY5M8vHc6EeI2WW9d/CkiO9MQJ0IOWX8hrLhxGbro/vBXJvaQXefW2cP0z0nQVTdQ/eNyGFV1GSKrxfw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.2.tgz", + "integrity": "sha512-voZT9Z+tpOxrvfKFyfDYPc4DO4rk06qamv1a/fkuzHpiVBMOhpjK+vBmWM8J1eiB3OLSMFYNaOaBNLXGChf5tg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.2.tgz", + "integrity": "sha512-dcXYOC6NXOqcykeDlwId9kB6OkPUxOEqU+rkrYVqJbK2hagWOMrsTGsMr8+rW02M+d5Op5NNlgMmjzecaRf7Tg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.2.tgz", + "integrity": "sha512-t/TkWwahkH0Tsgoq1Ju7QfgGhArkGLkF1uYz8nQS/PPFlXbP5YgRpqQR3ARRiC2iXoLTWFxc6DJMSK10dVXluw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.2.tgz", + "integrity": "sha512-cfZH1co2+imVdWCjd+D1gf9NjkchVhhdpgb1q5y6Hcv9TP6Zi9ZG/beI3ig8TvwT9lH9dlxLq5MQBBgwuj4xvA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.2.tgz", + "integrity": "sha512-7Loyjh+D/Nx/sOTzV8vfbB3GJuHdOQyrOryFdZvPHLf42Tk9ivBU5Aedi7iyX+x6rbn2Mh68T4qq1SDqJBQO5Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.2.tgz", + "integrity": "sha512-WRJgsz9un0nqZJ4MfhabxaD9Ft8KioqU3JMinOTvobbX6MOSUigSBlogP8QB3uxpJDsFS6yN+3FDBdqE5lg9kg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.2.tgz", + "integrity": "sha512-kM3HKb16VIXZyIeVrM1ygYmZBKybX8N4p754bw390wGO3Tf2j4L2/WYL+4suWujpgf6GBYs3jv7TyUivdd05JA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.6.0.tgz", + "integrity": "sha512-WhCn7Z7TauhBtmzhvKpoQs0Wwb/kBcy4CwpuI0/eEIr2Lx2auxmulAzLr91wVZJaz47iUZdkXOK7WlAfxGKCnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-visitor-keys": "^3.4.3" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.12.1.tgz", + "integrity": "sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/compat": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@eslint/compat/-/compat-1.2.8.tgz", + "integrity": "sha512-LqCYHdWL/QqKIJuZ/ucMAv8d4luKGs4oCPgpt8mWztQAtPrHfXKQ/XAUc8ljCHAfJCn6SvkpTcGt5Tsh8saowA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "peerDependencies": { + "eslint": "^9.10.0" + }, + "peerDependenciesMeta": { + "eslint": { + "optional": true + } + } + }, + "node_modules/@eslint/config-array": { + "version": "0.20.0", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.20.0.tgz", + "integrity": "sha512-fxlS1kkIjx8+vy2SjuCB94q3htSNrufYTXubwiBFeaQHbH6Ipi43gFJq2zCMt6PHhImH3Xmr0NksKDvchWlpQQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/object-schema": "^2.1.6", + "debug": "^4.3.1", + "minimatch": "^3.1.2" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/config-helpers": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.2.1.tgz", + "integrity": "sha512-RI17tsD2frtDu/3dmI7QRrD4bedNKPM08ziRYaC5AhkGrzIAJelm9kJU1TznK+apx6V+cqRz8tfpEeG3oIyjxw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/core": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.12.0.tgz", + "integrity": "sha512-cmrR6pytBuSMTaBweKoGMwu3EiHiEC+DoyupPmlZ0HxBJBtIxwe+j/E4XPIKNx+Q74c8lXKPwYawBf5glsTkHg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.1.tgz", + "integrity": "sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.24.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.24.0.tgz", + "integrity": "sha512-uIY/y3z0uvOGX8cp1C2fiC4+ZmBhp6yZWkojtHL1YEMnRt1Y63HB9TM17proGEmeG7HeUY+UP36F0aknKYTpYA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/object-schema": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.6.tgz", + "integrity": "sha512-RBMg5FRL0I0gs51M/guSAj5/e14VQ4tpZnQNWwuDT66P14I43ItmPfIZRhO9fUVIPOAQXU47atlywZ/czoqFPA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.2.8.tgz", + "integrity": "sha512-ZAoA40rNMPwSm+AeHpCq8STiNAwzWLJuP8Xv4CHIc9wv/PSuExjMrmjfYNj682vW0OOiZ1HKxzvjQr9XZIisQA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@eslint/core": "^0.13.0", + "levn": "^0.4.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@eslint/plugin-kit/node_modules/@eslint/core": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.13.0.tgz", + "integrity": "sha512-yfkgDw1KR66rkT5A8ci4irzDysN7FRpq3ttJolR88OqQikAWqwA8j5VZyas+vjyBNFIJ7MfybJ9plMILI2UrCw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/json-schema": "^7.0.15" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@humanfs/core": { + "version": "0.19.1", + "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", + "integrity": "sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node": { + "version": "0.16.6", + "resolved": "https://registry.npmjs.org/@humanfs/node/-/node-0.16.6.tgz", + "integrity": "sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@humanfs/core": "^0.19.1", + "@humanwhocodes/retry": "^0.3.0" + }, + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/@humanfs/node/node_modules/@humanwhocodes/retry": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.3.1.tgz", + "integrity": "sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.4.2.tgz", + "integrity": "sha512-xeO57FpIu4p1Ri3Jq/EXq4ClRm86dVF2z/+kvFnyqVYRavTZmaFaUBbWCOuuTh0o/g7DSsk6kc2vrS4Vl5oPOQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.8", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", + "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@playwright/test": { + "version": "1.51.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.51.1.tgz", + "integrity": "sha512-nM+kEaTSAoVlXmMPH10017vn3FSiFqr/bh4fKg9vmAdMfd9SDqRZNvPSiAHADc/itWak+qPvMPZQOPwCBW7k7Q==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright": "1.51.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", + "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz", + "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", + "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz", + "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz", + "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz", + "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz", + "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz", + "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz", + "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz", + "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-loongarch64-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz", + "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz", + "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz", + "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz", + "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz", + "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", + "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz", + "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz", + "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz", + "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz", + "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@sveltejs/acorn-typescript": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", + "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8.9.0" + } + }, + "node_modules/@sveltejs/adapter-auto": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-4.0.0.tgz", + "integrity": "sha512-kmuYSQdD2AwThymQF0haQhM8rE5rhutQXG4LNbnbShwhMO4qQGnKaaTy+88DuNSuoQDi58+thpq8XpHc1+oEKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "import-meta-resolve": "^4.1.0" + }, + "peerDependencies": { + "@sveltejs/kit": "^2.0.0" + } + }, + "node_modules/@sveltejs/kit": { + "version": "2.20.5", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.20.5.tgz", + "integrity": "sha512-zT/97KvVUo19jEGZa972ls7KICjPCB53j54TVxnEFT5VEwL16G+YFqRVwJbfxh7AmS7/Ptr1rKF7Qt4FBMDNlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^0.6.0", + "devalue": "^5.1.0", + "esm-env": "^1.2.2", + "import-meta-resolve": "^4.1.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.6.0", + "sirv": "^3.0.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.3 || ^6.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.0.3.tgz", + "integrity": "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", + "debug": "^4.4.0", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.15", + "vitefu": "^1.0.4" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@sveltejs/vite-plugin-svelte-inspector": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", + "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "^4.3.7" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^5.0.0", + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.1.3.tgz", + "integrity": "sha512-H/6r6IPFJkCfBJZ2dKZiPJ7Ueb2wbL592+9bQEl2r73qbX6yGnmQVIfiUvDRB2YI0a3PWDrzUwkvQx1XW1bNkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "enhanced-resolve": "^5.18.1", + "jiti": "^2.4.2", + "lightningcss": "1.29.2", + "tailwindcss": "4.1.3" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.1.3.tgz", + "integrity": "sha512-t16lpHCU7LBxDe/8dCj9ntyNpXaSTAgxWm1u2XQP5NiIu4KGSyrDJJRlK9hJ4U9yJxx0UKCVI67MJWFNll5mOQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.1.3", + "@tailwindcss/oxide-darwin-arm64": "4.1.3", + "@tailwindcss/oxide-darwin-x64": "4.1.3", + "@tailwindcss/oxide-freebsd-x64": "4.1.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.1.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.1.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.1.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.1.3", + "@tailwindcss/oxide-linux-x64-musl": "4.1.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.1.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.1.3" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.1.3.tgz", + "integrity": "sha512-cxklKjtNLwFl3mDYw4XpEfBY+G8ssSg9ADL4Wm6//5woi3XGqlxFsnV5Zb6v07dxw1NvEX2uoqsxO/zWQsgR+g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.1.3.tgz", + "integrity": "sha512-mqkf2tLR5VCrjBvuRDwzKNShRu99gCAVMkVsaEOFvv6cCjlEKXRecPu9DEnxp6STk5z+Vlbh1M5zY3nQCXMXhw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.1.3.tgz", + "integrity": "sha512-7sGraGaWzXvCLyxrc7d+CCpUN3fYnkkcso3rCzwUmo/LteAl2ZGCDlGvDD8Y/1D3ngxT8KgDj1DSwOnNewKhmg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.1.3.tgz", + "integrity": "sha512-E2+PbcbzIReaAYZe997wb9rId246yDkCwAakllAWSGqe6VTg9hHle67hfH6ExjpV2LSK/siRzBUs5wVff3RW9w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.1.3.tgz", + "integrity": "sha512-GvfbJ8wjSSjbLFFE3UYz4Eh8i4L6GiEYqCtA8j2Zd2oXriPuom/Ah/64pg/szWycQpzRnbDiJozoxFU2oJZyfg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.1.3.tgz", + "integrity": "sha512-35UkuCWQTeG9BHcBQXndDOrpsnt3Pj9NVIB4CgNiKmpG8GnCNXeMczkUpOoqcOhO6Cc/mM2W7kaQ/MTEENDDXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.1.3.tgz", + "integrity": "sha512-dm18aQiML5QCj9DQo7wMbt1Z2tl3Giht54uVR87a84X8qRtuXxUqnKQkRDK5B4bCOmcZ580lF9YcoMkbDYTXHQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.1.3.tgz", + "integrity": "sha512-LMdTmGe/NPtGOaOfV2HuO7w07jI3cflPrVq5CXl+2O93DCewADK0uW1ORNAcfu2YxDUS035eY2W38TxrsqngxA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.1.3.tgz", + "integrity": "sha512-aalNWwIi54bbFEizwl1/XpmdDrOaCjRFQRgtbv9slWjmNPuJJTIKPHf5/XXDARc9CneW9FkSTqTbyvNecYAEGw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.1.3.tgz", + "integrity": "sha512-PEj7XR4OGTGoboTIAdXicKuWl4EQIjKHKuR+bFy9oYN7CFZo0eu74+70O4XuERX4yjqVZGAkCdglBODlgqcCXg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.1.3.tgz", + "integrity": "sha512-T8gfxECWDBENotpw3HR9SmNiHC9AOJdxs+woasRZ8Q/J4VHN0OMs7F+4yVNZ9EVN26Wv6mZbK0jv7eHYuLJLwA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@tailwindcss/vite": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/vite/-/vite-4.1.3.tgz", + "integrity": "sha512-lUI/QaDxLtlV52Lho6pu07CG9pSnRYLOPmKGIQjyHdTBagemc6HmgZxyjGAQ/5HMPrNeWBfTVIpQl0/jLXvWHQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@tailwindcss/node": "4.1.3", + "@tailwindcss/oxide": "4.1.3", + "tailwindcss": "4.1.3" + }, + "peerDependencies": { + "vite": "^5.2.0 || ^6" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.0", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz", + "integrity": "sha512-pemlzrSESWbdAloYml3bAJMEfNh1Z7EduzqPKprCH5S341frlpYnUEW0H72dLxa6IsYr+mPno20GiSm+h9dEdQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "chalk": "^4.1.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/dom/node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/@testing-library/dom/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@testing-library/dom/node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@testing-library/jest-dom": { + "version": "6.6.3", + "resolved": "https://registry.npmjs.org/@testing-library/jest-dom/-/jest-dom-6.6.3.tgz", + "integrity": "sha512-IteBhl4XqYNkM54f4ejhLRJiZNqcSCoXUOG2CPK7qbD322KjQozM4kHQOfkG2oln9b9HTYqs+Sae8vBATubxxA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@adobe/css-tools": "^4.4.0", + "aria-query": "^5.0.0", + "chalk": "^3.0.0", + "css.escape": "^1.5.1", + "dom-accessibility-api": "^0.6.3", + "lodash": "^4.17.21", + "redent": "^3.0.0" + }, + "engines": { + "node": ">=14", + "npm": ">=6", + "yarn": ">=1" + } + }, + "node_modules/@testing-library/svelte": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/@testing-library/svelte/-/svelte-5.2.7.tgz", + "integrity": "sha512-aGhUaFmEXEVost4QOsbHUUbHLwi7ZZRRxAHFDO2Cmr0BZD3/3+XvaYEPq70Rdw0NRNjdqZHdARBEcrCOkPuAqw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@testing-library/dom": "^10.0.0" + }, + "engines": { + "node": ">= 10" + }, + "peerDependencies": { + "svelte": "^3 || ^4 || ^5 || ^5.0.0-next.0", + "vite": "*", + "vitest": "*" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + }, + "vitest": { + "optional": true + } + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.29.1.tgz", + "integrity": "sha512-ba0rr4Wfvg23vERs3eB+P3lfj2E+2g3lhWcCVukUuhtcdUx5lSIFZlGFEBHKr+3zizDa/TvZTptdNHVZWAkSBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/regexpp": "^4.10.0", + "@typescript-eslint/scope-manager": "8.29.1", + "@typescript-eslint/type-utils": "8.29.1", + "@typescript-eslint/utils": "8.29.1", + "@typescript-eslint/visitor-keys": "8.29.1", + "graphemer": "^1.4.0", + "ignore": "^5.3.1", + "natural-compare": "^1.4.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^8.0.0 || ^8.0.0-alpha.0", + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.29.1.tgz", + "integrity": "sha512-zczrHVEqEaTwh12gWBIJWj8nx+ayDcCJs06yoNMY0kwjMWDM6+kppljY+BxWI06d2Ja+h4+WdufDcwMnnMEWmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/scope-manager": "8.29.1", + "@typescript-eslint/types": "8.29.1", + "@typescript-eslint/typescript-estree": "8.29.1", + "@typescript-eslint/visitor-keys": "8.29.1", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-8.29.1.tgz", + "integrity": "sha512-2nggXGX5F3YrsGN08pw4XpMLO1Rgtnn4AzTegC2MDesv6q3QaTU5yU7IbS1tf1IwCR0Hv/1EFygLn9ms6LIpDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.29.1", + "@typescript-eslint/visitor-keys": "8.29.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-8.29.1.tgz", + "integrity": "sha512-DkDUSDwZVCYN71xA4wzySqqcZsHKic53A4BLqmrWFFpOpNSoxX233lwGu/2135ymTCR04PoKiEEEvN1gFYg4Tw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/typescript-estree": "8.29.1", + "@typescript-eslint/utils": "8.29.1", + "debug": "^4.3.4", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-8.29.1.tgz", + "integrity": "sha512-VT7T1PuJF1hpYC3AGm2rCgJBjHL3nc+A/bhOp9sGMKfi5v0WufsX/sHCFBfNTx2F+zA6qBc/PD0/kLRLjdt8mQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-8.29.1.tgz", + "integrity": "sha512-l1enRoSaUkQxOQnbi0KPUtqeZkSiFlqrx9/3ns2rEDhGKfTa+88RmXqedC1zmVTOWrLc2e6DEJrTA51C9iLH5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.29.1", + "@typescript-eslint/visitor-keys": "8.29.1", + "debug": "^4.3.4", + "fast-glob": "^3.3.2", + "is-glob": "^4.0.3", + "minimatch": "^9.0.4", + "semver": "^7.6.0", + "ts-api-utils": "^2.0.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.29.1.tgz", + "integrity": "sha512-QAkFEbytSaB8wnmB+DflhUPz6CLbFWE2SnSCrRMEa+KnXIzDYbpsn++1HGvnfAsUY44doDXmvRkO5shlM/3UfA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@typescript-eslint/scope-manager": "8.29.1", + "@typescript-eslint/types": "8.29.1", + "@typescript-eslint/typescript-estree": "8.29.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-8.29.1.tgz", + "integrity": "sha512-RGLh5CRaUEf02viP5c1Vh1cMGffQscyHe7HPAzGpfmfflFg1wUz2rYxd+OZqwpeypYvZ8UxSxuIpF++fmOzEcg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/types": "8.29.1", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@vitest/expect": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-3.1.1.tgz", + "integrity": "sha512-q/zjrW9lgynctNbwvFtQkGK9+vvHA5UzVi2V8APrp1C6fG6/MuYYkmlx4FubuqLycCeSdHD5aadWfua/Vr0EUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.1.1", + "@vitest/utils": "3.1.1", + "chai": "^5.2.0", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-3.1.1.tgz", + "integrity": "sha512-bmpJJm7Y7i9BBELlLuuM1J1Q6EQ6K5Ye4wcyOpOMXMcePYKSIYlpcrCm4l/O6ja4VJA5G2aMJiuZkZdnxlC3SA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/spy": "3.1.1", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.17" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-3.1.1.tgz", + "integrity": "sha512-dg0CIzNx+hMMYfNmSqJlLSXEmnNhMswcn3sXO7Tpldr0LiGmg3eXdLLhwkv2ZqgHb/d5xg5F7ezNFRA1fA13yA==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-3.1.1.tgz", + "integrity": "sha512-X/d46qzJuEDO8ueyjtKfxffiXraPRfmYasoC4i5+mlLEJ10UvPb0XH5M9C3gWuxd7BAQhpK42cJgJtq53YnWVA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/utils": "3.1.1", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-3.1.1.tgz", + "integrity": "sha512-bByMwaVWe/+1WDf9exFxWWgAixelSdiwo2p33tpqIlM14vW7PRV5ppayVXtfycqze4Qhtwag5sVhX400MLBOOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.1.1", + "magic-string": "^0.30.17", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-3.1.1.tgz", + "integrity": "sha512-+EmrUOOXbKzLkTDwlsc/xrwOlPDXyVk3Z6P6K4oiCndxz7YLpp/0R0UsWVOKT0IXWjjBJuSMk6D27qipaupcvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tinyspy": "^3.0.2" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-3.1.1.tgz", + "integrity": "sha512-1XIjflyaU2k3HMArJ50bwSh3wKWPD6Q47wz/NUSmRV0zNywPc4w79ARjg/i/aNINHwA+mIALhUVqD9/aUvZNgg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "3.1.1", + "loupe": "^3.1.3", + "tinyrainbow": "^2.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/acorn": { + "version": "8.14.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", + "integrity": "sha512-OvQ/2pUDKmgfCg++xsTX1wGxfTaszcHVcTctW4UJB4hibJx2HXxxO5UmVgyjMa+ZDsiaf5wWLXYpRWMmBI0QHg==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/agent-base": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.3.tgz", + "integrity": "sha512-jRR5wdylq8CkOe6hei19GGZnxM6rBGwFl3Bg0YItGDimvjGtAvdZk4Pu6Cl4u4Igsws4a1fd1Vq3ezrhn4KmFw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-query": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.2.tgz", + "integrity": "sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/chai": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.2.0.tgz", + "integrity": "sha512-mCuXncKXk5iCLhfhwTc0izo0gtEmpz5CtG2y8GiOINBlMVS6v8TMRc5TaLWKS6692m9+dVVfzgeVxR5UxWHTYw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, + "engines": { + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/clsx": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", + "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/css.escape": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/css.escape/-/css.escape-1.5.1.tgz", + "integrity": "sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "dev": true, + "license": "MIT", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/cssstyle": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.3.0.tgz", + "integrity": "sha512-6r0NiY0xizYqfBvWp1G7WXJ06/bZyrk7Dc6PHql82C/pKGUTKu4yAX4Y8JPamb1ob9nBKuxWzCGTRuGwU3yxJQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^3.1.1", + "rrweb-cssom": "^0.8.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/data-urls": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", + "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/debug": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.0.tgz", + "integrity": "sha512-6WTZ/IxCY/T6BALoZHaE4ctp9xm+Z5kY/pzYaCHRFeyVhojxlrm+46y68HA6hr0TcwEssoxNiDEUJQjfPZ/RYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.5.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.5.0.tgz", + "integrity": "sha512-8vDa8Qxvr/+d94hSh5P3IJwI5t8/c0KsMp+g8bNw9cY2icONa5aPfvKeieW1WlG0WQYwwhJ7mjui2xtiePQSXw==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/detect-libc": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.3.tgz", + "integrity": "sha512-bwy0MGW55bG41VqxxypOsdSdGqLwXPI/focwgTYCFMbdUiBAxLg9CFzG08sz2aqzknwiX7Hkl0bQENjg8iLByw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=8" + } + }, + "node_modules/devalue": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", + "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-accessibility-api": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", + "integrity": "sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==", + "dev": true, + "license": "MIT" + }, + "node_modules/enhanced-resolve": { + "version": "5.18.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.18.1.tgz", + "integrity": "sha512-ZSW3ma5GkcQBIpwZTSRAI8N71Uuwgs93IezB7mf7R60tC8ZbJideoDNKjHn2O9KIlx6rkGTTEk1xUCK2E1Y2Yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/es-module-lexer": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.6.0.tgz", + "integrity": "sha512-qqnD1yMU6tk/jnaMosogGySTZP8YtUgAffA9nMN+E/rjxcfRQ6IEk7IiozUjgxKoFHBGjTLnrHB/YC45r/59EQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/esbuild": { + "version": "0.25.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.2.tgz", + "integrity": "sha512-16854zccKPnC+toMywC+uKNeYSv+/eXkevRAfwRD/G9Cleq66m8XFIrigkbvauLLlCfDL45Q2cWegSg53gGBnQ==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.2", + "@esbuild/android-arm": "0.25.2", + "@esbuild/android-arm64": "0.25.2", + "@esbuild/android-x64": "0.25.2", + "@esbuild/darwin-arm64": "0.25.2", + "@esbuild/darwin-x64": "0.25.2", + "@esbuild/freebsd-arm64": "0.25.2", + "@esbuild/freebsd-x64": "0.25.2", + "@esbuild/linux-arm": "0.25.2", + "@esbuild/linux-arm64": "0.25.2", + "@esbuild/linux-ia32": "0.25.2", + "@esbuild/linux-loong64": "0.25.2", + "@esbuild/linux-mips64el": "0.25.2", + "@esbuild/linux-ppc64": "0.25.2", + "@esbuild/linux-riscv64": "0.25.2", + "@esbuild/linux-s390x": "0.25.2", + "@esbuild/linux-x64": "0.25.2", + "@esbuild/netbsd-arm64": "0.25.2", + "@esbuild/netbsd-x64": "0.25.2", + "@esbuild/openbsd-arm64": "0.25.2", + "@esbuild/openbsd-x64": "0.25.2", + "@esbuild/sunos-x64": "0.25.2", + "@esbuild/win32-arm64": "0.25.2", + "@esbuild/win32-ia32": "0.25.2", + "@esbuild/win32-x64": "0.25.2" + } + }, + "node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint": { + "version": "9.24.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.24.0.tgz", + "integrity": "sha512-eh/jxIEJyZrvbWRe4XuVclLPDYSYYYgLy5zXGGxD6j8zjSAxFEzI2fL/8xNq6O2yKqVt+eF2YhV+hxjV6UKXwQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.12.1", + "@eslint/config-array": "^0.20.0", + "@eslint/config-helpers": "^0.2.0", + "@eslint/core": "^0.12.0", + "@eslint/eslintrc": "^3.3.1", + "@eslint/js": "9.24.0", + "@eslint/plugin-kit": "^0.2.7", + "@humanfs/node": "^0.16.6", + "@humanwhocodes/module-importer": "^1.0.1", + "@humanwhocodes/retry": "^0.4.2", + "@types/estree": "^1.0.6", + "@types/json-schema": "^7.0.15", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.6", + "debug": "^4.3.2", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^8.3.0", + "eslint-visitor-keys": "^4.2.0", + "espree": "^10.3.0", + "esquery": "^1.5.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^8.0.0", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://eslint.org/donate" + }, + "peerDependencies": { + "jiti": "*" + }, + "peerDependenciesMeta": { + "jiti": { + "optional": true + } + } + }, + "node_modules/eslint-config-prettier": { + "version": "10.1.2", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-10.1.2.tgz", + "integrity": "sha512-Epgp/EofAUeEpIdZkW60MHKvPyru1ruQJxPL+WIycnaPApuseK0Zpkrh/FwL9oIpQvIhJwV7ptOy0DWUjTlCiA==", + "dev": true, + "license": "MIT", + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-svelte": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-svelte/-/eslint-plugin-svelte-3.5.1.tgz", + "integrity": "sha512-Qn1slddZHfqYiDO6IN8/iN3YL+VuHlgYjm30FT+hh0Jf/TX0jeZMTJXQMajFm5f6f6hURi+XO8P+NPYD+T4jkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.1", + "@jridgewell/sourcemap-codec": "^1.5.0", + "esutils": "^2.0.3", + "known-css-properties": "^0.35.0", + "postcss": "^8.4.49", + "postcss-load-config": "^3.1.4", + "postcss-safe-parser": "^7.0.0", + "semver": "^7.6.3", + "svelte-eslint-parser": "^1.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "eslint": "^8.57.1 || ^9.0.0", + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/eslint-scope": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.3.0.tgz", + "integrity": "sha512-pUNxi75F8MJ/GdeKtVLSbYg4ZI34J6C0C7sbL4YOp2exGwen7ZsuBqKzUhXd0qMQ362yET3z+uPwKeg/0C2XCQ==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", + "integrity": "sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/esm-env": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", + "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/espree": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", + "integrity": "sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.14.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^4.2.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esquery": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.6.0.tgz", + "integrity": "sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esrap": { + "version": "1.4.6", + "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.6.tgz", + "integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/expect-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.2.1.tgz", + "integrity": "sha512-/kP8CAwxzLVEeFrMm4kMmy4CCDlpipyA7MYLVrdJIkV0fYF0UaigQHRsxHiuY/GEea+bh4KSv3TIlgr+2UL6bw==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true, + "license": "MIT" + }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fdir": { + "version": "6.4.3", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", + "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/file-entry-cache": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", + "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "flat-cache": "^4.0.0" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", + "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/flatted": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.3.tgz", + "integrity": "sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-16.0.0.tgz", + "integrity": "sha512-iInW14XItCXET01CQFqudPOWP2jYMl7T+QRQT+UNcR/iQncN/F0UNpgd76iFkBPgNQb4+X3LV9tLJYzwh+Gl3A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true, + "license": "MIT" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz", + "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-encoding": "^3.1.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "agent-base": "^7.1.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", + "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-meta-resolve": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", + "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-reference": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", + "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "^1.0.6" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.2.tgz", + "integrity": "sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==", + "dev": true, + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "26.1.0", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-26.1.0.tgz", + "integrity": "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssstyle": "^4.2.1", + "data-urls": "^5.0.0", + "decimal.js": "^10.5.0", + "html-encoding-sniffer": "^4.0.0", + "http-proxy-agent": "^7.0.2", + "https-proxy-agent": "^7.0.6", + "is-potential-custom-element-name": "^1.0.1", + "nwsapi": "^2.2.16", + "parse5": "^7.2.1", + "rrweb-cssom": "^0.8.0", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^5.1.1", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^7.0.0", + "whatwg-encoding": "^3.1.1", + "whatwg-mimetype": "^4.0.0", + "whatwg-url": "^14.1.1", + "ws": "^8.18.0", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true, + "license": "MIT" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kleur": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", + "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/known-css-properties": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", + "integrity": "sha512-a/RAk2BfKk+WFGhhOCAYqSiFLc34k8Mt/6NWRI4joER0EYUzXIcFivjjnoD3+XU1DggLn/tZc3DOAgke7l8a4A==", + "dev": true, + "license": "MIT" + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lightningcss": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.29.2.tgz", + "integrity": "sha512-6b6gd/RUXKaw5keVdSEtqFVdzWnU5jMxTUjA2bVcMNPLwSQ08Sv/UodBVtETLCn7k4S1Ibxwh7k68IwLZPgKaA==", + "dev": true, + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-darwin-arm64": "1.29.2", + "lightningcss-darwin-x64": "1.29.2", + "lightningcss-freebsd-x64": "1.29.2", + "lightningcss-linux-arm-gnueabihf": "1.29.2", + "lightningcss-linux-arm64-gnu": "1.29.2", + "lightningcss-linux-arm64-musl": "1.29.2", + "lightningcss-linux-x64-gnu": "1.29.2", + "lightningcss-linux-x64-musl": "1.29.2", + "lightningcss-win32-arm64-msvc": "1.29.2", + "lightningcss-win32-x64-msvc": "1.29.2" + } + }, + "node_modules/lightningcss-darwin-arm64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.29.2.tgz", + "integrity": "sha512-cK/eMabSViKn/PG8U/a7aCorpeKLMlK0bQeNHmdb7qUnBkNPnL+oV5DjJUo0kqWsJUapZsM4jCfYItbqBDvlcA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-darwin-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.29.2.tgz", + "integrity": "sha512-j5qYxamyQw4kDXX5hnnCKMf3mLlHvG44f24Qyi2965/Ycz829MYqjrVg2H8BidybHBp9kom4D7DR5VqCKDXS0w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-freebsd-x64": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.29.2.tgz", + "integrity": "sha512-wDk7M2tM78Ii8ek9YjnY8MjV5f5JN2qNVO+/0BAGZRvXKtQrBC4/cn4ssQIpKIPP44YXw6gFdpUF+Ps+RGsCwg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.29.2.tgz", + "integrity": "sha512-IRUrOrAF2Z+KExdExe3Rz7NSTuuJ2HvCGlMKoquK5pjvo2JY4Rybr+NrKnq0U0hZnx5AnGsuFHjGnNT14w26sg==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.29.2.tgz", + "integrity": "sha512-KKCpOlmhdjvUTX/mBuaKemp0oeDIBBLFiU5Fnqxh1/DZ4JPZi4evEH7TKoSBFOSOV3J7iEmmBaw/8dpiUvRKlQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.29.2.tgz", + "integrity": "sha512-Q64eM1bPlOOUgxFmoPUefqzY1yV3ctFPE6d/Vt7WzLW4rKTv7MyYNky+FWxRpLkNASTnKQUaiMJ87zNODIrrKQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.29.2.tgz", + "integrity": "sha512-0v6idDCPG6epLXtBH/RPkHvYx74CVziHo6TMYga8O2EiQApnUPZsbR9nFNrg2cgBzk1AYqEd95TlrsL7nYABQg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.29.2.tgz", + "integrity": "sha512-rMpz2yawkgGT8RULc5S4WiZopVMOFWjiItBT7aSfDX4NQav6M44rhn5hjtkKzB+wMTRlLLqxkeYEtQ3dd9696w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.29.2.tgz", + "integrity": "sha512-nL7zRW6evGQqYVu/bKGK+zShyz8OVzsCotFgc7judbt6wnB2KbiKKJwBE4SGoDBQ1O94RjW4asrCjQL4i8Fhbw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.29.2", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.29.2.tgz", + "integrity": "sha512-EdIUW3B2vLuHmv7urfzMI/h2fmlnOQBk1xlsDxkN1tCWKjNFjfLhGxYk8C8mzpSfr+A6jFFIi8fU6LbQGsRWjA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/lilconfig": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.1.0.tgz", + "integrity": "sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "dev": true, + "license": "MIT" + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==", + "dev": true, + "license": "MIT" + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/loupe": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.3.tgz", + "integrity": "sha512-kkIp7XSkP78ZxJEsSxW3712C6teJVoeHHwgo9zJ380de7IYyJ2ISlxojcH2pC5OFLewESmnRi/+XCDIEEVyoug==", + "dev": true, + "license": "MIT" + }, + "node_modules/lru-cache": { + "version": "10.4.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.4.3.tgz", + "integrity": "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/magic-string": { + "version": "0.30.17", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.17.tgz", + "integrity": "sha512-sNPKHvyjVf7gyjwS4xGTaW/mCnF8wnjtifKBEhxfZ7E/S8tQ0rssrwGNn6q8JH/ohItJfSQp9mBtQYuTlH5QnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/min-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/min-indent/-/min-indent-1.0.1.tgz", + "integrity": "sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mri": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", + "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/nanoid": { + "version": "3.3.11", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.11.tgz", + "integrity": "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/nwsapi": { + "version": "2.2.20", + "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.20.tgz", + "integrity": "sha512-/ieB+mDe4MrrKMT8z+mQL8klXydZWGR5Dowt4RAGKbJ3kIGEx3X4ljUo+6V73IXtUPWgfOlU5B9MlGxFO5T+cA==", + "dev": true, + "license": "MIT" + }, + "node_modules/optionator": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", + "integrity": "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.5" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "license": "MIT", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse5": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.2.1.tgz", + "integrity": "sha512-BuBYQYlv1ckiPdQi/ohiivi9Sagc9JG+Ozs0r7b/0iK3sKmrb0b9FdWdBbOdx6hBCM/F9Ir82ofnBhtZOjCRPQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^4.5.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/playwright": { + "version": "1.51.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.51.1.tgz", + "integrity": "sha512-kkx+MB2KQRkyxjYPc3a0wLZZoDczmppyGJIvQ43l+aZihkaVvmu/21kiyaHeHjiFxjxNNFnUncKmcGIyOojsaw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.51.1" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.51.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.51.1.tgz", + "integrity": "sha512-/crRMj8+j/Nq5s8QcvegseuyeZPxpQCZb6HNk3Sos3BlZyAknRjoyJPFWkpNn8v0+P3WiwqFF8P+zQo4eqiNuw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/postcss": { + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "nanoid": "^3.3.8", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-load-config": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.4.tgz", + "integrity": "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==", + "dev": true, + "license": "MIT", + "dependencies": { + "lilconfig": "^2.0.5", + "yaml": "^1.10.2" + }, + "engines": { + "node": ">= 10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + "peerDependencies": { + "postcss": ">=8.0.9", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "postcss": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/postcss-load-config/node_modules/yaml": { + "version": "1.10.2", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz", + "integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/postcss-safe-parser": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/postcss-safe-parser/-/postcss-safe-parser-7.0.1.tgz", + "integrity": "sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-safe-parser" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=18.0" + }, + "peerDependencies": { + "postcss": "^8.4.31" + } + }, + "node_modules/postcss-scss": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/postcss-scss/-/postcss-scss-4.0.9.tgz", + "integrity": "sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss-scss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "engines": { + "node": ">=12.0" + }, + "peerDependencies": { + "postcss": "^8.4.29" + } + }, + "node_modules/postcss-selector-parser": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-7.1.0.tgz", + "integrity": "sha512-8sLjZwK0R+JlxlYcTuVnyT2v+htpdrjDOKuMcOVdYjt52Lh8hWRYpxBPoKx/Zg+bcjc3wx6fmQevMmUztS/ccA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.3.tgz", + "integrity": "sha512-QQtaxnoDJeAkDvDKWCLiwIXkTgRhwYDEQCghU9Z6q03iyek/rxRh/2lC3HB7P8sWT2xC/y5JDctPLBIGzHKbhw==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-plugin-svelte": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/prettier-plugin-svelte/-/prettier-plugin-svelte-3.3.3.tgz", + "integrity": "sha512-yViK9zqQ+H2qZD1w/bH7W8i+bVfKrD8GIFjkFe4Thl6kCT9SlAsXVNmt3jCvQOCsnOhcvYgsoVlRV/Eu6x5nNw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "prettier": "^3.0.0", + "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" + } + }, + "node_modules/prettier-plugin-tailwindcss": { + "version": "0.6.11", + "resolved": "https://registry.npmjs.org/prettier-plugin-tailwindcss/-/prettier-plugin-tailwindcss-0.6.11.tgz", + "integrity": "sha512-YxaYSIvZPAqhrrEpRtonnrXdghZg1irNg4qrjboCXrpybLWVs55cW2N3juhspVJiO0JBvYJT8SYsJpc8OQSnsA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.21.3" + }, + "peerDependencies": { + "@ianvs/prettier-plugin-sort-imports": "*", + "@prettier/plugin-pug": "*", + "@shopify/prettier-plugin-liquid": "*", + "@trivago/prettier-plugin-sort-imports": "*", + "@zackad/prettier-plugin-twig": "*", + "prettier": "^3.0", + "prettier-plugin-astro": "*", + "prettier-plugin-css-order": "*", + "prettier-plugin-import-sort": "*", + "prettier-plugin-jsdoc": "*", + "prettier-plugin-marko": "*", + "prettier-plugin-multiline-arrays": "*", + "prettier-plugin-organize-attributes": "*", + "prettier-plugin-organize-imports": "*", + "prettier-plugin-sort-imports": "*", + "prettier-plugin-style-order": "*", + "prettier-plugin-svelte": "*" + }, + "peerDependenciesMeta": { + "@ianvs/prettier-plugin-sort-imports": { + "optional": true + }, + "@prettier/plugin-pug": { + "optional": true + }, + "@shopify/prettier-plugin-liquid": { + "optional": true + }, + "@trivago/prettier-plugin-sort-imports": { + "optional": true + }, + "@zackad/prettier-plugin-twig": { + "optional": true + }, + "prettier-plugin-astro": { + "optional": true + }, + "prettier-plugin-css-order": { + "optional": true + }, + "prettier-plugin-import-sort": { + "optional": true + }, + "prettier-plugin-jsdoc": { + "optional": true + }, + "prettier-plugin-marko": { + "optional": true + }, + "prettier-plugin-multiline-arrays": { + "optional": true + }, + "prettier-plugin-organize-attributes": { + "optional": true + }, + "prettier-plugin-organize-imports": { + "optional": true + }, + "prettier-plugin-sort-imports": { + "optional": true + }, + "prettier-plugin-style-order": { + "optional": true + }, + "prettier-plugin-svelte": { + "optional": true + } + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.18.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/redent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", + "integrity": "sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==", + "dev": true, + "license": "MIT", + "dependencies": { + "indent-string": "^4.0.0", + "strip-indent": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true, + "license": "MIT" + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rollup": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", + "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/estree": "1.0.7" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.40.0", + "@rollup/rollup-android-arm64": "4.40.0", + "@rollup/rollup-darwin-arm64": "4.40.0", + "@rollup/rollup-darwin-x64": "4.40.0", + "@rollup/rollup-freebsd-arm64": "4.40.0", + "@rollup/rollup-freebsd-x64": "4.40.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", + "@rollup/rollup-linux-arm-musleabihf": "4.40.0", + "@rollup/rollup-linux-arm64-gnu": "4.40.0", + "@rollup/rollup-linux-arm64-musl": "4.40.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", + "@rollup/rollup-linux-riscv64-gnu": "4.40.0", + "@rollup/rollup-linux-riscv64-musl": "4.40.0", + "@rollup/rollup-linux-s390x-gnu": "4.40.0", + "@rollup/rollup-linux-x64-gnu": "4.40.0", + "@rollup/rollup-linux-x64-musl": "4.40.0", + "@rollup/rollup-win32-arm64-msvc": "4.40.0", + "@rollup/rollup-win32-ia32-msvc": "4.40.0", + "@rollup/rollup-win32-x64-msvc": "4.40.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/rrweb-cssom": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.8.0.tgz", + "integrity": "sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/sade": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", + "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "mri": "^1.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/semver": { + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/set-cookie-parser": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", + "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "dev": true, + "license": "ISC" + }, + "node_modules/sirv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", + "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "dev": true, + "license": "MIT" + }, + "node_modules/std-env": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.9.0.tgz", + "integrity": "sha512-UGvjygr6F6tpH7o2qyqR6QYpwraIjKSdtzyBdyytFOHmPZY917kwdwLG0RbOjWOnKmnm3PeHjaoLLMie7kPLQw==", + "dev": true, + "license": "MIT" + }, + "node_modules/strip-indent": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-3.0.0.tgz", + "integrity": "sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "min-indent": "^1.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/svelte": { + "version": "5.26.2", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.26.2.tgz", + "integrity": "sha512-e2TEcGK2YKVwDWYy5OsptVclYgDvfY1E/8IzPiOq63uG/GDo/j5VUYTC9EinQNraoZalbMWN+5f5TYC1QlAqOw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "acorn": "^8.12.1", + "aria-query": "^5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "esm-env": "^1.2.1", + "esrap": "^1.4.6", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/svelte-check": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.1.6.tgz", + "integrity": "sha512-P7w/6tdSfk3zEVvfsgrp3h3DFC75jCdZjTQvgGJtjPORs1n7/v2VMPIoty3PWv7jnfEm3x0G/p9wH4pecTb0Wg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "engines": { + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" + } + }, + "node_modules/svelte-eslint-parser": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/svelte-eslint-parser/-/svelte-eslint-parser-1.1.2.tgz", + "integrity": "sha512-vqFBRamDKo1l70KMfxxXj1/0Cco5TfMDnqaAjgz6D8PyoMhfMcDOLRkAwPg8WkMyZjMtQL3wW66TZ0x59iqO2w==", + "dev": true, + "license": "MIT", + "dependencies": { + "eslint-scope": "^8.2.0", + "eslint-visitor-keys": "^4.0.0", + "espree": "^10.0.0", + "postcss": "^8.4.49", + "postcss-scss": "^4.0.9", + "postcss-selector-parser": "^7.0.0" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + }, + "peerDependencies": { + "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + } + } + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tailwindcss": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.1.3.tgz", + "integrity": "sha512-2Q+rw9vy1WFXu5cIxlvsabCwhU2qUwodGq03ODhLJ0jW4ek5BUtoCsnLB0qG+m8AHgEsSJcJGDSDe06FXlP74g==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-0.3.2.tgz", + "integrity": "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinypool": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-1.0.2.tgz", + "integrity": "sha512-al6n+QEANGFOMf/dmUMsuS5/r9B06uwlyNjZZql/zv8J7ybHCgoihBNORZCY2mzUuAnomQa2JdhyHKzZxPCrFA==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^18.0.0 || >=20.0.0" + } + }, + "node_modules/tinyrainbow": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-2.0.0.tgz", + "integrity": "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tinyspy": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-3.0.2.tgz", + "integrity": "sha512-n1cw8k1k0x4pgA2+9XrOkFydTerNcJ1zWCO5Nn9scWHTD+5tp8dghT2x1uduQePZTZgd3Tupf+x9BxJjeJi77Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/tldts": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-6.1.86.tgz", + "integrity": "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^6.1.86" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "6.1.86", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-6.1.86.tgz", + "integrity": "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", + "integrity": "sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^6.1.32" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.1.0.tgz", + "integrity": "sha512-IUWnUK7ADYR5Sl1fZlO1INDUhVhatWl7BtJWsIhwJ0UAK7ilzzIa8uIqOO/aYVWHZPJkKbEL+362wrzoeRF7bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/ts-api-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.1.0.tgz", + "integrity": "sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18.12" + }, + "peerDependencies": { + "typescript": ">=4.8.4" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "license": "MIT", + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/typescript": { + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/typescript-eslint": { + "version": "8.29.1", + "resolved": "https://registry.npmjs.org/typescript-eslint/-/typescript-eslint-8.29.1.tgz", + "integrity": "sha512-f8cDkvndhbQMPcysk6CUSGBWV+g1utqdn71P5YKwMumVMOG/5k7cHq0KyG4O52nB0oKS4aN2Tp5+wB4APJGC+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@typescript-eslint/eslint-plugin": "8.29.1", + "@typescript-eslint/parser": "8.29.1", + "@typescript-eslint/utils": "8.29.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.57.0 || ^9.0.0", + "typescript": ">=4.8.4 <5.9.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vite": { + "version": "6.2.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.2.6.tgz", + "integrity": "sha512-9xpjNl3kR4rVDZgPNdTL0/c6ao4km69a/2ihNQbcANz8RuCOK3hQBmLSJf3bRKVQjVMda+YvizNE8AwvogcPbw==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.25.0", + "postcss": "^8.5.3", + "rollup": "^4.30.1" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/vite-node": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.1.1.tgz", + "integrity": "sha512-V+IxPAE2FvXpTCHXyNem0M+gWm6J7eRyWPR6vYoG/Gl+IscNOjXzztUhimQgTxaAoUoj40Qqimaa0NLIOOAH4w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cac": "^6.7.14", + "debug": "^4.4.0", + "es-module-lexer": "^1.6.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0" + }, + "bin": { + "vite-node": "vite-node.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/vite/node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/vitefu": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.6.tgz", + "integrity": "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==", + "dev": true, + "license": "MIT", + "workspaces": [ + "tests/deps/*", + "tests/projects/*" + ], + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "vite": { + "optional": true + } + } + }, + "node_modules/vitest": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.1.1.tgz", + "integrity": "sha512-kiZc/IYmKICeBAZr9DQ5rT7/6bD9G7uqQEki4fxazi1jdVl2mWGzedtBs5s6llz59yQhVb7FFY2MbHzHCnT79Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@vitest/expect": "3.1.1", + "@vitest/mocker": "3.1.1", + "@vitest/pretty-format": "^3.1.1", + "@vitest/runner": "3.1.1", + "@vitest/snapshot": "3.1.1", + "@vitest/spy": "3.1.1", + "@vitest/utils": "3.1.1", + "chai": "^5.2.0", + "debug": "^4.4.0", + "expect-type": "^1.2.0", + "magic-string": "^0.30.17", + "pathe": "^2.0.3", + "std-env": "^3.8.1", + "tinybench": "^2.9.0", + "tinyexec": "^0.3.2", + "tinypool": "^1.0.2", + "tinyrainbow": "^2.0.0", + "vite": "^5.0.0 || ^6.0.0", + "vite-node": "3.1.1", + "why-is-node-running": "^2.3.0" + }, + "bin": { + "vitest": "vitest.mjs" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "@edge-runtime/vm": "*", + "@types/debug": "^4.1.12", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "@vitest/browser": "3.1.1", + "@vitest/ui": "3.1.1", + "happy-dom": "*", + "jsdom": "*" + }, + "peerDependenciesMeta": { + "@edge-runtime/vm": { + "optional": true + }, + "@types/debug": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitest/browser": { + "optional": true + }, + "@vitest/ui": { + "optional": true + }, + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/whatwg-encoding": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz", + "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "iconv-lite": "0.6.3" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-mimetype": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz", + "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/whatwg-url": { + "version": "14.2.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.2.0.tgz", + "integrity": "sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^5.1.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "dev": true, + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/word-wrap": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", + "integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-RKW2aJZMXeMxVpnZ6bck+RswznaxmzdULiBr6KY7XkTnW8uvt0iT9H5DkHUChXrc+uurzwa0rVI16n/Xzjdz1w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/yaml": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.7.1.tgz", + "integrity": "sha512-10ULxpnOCQXxJvBgxsn9ptjq6uviG/htZKk9veJGhlqn3w/DxQ631zFF+nlQXLwmImeS5amR2dl2U8sg6U9jsQ==", + "dev": true, + "license": "ISC", + "optional": true, + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zimmerframe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", + "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", + "dev": true, + "license": "MIT" + } + } +} diff --git a/test-sveltekit/package.json b/test-sveltekit/package.json new file mode 100644 index 00000000..011e47e8 --- /dev/null +++ b/test-sveltekit/package.json @@ -0,0 +1,45 @@ +{ + "name": "test-sveltekit", + "private": true, + "version": "0.0.1", + "type": "module", + "scripts": { + "dev": "vite dev", + "build": "vite build", + "preview": "vite preview", + "prepare": "svelte-kit sync || echo ''", + "check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json", + "check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch", + "format": "prettier --write .", + "lint": "prettier --check . && eslint .", + "test:e2e": "playwright test", + "test": "npm run test:e2e && npm run test:unit -- --run", + "test:unit": "vitest" + }, + "devDependencies": { + "@eslint/compat": "^1.2.5", + "@eslint/js": "^9.18.0", + "@playwright/test": "^1.49.1", + "@sveltejs/adapter-auto": "^4.0.0", + "@sveltejs/kit": "file:../node_modules/@sveltejs/kit", + "@sveltejs/vite-plugin-svelte": "file:../node_modules/@sveltejs/vite-plugin-svelte", + "@tailwindcss/vite": "^4.0.0", + "@testing-library/jest-dom": "^6.6.3", + "@testing-library/svelte": "^5.2.4", + "eslint": "^9.18.0", + "eslint-config-prettier": "^10.0.1", + "eslint-plugin-svelte": "^3.0.0", + "globals": "^16.0.0", + "jsdom": "^26.0.0", + "prettier": "^3.4.2", + "prettier-plugin-svelte": "^3.3.3", + "prettier-plugin-tailwindcss": "^0.6.11", + "svelte": "file:../node_modules/svelte", + "svelte-check": "file:../node_modules/svelte-check", + "tailwindcss": "^4.0.0", + "typescript": "^5.0.0", + "typescript-eslint": "^8.20.0", + "vite": "^6.2.5", + "vitest": "^3.0.0" + } +} diff --git a/test-sveltekit/playwright.config.ts b/test-sveltekit/playwright.config.ts new file mode 100644 index 00000000..f6c81af8 --- /dev/null +++ b/test-sveltekit/playwright.config.ts @@ -0,0 +1,9 @@ +import { defineConfig } from '@playwright/test'; + +export default defineConfig({ + webServer: { + command: 'npm run build && npm run preview', + port: 4173 + }, + testDir: 'e2e' +}); diff --git a/test-sveltekit/src/app.css b/test-sveltekit/src/app.css new file mode 100644 index 00000000..d4b50785 --- /dev/null +++ b/test-sveltekit/src/app.css @@ -0,0 +1 @@ +@import 'tailwindcss'; diff --git a/test-sveltekit/src/app.d.ts b/test-sveltekit/src/app.d.ts new file mode 100644 index 00000000..da08e6da --- /dev/null +++ b/test-sveltekit/src/app.d.ts @@ -0,0 +1,13 @@ +// See https://svelte.dev/docs/kit/types#app.d.ts +// for information about these interfaces +declare global { + namespace App { + // interface Error {} + // interface Locals {} + // interface PageData {} + // interface PageState {} + // interface Platform {} + } +} + +export {}; diff --git a/test-sveltekit/src/app.html b/test-sveltekit/src/app.html new file mode 100644 index 00000000..77a5ff52 --- /dev/null +++ b/test-sveltekit/src/app.html @@ -0,0 +1,12 @@ + + + + + + + %sveltekit.head% + + +
%sveltekit.body%
+ + diff --git a/test-sveltekit/src/demo.spec.ts b/test-sveltekit/src/demo.spec.ts new file mode 100644 index 00000000..e07cbbd7 --- /dev/null +++ b/test-sveltekit/src/demo.spec.ts @@ -0,0 +1,7 @@ +import { describe, it, expect } from 'vitest'; + +describe('sum test', () => { + it('adds 1 + 2 to equal 3', () => { + expect(1 + 2).toBe(3); + }); +}); diff --git a/test-sveltekit/src/lib/index.ts b/test-sveltekit/src/lib/index.ts new file mode 100644 index 00000000..856f2b6c --- /dev/null +++ b/test-sveltekit/src/lib/index.ts @@ -0,0 +1 @@ +// place files you want to import through the `$lib` alias in this folder. diff --git a/test-sveltekit/src/routes/+layout.svelte b/test-sveltekit/src/routes/+layout.svelte new file mode 100644 index 00000000..b93e9bae --- /dev/null +++ b/test-sveltekit/src/routes/+layout.svelte @@ -0,0 +1,7 @@ + + +{@render children()} diff --git a/test-sveltekit/src/routes/+page.svelte b/test-sveltekit/src/routes/+page.svelte new file mode 100644 index 00000000..cc88df0e --- /dev/null +++ b/test-sveltekit/src/routes/+page.svelte @@ -0,0 +1,2 @@ +

Welcome to SvelteKit

+

Visit svelte.dev/docs/kit to read the documentation

diff --git a/test-sveltekit/src/routes/page.svelte.test.ts b/test-sveltekit/src/routes/page.svelte.test.ts new file mode 100644 index 00000000..a1106627 --- /dev/null +++ b/test-sveltekit/src/routes/page.svelte.test.ts @@ -0,0 +1,11 @@ +import { describe, test, expect } from 'vitest'; +import '@testing-library/jest-dom/vitest'; +import { render, screen } from '@testing-library/svelte'; +import Page from './+page.svelte'; + +describe('/+page.svelte', () => { + test('should render h1', () => { + render(Page); + expect(screen.getByRole('heading', { level: 1 })).toBeInTheDocument(); + }); +}); diff --git a/test-sveltekit/static/favicon.png b/test-sveltekit/static/favicon.png new file mode 100644 index 0000000000000000000000000000000000000000..825b9e65af7c104cfb07089bb28659393b4f2097 GIT binary patch literal 1571 zcmV+;2Hg3HP)Px)-AP12RCwC$UE6KzI1p6{F2N z1VK2vi|pOpn{~#djwYcWXTI_im_u^TJgMZ4JMOsSj!0ma>B?-(Hr@X&W@|R-$}W@Z zgj#$x=!~7LGqHW?IO8+*oE1MyDp!G=L0#^lUx?;!fXv@l^6SvTnf^ac{5OurzC#ZMYc20lI%HhX816AYVs1T3heS1*WaWH z%;x>)-J}YB5#CLzU@GBR6sXYrD>Vw(Fmt#|JP;+}<#6b63Ike{Fuo!?M{yEffez;| zp!PfsuaC)>h>-AdbnwN13g*1LowNjT5?+lFVd#9$!8Z9HA|$*6dQ8EHLu}U|obW6f z2%uGv?vr=KNq7YYa2Roj;|zooo<)lf=&2yxM@e`kM$CmCR#x>gI>I|*Ubr({5Y^rb zghxQU22N}F51}^yfDSt786oMTc!W&V;d?76)9KXX1 z+6Okem(d}YXmmOiZq$!IPk5t8nnS{%?+vDFz3BevmFNgpIod~R{>@#@5x9zJKEHLHv!gHeK~n)Ld!M8DB|Kfe%~123&Hz1Z(86nU7*G5chmyDe ziV7$pB7pJ=96hpxHv9rCR29%bLOXlKU<_13_M8x)6;P8E1Kz6G<&P?$P^%c!M5`2` zfY2zg;VK5~^>TJGQzc+33-n~gKt{{of8GzUkWmU110IgI0DLxRIM>0US|TsM=L|@F z0Bun8U!cRB7-2apz=y-7*UxOxz@Z0)@QM)9wSGki1AZ38ceG7Q72z5`i;i=J`ILzL z@iUO?SBBG-0cQuo+an4TsLy-g-x;8P4UVwk|D8{W@U1Zi z!M)+jqy@nQ$p?5tsHp-6J304Q={v-B>66$P0IDx&YT(`IcZ~bZfmn11#rXd7<5s}y zBi9eim&zQc0Dk|2>$bs0PnLmDfMP5lcXRY&cvJ=zKxI^f0%-d$tD!`LBf9^jMSYUA zI8U?CWdY@}cRq6{5~y+)#h1!*-HcGW@+gZ4B};0OnC~`xQOyH19z*TA!!BJ%9s0V3F?CAJ{hTd#*tf+ur-W9MOURF-@B77_-OshsY}6 zOXRY=5%C^*26z?l)1=$bz30!so5tfABdSYzO+H=CpV~aaUefmjvfZ3Ttu9W&W3Iu6 zROlh0MFA5h;my}8lB0tAV-Rvc2Zs_CCSJnx@d`**$idgy-iMob4dJWWw|21b4NB=LfsYp0Aeh{Ov)yztQi;eL4y5 zMi>8^SzKqk8~k?UiQK^^-5d8c%bV?$F8%X~czyiaKCI2=UH ({ + matches: false, + media: query, + onchange: null, + addEventListener: vi.fn(), + removeEventListener: vi.fn(), + dispatchEvent: vi.fn() + })) +}); + +// add more mocks here if you need them diff --git a/tsconfig.json b/tsconfig.json index cf091d9f..e70f1067 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -16,7 +16,8 @@ "paths": { "@convex-dev/auth/server": ["./src/server/index"], "@convex-dev/auth/providers/*": ["./src/providers/*"], - "@convex-dev/auth/react": ["./src/react/index"] + "@convex-dev/auth/react": ["./src/react/index"], + "@convex-dev/auth/svelte": ["./src/svelte/index"] } }, "include": ["**/*.ts", "**/*.tsx", "*.mjs"], @@ -26,6 +27,7 @@ "docs", "test", "test-router", - "test-nextjs" + "test-nextjs", + "test-svelte" ] } From 7a3907b797fa1143209b6f3b9645b687bacf0ff1 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Mon, 14 Apr 2025 12:54:11 +0200 Subject: [PATCH 02/88] Add Convex backend with auth, messages, and users functionality --- test-sveltekit/convex/README.md | 90 ++ test-sveltekit/convex/_generated/api.d.ts | 46 + test-sveltekit/convex/_generated/api.js | 22 + .../convex/_generated/dataModel.d.ts | 60 + test-sveltekit/convex/_generated/server.d.ts | 142 ++ test-sveltekit/convex/_generated/server.js | 89 ++ test-sveltekit/convex/auth.config.ts | 9 + test-sveltekit/convex/auth.ts | 24 + test-sveltekit/convex/helpers.ts | 19 + test-sveltekit/convex/http.ts | 8 + test-sveltekit/convex/messages.ts | 34 + test-sveltekit/convex/schema.ts | 11 + test-sveltekit/convex/tests.ts | 32 + test-sveltekit/convex/tsconfig.json | 25 + test-sveltekit/convex/users.ts | 10 + test-sveltekit/package-lock.json | 1163 ++++++++++------- test-sveltekit/package.json | 4 + 17 files changed, 1332 insertions(+), 456 deletions(-) create mode 100644 test-sveltekit/convex/README.md create mode 100644 test-sveltekit/convex/_generated/api.d.ts create mode 100644 test-sveltekit/convex/_generated/api.js create mode 100644 test-sveltekit/convex/_generated/dataModel.d.ts create mode 100644 test-sveltekit/convex/_generated/server.d.ts create mode 100644 test-sveltekit/convex/_generated/server.js create mode 100644 test-sveltekit/convex/auth.config.ts create mode 100644 test-sveltekit/convex/auth.ts create mode 100644 test-sveltekit/convex/helpers.ts create mode 100644 test-sveltekit/convex/http.ts create mode 100644 test-sveltekit/convex/messages.ts create mode 100644 test-sveltekit/convex/schema.ts create mode 100644 test-sveltekit/convex/tests.ts create mode 100644 test-sveltekit/convex/tsconfig.json create mode 100644 test-sveltekit/convex/users.ts diff --git a/test-sveltekit/convex/README.md b/test-sveltekit/convex/README.md new file mode 100644 index 00000000..4d82e136 --- /dev/null +++ b/test-sveltekit/convex/README.md @@ -0,0 +1,90 @@ +# Welcome to your Convex functions directory! + +Write your Convex functions here. +See https://docs.convex.dev/functions for more. + +A query function that takes two arguments looks like: + +```ts +// functions.js +import { query } from "./_generated/server"; +import { v } from "convex/values"; + +export const myQueryFunction = query({ + // Validators for arguments. + args: { + first: v.number(), + second: v.string(), + }, + + // Function implementation. + handler: async (ctx, args) => { + // Read the database as many times as you need here. + // See https://docs.convex.dev/database/reading-data. + const documents = await ctx.db.query("tablename").collect(); + + // Arguments passed from the client are properties of the args object. + console.log(args.first, args.second); + + // Write arbitrary JavaScript here: filter, aggregate, build derived data, + // remove non-public properties, or create new objects. + return documents; + }, +}); +``` + +Using this query function in a React component looks like: + +```ts +const data = useQuery(api.functions.myQueryFunction, { + first: 10, + second: "hello", +}); +``` + +A mutation function looks like: + +```ts +// functions.js +import { mutation } from "./_generated/server"; +import { v } from "convex/values"; + +export const myMutationFunction = mutation({ + // Validators for arguments. + args: { + first: v.string(), + second: v.string(), + }, + + // Function implementation. + handler: async (ctx, args) => { + // Insert or modify documents in the database here. + // Mutations can also read from the database like queries. + // See https://docs.convex.dev/database/writing-data. + const message = { body: args.first, author: args.second }; + const id = await ctx.db.insert("messages", message); + + // Optionally, return a value from your mutation. + return await ctx.db.get(id); + }, +}); +``` + +Using this mutation function in a React component looks like: + +```ts +const mutation = useMutation(api.functions.myMutationFunction); +function handleButtonPress() { + // fire and forget, the most common way to use mutations + mutation({ first: "Hello!", second: "me" }); + // OR + // use the result once the mutation has completed + mutation({ first: "Hello!", second: "me" }).then((result) => + console.log(result), + ); +} +``` + +Use the Convex CLI to push your functions to a deployment. See everything +the Convex CLI can do by running `npx convex -h` in your project root +directory. To learn more, launch the docs with `npx convex docs`. diff --git a/test-sveltekit/convex/_generated/api.d.ts b/test-sveltekit/convex/_generated/api.d.ts new file mode 100644 index 00000000..adbc4d15 --- /dev/null +++ b/test-sveltekit/convex/_generated/api.d.ts @@ -0,0 +1,46 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import type { + ApiFromModules, + FilterApi, + FunctionReference, +} from "convex/server"; +import type * as auth from "../auth.js"; +import type * as helpers from "../helpers.js"; +import type * as http from "../http.js"; +import type * as messages from "../messages.js"; +import type * as tests from "../tests.js"; +import type * as users from "../users.js"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +declare const fullApi: ApiFromModules<{ + auth: typeof auth; + helpers: typeof helpers; + http: typeof http; + messages: typeof messages; + tests: typeof tests; + users: typeof users; +}>; +export declare const api: FilterApi< + typeof fullApi, + FunctionReference +>; +export declare const internal: FilterApi< + typeof fullApi, + FunctionReference +>; diff --git a/test-sveltekit/convex/_generated/api.js b/test-sveltekit/convex/_generated/api.js new file mode 100644 index 00000000..3f9c482d --- /dev/null +++ b/test-sveltekit/convex/_generated/api.js @@ -0,0 +1,22 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { anyApi } from "convex/server"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +export const api = anyApi; +export const internal = anyApi; diff --git a/test-sveltekit/convex/_generated/dataModel.d.ts b/test-sveltekit/convex/_generated/dataModel.d.ts new file mode 100644 index 00000000..8541f319 --- /dev/null +++ b/test-sveltekit/convex/_generated/dataModel.d.ts @@ -0,0 +1,60 @@ +/* eslint-disable */ +/** + * Generated data model types. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import type { + DataModelFromSchemaDefinition, + DocumentByName, + TableNamesInDataModel, + SystemTableNames, +} from "convex/server"; +import type { GenericId } from "convex/values"; +import schema from "../schema.js"; + +/** + * The names of all of your Convex tables. + */ +export type TableNames = TableNamesInDataModel; + +/** + * The type of a document stored in Convex. + * + * @typeParam TableName - A string literal type of the table name (like "users"). + */ +export type Doc = DocumentByName< + DataModel, + TableName +>; + +/** + * An identifier for a document in Convex. + * + * Convex documents are uniquely identified by their `Id`, which is accessible + * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids). + * + * Documents can be loaded using `db.get(id)` in query and mutation functions. + * + * IDs are just strings at runtime, but this type can be used to distinguish them from other + * strings when type checking. + * + * @typeParam TableName - A string literal type of the table name (like "users"). + */ +export type Id = + GenericId; + +/** + * A type describing your Convex data model. + * + * This type includes information about what tables you have, the type of + * documents stored in those tables, and the indexes defined on them. + * + * This type is used to parameterize methods like `queryGeneric` and + * `mutationGeneric` to make them type-safe. + */ +export type DataModel = DataModelFromSchemaDefinition; diff --git a/test-sveltekit/convex/_generated/server.d.ts b/test-sveltekit/convex/_generated/server.d.ts new file mode 100644 index 00000000..7f337a43 --- /dev/null +++ b/test-sveltekit/convex/_generated/server.d.ts @@ -0,0 +1,142 @@ +/* eslint-disable */ +/** + * Generated utilities for implementing server-side Convex query and mutation functions. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { + ActionBuilder, + HttpActionBuilder, + MutationBuilder, + QueryBuilder, + GenericActionCtx, + GenericMutationCtx, + GenericQueryCtx, + GenericDatabaseReader, + GenericDatabaseWriter, +} from "convex/server"; +import type { DataModel } from "./dataModel.js"; + +/** + * Define a query in this Convex app's public API. + * + * This function will be allowed to read your Convex database and will be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export declare const query: QueryBuilder; + +/** + * Define a query that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to read from your Convex database. It will not be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export declare const internalQuery: QueryBuilder; + +/** + * Define a mutation in this Convex app's public API. + * + * This function will be allowed to modify your Convex database and will be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export declare const mutation: MutationBuilder; + +/** + * Define a mutation that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to modify your Convex database. It will not be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export declare const internalMutation: MutationBuilder; + +/** + * Define an action in this Convex app's public API. + * + * An action is a function which can execute any JavaScript code, including non-deterministic + * code and code with side-effects, like calling third-party services. + * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. + * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. + * + * @param func - The action. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped action. Include this as an `export` to name it and make it accessible. + */ +export declare const action: ActionBuilder; + +/** + * Define an action that is only accessible from other Convex functions (but not from the client). + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Include this as an `export` to name it and make it accessible. + */ +export declare const internalAction: ActionBuilder; + +/** + * Define an HTTP action. + * + * This function will be used to respond to HTTP requests received by a Convex + * deployment if the requests matches the path and method where this action + * is routed. Be sure to route your action in `convex/http.js`. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. + */ +export declare const httpAction: HttpActionBuilder; + +/** + * A set of services for use within Convex query functions. + * + * The query context is passed as the first argument to any Convex query + * function run on the server. + * + * This differs from the {@link MutationCtx} because all of the services are + * read-only. + */ +export type QueryCtx = GenericQueryCtx; + +/** + * A set of services for use within Convex mutation functions. + * + * The mutation context is passed as the first argument to any Convex mutation + * function run on the server. + */ +export type MutationCtx = GenericMutationCtx; + +/** + * A set of services for use within Convex action functions. + * + * The action context is passed as the first argument to any Convex action + * function run on the server. + */ +export type ActionCtx = GenericActionCtx; + +/** + * An interface to read from the database within Convex query functions. + * + * The two entry points are {@link DatabaseReader.get}, which fetches a single + * document by its {@link Id}, or {@link DatabaseReader.query}, which starts + * building a query. + */ +export type DatabaseReader = GenericDatabaseReader; + +/** + * An interface to read from and write to the database within Convex mutation + * functions. + * + * Convex guarantees that all writes within a single mutation are + * executed atomically, so you never have to worry about partial writes leaving + * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control) + * for the guarantees Convex provides your functions. + */ +export type DatabaseWriter = GenericDatabaseWriter; diff --git a/test-sveltekit/convex/_generated/server.js b/test-sveltekit/convex/_generated/server.js new file mode 100644 index 00000000..566d4858 --- /dev/null +++ b/test-sveltekit/convex/_generated/server.js @@ -0,0 +1,89 @@ +/* eslint-disable */ +/** + * Generated utilities for implementing server-side Convex query and mutation functions. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { + actionGeneric, + httpActionGeneric, + queryGeneric, + mutationGeneric, + internalActionGeneric, + internalMutationGeneric, + internalQueryGeneric, +} from "convex/server"; + +/** + * Define a query in this Convex app's public API. + * + * This function will be allowed to read your Convex database and will be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export const query = queryGeneric; + +/** + * Define a query that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to read from your Convex database. It will not be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export const internalQuery = internalQueryGeneric; + +/** + * Define a mutation in this Convex app's public API. + * + * This function will be allowed to modify your Convex database and will be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export const mutation = mutationGeneric; + +/** + * Define a mutation that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to modify your Convex database. It will not be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export const internalMutation = internalMutationGeneric; + +/** + * Define an action in this Convex app's public API. + * + * An action is a function which can execute any JavaScript code, including non-deterministic + * code and code with side-effects, like calling third-party services. + * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. + * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. + * + * @param func - The action. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped action. Include this as an `export` to name it and make it accessible. + */ +export const action = actionGeneric; + +/** + * Define an action that is only accessible from other Convex functions (but not from the client). + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Include this as an `export` to name it and make it accessible. + */ +export const internalAction = internalActionGeneric; + +/** + * Define a Convex HTTP action. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object + * as its second. + * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. + */ +export const httpAction = httpActionGeneric; diff --git a/test-sveltekit/convex/auth.config.ts b/test-sveltekit/convex/auth.config.ts new file mode 100644 index 00000000..0f8d3d4e --- /dev/null +++ b/test-sveltekit/convex/auth.config.ts @@ -0,0 +1,9 @@ +// eslint-disable-next-line import/no-anonymous-default-export +export default { + providers: [ + { + domain: process.env.CONVEX_SITE_URL, + applicationID: "convex", + }, + ], +}; diff --git a/test-sveltekit/convex/auth.ts b/test-sveltekit/convex/auth.ts new file mode 100644 index 00000000..0a4d47e4 --- /dev/null +++ b/test-sveltekit/convex/auth.ts @@ -0,0 +1,24 @@ +import { ConvexCredentials } from "@convex-dev/auth/providers/ConvexCredentials"; +import GitHub from "@auth/core/providers/github"; +import { convexAuth } from "@convex-dev/auth/server"; +import { internal } from "./_generated/api"; + +export const { auth, signIn, signOut, store, isAuthenticated } = convexAuth({ + providers: [ + GitHub, + ConvexCredentials({ + id: "secret", + authorize: async (params, ctx) => { + const secret = params.secret; + if ( + process.env.AUTH_E2E_TEST_SECRET && + secret === process.env.AUTH_E2E_TEST_SECRET + ) { + const user = await ctx.runQuery(internal.tests.getTestUser); + return { userId: user!._id }; + } + throw new Error("Invalid secret"); + }, + }), + ], +}); diff --git a/test-sveltekit/convex/helpers.ts b/test-sveltekit/convex/helpers.ts new file mode 100644 index 00000000..6673b23f --- /dev/null +++ b/test-sveltekit/convex/helpers.ts @@ -0,0 +1,19 @@ +import { authTables } from "@convex-dev/auth/server"; +import { internalMutation } from "./_generated/server"; +import { v } from "convex/values"; + +// Deletes all auth-related data. +// Just for demoing purposes, feel free to delete. +export const reset = internalMutation({ + args: { forReal: v.string() }, + handler: async (ctx, args) => { + if (args.forReal !== "I know what I'm doing") { + throw new Error("You must know what you're doing to reset the database."); + } + for (const table of Object.keys(authTables)) { + for (const { _id } of await ctx.db.query(table as any).collect()) { + await ctx.db.delete(_id); + } + } + }, +}); diff --git a/test-sveltekit/convex/http.ts b/test-sveltekit/convex/http.ts new file mode 100644 index 00000000..1816e5b2 --- /dev/null +++ b/test-sveltekit/convex/http.ts @@ -0,0 +1,8 @@ +import { httpRouter } from "convex/server"; +import { auth } from "./auth"; + +const http = httpRouter(); + +auth.addHttpRoutes(http); + +export default http; diff --git a/test-sveltekit/convex/messages.ts b/test-sveltekit/convex/messages.ts new file mode 100644 index 00000000..fe985686 --- /dev/null +++ b/test-sveltekit/convex/messages.ts @@ -0,0 +1,34 @@ +import { getAuthUserId } from "@convex-dev/auth/server"; +import { query, mutation } from "./_generated/server"; +import { v } from "convex/values"; + +export const list = query({ + args: {}, + handler: async (ctx) => { + const userId = await getAuthUserId(ctx); + if (userId === null) { + throw new Error("Not signed in"); + } + // Grab the most recent messages. + const messages = await ctx.db.query("messages").order("desc").take(100); + // Reverse the list so that it's in a chronological order. + return Promise.all( + messages.reverse().map(async (message) => { + const { name, email, phone } = (await ctx.db.get(message.userId))!; + return { ...message, author: name ?? email ?? phone ?? "Anonymous" }; + }), + ); + }, +}); + +export const send = mutation({ + args: { body: v.string() }, + handler: async (ctx, { body }) => { + const userId = await getAuthUserId(ctx); + if (userId === null) { + throw new Error("Not signed in"); + } + // Send a new message. + await ctx.db.insert("messages", { body, userId }); + }, +}); diff --git a/test-sveltekit/convex/schema.ts b/test-sveltekit/convex/schema.ts new file mode 100644 index 00000000..b8f2d212 --- /dev/null +++ b/test-sveltekit/convex/schema.ts @@ -0,0 +1,11 @@ +import { defineSchema, defineTable } from "convex/server"; +import { v } from "convex/values"; +import { authTables } from "@convex-dev/auth/server"; + +export default defineSchema({ + ...authTables, + messages: defineTable({ + userId: v.id("users"), + body: v.string(), + }), +}); diff --git a/test-sveltekit/convex/tests.ts b/test-sveltekit/convex/tests.ts new file mode 100644 index 00000000..f71f80d7 --- /dev/null +++ b/test-sveltekit/convex/tests.ts @@ -0,0 +1,32 @@ +import { createAccount } from "../../dist/server/index"; +import { internal } from "./_generated/api"; +import { internalAction, internalQuery } from "./_generated/server"; + +const TEST_USER_EMAIL = "secret@secret.com"; + +export const getTestUser = internalQuery({ + args: {}, + handler: async (ctx) => { + return await ctx.db + .query("users") + .withIndex("email", (q) => q.eq("email", TEST_USER_EMAIL)) + .unique(); + }, +}); + +export const init = internalAction({ + args: {}, + handler: async (ctx) => { + const existingUser = await ctx.runQuery(internal.tests.getTestUser); + if (existingUser !== null) { + console.info("Test user already exists, skipping creation"); + return; + } + await createAccount(ctx, { + provider: "secret", + account: { id: TEST_USER_EMAIL }, + profile: { email: TEST_USER_EMAIL }, + }); + console.info("Test user created"); + }, +}); diff --git a/test-sveltekit/convex/tsconfig.json b/test-sveltekit/convex/tsconfig.json new file mode 100644 index 00000000..6fa874e8 --- /dev/null +++ b/test-sveltekit/convex/tsconfig.json @@ -0,0 +1,25 @@ +{ + /* This TypeScript project config describes the environment that + * Convex functions run in and is used to typecheck them. + * You can modify it, but some settings required to use Convex. + */ + "compilerOptions": { + /* These settings are not required by Convex and can be modified. */ + "allowJs": true, + "strict": true, + "moduleResolution": "Bundler", + "jsx": "react-jsx", + "skipLibCheck": true, + "allowSyntheticDefaultImports": true, + + /* These compiler options are required by Convex */ + "target": "ESNext", + "lib": ["ES2021", "dom"], + "forceConsistentCasingInFileNames": true, + "module": "ESNext", + "isolatedModules": true, + "noEmit": true + }, + "include": ["./**/*"], + "exclude": ["./_generated"] +} diff --git a/test-sveltekit/convex/users.ts b/test-sveltekit/convex/users.ts new file mode 100644 index 00000000..37a16ce2 --- /dev/null +++ b/test-sveltekit/convex/users.ts @@ -0,0 +1,10 @@ +import { getAuthUserId } from "@convex-dev/auth/server"; +import { query } from "./_generated/server"; + +export const viewer = query({ + args: {}, + handler: async (ctx) => { + const userId = await getAuthUserId(ctx); + return userId !== null ? ctx.db.get(userId) : null; + }, +}); diff --git a/test-sveltekit/package-lock.json b/test-sveltekit/package-lock.json index 5ca7246d..25a55c65 100644 --- a/test-sveltekit/package-lock.json +++ b/test-sveltekit/package-lock.json @@ -7,13 +7,17 @@ "": { "name": "test-sveltekit", "version": "0.0.1", + "dependencies": { + "convex": "^1.23.0", + "convex-svelte": "^0.0.11" + }, "devDependencies": { "@eslint/compat": "^1.2.5", "@eslint/js": "^9.18.0", "@playwright/test": "^1.49.1", "@sveltejs/adapter-auto": "^4.0.0", - "@sveltejs/kit": "^2.16.0", - "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@sveltejs/kit": "file:../node_modules/@sveltejs/kit", + "@sveltejs/vite-plugin-svelte": "file:../node_modules/@sveltejs/vite-plugin-svelte", "@tailwindcss/vite": "^4.0.0", "@testing-library/jest-dom": "^6.6.3", "@testing-library/svelte": "^5.2.4", @@ -25,8 +29,8 @@ "prettier": "^3.4.2", "prettier-plugin-svelte": "^3.3.3", "prettier-plugin-tailwindcss": "^0.6.11", - "svelte": "^5.0.0", - "svelte-check": "^4.0.0", + "svelte": "file:../node_modules/svelte", + "svelte-check": "file:../node_modules/svelte-check", "tailwindcss": "^4.0.0", "typescript": "^5.0.0", "typescript-eslint": "^8.20.0", @@ -34,27 +38,164 @@ "vitest": "^3.0.0" } }, - "node_modules/@adobe/css-tools": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz", - "integrity": "sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==", + "../node_modules/@sveltejs/kit": { + "version": "2.20.5", "dev": true, - "license": "MIT" + "license": "MIT", + "dependencies": { + "@types/cookie": "^0.6.0", + "cookie": "^0.6.0", + "devalue": "^5.1.0", + "esm-env": "^1.2.2", + "import-meta-resolve": "^4.1.0", + "kleur": "^4.1.5", + "magic-string": "^0.30.5", + "mrmime": "^2.0.0", + "sade": "^1.8.1", + "set-cookie-parser": "^2.6.0", + "sirv": "^3.0.0" + }, + "bin": { + "svelte-kit": "svelte-kit.js" + }, + "devDependencies": { + "@playwright/test": "^1.44.1", + "@sveltejs/vite-plugin-svelte": "^5.0.1", + "@types/connect": "^3.4.38", + "@types/node": "^18.19.48", + "@types/set-cookie-parser": "^2.4.7", + "dts-buddy": "^0.5.5", + "rollup": "^4.14.2", + "svelte": "^5.23.1", + "svelte-preprocess": "^6.0.0", + "typescript": "^5.3.3", + "vite": "^6.0.11", + "vitest": "^3.0.1" + }, + "engines": { + "node": ">=18.13" + }, + "peerDependencies": { + "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", + "svelte": "^4.0.0 || ^5.0.0-next.0", + "vite": "^5.0.3 || ^6.0.0" + } }, - "node_modules/@ampproject/remapping": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", - "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "../node_modules/@sveltejs/vite-plugin-svelte": { + "version": "5.0.3", "dev": true, - "license": "Apache-2.0", + "license": "MIT", + "dependencies": { + "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", + "debug": "^4.4.0", + "deepmerge": "^4.3.1", + "kleur": "^4.1.5", + "magic-string": "^0.30.15", + "vitefu": "^1.0.4" + }, + "devDependencies": { + "@types/debug": "^4.1.12", + "esbuild": "^0.24.0", + "sass": "^1.83.0", + "svelte": "^5.12.0", + "vite": "^6.0.3" + }, + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22" + }, + "peerDependencies": { + "svelte": "^5.0.0", + "vite": "^6.0.0" + } + }, + "../node_modules/svelte": { + "version": "5.26.2", + "license": "MIT", + "dependencies": { + "@ampproject/remapping": "^2.3.0", + "@jridgewell/sourcemap-codec": "^1.5.0", + "@sveltejs/acorn-typescript": "^1.0.5", + "@types/estree": "^1.0.5", + "acorn": "^8.12.1", + "aria-query": "^5.3.1", + "axobject-query": "^4.1.0", + "clsx": "^2.1.1", + "esm-env": "^1.2.1", + "esrap": "^1.4.6", + "is-reference": "^3.0.3", + "locate-character": "^3.0.0", + "magic-string": "^0.30.11", + "zimmerframe": "^1.1.2" + }, + "devDependencies": { + "@jridgewell/trace-mapping": "^0.3.25", + "@playwright/test": "^1.46.1", + "@rollup/plugin-commonjs": "^28.0.1", + "@rollup/plugin-node-resolve": "^15.3.0", + "@rollup/plugin-terser": "^0.4.4", + "@rollup/plugin-virtual": "^3.0.2", + "@types/aria-query": "^5.0.4", + "@types/node": "^20.11.5", + "dts-buddy": "^0.5.5", + "esbuild": "^0.21.5", + "rollup": "^4.22.4", + "source-map": "^0.7.4", + "tinyglobby": "^0.2.12", + "typescript": "^5.5.4", + "vitest": "^2.1.9" + }, + "engines": { + "node": ">=18" + } + }, + "../node_modules/svelte-check": { + "version": "4.1.6", + "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@jridgewell/trace-mapping": "^0.3.25", + "chokidar": "^4.0.1", + "fdir": "^6.2.0", + "picocolors": "^1.0.0", + "sade": "^1.7.4" + }, + "bin": { + "svelte-check": "bin/svelte-check" + }, + "devDependencies": { + "@rollup/plugin-commonjs": "^24.0.0", + "@rollup/plugin-json": "^6.0.0", + "@rollup/plugin-node-resolve": "^15.0.0", + "@rollup/plugin-replace": "5.0.2", + "@rollup/plugin-typescript": "^10.0.0", + "@types/sade": "^1.7.2", + "builtin-modules": "^3.3.0", + "rollup": "3.7.5", + "rollup-plugin-cleanup": "^3.2.0", + "rollup-plugin-copy": "^3.4.0", + "svelte": "^4.2.19", + "svelte-language-server": "0.17.0", + "typescript": "^5.8.2", + "vscode-languageserver": "8.0.2", + "vscode-languageserver-protocol": "3.17.2", + "vscode-languageserver-types": "3.17.2", + "vscode-uri": "~3.0.0" }, "engines": { - "node": ">=6.0.0" + "node": ">= 18.0.0" + }, + "peerDependencies": { + "svelte": "^4.0.0 || ^5.0.0-next.0", + "typescript": ">=5.0.0" } }, + "node_modules/@adobe/css-tools": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@adobe/css-tools/-/css-tools-4.4.2.tgz", + "integrity": "sha512-baYZExFpsdkBNuvGKTKWCwKH57HRZLVtycZS05WTQNVOiXVSeAki3nU35zlRbToeMW8aHlJfyS+1C4BOv27q0A==", + "dev": true, + "license": "MIT" + }, "node_modules/@asamuzakjp/css-color": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-3.1.1.tgz", @@ -895,41 +1036,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.8", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.8.tgz", - "integrity": "sha512-imAbBGkb+ebQyxKgzv5Hu2nmROxoDOXHh80evxdoXNOrvAnVx7zimzc1Oo5h9RlfV4vPXaE2iM5pOFbvOCClWA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.0", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", @@ -937,17 +1043,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1002,13 +1097,6 @@ "node": ">=18" } }, - "node_modules/@polka/url": { - "version": "1.0.0-next.29", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", - "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", - "dev": true, - "license": "MIT" - }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.40.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", @@ -1289,16 +1377,6 @@ "win32" ] }, - "node_modules/@sveltejs/acorn-typescript": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@sveltejs/acorn-typescript/-/acorn-typescript-1.0.5.tgz", - "integrity": "sha512-IwQk4yfwLdibDlrXVE04jTZYlLnwsTT2PIOQQGNLWfjavGifnk1JD1LcZjZaBTRcxZu2FfPfNLOE04DSu9lqtQ==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "acorn": "^8.9.0" - } - }, "node_modules/@sveltejs/adapter-auto": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-4.0.0.tgz", @@ -1313,75 +1391,12 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.20.5", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.20.5.tgz", - "integrity": "sha512-zT/97KvVUo19jEGZa972ls7KICjPCB53j54TVxnEFT5VEwL16G+YFqRVwJbfxh7AmS7/Ptr1rKF7Qt4FBMDNlw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/cookie": "^0.6.0", - "cookie": "^0.6.0", - "devalue": "^5.1.0", - "esm-env": "^1.2.2", - "import-meta-resolve": "^4.1.0", - "kleur": "^4.1.5", - "magic-string": "^0.30.5", - "mrmime": "^2.0.0", - "sade": "^1.8.1", - "set-cookie-parser": "^2.6.0", - "sirv": "^3.0.0" - }, - "bin": { - "svelte-kit": "svelte-kit.js" - }, - "engines": { - "node": ">=18.13" - }, - "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0", - "svelte": "^4.0.0 || ^5.0.0-next.0", - "vite": "^5.0.3 || ^6.0.0" - } + "resolved": "../node_modules/@sveltejs/kit", + "link": true }, "node_modules/@sveltejs/vite-plugin-svelte": { - "version": "5.0.3", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte/-/vite-plugin-svelte-5.0.3.tgz", - "integrity": "sha512-MCFS6CrQDu1yGwspm4qtli0e63vaPCehf6V7pIMP15AsWgMKrqDGCPFF/0kn4SP0ii4aySu4Pa62+fIRGFMjgw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", - "debug": "^4.4.0", - "deepmerge": "^4.3.1", - "kleur": "^4.1.5", - "magic-string": "^0.30.15", - "vitefu": "^1.0.4" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22" - }, - "peerDependencies": { - "svelte": "^5.0.0", - "vite": "^6.0.0" - } - }, - "node_modules/@sveltejs/vite-plugin-svelte-inspector": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@sveltejs/vite-plugin-svelte-inspector/-/vite-plugin-svelte-inspector-4.0.1.tgz", - "integrity": "sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==", - "dev": true, - "license": "MIT", - "dependencies": { - "debug": "^4.3.7" - }, - "engines": { - "node": "^18.0.0 || ^20.0.0 || >=22" - }, - "peerDependencies": { - "@sveltejs/vite-plugin-svelte": "^5.0.0", - "svelte": "^5.0.0", - "vite": "^6.0.0" - } + "resolved": "../node_modules/@sveltejs/vite-plugin-svelte", + "link": true }, "node_modules/@tailwindcss/node": { "version": "4.1.3", @@ -1729,13 +1744,6 @@ "dev": true, "license": "MIT" }, - "node_modules/@types/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==", - "dev": true, - "license": "MIT" - }, "node_modules/@types/estree": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", @@ -2172,16 +2180,6 @@ "node": ">=12" } }, - "node_modules/axobject-query": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", - "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", - "dev": true, - "license": "Apache-2.0", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -2247,94 +2245,561 @@ "pathval": "^2.0.0" }, "engines": { - "node": ">=12" + "node": ">=12" + } + }, + "node_modules/chalk": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", + "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/convex": { + "version": "1.23.0", + "resolved": "https://registry.npmjs.org/convex/-/convex-1.23.0.tgz", + "integrity": "sha512-Mz2GpCrw3wXR+TWQgUjQPLkZ5ZhnSSJbvZ/+GUdBY4yMwPpoPw5T6DszAFUB2o1SKyhmyes1iYGijueNsZb/Xw==", + "license": "Apache-2.0", + "dependencies": { + "esbuild": "0.25.1", + "jwt-decode": "^4.0.0", + "prettier": "3.5.2" + }, + "bin": { + "convex": "bin/main.js" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=7.0.0" + }, + "peerDependencies": { + "@auth0/auth0-react": "^2.0.1", + "@clerk/clerk-react": "^4.12.8 || ^5.0.0", + "react": "^17.0.2 || ^18.0.0 || ^19.0.0-0 || ^19.0.0", + "react-dom": "^17.0.2 || ^18.0.0 || ^19.0.0-0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@auth0/auth0-react": { + "optional": true + }, + "@clerk/clerk-react": { + "optional": true + }, + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/convex-svelte": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/convex-svelte/-/convex-svelte-0.0.11.tgz", + "integrity": "sha512-N/29gg5Zqy72vKL4xHSLk3jGwXVKIWXPs6xzq6KxGL84y/D6hG85pG2CPOzn08EzMmByts5FTkJ5p3var6yDng==", + "license": "Apache-2.0", + "peerDependencies": { + "convex": "^1.10.0", + "svelte": "^5.0.0" + } + }, + "node_modules/convex/node_modules/@esbuild/aix-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.25.1.tgz", + "integrity": "sha512-kfYGy8IdzTGy+z0vFGvExZtxkFlA4zAxgKEahG9KE1ScBjpQnFsNOX8KTU5ojNru5ed5CVoJYXFtoxaq5nFbjQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/android-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/android-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.25.1.tgz", + "integrity": "sha512-50tM0zCJW5kGqgG7fQ7IHvQOcAn9TKiVRuQ/lN0xR+T2lzEFvAi1ZcS8DiksFcEpf1t/GYOeOfCAgDHFpkiSmA==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/android-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/darwin-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/darwin-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-loong64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-s390x": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/netbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.25.1.tgz", + "integrity": "sha512-O96poM2XGhLtpTh+s4+nP7YCCAfb4tJNRVZHfIE7dgmax+yMP2WgMd2OecBuaATHKTHsLWHQeuaxMRnCsH8+5g==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/netbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.25.1.tgz", + "integrity": "sha512-X53z6uXip6KFXBQ+Krbx25XHV/NCbzryM6ehOAeAil7X7oa4XIq+394PWGnwaSQ2WRA0KI6PUO6hTO5zeF5ijA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/openbsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.25.1.tgz", + "integrity": "sha512-Na9T3szbXezdzM/Kfs3GcRQNjHzM6GzFBeU1/6IV/npKP5ORtp9zbQjvkDJ47s6BCgaAZnnnu/cY1x342+MvZg==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/openbsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.25.1.tgz", + "integrity": "sha512-T3H78X2h1tszfRSf+txbt5aOp/e7TAz3ptVKu9Oyir3IAOFPGV6O9c2naym5TOriy1l0nNf6a4X5UXRZSGX/dw==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" } }, - "node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, + "node_modules/convex/node_modules/@esbuild/sunos-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.25.1.tgz", + "integrity": "sha512-2H3RUvcmULO7dIE5EWJH8eubZAI4xw54H1ilJnRNZdeo8dTADEZ21w6J22XBkXqGJbe0+wnNJtw3UXRoLJnFEg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=8" + "node": ">=18" } }, - "node_modules/check-error": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", - "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", - "dev": true, + "node_modules/convex/node_modules/@esbuild/win32-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.25.1.tgz", + "integrity": "sha512-GE7XvrdOzrb+yVKB9KsRMq+7a2U/K5Cf/8grVFRAGJmfADr/e/ODQ134RK2/eeHqYV5eQRFxb1hY7Nr15fv1NQ==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 16" + "node": ">=18" } }, - "node_modules/chokidar": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", - "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", - "dev": true, + "node_modules/convex/node_modules/@esbuild/win32-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.25.1.tgz", + "integrity": "sha512-uOxSJCIcavSiT6UnBhBzE8wy3n0hOkJsBOzy7HDAuTDE++1DJMRRVCPGisULScHL+a/ZwdXPpXD3IyFKjA7K8A==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "readdirp": "^4.0.1" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">= 14.16.0" - }, - "funding": { - "url": "https://paulmillr.com/funding/" + "node": ">=18" } }, - "node_modules/clsx": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz", - "integrity": "sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==", - "dev": true, + "node_modules/convex/node_modules/@esbuild/win32-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.25.1.tgz", + "integrity": "sha512-Y1EQdcfwMSeQN/ujR5VayLOJ1BHaK+ssyk0AEzPjC+t1lITgsnccPqFjb6V+LsTp/9Iov4ysfjxLaGJ9RPtkVg==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6" + "node": ">=18" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, + "node_modules/convex/node_modules/esbuild": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.25.1.tgz", + "integrity": "sha512-BGO5LtrGC7vxnqucAe/rmvKdJllfGaYWdyABvyMoXQlfYMb2bbRuReWR5tEGE//4LcNJj9XrkovTqNYRFZHAMQ==", + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "color-name": "~1.1.4" + "bin": { + "esbuild": "bin/esbuild" }, "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, - "node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", - "dev": true, + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.25.1", + "@esbuild/android-arm": "0.25.1", + "@esbuild/android-arm64": "0.25.1", + "@esbuild/android-x64": "0.25.1", + "@esbuild/darwin-arm64": "0.25.1", + "@esbuild/darwin-x64": "0.25.1", + "@esbuild/freebsd-arm64": "0.25.1", + "@esbuild/freebsd-x64": "0.25.1", + "@esbuild/linux-arm": "0.25.1", + "@esbuild/linux-arm64": "0.25.1", + "@esbuild/linux-ia32": "0.25.1", + "@esbuild/linux-loong64": "0.25.1", + "@esbuild/linux-mips64el": "0.25.1", + "@esbuild/linux-ppc64": "0.25.1", + "@esbuild/linux-riscv64": "0.25.1", + "@esbuild/linux-s390x": "0.25.1", + "@esbuild/linux-x64": "0.25.1", + "@esbuild/netbsd-arm64": "0.25.1", + "@esbuild/netbsd-x64": "0.25.1", + "@esbuild/openbsd-arm64": "0.25.1", + "@esbuild/openbsd-x64": "0.25.1", + "@esbuild/sunos-x64": "0.25.1", + "@esbuild/win32-arm64": "0.25.1", + "@esbuild/win32-ia32": "0.25.1", + "@esbuild/win32-x64": "0.25.1" + } + }, + "node_modules/convex/node_modules/prettier": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.5.2.tgz", + "integrity": "sha512-lc6npv5PH7hVqozBR7lkBNOGXV9vMwROAPlumdBkX0wTbbzPu/U1hk5yL8p2pt4Xoc+2mkT8t/sow2YrV/M5qg==", "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, "engines": { - "node": ">= 0.6" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, "node_modules/cross-spawn": { @@ -2442,16 +2907,6 @@ "dev": true, "license": "MIT" }, - "node_modules/deepmerge": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", - "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -2472,13 +2927,6 @@ "node": ">=8" } }, - "node_modules/devalue": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/devalue/-/devalue-5.1.1.tgz", - "integrity": "sha512-maua5KUiapvEwiEAe+XnlZ3Rh0GD+qI1J/nb9vrJc3muPXvcF/8gXYTWF76+5DAqHyDUtOIImEuo0YKE9mshVw==", - "dev": true, - "license": "MIT" - }, "node_modules/dom-accessibility-api": { "version": "0.6.3", "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.6.3.tgz", @@ -2728,13 +3176,6 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, - "node_modules/esm-env": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/esm-env/-/esm-env-1.2.2.tgz", - "integrity": "sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==", - "dev": true, - "license": "MIT" - }, "node_modules/espree": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", @@ -2766,16 +3207,6 @@ "node": ">=0.10" } }, - "node_modules/esrap": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/esrap/-/esrap-1.4.6.tgz", - "integrity": "sha512-F/D2mADJ9SHY3IwksD4DAXjTt7qt7GWUf3/8RhCNWmC/67tyb55dpimHmy7EplakFaflV0R/PC+fdSPqrRHAQw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" - } - }, "node_modules/esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -2890,21 +3321,6 @@ "reusify": "^1.0.4" } }, - "node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", - "dev": true, - "license": "MIT", - "peerDependencies": { - "picomatch": "^3 || ^4" - }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -3186,16 +3602,6 @@ "dev": true, "license": "MIT" }, - "node_modules/is-reference": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.3.tgz", - "integrity": "sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.6" - } - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", @@ -3294,6 +3700,15 @@ "dev": true, "license": "MIT" }, + "node_modules/jwt-decode": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", + "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -3304,16 +3719,6 @@ "json-buffer": "3.0.1" } }, - "node_modules/kleur": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/kleur/-/kleur-4.1.5.tgz", - "integrity": "sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/known-css-properties": { "version": "0.35.0", "resolved": "https://registry.npmjs.org/known-css-properties/-/known-css-properties-0.35.0.tgz", @@ -3584,13 +3989,6 @@ "node": ">=10" } }, - "node_modules/locate-character": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", - "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", - "dev": true, - "license": "MIT" - }, "node_modules/locate-path": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", @@ -3702,26 +4100,6 @@ "node": "*" } }, - "node_modules/mri": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", - "integrity": "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=4" - } - }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=10" - } - }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -4246,20 +4624,6 @@ "dev": true, "license": "MIT" }, - "node_modules/readdirp": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", - "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 14.18.0" - }, - "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" - } - }, "node_modules/redent": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/redent/-/redent-3.0.0.tgz", @@ -4373,19 +4737,6 @@ "queue-microtask": "^1.2.2" } }, - "node_modules/sade": { - "version": "1.8.1", - "resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz", - "integrity": "sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==", - "dev": true, - "license": "MIT", - "dependencies": { - "mri": "^1.1.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/safer-buffer": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", @@ -4419,13 +4770,6 @@ "node": ">=10" } }, - "node_modules/set-cookie-parser": { - "version": "2.7.1", - "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.1.tgz", - "integrity": "sha512-IOc8uWeOZgnb3ptbCURJWNjWUPcO3ZnTTdzsurqERrP6nPyv+paC55vJM0LpOlT2ne+Ix+9+CRG1MNLlyZ4GjQ==", - "dev": true, - "license": "MIT" - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -4456,21 +4800,6 @@ "dev": true, "license": "ISC" }, - "node_modules/sirv": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", - "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", - "dev": true, - "license": "MIT", - "dependencies": { - "@polka/url": "^1.0.0-next.24", - "mrmime": "^2.0.0", - "totalist": "^3.0.0" - }, - "engines": { - "node": ">=18" - } - }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -4535,54 +4864,12 @@ } }, "node_modules/svelte": { - "version": "5.26.2", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.26.2.tgz", - "integrity": "sha512-e2TEcGK2YKVwDWYy5OsptVclYgDvfY1E/8IzPiOq63uG/GDo/j5VUYTC9EinQNraoZalbMWN+5f5TYC1QlAqOw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@ampproject/remapping": "^2.3.0", - "@jridgewell/sourcemap-codec": "^1.5.0", - "@sveltejs/acorn-typescript": "^1.0.5", - "@types/estree": "^1.0.5", - "acorn": "^8.12.1", - "aria-query": "^5.3.1", - "axobject-query": "^4.1.0", - "clsx": "^2.1.1", - "esm-env": "^1.2.1", - "esrap": "^1.4.6", - "is-reference": "^3.0.3", - "locate-character": "^3.0.0", - "magic-string": "^0.30.11", - "zimmerframe": "^1.1.2" - }, - "engines": { - "node": ">=18" - } + "resolved": "../node_modules/svelte", + "link": true }, "node_modules/svelte-check": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.1.6.tgz", - "integrity": "sha512-P7w/6tdSfk3zEVvfsgrp3h3DFC75jCdZjTQvgGJtjPORs1n7/v2VMPIoty3PWv7jnfEm3x0G/p9wH4pecTb0Wg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/trace-mapping": "^0.3.25", - "chokidar": "^4.0.1", - "fdir": "^6.2.0", - "picocolors": "^1.0.0", - "sade": "^1.7.4" - }, - "bin": { - "svelte-check": "bin/svelte-check" - }, - "engines": { - "node": ">= 18.0.0" - }, - "peerDependencies": { - "svelte": "^4.0.0 || ^5.0.0-next.0", - "typescript": ">=5.0.0" - } + "resolved": "../node_modules/svelte-check", + "link": true }, "node_modules/svelte-eslint-parser": { "version": "1.1.2", @@ -4714,16 +5001,6 @@ "node": ">=8.0" } }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - } - }, "node_modules/tough-cookie": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.1.2.tgz", @@ -4940,25 +5217,6 @@ "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/vitefu": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.6.tgz", - "integrity": "sha512-+Rex1GlappUyNN6UfwbVZne/9cYC4+R2XDk9xkNXBKMw6HQagdX9PgZ8V2v1WUSK1wfBLp7qbI1+XSNIlB1xmA==", - "dev": true, - "license": "MIT", - "workspaces": [ - "tests/deps/*", - "tests/projects/*" - ], - "peerDependencies": { - "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0" - }, - "peerDependenciesMeta": { - "vite": { - "optional": true - } - } - }, "node_modules/vitest": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/vitest/-/vitest-3.1.1.tgz", @@ -5198,13 +5456,6 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } - }, - "node_modules/zimmerframe": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", - "integrity": "sha512-rAbqEGa8ovJy4pyBxZM70hg4pE6gDgaQ0Sl9M3enG3I0d6H4XSAM3GeNGLKnsBpuijUow064sf7ww1nutC5/3w==", - "dev": true, - "license": "MIT" } } } diff --git a/test-sveltekit/package.json b/test-sveltekit/package.json index 011e47e8..e01d4be6 100644 --- a/test-sveltekit/package.json +++ b/test-sveltekit/package.json @@ -41,5 +41,9 @@ "typescript-eslint": "^8.20.0", "vite": "^6.2.5", "vitest": "^3.0.0" + }, + "dependencies": { + "convex": "file:../node_modules/convex", + "convex-svelte": "file:../node_modules/convex-svelte" } } From cee8b89db01fd80ff36ac7a0cf86e31c16b0efa5 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Mon, 14 Apr 2025 18:48:22 +0200 Subject: [PATCH 03/88] Svelte Client --- src/svelte/client.svelte.ts | 595 ++++++++++++++++++++++++++++++++++++ src/svelte/clientType.ts | 38 +++ src/svelte/index.svelte.ts | 279 +++++++++++++++++ 3 files changed, 912 insertions(+) create mode 100644 src/svelte/client.svelte.ts create mode 100644 src/svelte/clientType.ts create mode 100644 src/svelte/index.svelte.ts diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts new file mode 100644 index 00000000..2d3b3e0f --- /dev/null +++ b/src/svelte/client.svelte.ts @@ -0,0 +1,595 @@ +/** + * Svelte implementation of Convex Auth client. + */ +import { getContext, setContext } from "svelte"; +import type { + SignInAction, + SignOutAction, +} from "../server/implementation/index.js"; +import { AuthClient } from "./clientType.js"; +import type { TokenStorage } from "./index.svelte.js"; +import isNetworkError from "is-network-error"; + +// Retry after this much time, based on the retry number. +const RETRY_BACKOFF = [500, 2000]; // In ms +const RETRY_JITTER = 100; // In ms + +// Storage keys +const VERIFIER_STORAGE_KEY = "__convexAuthOAuthVerifier"; +const JWT_STORAGE_KEY = "__convexAuthJWT"; +const REFRESH_TOKEN_STORAGE_KEY = "__convexAuthRefreshToken"; +const SERVER_STATE_FETCH_TIME_STORAGE_KEY = "__convexAuthServerStateFetchTime"; + +// Convex auth context key +const AUTH_CONTEXT_KEY = "$$_convexAuth"; + +/** + * Create a Convex Auth client with Svelte reactivity + */ +export function createAuthClient({ + client, + serverState, + onChange, + storage, + storageNamespace, + replaceURL, +}: { + client: AuthClient; + serverState?: { + _state: { token: string | null; refreshToken: string | null }; + _timeFetched: number; + }; + onChange?: () => Promise; + storage: TokenStorage | null; + storageNamespace: string; + replaceURL: (relativeUrl: string) => void | Promise; +}) { + // Initialize state with reactive variables + const state = $state({ + token: serverState?._state.token ?? null, + isLoading: serverState?._state.token === null, + isRefreshingToken: false + }); + const isAuthenticated = $derived(state.token !== null); + + // Debug logging + const verbose: boolean = client.verbose ?? false; + const logVerbose = (message: string) => { + if (verbose) { + console.debug(`${new Date().toISOString()} ${message}`); + client.logger?.logVerbose(message); + } + }; + + // Create storage helpers with namespace + const { storageSet, storageGet, storageRemove } = useNamespacedStorage( + storage, + storageNamespace + ); + + // Token management + const setToken = async ( + args: + | { shouldStore: true; tokens: { token: string; refreshToken: string } } + | { shouldStore: false; tokens: { token: string } } + | { shouldStore: boolean; tokens: null } + ) => { + const wasAuthenticated = state.token !== null; + let newToken: string | null; + + if (args.tokens === null) { + state.token = null; + if (args.shouldStore) { + await storageRemove(JWT_STORAGE_KEY); + await storageRemove(REFRESH_TOKEN_STORAGE_KEY); + } + newToken = null; + } else { + const { token: value } = args.tokens; + state.token = value; + if (args.shouldStore) { + const { refreshToken } = args.tokens; + await storageSet(JWT_STORAGE_KEY, value); + await storageSet(REFRESH_TOKEN_STORAGE_KEY, refreshToken); + + // Store server state fetch time + if (serverState && !state.isRefreshingToken) { + await storageSet(SERVER_STATE_FETCH_TIME_STORAGE_KEY, `${serverState._timeFetched}`); + } + } + newToken = value; + } + + if (wasAuthenticated !== (newToken !== null)) { + await onChange?.(); + } + + state.isLoading = false; + }; + + // Load tokens from storage on initialization + $effect(() => { + if (typeof window === "undefined") { + // Skip on server + return; + } + + const loadTokens = async () => { + if (serverState?._state) { + // Use server state + const { token: accessToken, refreshToken } = serverState._state; + if (accessToken !== null && refreshToken !== null) { + await setToken({ + shouldStore: true, + tokens: { token: accessToken, refreshToken }, + }); + return; + } + } + + // Try to load from storage + try { + const [storedToken, storedRefreshToken] = await Promise.all([ + storageGet(JWT_STORAGE_KEY), + storageGet(REFRESH_TOKEN_STORAGE_KEY), + ]); + + if (storedToken && storedRefreshToken) { + logVerbose("loaded from storage"); + await setToken({ + shouldStore: false, + tokens: { token: storedToken }, + }); + } else { + // No tokens in storage + logVerbose("no tokens in storage"); + state.isLoading = false; + } + } catch (e) { + console.error("Failed to load auth tokens", e); + state.isLoading = false; + } + }; + + // Check URL for auth code + const checkUrlForCode = async () => { + if (typeof window === "undefined") { + return; + } + + const url = new URL(window.location.href); + const code = url.searchParams.get("code"); + + if (code) { + logVerbose("found code in URL, removing"); + url.searchParams.delete("code"); + await replaceURL( + url.pathname + url.search + (url.hash ? url.hash : "") + ); + + // Get verifier from storage + const verifier = await storageGet(VERIFIER_STORAGE_KEY); + await storageRemove(VERIFIER_STORAGE_KEY); + + logVerbose(`verifying code, have verifier: ${!!verifier}`); + try { + const response = await verifyCode({ + code, + verifier: verifier ?? undefined, + }); + + // Extract tokens from the response + if (response.tokens) { + // If tokens is available in the response + await setToken({ + shouldStore: true, + tokens: response.tokens + }); + logVerbose("signed in with code from URL using tokens object"); + } else { + // No valid tokens in the response + console.error("No valid tokens in auth response:", response); + state.isLoading = false; + return; + } + + logVerbose("signed in with code from URL"); + } catch (e) { + console.error("Failed to verify code from URL:", e); + state.isLoading = false; + } + } + }; + + // Kick off loading tokens and checking for code + void loadTokens(); + void checkUrlForCode(); + }); + + // Listen for storage events (for cross-tab sync) + $effect(() => { + if (typeof window === "undefined") { + return; + } + + const storageListener = (event: StorageEvent) => { + if (event.storageArea !== storage) { + return; + } + + // Check if our JWT token changed + if (event.key === storageKey(JWT_STORAGE_KEY, storageNamespace)) { + const value = event.newValue; + logVerbose(`synced access token, is null: ${value === null}`); + + // Update our state without writing back to storage + void setToken({ + shouldStore: false, + tokens: value === null ? null : { token: value }, + }); + } + }; + + window.addEventListener("storage", storageListener); + return () => window.removeEventListener("storage", storageListener); + }); + + // Warning before leaving page during token refresh + $effect(() => { + if (typeof window === "undefined") { + return; + } + + const beforeUnloadListener = (e: BeforeUnloadEvent) => { + if (state.isRefreshingToken) { + e.preventDefault(); + const confirmationMessage = + "Are you sure you want to leave? Your changes may not be saved."; + e.returnValue = confirmationMessage; + return confirmationMessage; + } + }; + + window.addEventListener("beforeunload", beforeUnloadListener); + return () => window.removeEventListener("beforeunload", beforeUnloadListener); + }); + + // Auth methods + const verifyCode = async ( + args: { code: string; verifier?: string } | { refreshToken: string } + ) => { + let lastError; + // Retry the call if it fails due to a network error. + // This is especially common in mobile apps where an app is backgrounded + // while making a call and hits a network error, but will succeed with a + // retry once the app is brought to the foreground. + let retry = 0; + while (retry < RETRY_BACKOFF.length) { + try { + return await client.unauthenticatedCall( + "auth:signIn" as unknown as SignInAction, + "code" in args + ? { params: { code: args.code }, verifier: args.verifier } + : args + ); + } catch (e) { + lastError = e; + if (!isNetworkError(e)) { + break; + } + const wait = RETRY_BACKOFF[retry] + RETRY_JITTER * Math.random(); + retry++; + logVerbose( + `verifyCode failed with network error, retry ${retry} of ${RETRY_BACKOFF.length} in ${wait}ms` + ); + await new Promise((resolve) => setTimeout(resolve, wait)); + } + } + throw lastError; + }; + + const fetchAccessToken = async ({ + forceRefreshToken = false, + }: { + forceRefreshToken: boolean; + }): Promise => { + logVerbose(`fetchAccessToken forceRefreshToken=${forceRefreshToken}`); + + // Return the existing token if we have one and aren't forcing a refresh + if (state.token !== null && !forceRefreshToken) { + return state.token; + } + + try { + state.isRefreshingToken = true; + + // Get the refresh token from storage + const refreshToken = await storageGet(REFRESH_TOKEN_STORAGE_KEY); + if (!refreshToken) { + return null; + } + + logVerbose("using refresh token to get new access token"); + const response = await verifyCode({ refreshToken }); + + if (response.tokens) { + logVerbose(`got new access token, is null: ${response.tokens.token === null}`); + await setToken({ shouldStore: true, tokens: response.tokens }); + return response.tokens.token; + } else { + logVerbose("no tokens in refresh token response"); + return null; + } + } catch (e) { + console.error("Failed to refresh token:", e); + + // Clear tokens on failure + await setToken({ shouldStore: true, tokens: null }); + return null; + } finally { + state.isRefreshingToken = false; + } + }; + + const signIn = async ( + provider: string, + params?: FormData | Record + ): Promise => { + logVerbose(`signIn provider=${provider}`); + + try { + // Get verifier if it exists + const verifier = (await storageGet(VERIFIER_STORAGE_KEY)) ?? undefined; + + + const finalParams = params instanceof FormData + ? Object.fromEntries(params.entries()) + : params ?? {}; + + const response = await client.authenticatedCall( + "auth:signIn" as unknown as SignInAction, + { provider, params: finalParams, verifier } + ); + + if (response.started === true) { + // Redirect flow, need to store verifier + if (response.verifier) { + await storageSet(VERIFIER_STORAGE_KEY, response.verifier); + } + + if (typeof window !== "undefined" && response.redirect) { + window.location.href = response.redirect; + } + + return false; + } else if (!response.redirect) { + // Auth completed silently + if (response.tokens) { + await setToken({ shouldStore: true, tokens: response.tokens }); + return true; + } else { + console.error("No tokens in silent auth response"); + return false; + } + } else { + // Redirect flow + if (response.verifier) { + await storageSet(VERIFIER_STORAGE_KEY, response.verifier); + } + + if (typeof window !== "undefined") { + window.location.href = response.redirect; + } + + return false; + } + } catch (e) { + console.error("Failed to sign in:", e); + throw e; + } + }; + + const signOut = async (): Promise => { + logVerbose("signOut"); + + try { + // This can fail if the backend is unavailable, that's ok we will + // still sign out on the client. + await client.authenticatedCall( + "auth:signOut" as unknown as SignOutAction + ); + } catch (e) { + // Ignore any errors, they are usually caused by being + // already signed out, which is ok. + } + + // Always clear tokens locally, even if server call failed + await setToken({ shouldStore: true, tokens: null }); + logVerbose(`signed out, tokens erased`); + }; + + // Expose the auth API + const authApi = { + get isLoading() { return state.isLoading; }, + get isAuthenticated() { return isAuthenticated; }, + fetchAccessToken, + signIn, + signOut, + }; + + return authApi; +} + +/** + * Get the Convex Auth client from the context + */ +export function useAuth() { + const authClient = getContext(AUTH_CONTEXT_KEY); + if (!authClient) { + throw new Error( + "No ConvexAuth client found in context. Did you forget to use createAuthProvider?" + ); + } + return authClient; +} + +/** + * Set the Convex Auth client in the context + */ +export function setConvexAuthContext(authClient: ReturnType) { + setContext(AUTH_CONTEXT_KEY, authClient); + return authClient; +} + +/** + * Create a fully namespaced key for storage + */ +function storageKey(key: string, namespace: string): string { + return `${namespace}:${key}`; +} + +/** + * Create an in-memory storage implementation + */ +function createInMemoryStorage(): TokenStorage { + // Create a closure around the map to maintain state + const map = new Map(); + + return { + getItem: (key) => map.get(key) ?? null, + setItem: (key, value) => { + map.set(key, value); + }, + removeItem: (key) => { + map.delete(key); + }, + }; +} + +/** + * Helper to create namespaced storage functions + */ +function useNamespacedStorage(persistentStorage: TokenStorage | null, namespace: string) { + // Use either provided storage or create in-memory storage + const storage = persistentStorage ?? createInMemoryStorage(); + + // Normalize namespace to alphanumeric only (for compatibility with RN) + const normalizedNamespace = namespace.replace(/[^a-zA-Z0-9]/g, ""); + + const storageGet = async (key: string): Promise => { + try { + const value = await storage.getItem(storageKey(key, normalizedNamespace)); + return value ?? null; + } catch (e) { + console.error(`Failed to get ${key} from storage:`, e); + return null; + } + }; + + const storageSet = async (key: string, value: string): Promise => { + try { + await storage.setItem(storageKey(key, normalizedNamespace), value); + } catch (e) { + console.error(`Failed to set ${key} in storage:`, e); + } + }; + + const storageRemove = async (key: string): Promise => { + try { + await storage.removeItem(storageKey(key, normalizedNamespace)); + } catch (e) { + console.error(`Failed to remove ${key} from storage:`, e); + } + }; + + return { storageSet, storageGet, storageRemove }; +} + +// In the browser, executes the callback as the only tab / frame at a time. +export async function browserMutex( + key: string, + callback: () => Promise +): Promise { + if (typeof window === "undefined") { + return callback(); + } + const lockManager = window?.navigator?.locks; + return lockManager !== undefined + ? await lockManager.request(key, callback) + : await manualMutex(key, callback); +} + +function getMutexValue(key: string): { + currentlyRunning: Promise | null; + waiting: Array<() => Promise>; +} { + if ((globalThis as any).__convexAuthMutexes === undefined) { + (globalThis as any).__convexAuthMutexes = {} as Record< + string, + { + currentlyRunning: Promise; + waiting: Array<() => Promise>; + } + >; + } + let mutex = (globalThis as any).__convexAuthMutexes[key]; + if (mutex === undefined) { + (globalThis as any).__convexAuthMutexes[key] = { + currentlyRunning: null, + waiting: [], + }; + } + mutex = (globalThis as any).__convexAuthMutexes[key]; + return mutex; +} + +function setMutexValue( + key: string, + value: { + currentlyRunning: Promise | null; + waiting: Array<() => Promise>; + }, +) { + (globalThis as any).__convexAuthMutexes[key] = value; +} + +async function enqueueCallbackForMutex( + key: string, + callback: () => Promise, +) { + const mutex = getMutexValue(key); + if (mutex.currentlyRunning === null) { + setMutexValue(key, { + currentlyRunning: callback().finally(() => { + const nextCb = getMutexValue(key).waiting.shift(); + getMutexValue(key).currentlyRunning = null; + setMutexValue(key, { + ...getMutexValue(key), + currentlyRunning: + nextCb === undefined ? null : enqueueCallbackForMutex(key, nextCb), + }); + }), + waiting: [], + }); + } else { + setMutexValue(key, { + ...mutex, + waiting: [...mutex.waiting, callback], + }); + } +} + +async function manualMutex( + key: string, + callback: () => Promise, +): Promise { + const outerPromise = new Promise((resolve, reject) => { + const wrappedCallback: () => Promise = () => { + return callback() + .then((v) => resolve(v)) + .catch((e) => reject(e)); + }; + void enqueueCallbackForMutex(key, wrappedCallback); + }); + return outerPromise; +} diff --git a/src/svelte/clientType.ts b/src/svelte/clientType.ts new file mode 100644 index 00000000..92837b88 --- /dev/null +++ b/src/svelte/clientType.ts @@ -0,0 +1,38 @@ +/** + * Svelte client type definitions for Convex Auth. + */ + +import { FunctionReference, OptionalRestArgs } from "convex/server"; + +/** + * Client implementation for authenticating with the Convex backend. + */ +export interface AuthClient { + /** + * Makes an authenticated call to a Convex action. + */ + authenticatedCall>( + action: Action, + ...args: OptionalRestArgs + ): Promise; + + /** + * Makes an unauthenticated call to a Convex action. + */ + unauthenticatedCall>( + action: Action, + ...args: OptionalRestArgs + ): Promise; + + /** + * Whether to log verbose auth information. + */ + verbose?: boolean; + + /** + * Optional logger for Convex operations. + */ + logger?: { + logVerbose: (message: string) => void; + }; +} diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts new file mode 100644 index 00000000..32504b00 --- /dev/null +++ b/src/svelte/index.svelte.ts @@ -0,0 +1,279 @@ +/** + * Svelte bindings for Convex Auth. + * + * @module + */ + +import { ConvexClient } from "convex/browser"; +import { getContext, setContext } from "svelte"; +import { Value } from "convex/values"; +import { createAuthClient, setConvexAuthContext } from "./client.svelte.js"; +import { AuthClient } from "./clientType.js"; + +// Context key for Convex auth actions +const CONVEX_AUTH_ACTIONS_CONTEXT_KEY = "$$_convexAuthActions"; +const CONVEX_AUTH_TOKEN_CONTEXT_KEY = "$$_convexAuthToken"; + +/** + * A storage interface for storing and retrieving tokens and other secrets. + * + * In browsers `localStorage` and `sessionStorage` implement this interface. + * + * `sessionStorage` can be used for creating separate sessions for each + * browser tab. + * + * For mobile apps, we recommend using a secure storage mechanism. + */ +export interface TokenStorage { + /** + * Read a value. + * @param key Unique key. + */ + getItem: ( + key: string, + ) => string | undefined | null | Promise; + /** + * Write a value. + * @param key Unique key. + * @param value The value to store. + */ + setItem: (key: string, value: string) => void | Promise; + /** + * Remove a value. + * @param key Unique key. + */ + removeItem: (key: string) => void | Promise; +} + +/** + * The result of calling `useAuthActions`. + */ +export type ConvexAuthActionsContext = { + /** + * Sign in via one of your configured authentication providers. + * + * @returns Whether the user was immediately signed in (ie. the sign-in + * didn't trigger an additional step like email verification + * or OAuth signin). + */ + signIn( + /** + * The ID of the provider (lowercase version of the + * provider name or a configured `id` option value). + */ + provider: string, + /** + * Either a `FormData` object containing the sign-in + * parameters or a plain object containing them. + * The shape required depends on the chosen provider's + * implementation. + * + * Special fields: + * - `redirectTo`: If provided, customizes the destination the user is + * redirected to at the end of an OAuth flow or the magic link URL. + * See [redirect callback](https://labs.convex.dev/auth/api_reference/server#callbacksredirect). + * - `code`: OTP code for email or phone verification, or + * (used only in RN) the code from an OAuth flow or magic link URL. + */ + params?: + | FormData + | (Record & { + /** + * If provided, customizes the destination the user is + * redirected to at the end of an OAuth flow or the magic link URL. + */ + redirectTo?: string; + /** + * OTP code for email or phone verification, or + * (used only in RN) the code from an OAuth flow or magic link URL. + */ + code?: string; + }), + ): Promise; + /** + * Sign out the current user, deleting the token from storage. + * + * The default implementation in {@link ConvexAuthProvider} also: + * 1. Calls the `auth:signOut` action. This can fail if the backend is + * unavailable, in which case the user will be signed out on the client + * only. + */ + signOut(): Promise; +}; + +/** + * Create the Convex auth context provider. + * + * ```svelte + * + * + * + * + * + * ``` + */ +export function createConvexAuthProvider() { + // Return a Svelte component (as a function) + return function ConvexAuthProvider({ + client, + storage = typeof window !== "undefined" ? window.localStorage : null, + storageNamespace, + replaceURL = (url: string) => { + if (typeof window !== "undefined") { + window.history.replaceState({}, "", url); + } + }, + children = undefined, + }: { + client?: ConvexClient; + storage?: TokenStorage | null; + storageNamespace?: string; + replaceURL?: (relativeUrl: string) => void | Promise; + children?: any; + } = {}) { + // If client is not provided, try to get it from context + if (!client) { + try { + client = getContext("$$_convexClient"); + } catch (e) { + throw new Error( + "No ConvexClient was provided. Either pass one to ConvexAuthProvider or call setupConvex() first.", + ); + } + } + + // Create auth client with reactive memoization + const authClient = $derived.by( + () => + ({ + authenticatedCall(action, args) { + return client!.action(action, args); + }, + unauthenticatedCall(action, args) { + return new ConvexClient((client as any).address, { + logger: (client as any).logger, + }).action(action, args); + }, + verbose: (client as any).options?.verbose, + logger: (client as any).logger, + }) satisfies AuthClient, + ); + + // Create the auth store and set in context + const auth = createAuthClient({ + client: authClient, + storage, + storageNamespace: storageNamespace ?? (client as any).address, + replaceURL, + onChange: async () => { + // Handle auth state changes + // This is a hook for implementations to use + }, + }); + + // Set auth contexts + setConvexAuthContext(auth); + setContext(CONVEX_AUTH_ACTIONS_CONTEXT_KEY, { + signIn: auth.signIn, + signOut: auth.signOut, + }); + + // Set token context (reactive) + $effect(() => { + let isMounted = true; + + if (auth.isAuthenticated) { + // Use void to handle the promise without returning it + void (async () => { + try { + const token = await auth.fetchAccessToken({ + forceRefreshToken: false, + }); + if (isMounted) { + setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, token); + } + } catch (error) { + console.error("Failed to fetch auth token:", error); + if (isMounted) { + setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, null); + } + } + })(); + } else { + setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, null); + } + + // Return a cleanup function + return () => { + isMounted = false; + }; + }); + + // Return children (in Svelte, using ) + return children; + }; +} + +/** + * Use this hook to access the `signIn` and `signOut` methods: + * + * ```ts + * import { useAuthActions } from "@convex-dev/auth/svelte"; + * + * function SomeComponent() { + * const { signIn, signOut } = useAuthActions(); + * // ... + * } + * ``` + */ +export function useAuthActions() { + const actions = getContext( + CONVEX_AUTH_ACTIONS_CONTEXT_KEY, + ); + if (!actions) { + throw new Error( + "No auth actions found in context. Did you forget to use ConvexAuthProvider?", + ); + } + return actions; +} + +/** + * Use this function to access the JWT token, for authenticating + * your Convex HTTP actions. + * + * You should not pass this token to other servers (think of it + * as an "ID token"). + * + * ```ts + * import { useAuthToken } from "@convex-dev/auth/svelte"; + * + * function SomeComponent() { + * const token = useAuthToken(); + * + * async function handleClick() { + * await fetch(`${CONVEX_SITE_URL}/someEndpoint`, { + * headers: { + * Authorization: `Bearer ${token}`, + * }, + * }); + * } + * // ... + * } + * ``` + */ +export function useAuthToken(): string | null { + return getContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY) ?? null; +} + +// Re-export types +export type { AuthClient } from "./clientType.js"; From 16962cfa2bd14d14eeb5dab9f3b0cae87e6d2580 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Tue, 15 Apr 2025 18:17:33 +0200 Subject: [PATCH 04/88] Add SvelteKit auth implementation with server-side handlers and route protection --- src/sveltekit/README.md | 383 +++++++++++++++++++++++++++ src/sveltekit/client.ts | 85 ++++++ src/sveltekit/index.ts | 114 ++++++++ src/sveltekit/server/handlers.ts | 278 +++++++++++++++++++ src/sveltekit/server/index.ts | 29 ++ src/sveltekit/server/routeMatcher.ts | 52 ++++ 6 files changed, 941 insertions(+) create mode 100644 src/sveltekit/README.md create mode 100644 src/sveltekit/client.ts create mode 100644 src/sveltekit/index.ts create mode 100644 src/sveltekit/server/handlers.ts create mode 100644 src/sveltekit/server/index.ts create mode 100644 src/sveltekit/server/routeMatcher.ts diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md new file mode 100644 index 00000000..34e1b050 --- /dev/null +++ b/src/sveltekit/README.md @@ -0,0 +1,383 @@ +# Convex Auth for SvelteKit + +This package provides authentication functionality for SvelteKit applications using Convex as a backend. It includes both client-side components and server-side utilities for a complete authentication solution. + +## Installation + +```bash +npm install @convex-dev/auth +# or +pnpm add @convex-dev/auth +# or +yarn add @convex-dev/auth +``` + +## Setup + +### 1. Environment Variables + +Create or update your `.env` file with the following variables: + +``` +PUBLIC_CONVEX_URL=your_convex_deployment_url +``` + +For local development, you can also create a `.env.local` file. + +### 2. Configure Auth Provider (Client-side) + +Set up the Convex client and auth provider in your root layout: + +```html + + + + + + +``` + +### 3. Add Auth State in Layout Server + +Load the authentication state in your layout server: + +```typescript +// src/routes/+layout.server.ts +import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; +import { PUBLIC_CONVEX_URL } from '$env/static/public'; +import type { LayoutServerLoad } from './$types'; + +// Create auth handlers +const { loadAuthState } = createConvexAuthHandlers({ + convexUrl: PUBLIC_CONVEX_URL +}); + +// Export load function to provide auth state to layout +export const load: LayoutServerLoad = async (event) => { + return loadAuthState(event); +}; +``` + +### 4. Configure Auth Hooks (Server-side) + +Create hooks to handle authentication in `src/hooks.server.ts`: + +```typescript +// src/hooks.server.ts +import { sequence } from '@sveltejs/kit/hooks'; +import { PUBLIC_CONVEX_URL } from '$env/static/public'; +import { createConvexAuthHooks } from '@convex-dev/auth/sveltekit/server'; + +// Create auth hooks with your Convex URL +const { handleAuth, protectRoutes } = createConvexAuthHooks({ + convexUrl: PUBLIC_CONVEX_URL, + // Optional: Custom API route (default: '/api/auth') + apiRoute: '/api/auth', + // Optional: Custom cookie options + cookieOptions: { + path: '/', + httpOnly: true, + secure: true, + sameSite: 'lax' + } +}); + +// Apply hooks in sequence +export const handle = sequence( + handleAuth, // This handles all POST requests to /api/auth automatically + protectRoutes, + // Your other custom handlers... +); +``` + +## Usage + +### Pages (`+page.svelte`) + +Use authentication in your pages: + +```html + + + +{#if isLoading} +

Loading authentication state...

+{:else if isAuthenticated} +

Welcome, authenticated user!

+ +{:else} +

Please sign in

+ + +{/if} +``` + +### Page Server (`+page.server.ts`) + +Use auth state in page server load functions: + +```typescript +// src/routes/profile/+page.server.ts +import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; +import { PUBLIC_CONVEX_URL } from '$env/static/public'; +import { redirect } from '@sveltejs/kit'; +import type { PageServerLoad } from './$types'; + +// Create auth handlers +const { isAuthenticated } = createConvexAuthHandlers({ + convexUrl: PUBLIC_CONVEX_URL +}); + +// Protect routes at the page level +export const load: PageServerLoad = async (event) => { + // Check if user is authenticated + if (!(await isAuthenticated(event))) { + // Redirect to login if not authenticated + throw redirect(302, '/login'); + } + + // Return data for authenticated users + return { + user: { /* user data */ } + }; +}; +``` + +## Protecting Routes + +### Option 1: Using Hooks (App-wide Protection) + +Configure route protection patterns in your `hooks.server.ts`: + +```typescript +// src/hooks.server.ts +import { createConvexAuthHooks, createRouteMatcher } from '@convex-dev/auth/sveltekit/server'; + +// Create a matcher for protected routes +const protectedRoutes = createRouteMatcher((path) => { + return path.startsWith('/dashboard') || + path.startsWith('/profile') || + path.startsWith('/admin'); +}); + +// Create auth hooks with route protection +const { handleAuth, protectRoutes } = createConvexAuthHooks({ + convexUrl: PUBLIC_CONVEX_URL, + protectedRoutes, + // Where to redirect unauthenticated users + redirectUrl: '/login' +}); + +export const handle = sequence(handleAuth, protectRoutes); +``` + +### Option 2: Using Page Server Load (Page-level Protection) + +Protect individual pages in their `+page.server.ts`: + +```typescript +// src/routes/protected/+page.server.ts +import { redirect } from '@sveltejs/kit'; +import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; +import { PUBLIC_CONVEX_URL } from '$env/static/public'; + +const { isAuthenticated } = createConvexAuthHandlers({ + convexUrl: PUBLIC_CONVEX_URL +}); + +export async function load(event) { + if (!(await isAuthenticated(event))) { + throw redirect(302, '/login?redirectTo=' + event.url.pathname); + } + + return { + // Page data here + }; +} +``` + +## Authentication Actions + +### Sign In + +```svelte + +``` + +### Sign Out + +```svelte + +``` + +### Check Auth State + +```svelte + + +{#if isLoading} +

Loading...

+{:else if isAuthenticated} +

You are signed in!

+{:else} +

Not signed in.

+{/if} +``` + +## Advanced Usage + +### Custom Redirect Handler + +```typescript +// src/hooks.server.ts +const { handleAuth, protectRoutes } = createConvexAuthHooks({ + convexUrl: PUBLIC_CONVEX_URL, + onUnauthenticated: (event) => { + // Custom redirect logic + const url = new URL('/login', event.url.origin); + url.searchParams.set('from', event.url.pathname); + return new Response(null, { + status: 302, + headers: { Location: url.toString() } + }); + } +}); +``` + +### Route Matcher Patterns + +```typescript +// Match single route +createRouteMatcher('/dashboard'); + +// Match with regex +createRouteMatcher(/^\/api\/private\/.*$/); + +// Match with function +createRouteMatcher((path) => path.includes('/admin/')); + +// Match multiple patterns (OR) +createRouteMatcherGroup([ + '/dashboard', + /^\/profile\/.*$/, + (path) => path.startsWith('/settings') +]); +``` + +### Manual Token Handling + +```svelte + +``` + +### Alternative: Custom API Endpoint + +If you prefer to handle auth requests with a dedicated endpoint (instead of using the hooks approach), create a file at `src/routes/api/auth/+server.ts`: + +```typescript +// src/routes/api/auth/+server.ts +import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; +import { PUBLIC_CONVEX_URL } from '$env/static/public'; +import type { RequestHandler } from '@sveltejs/kit'; + +// Create auth handlers +const { handleAuthAction } = createConvexAuthHandlers({ + convexUrl: PUBLIC_CONVEX_URL +}); + +// Export POST handler for auth requests +export const POST: RequestHandler = handleAuthAction; +``` + +When using this approach, make sure to update your Auth Provider to use the same API route: + +```svelte + + + +``` + +## Troubleshooting + +### Common Issues + +1. **Auth Tokens Not Persisting**: Ensure cookie options are configured correctly, especially `secure` and `sameSite`. + +2. **CORS Errors**: If your Convex backend is on a different domain, you may need to configure CORS. + +3. **TypeScript Errors with `$env/static/public`**: Make sure you have run your SvelteKit app at least once to generate the proper type definitions. + +### Debug Mode + +Enable debug logging by setting an environment variable: + +``` +CONVEX_AUTH_DEBUG=true +``` + +This will output detailed logs about auth operations to help with troubleshooting. + +## License + +MIT diff --git a/src/sveltekit/client.ts b/src/sveltekit/client.ts new file mode 100644 index 00000000..a35aee1a --- /dev/null +++ b/src/sveltekit/client.ts @@ -0,0 +1,85 @@ +/** + * SvelteKit implementation of Convex Auth client. + */ +import { invalidateAll } from "$app/navigation"; +import { createAuthClient } from "../svelte/client.svelte.js"; +import { AuthClient } from "../svelte/clientType.js"; +import { PUBLIC_CONVEX_URL } from '$env/static/public'; + +/** + * Type definition for the server state from SvelteKit + */ +export type ConvexAuthServerState = { + _state: { token: string | null; refreshToken: string | null }; + _timeFetched: number; +}; + +/** + * Create a Convex Auth client for SvelteKit + */ +export function createSvelteKitAuthClient({ + apiRoute = "/api/auth", + serverState, + storage = "localStorage", + storageNamespace, + verbose, +}: { + apiRoute?: string; + serverState?: ConvexAuthServerState; + storage?: "localStorage" | "inMemory"; + storageNamespace?: string; + verbose?: boolean; +}) { + // Create SvelteKit-specific auth client + const authenticatedCall: AuthClient["authenticatedCall"] = async (action, args) => { + const params = { action, args }; + const response = await fetch(apiRoute, { + body: JSON.stringify(params), + method: "POST", + }); + return await response.json(); + }; + + const authClient: AuthClient = { + authenticatedCall, + unauthenticatedCall: authenticatedCall, + verbose, + }; + + // Create the auth client with SvelteKit-specific config + return createAuthClient({ + client: authClient, + serverState, + onChange: async () => { + // Invalidate SvelteKit data on auth changes + await invalidateAll(); + }, + storage: + // Handle SSR, Client, etc. + // Pretend we always have storage, the component checks + // it in first useEffect. + typeof window === "undefined" + ? null + : storage === "inMemory" + ? null + : window.localStorage, + storageNamespace: + storageNamespace ?? + requireEnv(PUBLIC_CONVEX_URL, "PUBLIC_CONVEX_URL"), + replaceURL: (url) => { + if (typeof window !== "undefined") { + window.history.replaceState({}, "", url); + } + }, + }); +} + +/** + * Validate that required environment variables are present + */ +function requireEnv(value: string | undefined, name: string): string { + if (value === undefined) { + throw new Error(`Missing environment variable \`${name}\``); + } + return value; +} diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts new file mode 100644 index 00000000..eb5138a9 --- /dev/null +++ b/src/sveltekit/index.ts @@ -0,0 +1,114 @@ +/** + * SvelteKit bindings for Convex Auth. + * + * @module + */ + +export { + useAuthActions, + useAuthToken, + type TokenStorage, + type ConvexAuthActionsContext +} from "../svelte/index.svelte.js"; + +export { + createSvelteKitAuthClient, + type ConvexAuthServerState, +} from "./client.js"; + +/** + * Create a SvelteKit auth provider component that can be used to provide + * authentication state to child components. + * + * @returns A Svelte component that provides auth context to children + * + * Usage: + * ```svelte + * + * + * + * + * + * ``` + */ +import { createConvexAuthProvider } from "../svelte/index.svelte.js"; +import { createSvelteKitAuthClient, type ConvexAuthServerState } from "./client.js"; + +export function createSvelteKitAuthProvider() { + // Return a component factory function + return function ConvexAuthSvelteKitProvider({ + apiRoute = "/api/auth", + serverState, + storage = "localStorage", + storageNamespace, + verbose = false, + children, + }: { + apiRoute?: string; + serverState?: ConvexAuthServerState; + storage?: "localStorage" | "inMemory"; + storageNamespace?: string; + verbose?: boolean; + children?: any; + } = {}) { + // Create the base auth provider + const AuthProvider = createConvexAuthProvider(); + + // Create the SvelteKit-specific auth client but don't use it directly + // We're creating it so it sets up the SvelteKit-specific authentication + // context that will be used by child components + createSvelteKitAuthClient({ + apiRoute, + serverState, + storage, + storageNamespace, + verbose, + }); + + // Return the auth provider with SvelteKit-specific configuration + // We pass undefined for client so it will use the one from context setup by setupConvex + return AuthProvider({ + client: undefined, // Will get ConvexClient from context + storage: typeof window === "undefined" + ? null + : storage === "inMemory" + ? null + : window.localStorage, + storageNamespace, + children, + }); + }; +} + +/** + * Create server-side handlers for SvelteKit. + * This provides utilities to work with Convex Auth in SvelteKit. + * + * Usage in hooks.server.ts: + * ```ts + * import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; + * + * const { getAuthState } = createConvexAuthHandlers({ + * convexUrl: process.env.CONVEX_URL!, + * }); + * + * export async function handle({ event, resolve }) { + * // Add auth state to event.locals + * event.locals.authState = await getAuthState(event); + * return resolve(event); + * } + * ``` + */ +export { createConvexAuthHandlers } from "./server/handlers.js"; diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts new file mode 100644 index 00000000..d2d2c589 --- /dev/null +++ b/src/sveltekit/server/handlers.ts @@ -0,0 +1,278 @@ +/** + * Server-side handlers for Convex Auth in SvelteKit + */ +import type { RequestEvent, RequestHandler } from "@sveltejs/kit"; +import type { ConvexAuthServerState } from "../client.js"; +import { json, error } from "@sveltejs/kit"; + +// Interface for cookie options +interface CookieOptions { + path?: string; + httpOnly?: boolean; + secure?: boolean; + maxAge?: number; + sameSite?: "strict" | "lax" | "none"; + domain?: string; +} + +// Cookie names +const AUTH_TOKEN_COOKIE = "__convex_auth_token"; +const AUTH_REFRESH_TOKEN_COOKIE = "__convex_auth_refresh_token"; + +// Default cookie options +const defaultCookieOptions: CookieOptions = { + path: "/", + httpOnly: true, + secure: process.env.NODE_ENV === "production", + sameSite: "lax", +}; + +// For debug logging +function logVerbose(message: string, ...args: any[]) { + if (process.env.CONVEX_AUTH_DEBUG === "true") { + console.log(`[ConvexAuth] ${message}`, ...args); + } +} + +/** + * Create server-side handlers for SvelteKit + */ +export function createConvexAuthHandlers({ + convexUrl, + cookieOptions = defaultCookieOptions, +}: { + convexUrl: string; + cookieOptions?: CookieOptions; +}) { + /** + * Get the auth state from cookies + */ + async function getAuthState(event: RequestEvent): Promise { + // Get tokens from cookies + const token = event.cookies.get(AUTH_TOKEN_COOKIE) || null; + const refreshToken = event.cookies.get(AUTH_REFRESH_TOKEN_COOKIE) || null; + + return { + _state: { token, refreshToken }, + _timeFetched: Date.now(), + }; + } + + /** + * Set auth cookies + */ + function setAuthCookies( + event: RequestEvent, + token: string | null, + refreshToken: string | null + ) { + logVerbose("Setting auth cookies", { token: !!token, refreshToken: !!refreshToken }); + + if (token === null) { + event.cookies.delete(AUTH_TOKEN_COOKIE, cookieOptions); + } else { + event.cookies.set(AUTH_TOKEN_COOKIE, token, { + ...cookieOptions, + maxAge: 60 * 60 // 1 hour for the main token + }); + } + + if (refreshToken === null) { + event.cookies.delete(AUTH_REFRESH_TOKEN_COOKIE, cookieOptions); + } else { + event.cookies.set(AUTH_REFRESH_TOKEN_COOKIE, refreshToken, { + ...cookieOptions, + maxAge: 60 * 60 * 24 * 30 // 30 days for refresh token + }); + } + } + + /** + * Proxy an auth action to Convex + * Used to forward authentication requests to Convex + */ + async function proxyAuthActionToConvex( + event: RequestEvent, + action: string, + args: any + ) { + logVerbose("Proxying auth action to Convex", { action, args }); + + try { + // Forward the request to Convex + const response = await fetch(`${convexUrl}/api/action`, { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + path: action, + args, + }), + }); + + if (!response.ok) { + throw new Error(`Failed to proxy auth action: ${response.statusText}`); + } + + const result = await response.json(); + logVerbose("Proxy result", result); + + // Handle authentication results + if (result.tokens) { + setAuthCookies( + event, + result.tokens.token, + result.tokens.refreshToken + ); + } else if (result.clearTokens) { + setAuthCookies(event, null, null); + } + + return result; + } catch (e) { + console.error("Error proxying auth action:", e); + throw error(500, "Error proxying auth action to Convex"); + } + } + + /** + * Create a SvelteKit API handler for auth actions + * This should be used in a +server.ts file at your desired API route (default: /api/auth) + */ + const handleAuthAction: RequestHandler = async (event) => { + try { + const body = await event.request.json(); + const { action, args } = body; + + // Only allow auth-related actions to be proxied + if (!action.startsWith("auth:")) { + throw error(403, "Only auth actions are allowed"); + } + + const result = await proxyAuthActionToConvex(event, action, args); + return json(result); + } catch (e) { + console.error("Error in auth action handler:", e); + throw error(500, "Error processing auth action"); + } + }; + + /** + * Load function for layout/page to get auth state + * Use in +layout.server.ts or +page.server.ts + */ + async function loadAuthState(event: RequestEvent) { + return { + authState: await getAuthState(event), + }; + } + + /** + * Middleware function to protect routes + * Use in hooks.server.ts in handle sequence + */ + async function protect( + event: RequestEvent, + resolver: (event: RequestEvent) => Promise + ) { + const authState = await getAuthState(event); + const isAuthenticated = !!authState._state.token; + + // Check if this is a protected route + // Customize this logic based on your app's route structure + const isProtectedRoute = event.url.pathname.startsWith("/protected"); + + if (isProtectedRoute && !isAuthenticated) { + // Redirect to login + return new Response("Unauthorized", { status: 302, headers: { Location: "/login" } }); + } + + // Continue processing the request + return resolver(event); + } + + /** + * Determine if the current request is authenticated + */ + async function isAuthenticated(event: RequestEvent): Promise { + const authState = await getAuthState(event); + return !!authState._state.token; + } + + return { + getAuthState, + setAuthCookies, + handleAuthAction, + loadAuthState, + protect, + proxyAuthActionToConvex, + isAuthenticated, + }; +} + +/** + * Get the server-side auth state + * This is similar to the Next.js convexAuthNextjsServerState function + */ +export async function convexAuthSvelteKitServerState( + event: RequestEvent +): Promise { + const token = event.cookies.get(AUTH_TOKEN_COOKIE) || null; + + // The server doesn't share the refresh token with the client + // for added security - the client has to use the server + // endpoint to refresh the token + return { + _state: { token, refreshToken: null }, + _timeFetched: Date.now(), + }; +} + +// Type definitions for the handle function +interface HandleArgs { + event: RequestEvent; + resolve: (event: RequestEvent) => Promise; +} + +/** + * Create server hooks for SvelteKit + * Use this in your hooks.server.ts file + */ +export function createConvexAuthHooks({ + convexUrl, + apiRoute = "/api/auth", + cookieOptions, +}: { + convexUrl: string; + apiRoute?: string; + cookieOptions?: CookieOptions; +}) { + const handlers = createConvexAuthHandlers({ convexUrl, cookieOptions }); + + /** + * Request handler for the hooks.server.ts handle function + */ + async function handleAuth({ event, resolve }: HandleArgs) { + // If this is the auth API route, handle the auth action + if (event.url.pathname === apiRoute && event.request.method === "POST") { + return handlers.handleAuthAction(event); + } + + // For other routes, just continue + return resolve(event); + } + + /** + * Protect routes from unauthenticated access + */ + async function protectRoutes({ event, resolve }: HandleArgs) { + return handlers.protect(event, () => resolve(event)); + } + + return { + ...handlers, + handleAuth, + protectRoutes, + }; +} diff --git a/src/sveltekit/server/index.ts b/src/sveltekit/server/index.ts new file mode 100644 index 00000000..b971e5fe --- /dev/null +++ b/src/sveltekit/server/index.ts @@ -0,0 +1,29 @@ +/** + * Server-side handlers for Convex Auth in SvelteKit + */ +import { + createConvexAuthHandlers, + createConvexAuthHooks, + convexAuthSvelteKitServerState +} from './handlers.js'; +import { + createRouteMatcher, + createRouteMatcherGroup, + type RouteMatcherParam, + type RouteMatcherFn +} from './routeMatcher.js'; + +// Export server handlers +export { + createConvexAuthHandlers, + createConvexAuthHooks, + convexAuthSvelteKitServerState +}; + +// Export route matchers (equivalent to NextJS implementation) +export { + createRouteMatcher, + createRouteMatcherGroup, + type RouteMatcherParam, + type RouteMatcherFn +}; diff --git a/src/sveltekit/server/routeMatcher.ts b/src/sveltekit/server/routeMatcher.ts new file mode 100644 index 00000000..cef1b0da --- /dev/null +++ b/src/sveltekit/server/routeMatcher.ts @@ -0,0 +1,52 @@ +/** + * Route matcher for SvelteKit to match paths for protection + */ + +// Types for route matching +export type RouteMatcherParam = string | RegExp | RouteMatcherFn; +export type RouteMatcherFn = (pathname: string) => boolean; + +/** + * Create a route matcher that checks if a route matches the given pattern + * + * @param pattern A string, regex, or function to match against routes + * @returns A function that returns true if the route matches + * + * Examples: + * ```ts + * // Match exact path + * const matcher = createRouteMatcher('/dashboard'); + * + * // Match with regex + * const matcher = createRouteMatcher(/^\/api\/.*$/); + * + * // Match with function + * const matcher = createRouteMatcher((path) => path.startsWith('/account')); + * ``` + */ +export function createRouteMatcher(pattern: RouteMatcherParam): RouteMatcherFn { + if (typeof pattern === 'string') { + return (pathname) => pathname === pattern; + } + + if (pattern instanceof RegExp) { + return (pathname) => pattern.test(pathname); + } + + if (typeof pattern === 'function') { + return pattern; + } + + throw new Error('Invalid route matcher pattern'); +} + +/** + * Create a matcher that combines multiple patterns with OR logic + */ +export function createRouteMatcherGroup(patterns: RouteMatcherParam[]): RouteMatcherFn { + const matchers = patterns.map(pattern => createRouteMatcher(pattern)); + + return (pathname) => { + return matchers.some(matcher => matcher(pathname)); + }; +} From c1d39cd22bcd4807ac02cf6af6f6f7b36c9222dc Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Tue, 15 Apr 2025 18:24:37 +0200 Subject: [PATCH 05/88] Update code block syntax highlighting from svelte to html in README --- src/sveltekit/README.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 34e1b050..22158d9c 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -220,7 +220,7 @@ export async function load(event) { ### Sign In -```svelte +```html @@ -50,6 +62,13 @@ Set up the Convex client and auth provider in your root layout: ``` +The auth provider will: +1. Use a client you provide directly (if any) +2. Look for a client in Svelte context (if available) +3. Create a new client automatically (if needed and not disabled) + +This makes it work seamlessly with different setup patterns. + ### 3. Add Auth State in Layout Server Load the authentication state in your layout server: @@ -57,13 +76,10 @@ Load the authentication state in your layout server: ```typescript // src/routes/+layout.server.ts import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; -import { PUBLIC_CONVEX_URL } from '$env/static/public'; import type { LayoutServerLoad } from './$types'; -// Create auth handlers -const { loadAuthState } = createConvexAuthHandlers({ - convexUrl: PUBLIC_CONVEX_URL -}); +// Create auth handlers - convexUrl is automatically detected from environment +const { loadAuthState } = createConvexAuthHandlers(); // Export load function to provide auth state to layout export const load: LayoutServerLoad = async (event) => { @@ -78,12 +94,10 @@ Create hooks to handle authentication in `src/hooks.server.ts`: ```typescript // src/hooks.server.ts import { sequence } from '@sveltejs/kit/hooks'; -import { PUBLIC_CONVEX_URL } from '$env/static/public'; import { createConvexAuthHooks } from '@convex-dev/auth/sveltekit/server'; -// Create auth hooks with your Convex URL +// Create auth hooks - convexUrl is automatically detected from environment const { handleAuth, protectRoutes } = createConvexAuthHooks({ - convexUrl: PUBLIC_CONVEX_URL, // Optional: Custom API route (default: '/api/auth') apiRoute: '/api/auth', // Optional: Custom cookie options @@ -139,14 +153,11 @@ Use auth state in page server load functions: ```typescript // src/routes/profile/+page.server.ts import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; -import { PUBLIC_CONVEX_URL } from '$env/static/public'; import { redirect } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; // Create auth handlers -const { isAuthenticated } = createConvexAuthHandlers({ - convexUrl: PUBLIC_CONVEX_URL -}); +const { isAuthenticated } = createConvexAuthHandlers(); // Protect routes at the page level export const load: PageServerLoad = async (event) => { @@ -182,7 +193,6 @@ const protectedRoutes = createRouteMatcher((path) => { // Create auth hooks with route protection const { handleAuth, protectRoutes } = createConvexAuthHooks({ - convexUrl: PUBLIC_CONVEX_URL, protectedRoutes, // Where to redirect unauthenticated users redirectUrl: '/login' @@ -199,11 +209,8 @@ Protect individual pages in their `+page.server.ts`: // src/routes/protected/+page.server.ts import { redirect } from '@sveltejs/kit'; import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; -import { PUBLIC_CONVEX_URL } from '$env/static/public'; -const { isAuthenticated } = createConvexAuthHandlers({ - convexUrl: PUBLIC_CONVEX_URL -}); +const { isAuthenticated } = createConvexAuthHandlers(); export async function load(event) { if (!(await isAuthenticated(event))) { @@ -277,7 +284,6 @@ export async function load(event) { ```typescript // src/hooks.server.ts const { handleAuth, protectRoutes } = createConvexAuthHooks({ - convexUrl: PUBLIC_CONVEX_URL, onUnauthenticated: (event) => { // Custom redirect logic const url = new URL('/login', event.url.origin); @@ -338,13 +344,10 @@ If you prefer to handle auth requests with a dedicated endpoint (instead of usin ```typescript // src/routes/api/auth/+server.ts import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; -import { PUBLIC_CONVEX_URL } from '$env/static/public'; import type { RequestHandler } from '@sveltejs/kit'; // Create auth handlers -const { handleAuthAction } = createConvexAuthHandlers({ - convexUrl: PUBLIC_CONVEX_URL -}); +const { handleAuthAction } = createConvexAuthHandlers(); // Export POST handler for auth requests export const POST: RequestHandler = handleAuthAction; diff --git a/src/sveltekit/client.ts b/src/sveltekit/client.ts index a35aee1a..02fbfa63 100644 --- a/src/sveltekit/client.ts +++ b/src/sveltekit/client.ts @@ -4,7 +4,6 @@ import { invalidateAll } from "$app/navigation"; import { createAuthClient } from "../svelte/client.svelte.js"; import { AuthClient } from "../svelte/clientType.js"; -import { PUBLIC_CONVEX_URL } from '$env/static/public'; /** * Type definition for the server state from SvelteKit @@ -65,7 +64,10 @@ export function createSvelteKitAuthClient({ : window.localStorage, storageNamespace: storageNamespace ?? - requireEnv(PUBLIC_CONVEX_URL, "PUBLIC_CONVEX_URL"), + requireEnv( + typeof process !== "undefined" ? process.env.PUBLIC_CONVEX_URL : undefined, + "PUBLIC_CONVEX_URL" + ), replaceURL: (url) => { if (typeof window !== "undefined") { window.history.replaceState({}, "", url); diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts index eb5138a9..6beba602 100644 --- a/src/sveltekit/index.ts +++ b/src/sveltekit/index.ts @@ -25,16 +25,12 @@ export { * Usage: * ```svelte * * @@ -45,8 +41,26 @@ export { */ import { createConvexAuthProvider } from "../svelte/index.svelte.js"; import { createSvelteKitAuthClient, type ConvexAuthServerState } from "./client.js"; +import { setupConvex } from "convex-svelte"; +import { getContext } from "svelte"; +import { ConvexClient } from "convex/browser"; -export function createSvelteKitAuthProvider() { +export function createSvelteKitAuthProvider(options?: { + /** + * ConvexClient instance to use. If not provided, will: + * 1. Try to get it from Svelte context + * 2. Initialize a new one using the Convex URL + */ + client?: ConvexClient; + + /** + * Convex URL to use if creating a new client. If not provided, will use + * PUBLIC_CONVEX_URL environment variable. + */ + convexUrl?: string; +}) { + const { client: providedClient, convexUrl } = options || {}; + // Return a component factory function return function ConvexAuthSvelteKitProvider({ apiRoute = "/api/auth", @@ -66,9 +80,42 @@ export function createSvelteKitAuthProvider() { // Create the base auth provider const AuthProvider = createConvexAuthProvider(); - // Create the SvelteKit-specific auth client but don't use it directly - // We're creating it so it sets up the SvelteKit-specific authentication - // context that will be used by child components + // Determine which client to use: + // 1. Use provided client if it exists + let client = providedClient; + + // 2. Try to get from context if not provided + if (!client) { + try { + client = getContext("$$_convexClient"); + } catch (e) { + // Context not available or no client in context + } + } + + // 3. Create a new client if requested and not found + if (!client) { + // Get URL from options or environment variable + const url = convexUrl || + (typeof process !== "undefined" ? process.env.PUBLIC_CONVEX_URL : undefined) || + (typeof window !== "undefined" && (window as any).PUBLIC_CONVEX_URL); + + if (!url) { + console.warn("No Convex URL provided. Please pass client or convexUrl to createSvelteKitAuthProvider or set PUBLIC_CONVEX_URL environment variable."); + } else { + // This will set the client in context for future use + setupConvex(url); + + // Try to get the newly created client + try { + client = getContext("$$_convexClient"); + } catch (e) { + // Context not available after setup + } + } + } + + // Create the SvelteKit-specific auth client createSvelteKitAuthClient({ apiRoute, serverState, @@ -78,9 +125,8 @@ export function createSvelteKitAuthProvider() { }); // Return the auth provider with SvelteKit-specific configuration - // We pass undefined for client so it will use the one from context setup by setupConvex return AuthProvider({ - client: undefined, // Will get ConvexClient from context + client, // Will pass through our client or undefined storage: typeof window === "undefined" ? null : storage === "inMemory" diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index d2d2c589..b8003491 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -34,16 +34,36 @@ function logVerbose(message: string, ...args: any[]) { } } +/** + * Helper to get the Convex URL from environment variables + * This allows SvelteKit implementations to automatically use the URL + */ +function getConvexUrl(): string { + // Try to load from process.env.PUBLIC_CONVEX_URL first + const envUrl = process.env.PUBLIC_CONVEX_URL; + + if (envUrl) { + return envUrl; + } + + // If running in Node.js environment, could try to load from .env file + // but this is usually handled by SvelteKit's config + + throw new Error( + "Convex URL not provided. Either pass convexUrl parameter or set PUBLIC_CONVEX_URL environment variable." + ); +} + /** * Create server-side handlers for SvelteKit */ export function createConvexAuthHandlers({ - convexUrl, + convexUrl = getConvexUrl(), cookieOptions = defaultCookieOptions, }: { - convexUrl: string; + convexUrl?: string; cookieOptions?: CookieOptions; -}) { +} = {}) { /** * Get the auth state from cookies */ @@ -240,14 +260,14 @@ interface HandleArgs { * Use this in your hooks.server.ts file */ export function createConvexAuthHooks({ - convexUrl, + convexUrl = getConvexUrl(), apiRoute = "/api/auth", cookieOptions, }: { - convexUrl: string; + convexUrl?: string; apiRoute?: string; cookieOptions?: CookieOptions; -}) { +} = {}) { const handlers = createConvexAuthHandlers({ convexUrl, cookieOptions }); /** From a3f4502ecd83f8dfdf592c590571544674002cf3 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Wed, 16 Apr 2025 16:00:16 +0200 Subject: [PATCH 07/88] Refactor Svelte auth provider to use new props syntax and improve client resolution --- src/svelte/client.svelte.ts | 2 +- src/svelte/index.svelte.ts | 96 ++++++++++++++++++++++++++++--------- src/sveltekit/README.md | 10 ++-- src/sveltekit/index.ts | 85 ++++++++++++-------------------- 4 files changed, 112 insertions(+), 81 deletions(-) diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index 2d3b3e0f..813e43f0 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -7,7 +7,7 @@ import type { SignOutAction, } from "../server/implementation/index.js"; import { AuthClient } from "./clientType.js"; -import type { TokenStorage } from "./index.svelte.js"; +import type { TokenStorage } from "./index.svelte"; import isNetworkError from "is-network-error"; // Retry after this much time, based on the retry number. diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index 32504b00..420a5802 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -102,26 +102,37 @@ export type ConvexAuthActionsContext = { }; /** - * Create the Convex auth context provider. + * Create a Convex Auth provider component for Svelte * + * @returns A Svelte component that provides auth context to children * ```svelte * - * + * * - * + * {@render children()} * * ``` */ -export function createConvexAuthProvider() { +export function createConvexAuthProvider(options?: { + /** + * ConvexClient instance to use. If not provided, will try to get from context. + */ + client?: ConvexClient; + + /** + * Convex URL to use if no client is provided and setupConvex is available. + */ + convexUrl?: string; +}) { + const { client: providedClient, convexUrl } = options || {}; + // Return a Svelte component (as a function) return function ConvexAuthProvider({ client, @@ -140,23 +151,59 @@ export function createConvexAuthProvider() { replaceURL?: (relativeUrl: string) => void | Promise; children?: any; } = {}) { - // If client is not provided, try to get it from context + // Client resolution priority: + // 1. Client passed to component directly + // 2. Client passed to provider factory + // 3. Client from context + // 4. Try to create one if setupConvex is available + + // If client is not explicitly provided to component, use factory client + if (!client) { + client = providedClient; + } + + // If still no client, try to get from context if (!client) { try { client = getContext("$$_convexClient"); } catch (e) { - throw new Error( - "No ConvexClient was provided. Either pass one to ConvexAuthProvider or call setupConvex() first.", - ); + // Context not available or no client in context + } + } + + // If still no client and convexUrl is provided, try to create one using setupConvex + if (!client && convexUrl && typeof window !== "undefined") { + try { + // Check if setupConvex is available (defined by convex-svelte) + const setupConvex = (window as any).setupConvex || + (typeof globalThis !== "undefined" && (globalThis as any).setupConvex); + + if (typeof setupConvex === 'function') { + setupConvex(convexUrl); + // After setting up, try to get the client from context + try { + client = getContext("$$_convexClient"); + } catch (e) { + // Context not available after setup + } + } + } catch (e) { + console.warn("Failed to create Convex client:", e); } } + + // If we still don't have a client, throw an error + if (!client) { + throw new Error( + "No ConvexClient was provided. Either pass one to ConvexAuthProvider or call setupConvex() first.", + ); + } // Create auth client with reactive memoization const authClient = $derived.by( - () => - ({ + () => ({ authenticatedCall(action, args) { - return client!.action(action, args); + return client.action(action, args); }, unauthenticatedCall(action, args) { return new ConvexClient((client as any).address, { @@ -236,15 +283,20 @@ export function createConvexAuthProvider() { * ``` */ export function useAuthActions() { - const actions = getContext( - CONVEX_AUTH_ACTIONS_CONTEXT_KEY, - ); - if (!actions) { + try { + return getContext(CONVEX_AUTH_ACTIONS_CONTEXT_KEY); + } catch (e) { throw new Error( - "No auth actions found in context. Did you forget to use ConvexAuthProvider?", + "useAuthActions must be used within a ConvexAuthProvider component", ); } - return actions; +} + +/** + * Get the authentication token from context (if available) + */ +export function getConvexAuthToken() { + return getContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY) ?? null; } /** diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index a6275376..71e7cefe 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -33,6 +33,8 @@ Set up the auth provider in your root layout: - + {@render children()} ``` @@ -357,7 +359,7 @@ When using this approach, make sure to update your Auth Provider to use the same ```html - + {@render children()} ``` diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts index 6beba602..6eeab646 100644 --- a/src/sveltekit/index.ts +++ b/src/sveltekit/index.ts @@ -4,17 +4,17 @@ * @module */ -export { +import { + createConvexAuthProvider, useAuthActions, + getConvexAuthToken, useAuthToken, type TokenStorage, - type ConvexAuthActionsContext -} from "../svelte/index.svelte.js"; + type ConvexAuthActionsContext +} from "../svelte/index.svelte"; -export { - createSvelteKitAuthClient, - type ConvexAuthServerState, -} from "./client.js"; +import { ConvexClient } from "convex/browser"; +import { createSvelteKitAuthClient, type ConvexAuthServerState } from "./client"; /** * Create a SvelteKit auth provider component that can be used to provide @@ -27,6 +27,8 @@ export { * * * - * + * {@render children()} * * ``` */ -import { createConvexAuthProvider } from "../svelte/index.svelte.js"; -import { createSvelteKitAuthClient, type ConvexAuthServerState } from "./client.js"; -import { setupConvex } from "convex-svelte"; -import { getContext } from "svelte"; -import { ConvexClient } from "convex/browser"; +/** + * Create a SvelteKit-specific auth provider component + */ export function createSvelteKitAuthProvider(options?: { /** * ConvexClient instance to use. If not provided, will: @@ -54,12 +54,13 @@ export function createSvelteKitAuthProvider(options?: { client?: ConvexClient; /** - * Convex URL to use if creating a new client. If not provided, will use + * Convex URL to use. If not provided, will use * PUBLIC_CONVEX_URL environment variable. */ convexUrl?: string; }) { - const { client: providedClient, convexUrl } = options || {}; + // Create the base provider with our options + const AuthProvider = createConvexAuthProvider(options); // Return a component factory function return function ConvexAuthSvelteKitProvider({ @@ -77,44 +78,6 @@ export function createSvelteKitAuthProvider(options?: { verbose?: boolean; children?: any; } = {}) { - // Create the base auth provider - const AuthProvider = createConvexAuthProvider(); - - // Determine which client to use: - // 1. Use provided client if it exists - let client = providedClient; - - // 2. Try to get from context if not provided - if (!client) { - try { - client = getContext("$$_convexClient"); - } catch (e) { - // Context not available or no client in context - } - } - - // 3. Create a new client if requested and not found - if (!client) { - // Get URL from options or environment variable - const url = convexUrl || - (typeof process !== "undefined" ? process.env.PUBLIC_CONVEX_URL : undefined) || - (typeof window !== "undefined" && (window as any).PUBLIC_CONVEX_URL); - - if (!url) { - console.warn("No Convex URL provided. Please pass client or convexUrl to createSvelteKitAuthProvider or set PUBLIC_CONVEX_URL environment variable."); - } else { - // This will set the client in context for future use - setupConvex(url); - - // Try to get the newly created client - try { - client = getContext("$$_convexClient"); - } catch (e) { - // Context not available after setup - } - } - } - // Create the SvelteKit-specific auth client createSvelteKitAuthClient({ apiRoute, @@ -126,7 +89,6 @@ export function createSvelteKitAuthProvider(options?: { // Return the auth provider with SvelteKit-specific configuration return AuthProvider({ - client, // Will pass through our client or undefined storage: typeof window === "undefined" ? null : storage === "inMemory" @@ -138,6 +100,21 @@ export function createSvelteKitAuthProvider(options?: { }; } +// Re-export core functionality +export { + createSvelteKitAuthClient, + useAuthActions, + getConvexAuthToken, + useAuthToken +}; + +// Re-export types +export type { + TokenStorage, + ConvexAuthActionsContext, + ConvexAuthServerState +}; + /** * Create server-side handlers for SvelteKit. * This provides utilities to work with Convex Auth in SvelteKit. From ccd32a307f61ad997dcfa8a1b9b24659d75a2f28 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Wed, 16 Apr 2025 20:48:44 +0200 Subject: [PATCH 08/88] Remove protect middleware and update docs with auth pattern examples --- src/sveltekit/README.md | 170 ++++++++++++++++++++++++++++--- src/sveltekit/server/handlers.ts | 35 +------ 2 files changed, 158 insertions(+), 47 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 71e7cefe..48027b48 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -91,7 +91,9 @@ export const load: LayoutServerLoad = async (event) => { ### 4. Configure Auth Hooks (Server-side) -Create hooks to handle authentication in `src/hooks.server.ts`: +Create hooks to handle authentication in `src/hooks.server.ts`. + +#### Minimal Example: ```typescript // src/hooks.server.ts @@ -99,22 +101,164 @@ import { sequence } from '@sveltejs/kit/hooks'; import { createConvexAuthHooks } from '@convex-dev/auth/sveltekit/server'; // Create auth hooks - convexUrl is automatically detected from environment -const { handleAuth, protectRoutes } = createConvexAuthHooks({ - // Optional: Custom API route (default: '/api/auth') - apiRoute: '/api/auth', - // Optional: Custom cookie options - cookieOptions: { - path: '/', - httpOnly: true, - secure: true, - sameSite: 'lax' - } -}); +const { handleAuth } = createConvexAuthHooks(); // Apply hooks in sequence export const handle = sequence( handleAuth, // This handles all POST requests to /api/auth automatically - protectRoutes, + // Your other custom handlers... +); +``` + +#### Advanced Example: + +```typescript +// src/hooks.server.ts +import { sequence } from '@sveltejs/kit/hooks'; +import { redirect } from '@sveltejs/kit'; +import { + createConvexAuthHooks, + createRouteMatcher +} from '@convex-dev/auth/sveltekit/server'; + +// Example 1: Auth-first approach (whitelist pattern) +// Most routes require authentication except for a few public ones + +const isPublicRoute = createRouteMatcher([ + '/login', + '/register', + '/about', + // Note: No need to add '/api/auth' here as the handleAuth middleware + // will process those requests before this middleware runs +]); + +// Create auth hooks +const { handleAuth, convexAuth } = createConvexAuthHooks(); + +// Custom handle function for auth-first pattern +async function authFirstPattern(event) { + // Skip auth check for public routes + if (isPublicRoute(event.url.pathname)) { + return; + } + + // For all other routes, check authentication + const isAuthenticated = await convexAuth.isAuthenticated(event); + + if (!isAuthenticated) { + // Store the original URL for redirect after login + const returnUrl = encodeURIComponent(event.url.pathname + event.url.search); + return redirect(302, `/login?redirectTo=${returnUrl}`); + } + + // User is authenticated, continue to next handler + return; +} + +// Example 2: Public-first approach (blacklist pattern) +// Most routes are public, only protect specific areas + +const isProtectedRoute = createRouteMatcher([ + '/admin(.*)', + '/dashboard(.*)', + '/profile(.*)', +]); + +// Custom handle function for public-first pattern +async function publicFirstPattern(event) { + // Check auth only for protected routes + if (isProtectedRoute(event.url.pathname)) { + const isAuthenticated = await convexAuth.isAuthenticated(event); + + if (!isAuthenticated) { + // Store the original URL for redirect after login + const returnUrl = encodeURIComponent(event.url.pathname + event.url.search); + return redirect(302, `/login?redirectTo=${returnUrl}`); + } + } + + // All other routes are public, or user is authenticated + return; +} + +// Choose which pattern to use based on your app's needs +// and apply hooks in sequence +export const handle = sequence( + handleAuth, // Handle auth API requests + // authFirstPattern, // Uncomment to use auth-first pattern + publicFirstPattern, // Comment out if using auth-first pattern + // Your other custom handlers... +); +``` + +### Handling Special Routes + +For more complex cases like handling invitations: + +```typescript +// src/hooks.server.ts +import { sequence } from '@sveltejs/kit/hooks'; +import { redirect } from '@sveltejs/kit'; +import { + createConvexAuthHooks, + createRouteMatcher +} from '@convex-dev/auth/sveltekit/server'; +import { api } from '@/convex/_generated/api'; +import { fetchMutation } from 'convex/svelte'; + +// Create auth hooks +const { handleAuth, convexAuth } = createConvexAuthHooks(); + +// Handle special route for invitation acceptance +const isInvitationRoute = createRouteMatcher(['/api/invitations/accept']); + +async function handleSpecialRoutes(event) { + if (isInvitationRoute(event.url.pathname)) { + const isAuthenticated = await convexAuth.isAuthenticated(event); + + if (!isAuthenticated) { + // Redirect to login with return URL + return redirect(302, + `/login?returnUrl=${encodeURIComponent(event.url.pathname + event.url.search)}` + ); + } + + // Get invitation ID from query params + const invitationId = event.url.searchParams.get('invitationId'); + + if (invitationId) { + try { + // Get auth token from server state + const authState = await convexAuth.getAuthState(event); + const token = authState._state.token; + + // Call the mutation with the auth token + await fetchMutation( + api.organizations.invitations.accept, + { invitationId }, + { token } + ); + + // Redirect to success page + return redirect(302, '/dashboard'); + } catch (error) { + console.error('Error accepting invitation:', error); + return new Response(JSON.stringify({ error: 'Failed to accept invitation' }), { + status: 500, + headers: { 'Content-Type': 'application/json' } + }); + } + } + } + + // Not a special route, continue to next handler + return; +} + +export const handle = sequence( + handleAuth, // Handle auth API requests + handleSpecialRoutes, // Handle special routes + // Add your auth pattern here... // Your other custom handlers... ); ``` diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index b8003491..1abddbf3 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -188,30 +188,6 @@ export function createConvexAuthHandlers({ }; } - /** - * Middleware function to protect routes - * Use in hooks.server.ts in handle sequence - */ - async function protect( - event: RequestEvent, - resolver: (event: RequestEvent) => Promise - ) { - const authState = await getAuthState(event); - const isAuthenticated = !!authState._state.token; - - // Check if this is a protected route - // Customize this logic based on your app's route structure - const isProtectedRoute = event.url.pathname.startsWith("/protected"); - - if (isProtectedRoute && !isAuthenticated) { - // Redirect to login - return new Response("Unauthorized", { status: 302, headers: { Location: "/login" } }); - } - - // Continue processing the request - return resolver(event); - } - /** * Determine if the current request is authenticated */ @@ -225,7 +201,6 @@ export function createConvexAuthHandlers({ setAuthCookies, handleAuthAction, loadAuthState, - protect, proxyAuthActionToConvex, isAuthenticated, }; @@ -283,16 +258,8 @@ export function createConvexAuthHooks({ return resolve(event); } - /** - * Protect routes from unauthenticated access - */ - async function protectRoutes({ event, resolve }: HandleArgs) { - return handlers.protect(event, () => resolve(event)); - } - return { ...handlers, - handleAuth, - protectRoutes, + handleAuth }; } From bd47c3b0f26dbff36cd8233b676e2375d8e53932 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 17 Apr 2025 11:27:12 +0200 Subject: [PATCH 09/88] Add Svelte and SvelteKit support with build configs and package exports --- package-lock.json | 1012 +++++++++++++++++++++++++++++++-------- package.json | 15 +- tsconfig.svelte.json | 8 + tsconfig.sveltekit.json | 8 + 4 files changed, 838 insertions(+), 205 deletions(-) create mode 100644 tsconfig.svelte.json create mode 100644 tsconfig.sveltekit.json diff --git a/package-lock.json b/package-lock.json index ee0e6e66..3d5ec8bb 100644 --- a/package-lock.json +++ b/package-lock.json @@ -47,6 +47,7 @@ "tsup": "^8.0.1", "typescript": "^5.5.2", "valibot": "^0.35.0", + "vite": "^6.3.1", "vitest": "^1.6.0" }, "peerDependencies": { @@ -633,7 +634,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -651,7 +651,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -669,7 +668,6 @@ "os": [ "android" ], - "peer": true, "engines": { "node": ">=18" } @@ -687,7 +685,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -705,7 +702,6 @@ "os": [ "darwin" ], - "peer": true, "engines": { "node": ">=18" } @@ -723,7 +719,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -741,7 +736,6 @@ "os": [ "freebsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -759,7 +753,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -777,7 +770,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -795,7 +787,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -813,7 +804,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -831,7 +821,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -849,7 +838,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -867,7 +855,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -885,7 +872,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -903,7 +889,6 @@ "os": [ "linux" ], - "peer": true, "engines": { "node": ">=18" } @@ -921,7 +906,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -939,7 +923,6 @@ "os": [ "netbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -957,7 +940,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -975,7 +957,6 @@ "os": [ "openbsd" ], - "peer": true, "engines": { "node": ">=18" } @@ -993,7 +974,6 @@ "os": [ "sunos" ], - "peer": true, "engines": { "node": ">=18" } @@ -1011,7 +991,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -1029,7 +1008,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -1047,7 +1025,6 @@ "os": [ "win32" ], - "peer": true, "engines": { "node": ">=18" } @@ -2433,247 +2410,280 @@ "license": "MIT" }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz", - "integrity": "sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.40.0.tgz", + "integrity": "sha512-+Fbls/diZ0RDerhE8kyC6hjADCXA1K4yVNlH0EYfd2XjyH0UGgzaQ8MlT0pCXAThfxv3QUAczHaL+qSv1E4/Cg==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.1.tgz", - "integrity": "sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.40.0.tgz", + "integrity": "sha512-PPA6aEEsTPRz+/4xxAmaoWDqh67N7wFbgFUJGMnanCFs0TV99M0M8QhhaSCks+n6EbQoFvLQgYOGXxlMGQe/6w==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.1.tgz", - "integrity": "sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.40.0.tgz", + "integrity": "sha512-GwYOcOakYHdfnjjKwqpTGgn5a6cUX7+Ra2HeNj/GdXvO2VJOOXCiYYlRFU4CubFM67EhbmzLOmACKEfvp3J1kQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.1.tgz", - "integrity": "sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.40.0.tgz", + "integrity": "sha512-CoLEGJ+2eheqD9KBSxmma6ld01czS52Iw0e2qMZNpPDlf7Z9mj8xmMemxEucinev4LgHalDPczMyxzbq+Q+EtA==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.1.tgz", - "integrity": "sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.40.0.tgz", + "integrity": "sha512-r7yGiS4HN/kibvESzmrOB/PxKMhPTlz+FcGvoUIKYoTyGd5toHp48g1uZy1o1xQvybwwpqpe010JrcGG2s5nkg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.1.tgz", - "integrity": "sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.40.0.tgz", + "integrity": "sha512-mVDxzlf0oLzV3oZOr0SMJ0lSDd3xC4CmnWJ8Val8isp9jRGl5Dq//LLDSPFrasS7pSm6m5xAcKaw3sHXhBjoRw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.1.tgz", - "integrity": "sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.40.0.tgz", + "integrity": "sha512-y/qUMOpJxBMy8xCXD++jeu8t7kzjlOCkoxxajL58G62PJGBZVl/Gwpm7JK9+YvlB701rcQTzjUZ1JgUoPTnoQA==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.1.tgz", - "integrity": "sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.40.0.tgz", + "integrity": "sha512-GoCsPibtVdJFPv/BOIvBKO/XmwZLwaNWdyD8TKlXuqp0veo2sHE+A/vpMQ5iSArRUz/uaoj4h5S6Pn0+PdhRjg==", "cpu": [ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.1.tgz", - "integrity": "sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.40.0.tgz", + "integrity": "sha512-L5ZLphTjjAD9leJzSLI7rr8fNqJMlGDKlazW2tX4IUF9P7R5TMQPElpH82Q7eNIDQnQlAyiNVfRPfP2vM5Avvg==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.1.tgz", - "integrity": "sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.40.0.tgz", + "integrity": "sha512-ATZvCRGCDtv1Y4gpDIXsS+wfFeFuLwVxyUBSLawjgXK2tRE6fnsQEkE4csQQYWlBlsFztRzCnBvWVfcae/1qxQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.1.tgz", - "integrity": "sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.40.0.tgz", + "integrity": "sha512-wG9e2XtIhd++QugU5MD9i7OnpaVb08ji3P1y/hNbxrQ3sYEelKJOq1UJ5dXczeo6Hj2rfDEL5GdtkMSVLa/AOg==", "cpu": [ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.1.tgz", - "integrity": "sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.40.0.tgz", + "integrity": "sha512-vgXfWmj0f3jAUvC7TZSU/m/cOE558ILWDzS7jBhiCAFpY2WEBn5jqgbqvmzlMjtp8KlLcBlXVD2mkTSEQE6Ixw==", "cpu": [ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.1.tgz", - "integrity": "sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.40.0.tgz", + "integrity": "sha512-uJkYTugqtPZBS3Z136arevt/FsKTF/J9dEMTX/cwR7lsAW4bShzI2R0pJVw+hcBTWF4dxVckYh72Hk3/hWNKvA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.40.0.tgz", + "integrity": "sha512-rKmSj6EXQRnhSkE22+WvrqOqRtk733x3p5sWpZilhmjnkHkpeCgWsFFo0dGnUGeA+OZjRl3+VYq+HyCOEuwcxQ==", "cpu": [ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.1.tgz", - "integrity": "sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.40.0.tgz", + "integrity": "sha512-SpnYlAfKPOoVsQqmTFJ0usx0z84bzGOS9anAC0AZ3rdSo3snecihbhFTlJZ8XMwzqAcodjFU4+/SM311dqE5Sw==", "cpu": [ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.1.tgz", - "integrity": "sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.40.0.tgz", + "integrity": "sha512-RcDGMtqF9EFN8i2RYN2W+64CdHruJ5rPqrlYw+cgM3uOVPSsnAQps7cpjXe9be/yDp8UC7VLoCoKC8J3Kn2FkQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.1.tgz", - "integrity": "sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.40.0.tgz", + "integrity": "sha512-HZvjpiUmSNx5zFgwtQAV1GaGazT2RWvqeDi0hV+AtC8unqqDSsaFjPxfsO6qPtKRRg25SisACWnJ37Yio8ttaw==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.1.tgz", - "integrity": "sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.40.0.tgz", + "integrity": "sha512-UtZQQI5k/b8d7d3i9AZmA/t+Q4tk3hOC0tMOMSq2GlMYOfxbesxG4mJSeDp0EHs30N9bsfwUvs3zF4v/RzOeTQ==", "cpu": [ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.1.tgz", - "integrity": "sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.40.0.tgz", + "integrity": "sha512-+m03kvI2f5syIqHXCZLPVYplP8pQch9JHyXKZ3AGMKlg8dCyr2PKHjwRLiW53LTrN/Nc3EqHOKxUxzoSPdKddA==", "cpu": [ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.1.tgz", - "integrity": "sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.40.0.tgz", + "integrity": "sha512-lpPE1cLfP5oPzVjKMx10pgBmKELQnFJXHgvtHCtuJWOv8MxqdEIMNtgHgBFf7Ea2/7EuVwa9fodWUfXAlXZLZQ==", "cpu": [ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -2809,9 +2819,10 @@ "license": "MIT" }, "node_modules/@types/estree": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", - "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.7.tgz", + "integrity": "sha512-w28IoSUCJpidD/TGviZwwMJckNESJZXFu7NBZ5YJ4mEUnNraUn9Pm8HSZm/jDF1pDWYKspWE7oVphigUPRakIQ==", + "license": "MIT" }, "node_modules/@types/inquirer": { "version": "9.0.7", @@ -5039,7 +5050,6 @@ "dev": true, "hasInstallScript": true, "license": "MIT", - "peer": true, "bin": { "esbuild": "bin/esbuild" }, @@ -5087,7 +5097,6 @@ "os": [ "aix" ], - "peer": true, "engines": { "node": ">=18" } @@ -7634,9 +7643,9 @@ } }, "node_modules/postcss": { - "version": "8.4.49", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz", - "integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==", + "version": "8.5.3", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.3.tgz", + "integrity": "sha512-dle9A3yYxlBSrt8Fu+IpjGT8SY8hN0mlaA6GY8t0P5PjIOZemULz/E2Bnm/2dcUOena75OTNkHI76uZBNUUq3A==", "dev": true, "funding": [ { @@ -7652,8 +7661,9 @@ "url": "https://github.com/sponsors/ai" } ], + "license": "MIT", "dependencies": { - "nanoid": "^3.3.7", + "nanoid": "^3.3.8", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" }, @@ -7972,12 +7982,13 @@ } }, "node_modules/rollup": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.1.tgz", - "integrity": "sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==", + "version": "4.40.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.40.0.tgz", + "integrity": "sha512-Noe455xmA96nnqH5piFtLobsGbCij7Tu+tb3c1vYjNbTkfzGqXqQXG3wJaYXkRZuQ0vEYN4bhwg7QnIrqB5B+w==", "dev": true, + "license": "MIT", "dependencies": { - "@types/estree": "1.0.6" + "@types/estree": "1.0.7" }, "bin": { "rollup": "dist/bin/rollup" @@ -7987,25 +7998,26 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.29.1", - "@rollup/rollup-android-arm64": "4.29.1", - "@rollup/rollup-darwin-arm64": "4.29.1", - "@rollup/rollup-darwin-x64": "4.29.1", - "@rollup/rollup-freebsd-arm64": "4.29.1", - "@rollup/rollup-freebsd-x64": "4.29.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.29.1", - "@rollup/rollup-linux-arm-musleabihf": "4.29.1", - "@rollup/rollup-linux-arm64-gnu": "4.29.1", - "@rollup/rollup-linux-arm64-musl": "4.29.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.29.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.29.1", - "@rollup/rollup-linux-riscv64-gnu": "4.29.1", - "@rollup/rollup-linux-s390x-gnu": "4.29.1", - "@rollup/rollup-linux-x64-gnu": "4.29.1", - "@rollup/rollup-linux-x64-musl": "4.29.1", - "@rollup/rollup-win32-arm64-msvc": "4.29.1", - "@rollup/rollup-win32-ia32-msvc": "4.29.1", - "@rollup/rollup-win32-x64-msvc": "4.29.1", + "@rollup/rollup-android-arm-eabi": "4.40.0", + "@rollup/rollup-android-arm64": "4.40.0", + "@rollup/rollup-darwin-arm64": "4.40.0", + "@rollup/rollup-darwin-x64": "4.40.0", + "@rollup/rollup-freebsd-arm64": "4.40.0", + "@rollup/rollup-freebsd-x64": "4.40.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.40.0", + "@rollup/rollup-linux-arm-musleabihf": "4.40.0", + "@rollup/rollup-linux-arm64-gnu": "4.40.0", + "@rollup/rollup-linux-arm64-musl": "4.40.0", + "@rollup/rollup-linux-loongarch64-gnu": "4.40.0", + "@rollup/rollup-linux-powerpc64le-gnu": "4.40.0", + "@rollup/rollup-linux-riscv64-gnu": "4.40.0", + "@rollup/rollup-linux-riscv64-musl": "4.40.0", + "@rollup/rollup-linux-s390x-gnu": "4.40.0", + "@rollup/rollup-linux-x64-gnu": "4.40.0", + "@rollup/rollup-linux-x64-musl": "4.40.0", + "@rollup/rollup-win32-arm64-msvc": "4.40.0", + "@rollup/rollup-win32-ia32-msvc": "4.40.0", + "@rollup/rollup-win32-x64-msvc": "4.40.0", "fsevents": "~2.3.2" } }, @@ -8857,15 +8869,19 @@ "dev": true }, "node_modules/tinyglobby": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz", - "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==", + "version": "0.2.12", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", + "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "license": "MIT", "dependencies": { - "fdir": "^6.4.2", + "fdir": "^6.4.3", "picomatch": "^4.0.2" }, "engines": { "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, "node_modules/tinypool": { @@ -9572,20 +9588,24 @@ } }, "node_modules/vite": { - "version": "5.4.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.11.tgz", - "integrity": "sha512-c7jFQRklXua0mTzneGW9QVyxFjUgwcihC4bXEtujIo2ouWCe1Ajt/amn2PCxYnhYfd5k09JX3SB7OYWFKYqj8Q==", + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.1.tgz", + "integrity": "sha512-kkzzkqtMESYklo96HKKPE5KKLkC1amlsqt+RjFMlX2AvbRB/0wghap19NdBxxwGZ+h/C6DLCrcEphPIItlGrRQ==", "dev": true, + "license": "MIT", "dependencies": { - "esbuild": "^0.21.3", - "postcss": "^8.4.43", - "rollup": "^4.20.0" + "esbuild": "^0.25.0", + "fdir": "^6.4.3", + "picomatch": "^4.0.2", + "postcss": "^8.5.3", + "rollup": "^4.34.9", + "tinyglobby": "^0.2.12" }, "bin": { "vite": "bin/vite.js" }, "engines": { - "node": "^18.0.0 || >=20.0.0" + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, "funding": { "url": "https://github.com/vitejs/vite?sponsor=1" @@ -9594,19 +9614,25 @@ "fsevents": "~2.3.3" }, "peerDependencies": { - "@types/node": "^18.0.0 || >=20.0.0", + "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", + "jiti": ">=1.21.0", "less": "*", "lightningcss": "^1.21.0", "sass": "*", "sass-embedded": "*", "stylus": "*", "sugarss": "*", - "terser": "^5.4.0" + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { "@types/node": { "optional": true }, + "jiti": { + "optional": true + }, "less": { "optional": true }, @@ -9627,6 +9653,12 @@ }, "terser": { "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true } } }, @@ -9652,7 +9684,7 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "node_modules/vite-node/node_modules/@esbuild/aix-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", @@ -9660,6 +9692,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "aix" @@ -9668,7 +9701,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/android-arm": { + "node_modules/vite-node/node_modules/@esbuild/android-arm": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", @@ -9676,6 +9709,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -9684,7 +9718,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/android-arm64": { + "node_modules/vite-node/node_modules/@esbuild/android-arm64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", @@ -9692,6 +9726,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -9700,7 +9735,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/android-x64": { + "node_modules/vite-node/node_modules/@esbuild/android-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", @@ -9708,6 +9743,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "android" @@ -9716,7 +9752,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "node_modules/vite-node/node_modules/@esbuild/darwin-arm64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", @@ -9724,6 +9760,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -9732,7 +9769,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "node_modules/vite-node/node_modules/@esbuild/darwin-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", @@ -9740,6 +9777,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" @@ -9748,7 +9786,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "node_modules/vite-node/node_modules/@esbuild/freebsd-arm64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", @@ -9756,6 +9794,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -9764,7 +9803,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "node_modules/vite-node/node_modules/@esbuild/freebsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", @@ -9772,6 +9811,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" @@ -9780,7 +9820,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-arm": { + "node_modules/vite-node/node_modules/@esbuild/linux-arm": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", @@ -9788,6 +9828,7 @@ "arm" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -9796,7 +9837,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "node_modules/vite-node/node_modules/@esbuild/linux-arm64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", @@ -9804,6 +9845,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -9812,7 +9854,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "node_modules/vite-node/node_modules/@esbuild/linux-ia32": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", @@ -9820,6 +9862,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -9828,7 +9871,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "node_modules/vite-node/node_modules/@esbuild/linux-loong64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", @@ -9836,6 +9879,7 @@ "loong64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -9844,7 +9888,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "node_modules/vite-node/node_modules/@esbuild/linux-mips64el": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", @@ -9852,6 +9896,7 @@ "mips64el" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -9860,7 +9905,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "node_modules/vite-node/node_modules/@esbuild/linux-ppc64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", @@ -9868,6 +9913,7 @@ "ppc64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -9876,7 +9922,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "node_modules/vite-node/node_modules/@esbuild/linux-riscv64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", @@ -9884,6 +9930,7 @@ "riscv64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -9892,7 +9939,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "node_modules/vite-node/node_modules/@esbuild/linux-s390x": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", @@ -9900,6 +9947,7 @@ "s390x" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -9908,7 +9956,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/linux-x64": { + "node_modules/vite-node/node_modules/@esbuild/linux-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", @@ -9916,6 +9964,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" @@ -9924,7 +9973,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "node_modules/vite-node/node_modules/@esbuild/netbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", @@ -9932,6 +9981,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "netbsd" @@ -9940,7 +9990,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "node_modules/vite-node/node_modules/@esbuild/openbsd-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", @@ -9948,6 +9998,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "openbsd" @@ -9956,7 +10007,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "node_modules/vite-node/node_modules/@esbuild/sunos-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", @@ -9964,6 +10015,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "sunos" @@ -9972,7 +10024,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "node_modules/vite-node/node_modules/@esbuild/win32-arm64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", @@ -9980,6 +10032,7 @@ "arm64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -9988,7 +10041,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "node_modules/vite-node/node_modules/@esbuild/win32-ia32": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", @@ -9996,6 +10049,7 @@ "ia32" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -10004,7 +10058,7 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/@esbuild/win32-x64": { + "node_modules/vite-node/node_modules/@esbuild/win32-x64": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", @@ -10012,6 +10066,7 @@ "x64" ], "dev": true, + "license": "MIT", "optional": true, "os": [ "win32" @@ -10020,12 +10075,13 @@ "node": ">=12" } }, - "node_modules/vite/node_modules/esbuild": { + "node_modules/vite-node/node_modules/esbuild": { "version": "0.21.5", "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", "dev": true, "hasInstallScript": true, + "license": "MIT", "bin": { "esbuild": "bin/esbuild" }, @@ -10058,6 +10114,66 @@ "@esbuild/win32-x64": "0.21.5" } }, + "node_modules/vite-node/node_modules/vite": { + "version": "5.4.18", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.18.tgz", + "integrity": "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, "node_modules/vitefu": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/vitefu/-/vitefu-1.0.6.tgz", @@ -10142,76 +10258,506 @@ } } }, - "node_modules/vitest/node_modules/execa": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", - "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.3", - "get-stream": "^8.0.1", - "human-signals": "^5.0.0", - "is-stream": "^3.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^5.1.0", - "onetime": "^6.0.0", - "signal-exit": "^4.1.0", - "strip-final-newline": "^3.0.0" - }, - "engines": { - "node": ">=16.17" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/vitest/node_modules/get-stream": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", - "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "node_modules/vitest/node_modules/@esbuild/aix-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.21.5.tgz", + "integrity": "sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==", + "cpu": [ + "ppc64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "aix" + ], "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/vitest/node_modules/human-signals": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", - "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "node_modules/vitest/node_modules/@esbuild/android-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.21.5.tgz", + "integrity": "sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==", + "cpu": [ + "arm" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=16.17.0" + "node": ">=12" } }, - "node_modules/vitest/node_modules/is-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", - "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "node_modules/vitest/node_modules/@esbuild/android-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.21.5.tgz", + "integrity": "sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==", + "cpu": [ + "arm64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=12" } }, - "node_modules/vitest/node_modules/mimic-fn": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", - "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "node_modules/vitest/node_modules/@esbuild/android-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.21.5.tgz", + "integrity": "sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/vitest/node_modules/npm-run-path": { - "version": "5.3.0", + "node_modules/vitest/node_modules/@esbuild/darwin-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.21.5.tgz", + "integrity": "sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/darwin-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.21.5.tgz", + "integrity": "sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.21.5.tgz", + "integrity": "sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/freebsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.21.5.tgz", + "integrity": "sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.21.5.tgz", + "integrity": "sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.21.5.tgz", + "integrity": "sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.21.5.tgz", + "integrity": "sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-loong64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.21.5.tgz", + "integrity": "sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==", + "cpu": [ + "loong64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-mips64el": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.21.5.tgz", + "integrity": "sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==", + "cpu": [ + "mips64el" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-ppc64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.21.5.tgz", + "integrity": "sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-riscv64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.21.5.tgz", + "integrity": "sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-s390x": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.21.5.tgz", + "integrity": "sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/linux-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.21.5.tgz", + "integrity": "sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/netbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.21.5.tgz", + "integrity": "sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/openbsd-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.21.5.tgz", + "integrity": "sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/sunos-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.21.5.tgz", + "integrity": "sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-arm64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.21.5.tgz", + "integrity": "sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-ia32": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.21.5.tgz", + "integrity": "sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/@esbuild/win32-x64": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.21.5.tgz", + "integrity": "sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vitest/node_modules/esbuild": { + "version": "0.21.5", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.21.5.tgz", + "integrity": "sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.21.5", + "@esbuild/android-arm": "0.21.5", + "@esbuild/android-arm64": "0.21.5", + "@esbuild/android-x64": "0.21.5", + "@esbuild/darwin-arm64": "0.21.5", + "@esbuild/darwin-x64": "0.21.5", + "@esbuild/freebsd-arm64": "0.21.5", + "@esbuild/freebsd-x64": "0.21.5", + "@esbuild/linux-arm": "0.21.5", + "@esbuild/linux-arm64": "0.21.5", + "@esbuild/linux-ia32": "0.21.5", + "@esbuild/linux-loong64": "0.21.5", + "@esbuild/linux-mips64el": "0.21.5", + "@esbuild/linux-ppc64": "0.21.5", + "@esbuild/linux-riscv64": "0.21.5", + "@esbuild/linux-s390x": "0.21.5", + "@esbuild/linux-x64": "0.21.5", + "@esbuild/netbsd-x64": "0.21.5", + "@esbuild/openbsd-x64": "0.21.5", + "@esbuild/sunos-x64": "0.21.5", + "@esbuild/win32-arm64": "0.21.5", + "@esbuild/win32-ia32": "0.21.5", + "@esbuild/win32-x64": "0.21.5" + } + }, + "node_modules/vitest/node_modules/execa": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-8.0.1.tgz", + "integrity": "sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^8.0.1", + "human-signals": "^5.0.0", + "is-stream": "^3.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^5.1.0", + "onetime": "^6.0.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^3.0.0" + }, + "engines": { + "node": ">=16.17" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/vitest/node_modules/get-stream": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-8.0.1.tgz", + "integrity": "sha512-VaUJspBffn/LMCJVoMvSAdmscJyS1auj5Zulnn5UoYcY531UWmdwhRWkcGKnGU93m5HSXP9LP2usOryrBtQowA==", + "dev": true, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/human-signals": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-5.0.0.tgz", + "integrity": "sha512-AXcZb6vzzrFAUE61HnN4mpLqd/cSIwNQjtNWR0euPm6y0iqx3G4gOXaIDdtdDwZmhwe82LA6+zinmW4UBWVePQ==", + "dev": true, + "engines": { + "node": ">=16.17.0" + } + }, + "node_modules/vitest/node_modules/is-stream": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-3.0.0.tgz", + "integrity": "sha512-LnQR4bZ9IADDRSkvpqMGvt/tEJWclzklNgSw48V5EAaAeDd6qGvN8ei6k5p0tvxSR171VmGyHuTiAOfxAbr8kA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/mimic-fn": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-4.0.0.tgz", + "integrity": "sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/vitest/node_modules/npm-run-path": { + "version": "5.3.0", "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-5.3.0.tgz", "integrity": "sha512-ppwTtiJZq0O/ai0z7yfudtBpWIoxM8yE6nHi1X47eFR2EWORqfbu6CnPlNsjeN683eT0qG6H/Pyf9fCcvjnnnQ==", "dev": true, @@ -10276,6 +10822,66 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/vitest/node_modules/vite": { + "version": "5.4.18", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.18.tgz", + "integrity": "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "esbuild": "^0.21.3", + "postcss": "^8.4.43", + "rollup": "^4.20.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "sass-embedded": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, "node_modules/vscode-languageserver-textdocument": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", diff --git a/package.json b/package.json index 4438eb79..f9c53c7f 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,9 @@ "build:server": "tsc --project tsconfig.server.json", "build:react": "tsc --project tsconfig.react.json && mkdir -p dist && rm -rf dist/react && mv distreact/react dist/react && rm -r distreact", "build:nextjs": "tsc --project tsconfig.nextjs.json && mkdir -p dist && rm -rf dist/nextjs && mv distnextjs/nextjs dist/nextjs && rm -r distnextjs", - "build": "rm -rf dist && npm run build:bin && npm run build:server && npm run build:react && npm run build:nextjs", + "build:svelte": "tsc --project tsconfig.svelte.json && mkdir -p dist && rm -rf dist/svelte && mv distsvelte/svelte dist/svelte && rm -r distsvelte", + "build:sveltekit": "tsc --project tsconfig.sveltekit.json && mkdir -p dist && rm -rf dist/sveltekit && mv distsveltekit/sveltekit dist/sveltekit && rm -r distsveltekit", + "build": "rm -rf dist && npm run build:bin && npm run build:server && npm run build:react && npm run build:nextjs && npm run build:svelte && npm run build:sveltekit", "docs": "cd docs && npm run dev", "lint": "tsc && eslint . && cd test && npm run lint", "spellcheck": "cspell \"docs/pages/**/*.md*\"", @@ -60,6 +62,14 @@ "./nextjs/server": { "import": "./dist/nextjs/server/index.js", "require": "./dist/nextjs/server/index.js" + }, + "./svelte": { + "import": "./dist/svelte/index.js", + "require": "./dist/svelte/index.js" + }, + "./sveltekit": { + "import": "./dist/sveltekit/index.js", + "require": "./dist/sveltekit/index.js" } }, "dependencies": { @@ -113,6 +123,7 @@ "tsup": "^8.0.1", "typescript": "^5.5.2", "valibot": "^0.35.0", - "vitest": "^1.6.0" + "vitest": "^1.6.0", + "vite": "^6.3.1" } } diff --git a/tsconfig.svelte.json b/tsconfig.svelte.json new file mode 100644 index 00000000..2cc606ad --- /dev/null +++ b/tsconfig.svelte.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./distsvelte", + "rootDir": "./src" + }, + "include": ["src/svelte/**/*"] +} diff --git a/tsconfig.sveltekit.json b/tsconfig.sveltekit.json new file mode 100644 index 00000000..4d724e77 --- /dev/null +++ b/tsconfig.sveltekit.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "outDir": "./distsveltekit", + "rootDir": "./src" + }, + "include": ["src/sveltekit/**/*"] +} From 93afe37bd2377d2d9341dc973f9a6c0e57363573 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 17 Apr 2025 12:11:49 +0200 Subject: [PATCH 10/88] Add SvelteKit auth integration with server-side hooks and layout handlers --- package.json | 4 + src/sveltekit/README.md | 4 +- test-sveltekit/package-lock.json | 681 ++++---------------- test-sveltekit/package.json | 9 +- test-sveltekit/src/hooks.server.ts | 10 + test-sveltekit/src/routes/+layout.server.ts | 10 + test-sveltekit/src/routes/+layout.svelte | 9 +- 7 files changed, 151 insertions(+), 576 deletions(-) create mode 100644 test-sveltekit/src/hooks.server.ts create mode 100644 test-sveltekit/src/routes/+layout.server.ts diff --git a/package.json b/package.json index f9c53c7f..baa5ec11 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,10 @@ "./sveltekit": { "import": "./dist/sveltekit/index.js", "require": "./dist/sveltekit/index.js" + }, + "./sveltekit/server": { + "import": "./dist/sveltekit/server/index.js", + "require": "./dist/sveltekit/server/index.js" } }, "dependencies": { diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 48027b48..f171e8ed 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -33,10 +33,8 @@ Set up the auth provider in your root layout: -{@render children()} + + {@render children()} + From d5ee46d7e0b20dcc41b397ac3fbacc66737f373f Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 17 Apr 2025 14:47:02 +0200 Subject: [PATCH 11/88] Update resolve type to support sync responses --- src/sveltekit/server/handlers.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index 1abddbf3..c2aba421 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -227,7 +227,7 @@ export async function convexAuthSvelteKitServerState( // Type definitions for the handle function interface HandleArgs { event: RequestEvent; - resolve: (event: RequestEvent) => Promise; + resolve: (event: RequestEvent) => Response | Promise; } /** From 2cbede8ca3d00de0746ef7f9831f591f36b02576 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 17 Apr 2025 20:04:31 +0200 Subject: [PATCH 12/88] Refactor auth provider to use setupConvexAuth function instead of component-based approach --- src/svelte/index.svelte.ts | 337 +++++++++++++++++++------------------ src/sveltekit/README.md | 333 ++++++++++++------------------------ src/sveltekit/index.ts | 94 +++++------ 3 files changed, 324 insertions(+), 440 deletions(-) diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index 420a5802..b102712a 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -14,6 +14,15 @@ import { AuthClient } from "./clientType.js"; const CONVEX_AUTH_ACTIONS_CONTEXT_KEY = "$$_convexAuthActions"; const CONVEX_AUTH_TOKEN_CONTEXT_KEY = "$$_convexAuthToken"; +// Extended client type to access internal properties +interface ExtendedConvexClient extends ConvexClient { + address: string; + logger: any; + options?: { + verbose?: boolean; + }; +} + /** * A storage interface for storing and retrieving tokens and other secrets. * @@ -45,6 +54,161 @@ export interface TokenStorage { removeItem: (key: string) => void | Promise; } +/** + * Initialize Convex Auth for Svelte. + * + * This function sets up authentication for your Svelte application. + * It should be called in your root layout or App component. + * + * @returns The auth client instance that can be used to access auth methods + * + * Usage: + * ```svelte + * + * + * + * ``` + */ +export function setupConvexAuth({ + client, + storage = typeof window !== "undefined" ? window.localStorage : null, + storageNamespace, + replaceURL = (url: string) => { + if (typeof window !== "undefined") { + window.history.replaceState({}, "", url); + } + }, + convexUrl +}: { + /** ConvexClient instance to use */ + client?: ConvexClient; + /** Storage for auth tokens */ + storage?: TokenStorage | null; + /** Namespace for storing tokens */ + storageNamespace?: string; + /** Function to replace the current URL */ + replaceURL?: (relativeUrl: string) => void | Promise; + /** Convex URL if no client is provided */ + convexUrl?: string; +} = {}) { + // Client resolution priority: + // 1. Client passed directly + // 2. Client from context + // 3. Try to create one if setupConvex is available + + // If no client provided, try to get from context + if (!client) { + try { + client = getContext("$$_convexClient"); + } catch (e) { + // Context not available or no client in context + } + } + + // If still no client and convexUrl is provided, try to create one using setupConvex + if (!client && convexUrl && typeof window !== "undefined") { + try { + // Check if setupConvex is available (defined by convex-svelte) + const setupConvex = (window as any).setupConvex || + (typeof globalThis !== "undefined" && (globalThis as any).setupConvex); + + if (typeof setupConvex === 'function') { + setupConvex(convexUrl); + // After setting up, try to get the client from context + try { + client = getContext("$$_convexClient"); + } catch (e) { + // Context not available after setup + } + } + } catch (e) { + console.warn("Failed to create Convex client:", e); + } + } + + // If we still don't have a client, throw an error + if (!client) { + throw new Error( + "No ConvexClient was provided. Either pass one to setupConvexAuth or call setupConvex() first.", + ); + } + + // Create auth client + const extendedClient = client as ExtendedConvexClient; + const authClient: AuthClient = { + authenticatedCall(action, args) { + return client.action(action, args); + }, + unauthenticatedCall(action, args) { + return new ConvexClient(extendedClient.address, { + logger: extendedClient.logger, + }).action(action, args); + }, + verbose: extendedClient.options?.verbose, + logger: extendedClient.logger, + }; + + // Create the auth client and set up context + const auth = createAuthClient({ + client: authClient, + storage, + storageNamespace: storageNamespace ?? extendedClient.address, + replaceURL, + onChange: async () => { + // Handle auth state changes + // This is a hook for implementations to use + }, + }); + + // Set auth contexts + setConvexAuthContext(auth); + setContext(CONVEX_AUTH_ACTIONS_CONTEXT_KEY, { + signIn: auth.signIn, + signOut: auth.signOut, + }); + + // Handle token updates reactively + if (typeof window !== "undefined") { + // Set token context reactively with $effect + $effect(() => { + let isMounted = true; + + if (auth.isAuthenticated) { + // Use void to handle the promise without returning it + void (async () => { + try { + const token = await auth.fetchAccessToken({ + forceRefreshToken: false, + }); + if (isMounted) { + setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, token); + } + } catch (error) { + console.error("Failed to fetch auth token:", error); + if (isMounted) { + setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, null); + } + } + })(); + } else { + setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, null); + } + + // Return a cleanup function + return () => { + isMounted = false; + }; + }); + } + + return auth; +} + /** * The result of calling `useAuthActions`. */ @@ -102,173 +266,26 @@ export type ConvexAuthActionsContext = { }; /** - * Create a Convex Auth provider component for Svelte - * - * @returns A Svelte component that provides auth context to children + * Create a Convex Auth provider for Svelte. + * + * This function sets up authentication for your Svelte application. + * It should be called in your root layout or App component. + * + * @returns The auth client instance that can be used to access auth methods + * + * Usage: * ```svelte * * - * - * {@render children()} - * + * * ``` */ -export function createConvexAuthProvider(options?: { - /** - * ConvexClient instance to use. If not provided, will try to get from context. - */ - client?: ConvexClient; - - /** - * Convex URL to use if no client is provided and setupConvex is available. - */ - convexUrl?: string; -}) { - const { client: providedClient, convexUrl } = options || {}; - - // Return a Svelte component (as a function) - return function ConvexAuthProvider({ - client, - storage = typeof window !== "undefined" ? window.localStorage : null, - storageNamespace, - replaceURL = (url: string) => { - if (typeof window !== "undefined") { - window.history.replaceState({}, "", url); - } - }, - children = undefined, - }: { - client?: ConvexClient; - storage?: TokenStorage | null; - storageNamespace?: string; - replaceURL?: (relativeUrl: string) => void | Promise; - children?: any; - } = {}) { - // Client resolution priority: - // 1. Client passed to component directly - // 2. Client passed to provider factory - // 3. Client from context - // 4. Try to create one if setupConvex is available - - // If client is not explicitly provided to component, use factory client - if (!client) { - client = providedClient; - } - - // If still no client, try to get from context - if (!client) { - try { - client = getContext("$$_convexClient"); - } catch (e) { - // Context not available or no client in context - } - } - - // If still no client and convexUrl is provided, try to create one using setupConvex - if (!client && convexUrl && typeof window !== "undefined") { - try { - // Check if setupConvex is available (defined by convex-svelte) - const setupConvex = (window as any).setupConvex || - (typeof globalThis !== "undefined" && (globalThis as any).setupConvex); - - if (typeof setupConvex === 'function') { - setupConvex(convexUrl); - // After setting up, try to get the client from context - try { - client = getContext("$$_convexClient"); - } catch (e) { - // Context not available after setup - } - } - } catch (e) { - console.warn("Failed to create Convex client:", e); - } - } - - // If we still don't have a client, throw an error - if (!client) { - throw new Error( - "No ConvexClient was provided. Either pass one to ConvexAuthProvider or call setupConvex() first.", - ); - } - - // Create auth client with reactive memoization - const authClient = $derived.by( - () => ({ - authenticatedCall(action, args) { - return client.action(action, args); - }, - unauthenticatedCall(action, args) { - return new ConvexClient((client as any).address, { - logger: (client as any).logger, - }).action(action, args); - }, - verbose: (client as any).options?.verbose, - logger: (client as any).logger, - }) satisfies AuthClient, - ); - - // Create the auth store and set in context - const auth = createAuthClient({ - client: authClient, - storage, - storageNamespace: storageNamespace ?? (client as any).address, - replaceURL, - onChange: async () => { - // Handle auth state changes - // This is a hook for implementations to use - }, - }); - - // Set auth contexts - setConvexAuthContext(auth); - setContext(CONVEX_AUTH_ACTIONS_CONTEXT_KEY, { - signIn: auth.signIn, - signOut: auth.signOut, - }); - - // Set token context (reactive) - $effect(() => { - let isMounted = true; - - if (auth.isAuthenticated) { - // Use void to handle the promise without returning it - void (async () => { - try { - const token = await auth.fetchAccessToken({ - forceRefreshToken: false, - }); - if (isMounted) { - setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, token); - } - } catch (error) { - console.error("Failed to fetch auth token:", error); - if (isMounted) { - setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, null); - } - } - })(); - } else { - setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, null); - } - - // Return a cleanup function - return () => { - isMounted = false; - }; - }); - - // Return children (in Svelte, using ) - return children; - }; -} +export const createConvexAuthProvider = setupConvexAuth; /** * Use this hook to access the `signIn` and `signOut` methods: diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index f171e8ed..1764b2e6 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -18,51 +18,50 @@ yarn add @convex-dev/auth Create or update your `.env` file with the following variables: -``` +```bash PUBLIC_CONVEX_URL=your_convex_deployment_url ``` For local development, you can also create a `.env.local` file. -### 2. Configure Auth Provider (Client-side) +### 2. Initialize Auth (Client-side) -Set up the auth provider in your root layout: +Set up authentication in your root layout: ```html - {@render children()} - ``` -The auth provider will: +The `setupConvexAuth` function will: 1. Use a client you provide directly (if any) 2. Look for a client in Svelte context (if available) 3. Create a new client automatically (if needed and not disabled) @@ -73,7 +72,7 @@ This makes it work seamlessly with different setup patterns. Load the authentication state in your layout server: -```typescript +```ts // src/routes/+layout.server.ts import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; import type { LayoutServerLoad } from './$types'; @@ -91,9 +90,7 @@ export const load: LayoutServerLoad = async (event) => { Create hooks to handle authentication in `src/hooks.server.ts`. -#### Minimal Example: - -```typescript +```ts // src/hooks.server.ts import { sequence } from '@sveltejs/kit/hooks'; import { createConvexAuthHooks } from '@convex-dev/auth/sveltekit/server'; @@ -108,9 +105,79 @@ export const handle = sequence( ); ``` -#### Advanced Example: -```typescript +## Usage + +### Pages (`+page.svelte`) + +Use authentication in your pages: + +```html + + + +{#if isLoading} +

Loading authentication state...

+{:else if isAuthenticated} +

Welcome, authenticated user!

+ +{:else} +

Please sign in

+ + +{/if} +``` + +### Page Server (`+page.server.ts`) + +Use auth state in page server load functions: + +```ts +// src/routes/profile/+page.server.ts +import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; +import { redirect } from '@sveltejs/kit'; +import type { PageServerLoad } from './$types'; + +// Create auth handlers +const { isAuthenticated } = createConvexAuthHandlers(); + +// Protect routes at the page level +export const load: PageServerLoad = async (event) => { + // Check if user is authenticated + if (!(await isAuthenticated(event))) { + // Redirect to login if not authenticated + throw redirect(302, '/login'); + } + + // Return data for authenticated users + return { + user: { /* user data */ } + }; +}; +``` + +## Protecting Routes + +### Option 1: Using Hooks (App-wide Protection) (Recommended) + +#### Example 1: Auth-first approach (whitelist pattern) +Most routes require authentication except for a few public ones +```ts +const isPublicRoute = createRouteMatcher([ + '/login', + '/register', + '/about', +]); +``` + +```ts // src/hooks.server.ts import { sequence } from '@sveltejs/kit/hooks'; import { redirect } from '@sveltejs/kit'; @@ -119,9 +186,6 @@ import { createRouteMatcher } from '@convex-dev/auth/sveltekit/server'; -// Example 1: Auth-first approach (whitelist pattern) -// Most routes require authentication except for a few public ones - const isPublicRoute = createRouteMatcher([ '/login', '/register', @@ -152,9 +216,27 @@ async function authFirstPattern(event) { // User is authenticated, continue to next handler return; } +``` + +#### Example 2: Public-first approach (blacklist pattern) + Most routes are public, only protect specific areas +```ts +const isProtectedRoute = createRouteMatcher([ + '/admin(.*)', + '/dashboard(.*)', + '/profile(.*)', +]); +``` -// Example 2: Public-first approach (blacklist pattern) -// Most routes are public, only protect specific areas + +```ts +// src/hooks.server.ts +import { sequence } from '@sveltejs/kit/hooks'; +import { redirect } from '@sveltejs/kit'; +import { + createConvexAuthHooks, + createRouteMatcher +} from '@convex-dev/auth/sveltekit/server'; const isProtectedRoute = createRouteMatcher([ '/admin(.*)', @@ -189,167 +271,11 @@ export const handle = sequence( ); ``` -### Handling Special Routes - -For more complex cases like handling invitations: - -```typescript -// src/hooks.server.ts -import { sequence } from '@sveltejs/kit/hooks'; -import { redirect } from '@sveltejs/kit'; -import { - createConvexAuthHooks, - createRouteMatcher -} from '@convex-dev/auth/sveltekit/server'; -import { api } from '@/convex/_generated/api'; -import { fetchMutation } from 'convex/svelte'; - -// Create auth hooks -const { handleAuth, convexAuth } = createConvexAuthHooks(); - -// Handle special route for invitation acceptance -const isInvitationRoute = createRouteMatcher(['/api/invitations/accept']); - -async function handleSpecialRoutes(event) { - if (isInvitationRoute(event.url.pathname)) { - const isAuthenticated = await convexAuth.isAuthenticated(event); - - if (!isAuthenticated) { - // Redirect to login with return URL - return redirect(302, - `/login?returnUrl=${encodeURIComponent(event.url.pathname + event.url.search)}` - ); - } - - // Get invitation ID from query params - const invitationId = event.url.searchParams.get('invitationId'); - - if (invitationId) { - try { - // Get auth token from server state - const authState = await convexAuth.getAuthState(event); - const token = authState._state.token; - - // Call the mutation with the auth token - await fetchMutation( - api.organizations.invitations.accept, - { invitationId }, - { token } - ); - - // Redirect to success page - return redirect(302, '/dashboard'); - } catch (error) { - console.error('Error accepting invitation:', error); - return new Response(JSON.stringify({ error: 'Failed to accept invitation' }), { - status: 500, - headers: { 'Content-Type': 'application/json' } - }); - } - } - } - - // Not a special route, continue to next handler - return; -} - -export const handle = sequence( - handleAuth, // Handle auth API requests - handleSpecialRoutes, // Handle special routes - // Add your auth pattern here... - // Your other custom handlers... -); -``` - -## Usage - -### Pages (`+page.svelte`) - -Use authentication in your pages: - -```html - - - -{#if isLoading} -

Loading authentication state...

-{:else if isAuthenticated} -

Welcome, authenticated user!

- -{:else} -

Please sign in

- - -{/if} -``` - -### Page Server (`+page.server.ts`) - -Use auth state in page server load functions: - -```typescript -// src/routes/profile/+page.server.ts -import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; -import { redirect } from '@sveltejs/kit'; -import type { PageServerLoad } from './$types'; - -// Create auth handlers -const { isAuthenticated } = createConvexAuthHandlers(); - -// Protect routes at the page level -export const load: PageServerLoad = async (event) => { - // Check if user is authenticated - if (!(await isAuthenticated(event))) { - // Redirect to login if not authenticated - throw redirect(302, '/login'); - } - - // Return data for authenticated users - return { - user: { /* user data */ } - }; -}; -``` - -## Protecting Routes - -### Option 1: Using Hooks (App-wide Protection) - -Configure route protection patterns in your `hooks.server.ts`: - -```typescript -// src/hooks.server.ts -import { createConvexAuthHooks, createRouteMatcher } from '@convex-dev/auth/sveltekit/server'; - -// Create a matcher for protected routes -const protectedRoutes = createRouteMatcher((path) => { - return path.startsWith('/dashboard') || - path.startsWith('/profile') || - path.startsWith('/admin'); -}); - -// Create auth hooks with route protection -const { handleAuth, protectRoutes } = createConvexAuthHooks({ - protectedRoutes, - // Where to redirect unauthenticated users - redirectUrl: '/login' -}); - -export const handle = sequence(handleAuth, protectRoutes); -``` - ### Option 2: Using Page Server Load (Page-level Protection) Protect individual pages in their `+page.server.ts`: -```typescript +```ts // src/routes/protected/+page.server.ts import { redirect } from '@sveltejs/kit'; import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; @@ -423,43 +349,6 @@ export async function load(event) { ## Advanced Usage -### Custom Redirect Handler - -```typescript -// src/hooks.server.ts -const { handleAuth, protectRoutes } = createConvexAuthHooks({ - onUnauthenticated: (event) => { - // Custom redirect logic - const url = new URL('/login', event.url.origin); - url.searchParams.set('from', event.url.pathname); - return new Response(null, { - status: 302, - headers: { Location: url.toString() } - }); - } -}); -``` - -### Route Matcher Patterns - -```typescript -// Match single route -createRouteMatcher('/dashboard'); - -// Match with regex -createRouteMatcher(/^\/api\/private\/.*$/); - -// Match with function -createRouteMatcher((path) => path.includes('/admin/')); - -// Match multiple patterns (OR) -createRouteMatcherGroup([ - '/dashboard', - /^\/profile\/.*$/, - (path) => path.startsWith('/settings') -]); -``` - ### Manual Token Handling ```html @@ -499,10 +388,8 @@ export const POST: RequestHandler = handleAuthAction; When using this approach, make sure to update your Auth Provider to use the same API route: -```html - - {@render children()} - +```ts +setupConvexAuth({ serverState: data.authState, apiRoute: "/api/auth" }); ``` ## Troubleshooting @@ -524,7 +411,3 @@ CONVEX_AUTH_DEBUG=true ``` This will output detailed logs about auth operations to help with troubleshooting. - -## License - -MIT diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts index 6eeab646..225cd7d1 100644 --- a/src/sveltekit/index.ts +++ b/src/sveltekit/index.ts @@ -5,7 +5,7 @@ */ import { - createConvexAuthProvider, + setupConvexAuth as setupSvelteConvexAuth, useAuthActions, getConvexAuthToken, useAuthToken, @@ -17,89 +17,73 @@ import { ConvexClient } from "convex/browser"; import { createSvelteKitAuthClient, type ConvexAuthServerState } from "./client"; /** - * Create a SvelteKit auth provider component that can be used to provide - * authentication state to child components. + * Initialize Convex Auth for SvelteKit. * - * @returns A Svelte component that provides auth context to children + * This function sets up authentication for your SvelteKit application. + * It should be called in your root +layout.svelte file. + * + * @returns The auth client instance that can be used to access auth methods * * Usage: * ```svelte * * - * - * {@render children()} - * + * {@render children()} * ``` */ - -/** - * Create a SvelteKit-specific auth provider component - */ -export function createSvelteKitAuthProvider(options?: { +export function setupConvexAuth({ + apiRoute = "/api/auth", + serverState, + storage = "localStorage", + storageNamespace, + verbose = false, + client, + convexUrl +}: { + /** API route to use for auth requests */ + apiRoute?: string; + /** Server-provided authentication state */ + serverState?: ConvexAuthServerState; + /** Storage type to use */ + storage?: "localStorage" | "inMemory"; + /** Storage namespace for auth tokens */ + storageNamespace?: string; + /** Enable verbose logging */ + verbose?: boolean; /** * ConvexClient instance to use. If not provided, will: * 1. Try to get it from Svelte context * 2. Initialize a new one using the Convex URL */ client?: ConvexClient; - /** * Convex URL to use. If not provided, will use * PUBLIC_CONVEX_URL environment variable. */ convexUrl?: string; -}) { - // Create the base provider with our options - const AuthProvider = createConvexAuthProvider(options); +} = {}) { + // Initialize the base Svelte auth + setupSvelteConvexAuth({ client, convexUrl }); - // Return a component factory function - return function ConvexAuthSvelteKitProvider({ - apiRoute = "/api/auth", + // Return the initialized auth client + return createSvelteKitAuthClient({ + apiRoute, serverState, - storage = "localStorage", + storage, storageNamespace, - verbose = false, - children, - }: { - apiRoute?: string; - serverState?: ConvexAuthServerState; - storage?: "localStorage" | "inMemory"; - storageNamespace?: string; - verbose?: boolean; - children?: any; - } = {}) { - // Create the SvelteKit-specific auth client - createSvelteKitAuthClient({ - apiRoute, - serverState, - storage, - storageNamespace, - verbose, - }); - - // Return the auth provider with SvelteKit-specific configuration - return AuthProvider({ - storage: typeof window === "undefined" - ? null - : storage === "inMemory" - ? null - : window.localStorage, - storageNamespace, - children, - }); - }; + verbose, + }); } + // Re-export core functionality export { createSvelteKitAuthClient, From 647f610c28076089e775f4a50cd7c2e3436b2dc8 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 17 Apr 2025 20:05:43 +0200 Subject: [PATCH 13/88] Migrate from AuthProvider to setupConvexAuth --- test-sveltekit/src/routes/+layout.svelte | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/test-sveltekit/src/routes/+layout.svelte b/test-sveltekit/src/routes/+layout.svelte index cc657064..3fc97fa9 100644 --- a/test-sveltekit/src/routes/+layout.svelte +++ b/test-sveltekit/src/routes/+layout.svelte @@ -1,12 +1,10 @@ - - {@render children()} - +{@render children()} From 9a04f0d521fc3ecfeae8c7e8eabb2e97000b07be Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 17 Apr 2025 21:16:43 +0200 Subject: [PATCH 14/88] Update Svelte auth provider API and add auth example to SvelteKit test app --- package.json | 2 +- src/svelte/index.svelte.ts | 24 +----------------------- test-nextjs/package-lock.json | 10 +++++++++- test-sveltekit/src/routes/+page.svelte | 23 +++++++++++++++++++++++ 4 files changed, 34 insertions(+), 25 deletions(-) diff --git a/package.json b/package.json index baa5ec11..e6dd8958 100644 --- a/package.json +++ b/package.json @@ -65,7 +65,7 @@ }, "./svelte": { "import": "./dist/svelte/index.js", - "require": "./dist/svelte/index.js" + "types": "./dist/svelte/index.d.ts" }, "./sveltekit": { "import": "./dist/sveltekit/index.js", diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index b102712a..38455f49 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -265,28 +265,6 @@ export type ConvexAuthActionsContext = { signOut(): Promise; }; -/** - * Create a Convex Auth provider for Svelte. - * - * This function sets up authentication for your Svelte application. - * It should be called in your root layout or App component. - * - * @returns The auth client instance that can be used to access auth methods - * - * Usage: - * ```svelte - * - * - * - * ``` - */ -export const createConvexAuthProvider = setupConvexAuth; - /** * Use this hook to access the `signIn` and `signOut` methods: * @@ -304,7 +282,7 @@ export function useAuthActions() { return getContext(CONVEX_AUTH_ACTIONS_CONTEXT_KEY); } catch (e) { throw new Error( - "useAuthActions must be used within a ConvexAuthProvider component", + "setupConvexAuth must be called before useAuthActions", ); } } diff --git a/test-nextjs/package-lock.json b/test-nextjs/package-lock.json index 0e78d624..2a04e0ea 100644 --- a/test-nextjs/package-lock.json +++ b/test-nextjs/package-lock.json @@ -41,11 +41,13 @@ }, "..": { "name": "@convex-dev/auth", - "version": "0.0.80", + "version": "0.0.81", "license": "Apache-2.0", "dependencies": { "arctic": "^1.2.0", "cookie": "^1.0.1", + "cspell": "^8.17.2", + "is-network-error": "^1.1.0", "jose": "^5.2.2", "jwt-decode": "^4.0.0", "lucia": "^3.2.0", @@ -60,6 +62,8 @@ "devDependencies": { "@commander-js/extra-typings": "^12.1.0", "@edge-runtime/vm": "^3.2.0", + "@sveltejs/kit": "^2.16.0", + "@sveltejs/vite-plugin-svelte": "^5.0.0", "@types/inquirer": "^9.0.7", "@types/node": "20.6.0", "@types/react": "^18.3.12", @@ -73,14 +77,18 @@ "npm-run-all": "^4.1.5", "react-dom": "^18.3.1", "shelljs": "^0.8.5", + "svelte": "^5.0.0", + "svelte-check": "^4.0.0", "tsup": "^8.0.1", "typescript": "^5.5.2", "valibot": "^0.35.0", + "vite": "^6.3.1", "vitest": "^1.6.0" }, "peerDependencies": { "@auth/core": "^0.37.0", "convex": "^1.17.0", + "convex-svelte": "^0.0.11", "react": "^18.2.0 || ^19.0.0-0" }, "peerDependenciesMeta": { diff --git a/test-sveltekit/src/routes/+page.svelte b/test-sveltekit/src/routes/+page.svelte index cc88df0e..173ed138 100644 --- a/test-sveltekit/src/routes/+page.svelte +++ b/test-sveltekit/src/routes/+page.svelte @@ -1,2 +1,25 @@ + +

Welcome to SvelteKit

Visit svelte.dev/docs/kit to read the documentation

+ +
+ {#if isAuthenticated} +

You are authenticated!

+ + {:else} +

You are not authenticated.

+ + {/if} +
From 62fcdb2fba410da4f4ee5724a76edf5a71f3686c Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 17 Apr 2025 21:30:42 +0200 Subject: [PATCH 15/88] Simplify auth API by consolidating hooks into single useAuth function --- src/svelte/index.svelte.ts | 104 ++++++++++++++----------- src/sveltekit/index.ts | 8 +- test-sveltekit/src/routes/+page.svelte | 10 +-- 3 files changed, 64 insertions(+), 58 deletions(-) diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index 38455f49..532185ee 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -13,6 +13,7 @@ import { AuthClient } from "./clientType.js"; // Context key for Convex auth actions const CONVEX_AUTH_ACTIONS_CONTEXT_KEY = "$$_convexAuthActions"; const CONVEX_AUTH_TOKEN_CONTEXT_KEY = "$$_convexAuthToken"; +const CONVEX_AUTH_CONTEXT_KEY = "$$_convexAuth"; // Extended client type to access internal properties interface ExtendedConvexClient extends ConvexClient { @@ -171,6 +172,7 @@ export function setupConvexAuth({ signIn: auth.signIn, signOut: auth.signOut, }); + setContext(CONVEX_AUTH_CONTEXT_KEY, auth); // Handle token updates reactively if (typeof window !== "undefined") { @@ -266,61 +268,75 @@ export type ConvexAuthActionsContext = { }; /** - * Use this hook to access the `signIn` and `signOut` methods: - * + * Use this function to access all authentication functionality including state, token, and actions. + * * ```ts - * import { useAuthActions } from "@convex-dev/auth/svelte"; - * + * import { useAuth } from "@convex-dev/auth/svelte"; + * * function SomeComponent() { - * const { signIn, signOut } = useAuthActions(); - * // ... + * const { isLoading, isAuthenticated, token, signIn, signOut } = useAuth(); + * + * // Use authentication state + * if (isLoading) { + * return

Loading...

; + * } + * + * if (isAuthenticated) { + * return ( + *
+ *

You are signed in!

+ * + *
+ * ); + * } + * + * return ( + *
+ *

You need to sign in

+ * + *
+ * ); * } * ``` */ -export function useAuthActions() { +export function useAuth(): { + isLoading: boolean; + isAuthenticated: boolean; + token: string | null; + signIn: ConvexAuthActionsContext["signIn"]; + signOut: ConvexAuthActionsContext["signOut"]; +} { try { - return getContext(CONVEX_AUTH_ACTIONS_CONTEXT_KEY); + // Get the auth client and actions from context + const auth = getContext>(CONVEX_AUTH_CONTEXT_KEY); + const actions = getContext(CONVEX_AUTH_ACTIONS_CONTEXT_KEY); + const token = getContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY) ?? null; + + if (!auth || !actions) { + throw new Error( + "setupConvexAuth must be called before useAuth" + ); + } + + // Return a unified object with all auth functionality + return { + // Auth state + get isLoading() { return auth.isLoading; }, + get isAuthenticated() { return auth.isAuthenticated; }, + + // Auth token + get token() { return token; }, + + // Auth actions + signIn: (...args) => actions.signIn(...args), + signOut: () => actions.signOut(), + }; } catch (e) { throw new Error( - "setupConvexAuth must be called before useAuthActions", + "setupConvexAuth must be called before useAuth" ); } } -/** - * Get the authentication token from context (if available) - */ -export function getConvexAuthToken() { - return getContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY) ?? null; -} - -/** - * Use this function to access the JWT token, for authenticating - * your Convex HTTP actions. - * - * You should not pass this token to other servers (think of it - * as an "ID token"). - * - * ```ts - * import { useAuthToken } from "@convex-dev/auth/svelte"; - * - * function SomeComponent() { - * const token = useAuthToken(); - * - * async function handleClick() { - * await fetch(`${CONVEX_SITE_URL}/someEndpoint`, { - * headers: { - * Authorization: `Bearer ${token}`, - * }, - * }); - * } - * // ... - * } - * ``` - */ -export function useAuthToken(): string | null { - return getContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY) ?? null; -} - // Re-export types export type { AuthClient } from "./clientType.js"; diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts index 225cd7d1..a6e8d1fd 100644 --- a/src/sveltekit/index.ts +++ b/src/sveltekit/index.ts @@ -6,9 +6,7 @@ import { setupConvexAuth as setupSvelteConvexAuth, - useAuthActions, - getConvexAuthToken, - useAuthToken, + useAuth, type TokenStorage, type ConvexAuthActionsContext } from "../svelte/index.svelte"; @@ -87,9 +85,7 @@ export function setupConvexAuth({ // Re-export core functionality export { createSvelteKitAuthClient, - useAuthActions, - getConvexAuthToken, - useAuthToken + useAuth }; // Re-export types diff --git a/test-sveltekit/src/routes/+page.svelte b/test-sveltekit/src/routes/+page.svelte index 173ed138..896ade5d 100644 --- a/test-sveltekit/src/routes/+page.svelte +++ b/test-sveltekit/src/routes/+page.svelte @@ -1,14 +1,8 @@

Welcome to SvelteKit

From d9a0837b15f6c5d32f0b3a88ae45bc4f80e1d120 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Fri, 18 Apr 2025 10:16:57 +0200 Subject: [PATCH 16/88] Refactor auth context and add explicit convexUrl handling in SvelteKit integration --- .gitignore | 2 + src/svelte/client.svelte.ts | 7 ++ src/svelte/index.svelte.ts | 122 +++++++++----------- test-sveltekit/src/hooks.server.ts | 7 +- test-sveltekit/src/routes/+layout.server.ts | 7 +- test-sveltekit/src/routes/+layout.svelte | 6 +- 6 files changed, 80 insertions(+), 71 deletions(-) diff --git a/.gitignore b/.gitignore index ab5b60f3..fdac14c5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ /dist /distreact /distnextjs +/distsvelte +/distsveltekit /publish-example # dependencies diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index 813e43f0..d2c273e5 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -441,6 +441,13 @@ export function setConvexAuthContext(authClient: ReturnType>(AUTH_CONTEXT_KEY); +} + /** * Create a fully namespaced key for storage */ diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index 532185ee..b22153c1 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -7,13 +7,16 @@ import { ConvexClient } from "convex/browser"; import { getContext, setContext } from "svelte"; import { Value } from "convex/values"; -import { createAuthClient, setConvexAuthContext } from "./client.svelte.js"; +import { + createAuthClient, + getConvexAuthContext, + setConvexAuthContext, +} from "./client.svelte.js"; import { AuthClient } from "./clientType.js"; +import { setupConvex } from "convex-svelte"; // Context key for Convex auth actions -const CONVEX_AUTH_ACTIONS_CONTEXT_KEY = "$$_convexAuthActions"; -const CONVEX_AUTH_TOKEN_CONTEXT_KEY = "$$_convexAuthToken"; -const CONVEX_AUTH_CONTEXT_KEY = "$$_convexAuth"; +const AUTH_TOKEN_CONTEXT_KEY = "$$_convexAuthToken"; // Extended client type to access internal properties interface ExtendedConvexClient extends ConvexClient { @@ -57,21 +60,21 @@ export interface TokenStorage { /** * Initialize Convex Auth for Svelte. - * + * * This function sets up authentication for your Svelte application. * It should be called in your root layout or App component. - * + * * @returns The auth client instance that can be used to access auth methods - * + * * Usage: * ```svelte * - * + * * * ``` */ @@ -84,7 +87,7 @@ export function setupConvexAuth({ window.history.replaceState({}, "", url); } }, - convexUrl + convexUrl, }: { /** ConvexClient instance to use */ client?: ConvexClient; @@ -110,28 +113,22 @@ export function setupConvexAuth({ // Context not available or no client in context } } - + // If still no client and convexUrl is provided, try to create one using setupConvex - if (!client && convexUrl && typeof window !== "undefined") { + if (!client && convexUrl) { try { - // Check if setupConvex is available (defined by convex-svelte) - const setupConvex = (window as any).setupConvex || - (typeof globalThis !== "undefined" && (globalThis as any).setupConvex); - - if (typeof setupConvex === 'function') { - setupConvex(convexUrl); - // After setting up, try to get the client from context - try { - client = getContext("$$_convexClient"); - } catch (e) { - // Context not available after setup - } + setupConvex(convexUrl); + // After setting up, try to get the client from context + try { + client = getContext("$$_convexClient"); + } catch (e) { + // Context not available after setup } } catch (e) { console.warn("Failed to create Convex client:", e); } } - + // If we still don't have a client, throw an error if (!client) { throw new Error( @@ -166,20 +163,15 @@ export function setupConvexAuth({ }, }); - // Set auth contexts + // Set auth context setConvexAuthContext(auth); - setContext(CONVEX_AUTH_ACTIONS_CONTEXT_KEY, { - signIn: auth.signIn, - signOut: auth.signOut, - }); - setContext(CONVEX_AUTH_CONTEXT_KEY, auth); // Handle token updates reactively if (typeof window !== "undefined") { // Set token context reactively with $effect $effect(() => { let isMounted = true; - + if (auth.isAuthenticated) { // Use void to handle the promise without returning it void (async () => { @@ -188,19 +180,19 @@ export function setupConvexAuth({ forceRefreshToken: false, }); if (isMounted) { - setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, token); + setContext(AUTH_TOKEN_CONTEXT_KEY, token); } } catch (error) { console.error("Failed to fetch auth token:", error); if (isMounted) { - setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, null); + setContext(AUTH_TOKEN_CONTEXT_KEY, null); } } })(); } else { - setContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY, null); + setContext(AUTH_TOKEN_CONTEXT_KEY, null); } - + // Return a cleanup function return () => { isMounted = false; @@ -269,18 +261,18 @@ export type ConvexAuthActionsContext = { /** * Use this function to access all authentication functionality including state, token, and actions. - * + * * ```ts * import { useAuth } from "@convex-dev/auth/svelte"; - * + * * function SomeComponent() { * const { isLoading, isAuthenticated, token, signIn, signOut } = useAuth(); - * + * * // Use authentication state * if (isLoading) { * return

Loading...

; * } - * + * * if (isAuthenticated) { * return ( *
@@ -289,7 +281,7 @@ export type ConvexAuthActionsContext = { *
* ); * } - * + * * return ( *
*

You need to sign in

@@ -299,42 +291,42 @@ export type ConvexAuthActionsContext = { * } * ``` */ -export function useAuth(): { - isLoading: boolean; - isAuthenticated: boolean; +export function useAuth(): Omit< + ReturnType, + "fetchAccessToken" +> & { token: string | null; - signIn: ConvexAuthActionsContext["signIn"]; - signOut: ConvexAuthActionsContext["signOut"]; } { try { // Get the auth client and actions from context - const auth = getContext>(CONVEX_AUTH_CONTEXT_KEY); - const actions = getContext(CONVEX_AUTH_ACTIONS_CONTEXT_KEY); - const token = getContext(CONVEX_AUTH_TOKEN_CONTEXT_KEY) ?? null; - - if (!auth || !actions) { - throw new Error( - "setupConvexAuth must be called before useAuth" - ); + const auth = getConvexAuthContext(); + const token = getContext(AUTH_TOKEN_CONTEXT_KEY) ?? null; + + if (!auth) { + throw new Error("setupConvexAuth must be called before useAuth"); } - + // Return a unified object with all auth functionality return { // Auth state - get isLoading() { return auth.isLoading; }, - get isAuthenticated() { return auth.isAuthenticated; }, - + get isLoading() { + return auth.isLoading; + }, + get isAuthenticated() { + return auth.isAuthenticated; + }, + // Auth token - get token() { return token; }, - + get token() { + return token; + }, + // Auth actions - signIn: (...args) => actions.signIn(...args), - signOut: () => actions.signOut(), + signIn: (...args) => auth.signIn(...args), + signOut: () => auth.signOut(), }; } catch (e) { - throw new Error( - "setupConvexAuth must be called before useAuth" - ); + throw new Error("setupConvexAuth must be called before useAuth"); } } diff --git a/test-sveltekit/src/hooks.server.ts b/test-sveltekit/src/hooks.server.ts index 6734c828..6a641df3 100644 --- a/test-sveltekit/src/hooks.server.ts +++ b/test-sveltekit/src/hooks.server.ts @@ -1,8 +1,11 @@ import { sequence } from '@sveltejs/kit/hooks'; import { createConvexAuthHooks } from '@convex-dev/auth/sveltekit/server'; +import { PUBLIC_CONVEX_URL } from '$env/static/public'; -// Create auth hooks - convexUrl is automatically detected from environment -const { handleAuth } = createConvexAuthHooks(); +// Create auth hooks - explicitly pass the convexUrl from environment variables +const { handleAuth } = createConvexAuthHooks({ + convexUrl: PUBLIC_CONVEX_URL +}); // Apply hooks in sequence export const handle = sequence( diff --git a/test-sveltekit/src/routes/+layout.server.ts b/test-sveltekit/src/routes/+layout.server.ts index ab5e02c8..7a6050da 100644 --- a/test-sveltekit/src/routes/+layout.server.ts +++ b/test-sveltekit/src/routes/+layout.server.ts @@ -1,8 +1,11 @@ import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; import type { LayoutServerLoad } from './$types'; +import { PUBLIC_CONVEX_URL } from '$env/static/public'; -// Create auth handlers - convexUrl is automatically detected from environment -const { loadAuthState } = createConvexAuthHandlers(); +// Create auth handlers - explicitly pass the convexUrl from environment variables +const { loadAuthState } = createConvexAuthHandlers({ + convexUrl: PUBLIC_CONVEX_URL +}); // Export load function to provide auth state to layout export const load: LayoutServerLoad = async (event) => { diff --git a/test-sveltekit/src/routes/+layout.svelte b/test-sveltekit/src/routes/+layout.svelte index 3fc97fa9..04312201 100644 --- a/test-sveltekit/src/routes/+layout.svelte +++ b/test-sveltekit/src/routes/+layout.svelte @@ -1,10 +1,12 @@ {@render children()} From 4ce0bb779537229e32a8b239fd2ad6013930743d Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Fri, 18 Apr 2025 11:10:01 +0200 Subject: [PATCH 17/88] Improve auth configuration with better env handling --- src/svelte/index.svelte.ts | 71 +++++++++++++++++++++++++------------- src/sveltekit/index.ts | 39 ++++++++++----------- 2 files changed, 66 insertions(+), 44 deletions(-) diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index b22153c1..134023dd 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -4,7 +4,7 @@ * @module */ -import { ConvexClient } from "convex/browser"; +import { ConvexClient, ConvexClientOptions } from "convex/browser"; import { getContext, setContext } from "svelte"; import { Value } from "convex/values"; import { @@ -18,15 +18,6 @@ import { setupConvex } from "convex-svelte"; // Context key for Convex auth actions const AUTH_TOKEN_CONTEXT_KEY = "$$_convexAuthToken"; -// Extended client type to access internal properties -interface ExtendedConvexClient extends ConvexClient { - address: string; - logger: any; - options?: { - verbose?: boolean; - }; -} - /** * A storage interface for storing and retrieving tokens and other secrets. * @@ -88,18 +79,50 @@ export function setupConvexAuth({ } }, convexUrl, + options, }: { /** ConvexClient instance to use */ client?: ConvexClient; - /** Storage for auth tokens */ + /** + * Optional custom storage object that implements + * the {@link TokenStorage} interface, otherwise + * [`localStorage`](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage) + * is used. + * + * You must set this for Svelte Native. + */ storage?: TokenStorage | null; - /** Namespace for storing tokens */ + /** + * Optional namespace for keys used to store tokens. The keys + * determine whether the tokens are shared or not. + * + * Any non-alphanumeric characters will be ignored (for RN compatibility). + * + * Defaults to the deployment URL, as configured in the given `client`. + */ storageNamespace?: string; - /** Function to replace the current URL */ - replaceURL?: (relativeUrl: string) => void | Promise; - /** Convex URL if no client is provided */ - convexUrl?: string; -} = {}) { + /** + * Provide this function if you're using a JS router (Expo router etc.) + * and after OAuth or magic link sign-in the `code` param is not being + * erased from the URL. + * + * The implementation will depend on your chosen router. + */ + replaceURL?: ( + /** + * The URL, always starting with '/' and include the path, query and + * fragment components, that the window location should be set to. + */ + relativeUrl: string, + ) => void | Promise; + /** + * The url of your Convex deployment, often provided + * by an environment variable. E.g. `https://small-mouse-123.convex.cloud`. + */ + convexUrl: string; + + options?: ConvexClientOptions +}) { // Client resolution priority: // 1. Client passed directly // 2. Client from context @@ -117,7 +140,7 @@ export function setupConvexAuth({ // If still no client and convexUrl is provided, try to create one using setupConvex if (!client && convexUrl) { try { - setupConvex(convexUrl); + setupConvex(convexUrl, options); // After setting up, try to get the client from context try { client = getContext("$$_convexClient"); @@ -136,26 +159,26 @@ export function setupConvexAuth({ ); } + // Create auth client - const extendedClient = client as ExtendedConvexClient; const authClient: AuthClient = { authenticatedCall(action, args) { return client.action(action, args); }, unauthenticatedCall(action, args) { - return new ConvexClient(extendedClient.address, { - logger: extendedClient.logger, + return new ConvexClient(convexUrl, { + logger: options?.logger, }).action(action, args); }, - verbose: extendedClient.options?.verbose, - logger: extendedClient.logger, + verbose: options?.verbose, + logger: options?.logger, }; // Create the auth client and set up context const auth = createAuthClient({ client: authClient, storage, - storageNamespace: storageNamespace ?? extendedClient.address, + storageNamespace: storageNamespace ?? convexUrl, replaceURL, onChange: async () => { // Handle auth state changes diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts index a6e8d1fd..95185d09 100644 --- a/src/sveltekit/index.ts +++ b/src/sveltekit/index.ts @@ -11,7 +11,7 @@ import { type ConvexAuthActionsContext } from "../svelte/index.svelte"; -import { ConvexClient } from "convex/browser"; +import { ConvexClient, ConvexClientOptions } from "convex/browser"; import { createSvelteKitAuthClient, type ConvexAuthServerState } from "./client"; /** @@ -38,14 +38,20 @@ import { createSvelteKitAuthClient, type ConvexAuthServerState } from "./client" * ``` */ export function setupConvexAuth({ + client, apiRoute = "/api/auth", serverState, storage = "localStorage", storageNamespace, - verbose = false, - client, - convexUrl + convexUrl, + options }: { + /** + * ConvexClient instance to use. If not provided, will: + * 1. Try to get it from Svelte context + * 2. Initialize a new one using the Convex URL + */ + client?: ConvexClient; /** API route to use for auth requests */ apiRoute?: string; /** Server-provided authentication state */ @@ -54,30 +60,23 @@ export function setupConvexAuth({ storage?: "localStorage" | "inMemory"; /** Storage namespace for auth tokens */ storageNamespace?: string; - /** Enable verbose logging */ - verbose?: boolean; - /** - * ConvexClient instance to use. If not provided, will: - * 1. Try to get it from Svelte context - * 2. Initialize a new one using the Convex URL - */ - client?: ConvexClient; - /** - * Convex URL to use. If not provided, will use - * PUBLIC_CONVEX_URL environment variable. + /** + * The url of your Convex deployment, often provided + * by an environment variable. E.g. `https://small-mouse-123.convex.cloud`. */ - convexUrl?: string; -} = {}) { + convexUrl: string; + options?: ConvexClientOptions +}) { // Initialize the base Svelte auth - setupSvelteConvexAuth({ client, convexUrl }); + setupSvelteConvexAuth({ client, convexUrl, options }); // Return the initialized auth client return createSvelteKitAuthClient({ apiRoute, serverState, storage, - storageNamespace, - verbose, + storageNamespace: storageNamespace ?? convexUrl, + verbose: options?.verbose, }); } From 9c1a714c75edb8960cba9aff1a95d927a5682c55 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 09:07:24 +0200 Subject: [PATCH 18/88] Add Skeleton UI components to SvelteKit test app --- src/sveltekit/index.ts | 3 +- test-sveltekit/package.json | 6 ++- test-sveltekit/src/app.css | 6 +++ test-sveltekit/src/app.html | 2 +- test-sveltekit/src/routes/+page.svelte | 23 +++++----- test-sveltekit/src/routes/signin/+page.svelte | 45 +++++++++++++++++++ 6 files changed, 69 insertions(+), 16 deletions(-) create mode 100644 test-sveltekit/src/routes/signin/+page.svelte diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts index 95185d09..1f8600dd 100644 --- a/src/sveltekit/index.ts +++ b/src/sveltekit/index.ts @@ -101,9 +101,10 @@ export type { * Usage in hooks.server.ts: * ```ts * import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; + * import { PUBLIC_CONVEX_URL } from '$env/static/public'; * * const { getAuthState } = createConvexAuthHandlers({ - * convexUrl: process.env.CONVEX_URL!, + * convexUrl: PUBLIC_CONVEX_URL, * }); * * export async function handle({ event, resolve }) { diff --git a/test-sveltekit/package.json b/test-sveltekit/package.json index 93d63d41..029a029d 100644 --- a/test-sveltekit/package.json +++ b/test-sveltekit/package.json @@ -17,14 +17,16 @@ "test:unit": "vitest" }, "dependencies": { + "@convex-dev/auth": "file:..", "convex": "file:../node_modules/convex", - "convex-svelte": "file:../node_modules/convex-svelte", - "@convex-dev/auth": "file:.." + "convex-svelte": "file:../node_modules/convex-svelte" }, "devDependencies": { "@eslint/compat": "^1.2.5", "@eslint/js": "^9.18.0", "@playwright/test": "^1.49.1", + "@skeletonlabs/skeleton": "^3.1.2", + "@skeletonlabs/skeleton-svelte": "^1.2.1", "@sveltejs/adapter-auto": "^4.0.0", "@sveltejs/kit": "file:../node_modules/@sveltejs/kit", "@sveltejs/vite-plugin-svelte": "file:../node_modules/@sveltejs/vite-plugin-svelte", diff --git a/test-sveltekit/src/app.css b/test-sveltekit/src/app.css index d4b50785..dbcb3638 100644 --- a/test-sveltekit/src/app.css +++ b/test-sveltekit/src/app.css @@ -1 +1,7 @@ @import 'tailwindcss'; + +@import '@skeletonlabs/skeleton'; +@import '@skeletonlabs/skeleton/optional/presets'; +@import '@skeletonlabs/skeleton/themes/cerberus'; + +@source '../node_modules/@skeletonlabs/skeleton-svelte/dist'; diff --git a/test-sveltekit/src/app.html b/test-sveltekit/src/app.html index 77a5ff52..4376c511 100644 --- a/test-sveltekit/src/app.html +++ b/test-sveltekit/src/app.html @@ -1,5 +1,5 @@ - + diff --git a/test-sveltekit/src/routes/+page.svelte b/test-sveltekit/src/routes/+page.svelte index 896ade5d..1e8ad44c 100644 --- a/test-sveltekit/src/routes/+page.svelte +++ b/test-sveltekit/src/routes/+page.svelte @@ -1,19 +1,18 @@ + import { useAuth } from '@convex-dev/auth/sveltekit'; + + const { signIn, signOut, isAuthenticated } = useAuth(); +

Welcome to SvelteKit

Visit svelte.dev/docs/kit to read the documentation

- {#if isAuthenticated} -

You are authenticated!

- - {:else} -

You are not authenticated.

- - {/if} + {#if isAuthenticated} +

You are authenticated!

+ + {:else} +

You are not authenticated.

+ + {/if}
diff --git a/test-sveltekit/src/routes/signin/+page.svelte b/test-sveltekit/src/routes/signin/+page.svelte new file mode 100644 index 00000000..2566b80b --- /dev/null +++ b/test-sveltekit/src/routes/signin/+page.svelte @@ -0,0 +1,45 @@ + + +
+
+

Sign in or create an account

+ + {#if env.PUBLIC_E2E_TEST} +
{ + event.preventDefault(); + const formData = new FormData(event.currentTarget); + signIn('secret', formData) + .then(() => { + goto('/product'); + }) + .catch(() => { + window.alert('Invalid secret'); + }); + }} + > + Test only: Sign in with a secret + + +
+ {/if} + + Cancel +
+
From 289becee6ecc9d26747085241a394bb3b3047764 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 09:07:43 +0200 Subject: [PATCH 19/88] Add package-.lock.json --- test-sveltekit/package-lock.json | 520 ++++++++++++++++++++++++++++++- 1 file changed, 519 insertions(+), 1 deletion(-) diff --git a/test-sveltekit/package-lock.json b/test-sveltekit/package-lock.json index b1df5f21..88f2ab36 100644 --- a/test-sveltekit/package-lock.json +++ b/test-sveltekit/package-lock.json @@ -16,6 +16,8 @@ "@eslint/compat": "^1.2.5", "@eslint/js": "^9.18.0", "@playwright/test": "^1.49.1", + "@skeletonlabs/skeleton": "^3.1.2", + "@skeletonlabs/skeleton-svelte": "^1.2.1", "@sveltejs/adapter-auto": "^4.0.0", "@sveltejs/kit": "file:../node_modules/@sveltejs/kit", "@sveltejs/vite-plugin-svelte": "file:../node_modules/@sveltejs/vite-plugin-svelte", @@ -192,7 +194,6 @@ }, "../node_modules/svelte": { "version": "5.26.2", - "dev": true, "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", @@ -1021,6 +1022,34 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@floating-ui/core": { + "version": "1.6.9", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.6.9.tgz", + "integrity": "sha512-uMXCuQ3BItDUbAMhIXw7UPXRfAlOAvZzdK9BWpE60MCn+Svt3aLn9jsPTi/WNGlRUu2uI0v5S7JiIUsbsvh3fw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/dom": { + "version": "1.6.13", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.6.13.tgz", + "integrity": "sha512-umqzocjDgNRGTuO7Q8CU32dkHkECqI8ZdMZ5Swb6QAM0t5rnlrN3lGo1hdpscRd3WS8T6DKYK4ephgIH9iRh3w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/core": "^1.6.0", + "@floating-ui/utils": "^0.2.9" + } + }, + "node_modules/@floating-ui/utils": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.9.tgz", + "integrity": "sha512-MDWhGtE+eHw5JW7lq4qhc5yRLS11ERl1c7Z6Xd0a58DozHES6EnNNwUWbMiG4J9Cgj053Bhk8zvlhFYKVhULwg==", + "dev": true, + "license": "MIT" + }, "node_modules/@humanfs/core": { "version": "0.19.1", "resolved": "https://registry.npmjs.org/@humanfs/core/-/core-0.19.1.tgz", @@ -1428,6 +1457,44 @@ "win32" ] }, + "node_modules/@skeletonlabs/skeleton": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@skeletonlabs/skeleton/-/skeleton-3.1.2.tgz", + "integrity": "sha512-ZrBFgSFEa1/ntkbXBKdRRhuDA9iigTTuq4Qph1QbxB+GBeuBQevHP6NXLTRKtED7MQYi43dc0kLPSUS2b1+cSA==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "tailwindcss": "^4.0.0" + } + }, + "node_modules/@skeletonlabs/skeleton-svelte": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@skeletonlabs/skeleton-svelte/-/skeleton-svelte-1.2.1.tgz", + "integrity": "sha512-lb0P+qgK1Lgs2EbTHxc2OSkq0Rr9W7Xtm8nyVWHOjM07Mm5OuTmP2ThfUXj8Z76JlrnJPayGrRZz5P+GefF0GQ==", + "dev": true, + "dependencies": { + "@zag-js/accordion": "^1.7.0", + "@zag-js/avatar": "^1.7.0", + "@zag-js/combobox": "^1.7.0", + "@zag-js/dialog": "^1.7.0", + "@zag-js/file-upload": "^1.7.0", + "@zag-js/pagination": "^1.7.0", + "@zag-js/popover": "^1.7.0", + "@zag-js/progress": "^1.7.0", + "@zag-js/radio-group": "^1.7.0", + "@zag-js/rating-group": "^1.7.0", + "@zag-js/slider": "^1.7.0", + "@zag-js/svelte": "^1.7.0", + "@zag-js/switch": "^1.7.0", + "@zag-js/tabs": "^1.7.0", + "@zag-js/tags-input": "^1.7.0", + "@zag-js/toast": "^1.7.0", + "@zag-js/tooltip": "^1.7.0" + }, + "peerDependencies": { + "svelte": "^5.20.0" + } + }, "node_modules/@sveltejs/adapter-auto": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/@sveltejs/adapter-auto/-/adapter-auto-4.0.0.tgz", @@ -2128,6 +2195,443 @@ "url": "https://opencollective.com/vitest" } }, + "node_modules/@zag-js/accordion": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/accordion/-/accordion-1.10.0.tgz", + "integrity": "sha512-VNAr4PlDXYRYo8pRaWrVRjawmSVAvOi5jRq9rO29nhkrYpuDdDfWK9H35/wO9UkeIRWxCT90RsKZZgoLRRVJTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/anatomy": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/anatomy/-/anatomy-1.10.0.tgz", + "integrity": "sha512-WbVCkHxaNauzXDt/5dt8yc8pb80leE+6sbuX5xVcXhAy+urLfDgTCjyShQxmgg5n9j5DqPPnqVOhRPH3h/bs3g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@zag-js/aria-hidden": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/aria-hidden/-/aria-hidden-1.10.0.tgz", + "integrity": "sha512-/fexQ+ngSgKRb226M60oDN/KDis1trMznU+dOd5z+TZZTcJZMFIRk+QZ0OcYuUHLE1vgyflRO2bkJeuT8GRqQg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@zag-js/auto-resize": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/auto-resize/-/auto-resize-1.10.0.tgz", + "integrity": "sha512-LiZM5InvOG2Siv0V4RsN4UZzzfnb1Dbxo6K2uQHZPPstmwx28lHcLJNQ45iEszuK0MQfNFQJZj842MjYmHPm3A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/dom-query": "1.10.0" + } + }, + "node_modules/@zag-js/avatar": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/avatar/-/avatar-1.10.0.tgz", + "integrity": "sha512-10u97C5iYHbLQGGvnwwqAm5xzxSmD0BJmUmYZneLCr0CqFkBjcEMaSfGLz+Qop9LYC5636ljZchN3LoCIbgCXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/collection": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/collection/-/collection-1.10.0.tgz", + "integrity": "sha512-z14taqIW/6YONkXz11qxKKdwK7A+zgi67KAu+mk93aDceyHebUz+F0Yrc3NkP6uMd+s6w2AQHqC51TuNivYvzw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/combobox": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/combobox/-/combobox-1.10.0.tgz", + "integrity": "sha512-qTs5y8JxOTT+K6/tA4yD+7fUj8QmaiCcCxc8N9/vk3jo7JMB05WpUsWvRW42xH4F2RFs64+fIW7qhfmKAbBzBw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/aria-hidden": "1.10.0", + "@zag-js/collection": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dismissable": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/popper": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/core": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/core/-/core-1.10.0.tgz", + "integrity": "sha512-pGSl55A02Y1VsRNuyUGam7CGshzLYy9YbE3QjfNNXD6DKvAXBxMUdDSMtzAXYkWGo3CsbjE/X0PRFnYjYACWmg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/dom-query": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/dialog": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/dialog/-/dialog-1.10.0.tgz", + "integrity": "sha512-PQsKZeboCpzpoeixY1YMuPnI4U4hBm+NaVnHJwB3dBD9mRM9WUdI+pP7U5mziuekyl69TJccUA6+Q1B0rQf2Gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/aria-hidden": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dismissable": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/focus-trap": "1.10.0", + "@zag-js/remove-scroll": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/dismissable": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/dismissable/-/dismissable-1.10.0.tgz", + "integrity": "sha512-sSqWGrK4qwW4iX36C6jSPirZA81cinN062gCPTeweS7GHoLFYqmd0SWWPAthrWrl/ldCcRb45HIrlNkrB43T+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/dom-query": "1.10.0", + "@zag-js/interact-outside": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/dom-query": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/dom-query/-/dom-query-1.10.0.tgz", + "integrity": "sha512-UQM4pHPPwpPNyuIcaDvuTjI4ntvBCV0oatpd+OcOW8NdUc2VVcPzL4cN6q1h+Q9s0Rpi+q77X0x6t9c1QWj1Iw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/types": "1.10.0" + } + }, + "node_modules/@zag-js/file-upload": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/file-upload/-/file-upload-1.10.0.tgz", + "integrity": "sha512-gAHvwPypsQcyVBA7F5bBLdgvvbtxPyzaxvC01WCFGPkFgHNfAtA1tx0Ez2aGuMoywB4rEA08xJdpI/UFz6AfXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/file-utils": "1.10.0", + "@zag-js/i18n-utils": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/file-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/file-utils/-/file-utils-1.10.0.tgz", + "integrity": "sha512-kvl0CL2VhkGywP5u/+Do+tAp9Lu9vljs5NneoT+BUXD9RsElZBPsSBk0sRJI1d1cQt0K3UjapoXyQuwCPBGiHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/i18n-utils": "1.10.0" + } + }, + "node_modules/@zag-js/focus-trap": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/focus-trap/-/focus-trap-1.10.0.tgz", + "integrity": "sha512-6+SPzXws7BurUb5AxHD6RoygInvPkGhleJmClQadeFhOlOdZdaeqwZjnoA3WoH/15V4NfUnoIzy72Su36D8RmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/dom-query": "1.10.0" + } + }, + "node_modules/@zag-js/focus-visible": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/focus-visible/-/focus-visible-1.10.0.tgz", + "integrity": "sha512-FQLi5w7Tq7oUuPNkCrieyCsxrc48betJQofTq1xLA46/+67dnOpDojRvAnY5Y4DDTuMZtjizw6B7WIwWNstOyw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/dom-query": "1.10.0" + } + }, + "node_modules/@zag-js/i18n-utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/i18n-utils/-/i18n-utils-1.10.0.tgz", + "integrity": "sha512-W/A6fATphw0T3DjbNqfVr6Ve1TnJ2Pr3WOcE2VOf8YKrTLVzeScIaqb+6qC/R6yQHtOkrKoQb1qScB/4PInvQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/dom-query": "1.10.0" + } + }, + "node_modules/@zag-js/interact-outside": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/interact-outside/-/interact-outside-1.10.0.tgz", + "integrity": "sha512-K5E2zArV6bExx1TTJKlmy+lAS7/Of6w50AYt77YUcsmwb6VeBVwe2+egid0pPeULNsuDvC7/DLmIumdn+WLiFA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/dom-query": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/live-region": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/live-region/-/live-region-1.10.0.tgz", + "integrity": "sha512-0DtzznoMIAg4HdLHZRsRWYBGsaIoTyeq3LLO1UGLcyboRiITtdUBRvTgLanQUzpi6iEiygJAmtIgxTmwYip9UQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@zag-js/pagination": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/pagination/-/pagination-1.10.0.tgz", + "integrity": "sha512-x5KwPzKhrg3k/osZLYrkNrfeulrfPeXdd1Mne8HwKkcANCk7zUmguThlym1bdB0LbUE+QkXuPwl55BJExfS3cQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/popover": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/popover/-/popover-1.10.0.tgz", + "integrity": "sha512-e3h1JfX9UF1Hs6YwJncDmhmWdaufph9UYWEcSAflyJVUtpltKb4MooyQXFMpdwnMNQ9E+5t0QHD0W1y+WvKndw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/aria-hidden": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dismissable": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/focus-trap": "1.10.0", + "@zag-js/popper": "1.10.0", + "@zag-js/remove-scroll": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/popper": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/popper/-/popper-1.10.0.tgz", + "integrity": "sha512-fruKqvG9wi8xEeQSfrPguPJVJGUAIvAvG6VpjJmZCb9oMPaCFZym7o3+RIEAA84/rviNA+S1mYh8gUPerWPpFQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@floating-ui/dom": "1.6.13", + "@zag-js/dom-query": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/progress": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/progress/-/progress-1.10.0.tgz", + "integrity": "sha512-7GC0jz6cxK0Mgu6tzNH2F8zNWp1L/sBSkvY4j+nu/Xg9Ql8nm6I5Re3/XknCfRVbMB5p3OnTmTOEzVrVbZ8rCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/radio-group": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/radio-group/-/radio-group-1.10.0.tgz", + "integrity": "sha512-dm8BcbbBZIQSPECArjBGGcHEDYTQDpYZfuK+kXuUm+zbeFmbaNPcz6kKk93QnSJnAv8BiseCd1njUCn9sG/VhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/focus-visible": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/rating-group": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/rating-group/-/rating-group-1.10.0.tgz", + "integrity": "sha512-P1UzjeTkz8Ig80cc8TlJ00dcmeT/RP4l9sxRcmyKxH6UQG1g8Lwb88ASYhhCTRFybAUeA+170vJ3/AOTi5/b7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/remove-scroll": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/remove-scroll/-/remove-scroll-1.10.0.tgz", + "integrity": "sha512-ZxWi1sG2YIImkkKRx0U8mlwt9qiv0cgXX3g6v5JSznrVk1BioMXND9hGptmHryyT4KHnzKUQAJcbhBh47foKLQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/dom-query": "1.10.0" + } + }, + "node_modules/@zag-js/slider": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/slider/-/slider-1.10.0.tgz", + "integrity": "sha512-mzuwv2aSIV7CCx6bmep5oK3bZktoxWuffTqvQe4Ay4EF1AmspE94IkfSiNWydbsRiWkoxwEGKwVISLJKyjKesA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/store": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/store/-/store-1.10.0.tgz", + "integrity": "sha512-QjUN29qo2fRXPUWvYgXPAY0lN7RowslAfqvbjLbhy3bQQ7s1/Ag/Ok6KX3Bk44fPqtSYYwn2rQORhHIed1pM4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "proxy-compare": "3.0.1" + } + }, + "node_modules/@zag-js/svelte": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/svelte/-/svelte-1.10.0.tgz", + "integrity": "sha512-XTr/Uikabp9ULETs2s/hyuIYbtSlLJrxKzLqtqqquuOngMc1fBnEgsI0p35Gup0/7ZGiBBXkwJPQuloxfAV5OQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/core": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + }, + "peerDependencies": { + "svelte": "^5.0.0-next.1" + } + }, + "node_modules/@zag-js/switch": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/switch/-/switch-1.10.0.tgz", + "integrity": "sha512-oeFwpbb3R01HW1lZVzNIsosMWuz58z6QcTNn66cyuO3YJx8+I/NN3XqxDq3Q4UxzJUXMYhSRhDbMv6HbQ3F84w==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/focus-visible": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/tabs": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/tabs/-/tabs-1.10.0.tgz", + "integrity": "sha512-c+wfprm2uVT0kTTYpx6A+BS0q4l1nWcov1eO0qjXtZ4qwbY6QzSMCA9g/8de3HuEnx6CiRBvE6cUY/sh673GnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/tags-input": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/tags-input/-/tags-input-1.10.0.tgz", + "integrity": "sha512-zrp0PZJMEFcvoTcNh1G65lsuge2XxVXGlb+xWl6HxpT62oJWd/W9egbTCgLsM07c522r63afwBwRg7MeXQRSpw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/auto-resize": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/interact-outside": "1.10.0", + "@zag-js/live-region": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/toast": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/toast/-/toast-1.10.0.tgz", + "integrity": "sha512-r6cOC4ic8K1henKiiGC+P3jsOSqv3Q6whcSMHUipupL1Tj6V+5uUK70AntmC8t0TrNqHdRMeFKoSCnUiqxlsvQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dismissable": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/tooltip": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/tooltip/-/tooltip-1.10.0.tgz", + "integrity": "sha512-OtOWiNjqMRBjaswxAkvmE5KpLVY6y5Sda3a0FHNuuNhVggjdWZJ7ohvzDlb0r/7jVBG8+fuh2kfuRGI5B4pWiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@zag-js/anatomy": "1.10.0", + "@zag-js/core": "1.10.0", + "@zag-js/dom-query": "1.10.0", + "@zag-js/focus-visible": "1.10.0", + "@zag-js/popper": "1.10.0", + "@zag-js/store": "1.10.0", + "@zag-js/types": "1.10.0", + "@zag-js/utils": "1.10.0" + } + }, + "node_modules/@zag-js/types": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/types/-/types-1.10.0.tgz", + "integrity": "sha512-HlM+EHYPLPaHgmuf2Bg5isNy2Kv30nwaANbkcMhVQYi8OfrTraxUQbTDXk3hb56qFmW1HQCMZzt1L7aS2qlOyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "3.1.3" + } + }, + "node_modules/@zag-js/utils": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/@zag-js/utils/-/utils-1.10.0.tgz", + "integrity": "sha512-Ze3QU9lV0nihfy+urze5rGUx5c615GguPoshHFov3JhFczEvze/Ewp5Am59l8UoHxU9DUQHC3Dcq9vIPANLL3Q==", + "dev": true, + "license": "MIT" + }, "node_modules/acorn": { "version": "8.14.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", @@ -2407,6 +2911,13 @@ "node": ">=18" } }, + "node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "dev": true, + "license": "MIT" + }, "node_modules/data-urls": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz", @@ -4133,6 +4644,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/proxy-compare": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/proxy-compare/-/proxy-compare-3.0.1.tgz", + "integrity": "sha512-V9plBAt3qjMlS1+nC8771KNf6oJ12gExvaxnNzN/9yVRLdTv/lc+oJlnSzrdYDAvBfTStPCoiaCOTmTs0adv7Q==", + "dev": true, + "license": "MIT" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", From 5dd7489a3ca99c8c447bdf8d4eb6a36517d66ac8 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 11:14:55 +0200 Subject: [PATCH 20/88] Upgrade path-to-regexp and improve route matching for Next.js and SvelteKit --- package-lock.json | 13 ++- package.json | 2 +- src/nextjs/server/routeMatcher.ts | 159 +++++++++++++++++---------- src/sveltekit/server/index.ts | 4 +- src/sveltekit/server/routeMatcher.ts | 146 +++++++++++++++++------- 5 files changed, 221 insertions(+), 103 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3d5ec8bb..534e51c2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,7 +18,7 @@ "lucia": "^3.2.0", "oauth4webapi": "^3.1.2", "oslo": "^1.1.2", - "path-to-regexp": "^6.3.0", + "path-to-regexp": "^8.2.0", "server-only": "^0.0.1" }, "bin": { @@ -7545,10 +7545,13 @@ } }, "node_modules/path-to-regexp": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", - "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", - "license": "MIT" + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", + "integrity": "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } }, "node_modules/path-type": { "version": "4.0.0", diff --git a/package.json b/package.json index e6dd8958..0ce47603 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "lucia": "^3.2.0", "oauth4webapi": "^3.1.2", "oslo": "^1.1.2", - "path-to-regexp": "^6.3.0", + "path-to-regexp": "^8.2.0", "server-only": "^0.0.1" }, "peerDependencies": { diff --git a/src/nextjs/server/routeMatcher.ts b/src/nextjs/server/routeMatcher.ts index 56dca78b..bb85208c 100644 --- a/src/nextjs/server/routeMatcher.ts +++ b/src/nextjs/server/routeMatcher.ts @@ -1,83 +1,128 @@ -// Adapted from Clerk -// -// MIT License -// -// Copyright (c) 2022 Clerk, Inc. -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to deal -// in the Software without restriction, including without limitation the rights -// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -// copies of the Software, and to permit persons to whom the Software is -// furnished to do so, subject to the following conditions: -// -// The above copyright notice and this permission notice shall be included in all -// copies or substantial portions of the Software. -// -// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -// SOFTWARE. +/** + * Adapted from Clerk's createRouteMatcher (MIT, 2022 Clerk, Inc.) + * Additional modifications 2025 Convex. + * + * The original licence follows: + * ----------------------------------------------------------- + * + * MIT License + * + * Copyright (c) 2022 Clerk, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * ------------------------------------------------------------ + */ -import { pathToRegexp } from "path-to-regexp"; +import { match } from "path-to-regexp"; import type Link from "next/link"; import type { NextRequest } from "next/server"; -type WithPathPatternWildcard = `${T & string}(.*)`; -type NextTypedRoute["0"]["href"]> = T extends string +/** + * Type for route matching paths using path-to-regexp v8.2 syntax. + * Supports: + * - Normal paths ('/dashboard') + * - Parameter paths ('/:id') + * - Wildcard paths ('/*splat') + * - Optional segments ('/users{/:id}/profile') + */ +export type PathPattern = string; + +/** + * Base type for Next.js routes - extracts types from the Link component + */ +export type NextTypedRoute["0"]["href"]> = T extends string ? T : never; -type Autocomplete = U | (T & Record); - -type RouteMatcherWithNextTypedRoutes = Autocomplete< - // eslint-disable-next-line @typescript-eslint/no-redundant-type-constituents - WithPathPatternWildcard | NextTypedRoute ->; - /** - * See {@link createRouteMatcher} for more information. + * Parameters that can be passed to createRouteMatcher. + * Can be a single pattern, an array of patterns, a RegExp, or a custom matcher function. */ export type RouteMatcherParam = - | Array + | PathPattern + | PathPattern[] | RegExp - | RouteMatcherWithNextTypedRoutes | ((req: NextRequest) => boolean); /** - * Returns a function that accepts a `Request` object and returns whether the request matches the list of + * Returns a function that accepts a `NextRequest` object and returns whether the request matches the list of * predefined routes that can be passed in as the first argument. * * You can use glob patterns to match multiple routes or a function to match against the request object. * Path patterns and limited regular expressions are supported. - * For more information, see: https://www.npmjs.com/package/path-to-regexp/v/6.3.0 + * For more information, see: https://www.npmjs.com/package/path-to-regexp/v/8.2.0 + * + * Examples: + * ```ts + * // Match exact path + * const isDashboard = createRouteMatcher('/dashboard'); + * + * // Match with Parameters + * const isOrgDashboard = createRouteMatcher('/:org/dashboard'); + * + * // Match with Wildcard + * const isApi = createRouteMatcher('/api/*'); + * + * // Match with Optional + * const isUsersDelete = createRouteMatcher('/users{/:id}/delete'); + * + * // Match multiple paths + * const matcher = createRouteMatcher(['/dashboard', '/account', '/api/*']); + * ``` */ export const createRouteMatcher = (routes: RouteMatcherParam) => { + // If routes is a function, use it directly if (typeof routes === "function") { return (req: NextRequest) => routes(req); } - const routePatterns = [routes || ""].flat().filter(Boolean); - const matchers = precomputePathRegex(routePatterns); - return (req: NextRequest) => - matchers.some((matcher) => matcher.test(req.nextUrl.pathname)); -}; + // If routes is a RegExp, use it directly + if (routes instanceof RegExp) { + return (req: NextRequest) => routes.test(req.nextUrl.pathname); + } -const precomputePathRegex = (patterns: Array) => { - return patterns.map((pattern) => - pattern instanceof RegExp ? pattern : pathStringToRegExp(pattern), - ); -}; + // Convert routes to an array if it's not already + const routePatterns = Array.isArray(routes) ? routes : [routes]; + + // Filter out empty patterns + const filteredPatterns = routePatterns.filter(Boolean) as Array< + string | RegExp + >; + + // Create matcher functions for each pattern + const matchers = filteredPatterns.map((pattern) => { + if (pattern instanceof RegExp) { + return (pathname: string) => pattern.test(pathname); + } else { + try { + // Use the match function from path-to-regexp + const matchFn = match(pattern, { end: true }); + return (pathname: string) => matchFn(pathname) !== false; + } catch (e: any) { + throw new Error( + `Invalid path: ${pattern}.\nConsult the documentation of path-to-regexp here: https://github.com/pillarjs/path-to-regexp\n${e.message}`, + ); + } + } + }); -function pathStringToRegExp(path: string) { - try { - return pathToRegexp(path); - } catch (e: any) { - throw new Error( - `Invalid path: ${path}.\nConsult the documentation of path-to-regexp here: https://github.com/pillarjs/path-to-regexp\n${e.message}`, - ); - } -} + // Return a function that returns true if any of the matchers return true + return (req: NextRequest) => + matchers.some((matcher) => matcher(req.nextUrl.pathname)); +}; diff --git a/src/sveltekit/server/index.ts b/src/sveltekit/server/index.ts index b971e5fe..ebe02aed 100644 --- a/src/sveltekit/server/index.ts +++ b/src/sveltekit/server/index.ts @@ -8,7 +8,6 @@ import { } from './handlers.js'; import { createRouteMatcher, - createRouteMatcherGroup, type RouteMatcherParam, type RouteMatcherFn } from './routeMatcher.js'; @@ -22,8 +21,7 @@ export { // Export route matchers (equivalent to NextJS implementation) export { - createRouteMatcher, - createRouteMatcherGroup, + createRouteMatcher, type RouteMatcherParam, type RouteMatcherFn }; diff --git a/src/sveltekit/server/routeMatcher.ts b/src/sveltekit/server/routeMatcher.ts index cef1b0da..b2cd7991 100644 --- a/src/sveltekit/server/routeMatcher.ts +++ b/src/sveltekit/server/routeMatcher.ts @@ -1,52 +1,124 @@ /** - * Route matcher for SvelteKit to match paths for protection + * Adapted from Clerk’s createRouteMatcher (MIT, ©2022 Clerk, Inc.) + * Additional modifications ©2025 Convex. + * + * The original licence follows: + * ----------------------------------------------------------- + * + * MIT License + * + * Copyright (c) 2022 Clerk, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + * ------------------------------------------------------------ + */ + +import { match } from "path-to-regexp"; + +/** + * Type for route matching paths using path-to-regexp v8.2 syntax. + * Supports: + * - Normal paths ('/dashboard') + * - Parameter paths ('/:id') + * - Wildcard paths ('/*splat') + * - Optional segments ('/users{/:id}/profile') */ +export type PathPattern = string; -// Types for route matching -export type RouteMatcherParam = string | RegExp | RouteMatcherFn; +/** + * Function type for route matching. + * Takes a pathname string and returns a boolean indicating if it matches. + */ export type RouteMatcherFn = (pathname: string) => boolean; /** - * Create a route matcher that checks if a route matches the given pattern - * - * @param pattern A string, regex, or function to match against routes - * @returns A function that returns true if the route matches - * + * Parameters that can be passed to createRouteMatcher. + * Can be a single pattern, an array of patterns, a RegExp, or a custom matcher function. + */ +export type RouteMatcherParam = + | PathPattern + | PathPattern[] + | RegExp + | ((pathname: string) => boolean); + +/** + * Returns a function that accepts a pathname string and returns whether the request matches the list of + * predefined routes that can be passed in as the first argument. + * + * You can use glob patterns to match multiple routes or a function to match against the pathname. + * Path patterns and limited regular expressions are supported. + * For more information, see: https://www.npmjs.com/package/path-to-regexp/v/8.2.0 + * * Examples: * ```ts * // Match exact path - * const matcher = createRouteMatcher('/dashboard'); - * - * // Match with regex - * const matcher = createRouteMatcher(/^\/api\/.*$/); - * - * // Match with function - * const matcher = createRouteMatcher((path) => path.startsWith('/account')); + * const isDashboard = createRouteMatcher('/dashboard'); + * + * // Match with Parameters + * const isOrgDashboard = createRouteMatcher('/:org/dashboard'); + * + * // Match with Wildcard + * const isApi = createRouteMatcher('/api/*'); + * + * // Match with Optional + * const isUsersDelete = createRouteMatcher('/users{/:id}/delete'); + * + * // Match multiple paths + * const matcher = createRouteMatcher(['/dashboard', '/account', '/api/*']); * ``` */ -export function createRouteMatcher(pattern: RouteMatcherParam): RouteMatcherFn { - if (typeof pattern === 'string') { - return (pathname) => pathname === pattern; - } - - if (pattern instanceof RegExp) { - return (pathname) => pattern.test(pathname); +export function createRouteMatcher(routes: RouteMatcherParam): RouteMatcherFn { + // If routes is a function, use it directly + if (typeof routes === "function") { + return (pathname: string) => routes(pathname); } - - if (typeof pattern === 'function') { - return pattern; + + // If routes is a RegExp, use it directly + if (routes instanceof RegExp) { + return (pathname: string) => routes.test(pathname); } - - throw new Error('Invalid route matcher pattern'); -} -/** - * Create a matcher that combines multiple patterns with OR logic - */ -export function createRouteMatcherGroup(patterns: RouteMatcherParam[]): RouteMatcherFn { - const matchers = patterns.map(pattern => createRouteMatcher(pattern)); - - return (pathname) => { - return matchers.some(matcher => matcher(pathname)); - }; + // Convert routes to an array if it's not already + const routePatterns = Array.isArray(routes) ? routes : [routes]; + + // Filter out empty patterns + const filteredPatterns = routePatterns.filter(Boolean) as Array< + string | RegExp + >; + + // Create matcher functions for each pattern + const matchers = filteredPatterns.map((pattern) => { + if (pattern instanceof RegExp) { + return (pathname: string) => pattern.test(pathname); + } else { + try { + // Use the match function from path-to-regexp + const matchFn = match(pattern, { end: true }); + return (pathname: string) => matchFn(pathname) !== false; + } catch (e: any) { + throw new Error( + `Invalid path: ${pattern}.\nConsult the documentation of path-to-regexp here: https://github.com/pillarjs/path-to-regexp\n${e.message}`, + ); + } + } + }); + + // Return a function that returns true if any of the matchers return true + return (pathname: string) => matchers.some((matcher) => matcher(pathname)); } From 107ee4b19b5134cc13a51642aaffaa8b83ce3b3b Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 11:22:56 +0200 Subject: [PATCH 21/88] Improve SvelteKit auth handling --- src/sveltekit/README.md | 16 ++++++++-------- test-sveltekit/src/hooks.server.ts | 27 +++++++++++++++++++-------- 2 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 1764b2e6..28b67458 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -180,7 +180,7 @@ const isPublicRoute = createRouteMatcher([ ```ts // src/hooks.server.ts import { sequence } from '@sveltejs/kit/hooks'; -import { redirect } from '@sveltejs/kit'; +import { redirect, type Handle } from '@sveltejs/kit'; import { createConvexAuthHooks, createRouteMatcher @@ -198,7 +198,7 @@ const isPublicRoute = createRouteMatcher([ const { handleAuth, convexAuth } = createConvexAuthHooks(); // Custom handle function for auth-first pattern -async function authFirstPattern(event) { +const authFirstPattern: Handle = async ({ event, resolve }) => { // Skip auth check for public routes if (isPublicRoute(event.url.pathname)) { return; @@ -210,11 +210,11 @@ async function authFirstPattern(event) { if (!isAuthenticated) { // Store the original URL for redirect after login const returnUrl = encodeURIComponent(event.url.pathname + event.url.search); - return redirect(302, `/login?redirectTo=${returnUrl}`); + return redirect(307, `/login?redirectTo=${returnUrl}`); } // User is authenticated, continue to next handler - return; + return resolve(event); } ``` @@ -232,7 +232,7 @@ const isProtectedRoute = createRouteMatcher([ ```ts // src/hooks.server.ts import { sequence } from '@sveltejs/kit/hooks'; -import { redirect } from '@sveltejs/kit'; +import { redirect, type Handle } from '@sveltejs/kit'; import { createConvexAuthHooks, createRouteMatcher @@ -245,7 +245,7 @@ const isProtectedRoute = createRouteMatcher([ ]); // Custom handle function for public-first pattern -async function publicFirstPattern(event) { +const publicFirstPattern: Handle = async ({ event, resolve }) => { // Check auth only for protected routes if (isProtectedRoute(event.url.pathname)) { const isAuthenticated = await convexAuth.isAuthenticated(event); @@ -253,12 +253,12 @@ async function publicFirstPattern(event) { if (!isAuthenticated) { // Store the original URL for redirect after login const returnUrl = encodeURIComponent(event.url.pathname + event.url.search); - return redirect(302, `/login?redirectTo=${returnUrl}`); + return redirect(307, `/login?redirectTo=${returnUrl}`); } } // All other routes are public, or user is authenticated - return; + return resolve(event); } // Choose which pattern to use based on your app's needs diff --git a/test-sveltekit/src/hooks.server.ts b/test-sveltekit/src/hooks.server.ts index 6a641df3..a5474730 100644 --- a/test-sveltekit/src/hooks.server.ts +++ b/test-sveltekit/src/hooks.server.ts @@ -1,13 +1,24 @@ import { sequence } from '@sveltejs/kit/hooks'; -import { createConvexAuthHooks } from '@convex-dev/auth/sveltekit/server'; +import { createConvexAuthHooks, createRouteMatcher } from '@convex-dev/auth/sveltekit/server'; import { PUBLIC_CONVEX_URL } from '$env/static/public'; +import { redirect, type Handle } from '@sveltejs/kit'; -// Create auth hooks - explicitly pass the convexUrl from environment variables -const { handleAuth } = createConvexAuthHooks({ - convexUrl: PUBLIC_CONVEX_URL +const isSignInPage = createRouteMatcher(['/signin']); +const isProtectedRoute = createRouteMatcher(['/product/*']); + +const { handleAuth, isAuthenticated } = createConvexAuthHooks({ + convexUrl: PUBLIC_CONVEX_URL }); -// Apply hooks in sequence -export const handle = sequence( - handleAuth -); \ No newline at end of file +const authFirstPattern: Handle = async ({ event, resolve }) => { + if (isSignInPage(event.url.pathname) && (await isAuthenticated(event))) { + redirect(307, '/product'); + } + if (isProtectedRoute(event.url.pathname) && !(await isAuthenticated(event))) { + redirect(307, `/signin?redirectTo=${encodeURIComponent(event.url.pathname + event.url.search)}`); + } + + return resolve(event); +} + +export const handle = sequence(handleAuth, authFirstPattern); From 39eab0566aff900e9972ebc1b2a49d08778dd1a2 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 11:32:42 +0200 Subject: [PATCH 22/88] Update route matcher patterns --- src/sveltekit/README.md | 12 ++++++------ src/sveltekit/server/routeMatcher.ts | 2 +- test-sveltekit/src/hooks.server.ts | 4 ++-- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 28b67458..54d51671 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -222,9 +222,9 @@ const authFirstPattern: Handle = async ({ event, resolve }) => { Most routes are public, only protect specific areas ```ts const isProtectedRoute = createRouteMatcher([ - '/admin(.*)', - '/dashboard(.*)', - '/profile(.*)', + '/admin/*path', + '/dashboard/*path', + '/profile/*path', ]); ``` @@ -239,9 +239,9 @@ import { } from '@convex-dev/auth/sveltekit/server'; const isProtectedRoute = createRouteMatcher([ - '/admin(.*)', - '/dashboard(.*)', - '/profile(.*)', + '/admin/*path', + '/dashboard/*path', + '/profile/*path', ]); // Custom handle function for public-first pattern diff --git a/src/sveltekit/server/routeMatcher.ts b/src/sveltekit/server/routeMatcher.ts index b2cd7991..6f514c48 100644 --- a/src/sveltekit/server/routeMatcher.ts +++ b/src/sveltekit/server/routeMatcher.ts @@ -74,7 +74,7 @@ export type RouteMatcherParam = * const isOrgDashboard = createRouteMatcher('/:org/dashboard'); * * // Match with Wildcard - * const isApi = createRouteMatcher('/api/*'); + * const isApi = createRouteMatcher('/api/*path'); * * // Match with Optional * const isUsersDelete = createRouteMatcher('/users{/:id}/delete'); diff --git a/test-sveltekit/src/hooks.server.ts b/test-sveltekit/src/hooks.server.ts index a5474730..3b3b28cd 100644 --- a/test-sveltekit/src/hooks.server.ts +++ b/test-sveltekit/src/hooks.server.ts @@ -3,8 +3,8 @@ import { createConvexAuthHooks, createRouteMatcher } from '@convex-dev/auth/svel import { PUBLIC_CONVEX_URL } from '$env/static/public'; import { redirect, type Handle } from '@sveltejs/kit'; -const isSignInPage = createRouteMatcher(['/signin']); -const isProtectedRoute = createRouteMatcher(['/product/*']); +const isSignInPage = createRouteMatcher('/signin'); +const isProtectedRoute = createRouteMatcher('/product/*path'); const { handleAuth, isAuthenticated } = createConvexAuthHooks({ convexUrl: PUBLIC_CONVEX_URL From 85612a2a8cbc96124485d3b697d665ee90596b32 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 11:36:56 +0200 Subject: [PATCH 23/88] fix Vite file serving configuration --- test-sveltekit/vite.config.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/test-sveltekit/vite.config.ts b/test-sveltekit/vite.config.ts index 639f7fa7..5ff294d8 100644 --- a/test-sveltekit/vite.config.ts +++ b/test-sveltekit/vite.config.ts @@ -3,8 +3,16 @@ import tailwindcss from '@tailwindcss/vite'; import { sveltekit } from '@sveltejs/kit/vite'; import { defineConfig } from 'vite'; +// Allowing Vite to serve files from outside the project directory +// This addresses the error: The request url is outside of Vite serving allow list export default defineConfig({ plugins: [tailwindcss(), sveltekit()], + server: { + fs: { + // Allow serving files from one level up from the project root (includes node_modules) + allow: ['..'] + } + }, test: { workspace: [ { From 8c0148d85f0fa3cfce0d6ffe31831507404ddd6a Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 12:24:27 +0200 Subject: [PATCH 24/88] Move convex --- test-sveltekit/convex.json | 3 + test-sveltekit/convex/_generated/api.d.ts | 15 +- .../convex/_generated/dataModel.d.ts | 34 ++--- test-sveltekit/src/components/UserMenu.svelte | 28 ++++ test-sveltekit/src/convex/_generated/api.d.ts | 33 ++++ test-sveltekit/src/convex/_generated/api.js | 22 +++ .../src/convex/_generated/dataModel.d.ts | 58 +++++++ .../src/convex/_generated/server.d.ts | 142 ++++++++++++++++++ .../src/convex/_generated/server.js | 89 +++++++++++ test-sveltekit/{ => src/lib}/convex/README.md | 0 .../src/lib/convex/_generated/api.d.ts | 46 ++++++ .../src/lib/convex/_generated/api.js | 22 +++ .../src/lib/convex/_generated/dataModel.d.ts | 60 ++++++++ .../src/lib/convex/_generated/server.d.ts | 142 ++++++++++++++++++ .../src/lib/convex/_generated/server.js | 89 +++++++++++ .../{ => src/lib}/convex/auth.config.ts | 0 test-sveltekit/{ => src/lib}/convex/auth.ts | 0 .../{ => src/lib}/convex/helpers.ts | 0 test-sveltekit/{ => src/lib}/convex/http.ts | 0 .../{ => src/lib}/convex/messages.ts | 0 test-sveltekit/{ => src/lib}/convex/schema.ts | 0 test-sveltekit/{ => src/lib}/convex/tests.ts | 2 +- .../{ => src/lib}/convex/tsconfig.json | 0 test-sveltekit/{ => src/lib}/convex/users.ts | 0 24 files changed, 752 insertions(+), 33 deletions(-) create mode 100644 test-sveltekit/convex.json create mode 100644 test-sveltekit/src/components/UserMenu.svelte create mode 100644 test-sveltekit/src/convex/_generated/api.d.ts create mode 100644 test-sveltekit/src/convex/_generated/api.js create mode 100644 test-sveltekit/src/convex/_generated/dataModel.d.ts create mode 100644 test-sveltekit/src/convex/_generated/server.d.ts create mode 100644 test-sveltekit/src/convex/_generated/server.js rename test-sveltekit/{ => src/lib}/convex/README.md (100%) create mode 100644 test-sveltekit/src/lib/convex/_generated/api.d.ts create mode 100644 test-sveltekit/src/lib/convex/_generated/api.js create mode 100644 test-sveltekit/src/lib/convex/_generated/dataModel.d.ts create mode 100644 test-sveltekit/src/lib/convex/_generated/server.d.ts create mode 100644 test-sveltekit/src/lib/convex/_generated/server.js rename test-sveltekit/{ => src/lib}/convex/auth.config.ts (100%) rename test-sveltekit/{ => src/lib}/convex/auth.ts (100%) rename test-sveltekit/{ => src/lib}/convex/helpers.ts (100%) rename test-sveltekit/{ => src/lib}/convex/http.ts (100%) rename test-sveltekit/{ => src/lib}/convex/messages.ts (100%) rename test-sveltekit/{ => src/lib}/convex/schema.ts (100%) rename test-sveltekit/{ => src/lib}/convex/tests.ts (93%) rename test-sveltekit/{ => src/lib}/convex/tsconfig.json (100%) rename test-sveltekit/{ => src/lib}/convex/users.ts (100%) diff --git a/test-sveltekit/convex.json b/test-sveltekit/convex.json new file mode 100644 index 00000000..89700aab --- /dev/null +++ b/test-sveltekit/convex.json @@ -0,0 +1,3 @@ +{ + "functions": "src/convex/" +} diff --git a/test-sveltekit/convex/_generated/api.d.ts b/test-sveltekit/convex/_generated/api.d.ts index adbc4d15..7d71a015 100644 --- a/test-sveltekit/convex/_generated/api.d.ts +++ b/test-sveltekit/convex/_generated/api.d.ts @@ -13,12 +13,6 @@ import type { FilterApi, FunctionReference, } from "convex/server"; -import type * as auth from "../auth.js"; -import type * as helpers from "../helpers.js"; -import type * as http from "../http.js"; -import type * as messages from "../messages.js"; -import type * as tests from "../tests.js"; -import type * as users from "../users.js"; /** * A utility for referencing Convex functions in your app's API. @@ -28,14 +22,7 @@ import type * as users from "../users.js"; * const myFunctionReference = api.myModule.myFunction; * ``` */ -declare const fullApi: ApiFromModules<{ - auth: typeof auth; - helpers: typeof helpers; - http: typeof http; - messages: typeof messages; - tests: typeof tests; - users: typeof users; -}>; +declare const fullApi: ApiFromModules<{}>; export declare const api: FilterApi< typeof fullApi, FunctionReference diff --git a/test-sveltekit/convex/_generated/dataModel.d.ts b/test-sveltekit/convex/_generated/dataModel.d.ts index 8541f319..fb12533b 100644 --- a/test-sveltekit/convex/_generated/dataModel.d.ts +++ b/test-sveltekit/convex/_generated/dataModel.d.ts @@ -8,29 +8,29 @@ * @module */ -import type { - DataModelFromSchemaDefinition, - DocumentByName, - TableNamesInDataModel, - SystemTableNames, -} from "convex/server"; +import { AnyDataModel } from "convex/server"; import type { GenericId } from "convex/values"; -import schema from "../schema.js"; + +/** + * No `schema.ts` file found! + * + * This generated code has permissive types like `Doc = any` because + * Convex doesn't know your schema. If you'd like more type safety, see + * https://docs.convex.dev/using/schemas for instructions on how to add a + * schema file. + * + * After you change a schema, rerun codegen with `npx convex dev`. + */ /** * The names of all of your Convex tables. */ -export type TableNames = TableNamesInDataModel; +export type TableNames = string; /** * The type of a document stored in Convex. - * - * @typeParam TableName - A string literal type of the table name (like "users"). */ -export type Doc = DocumentByName< - DataModel, - TableName ->; +export type Doc = any; /** * An identifier for a document in Convex. @@ -42,10 +42,8 @@ export type Doc = DocumentByName< * * IDs are just strings at runtime, but this type can be used to distinguish them from other * strings when type checking. - * - * @typeParam TableName - A string literal type of the table name (like "users"). */ -export type Id = +export type Id = GenericId; /** @@ -57,4 +55,4 @@ export type Id = * This type is used to parameterize methods like `queryGeneric` and * `mutationGeneric` to make them type-safe. */ -export type DataModel = DataModelFromSchemaDefinition; +export type DataModel = AnyDataModel; diff --git a/test-sveltekit/src/components/UserMenu.svelte b/test-sveltekit/src/components/UserMenu.svelte new file mode 100644 index 00000000..6210cc30 --- /dev/null +++ b/test-sveltekit/src/components/UserMenu.svelte @@ -0,0 +1,28 @@ + + +
+ {username} + +
diff --git a/test-sveltekit/src/convex/_generated/api.d.ts b/test-sveltekit/src/convex/_generated/api.d.ts new file mode 100644 index 00000000..7d71a015 --- /dev/null +++ b/test-sveltekit/src/convex/_generated/api.d.ts @@ -0,0 +1,33 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import type { + ApiFromModules, + FilterApi, + FunctionReference, +} from "convex/server"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +declare const fullApi: ApiFromModules<{}>; +export declare const api: FilterApi< + typeof fullApi, + FunctionReference +>; +export declare const internal: FilterApi< + typeof fullApi, + FunctionReference +>; diff --git a/test-sveltekit/src/convex/_generated/api.js b/test-sveltekit/src/convex/_generated/api.js new file mode 100644 index 00000000..3f9c482d --- /dev/null +++ b/test-sveltekit/src/convex/_generated/api.js @@ -0,0 +1,22 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { anyApi } from "convex/server"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +export const api = anyApi; +export const internal = anyApi; diff --git a/test-sveltekit/src/convex/_generated/dataModel.d.ts b/test-sveltekit/src/convex/_generated/dataModel.d.ts new file mode 100644 index 00000000..fb12533b --- /dev/null +++ b/test-sveltekit/src/convex/_generated/dataModel.d.ts @@ -0,0 +1,58 @@ +/* eslint-disable */ +/** + * Generated data model types. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { AnyDataModel } from "convex/server"; +import type { GenericId } from "convex/values"; + +/** + * No `schema.ts` file found! + * + * This generated code has permissive types like `Doc = any` because + * Convex doesn't know your schema. If you'd like more type safety, see + * https://docs.convex.dev/using/schemas for instructions on how to add a + * schema file. + * + * After you change a schema, rerun codegen with `npx convex dev`. + */ + +/** + * The names of all of your Convex tables. + */ +export type TableNames = string; + +/** + * The type of a document stored in Convex. + */ +export type Doc = any; + +/** + * An identifier for a document in Convex. + * + * Convex documents are uniquely identified by their `Id`, which is accessible + * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids). + * + * Documents can be loaded using `db.get(id)` in query and mutation functions. + * + * IDs are just strings at runtime, but this type can be used to distinguish them from other + * strings when type checking. + */ +export type Id = + GenericId; + +/** + * A type describing your Convex data model. + * + * This type includes information about what tables you have, the type of + * documents stored in those tables, and the indexes defined on them. + * + * This type is used to parameterize methods like `queryGeneric` and + * `mutationGeneric` to make them type-safe. + */ +export type DataModel = AnyDataModel; diff --git a/test-sveltekit/src/convex/_generated/server.d.ts b/test-sveltekit/src/convex/_generated/server.d.ts new file mode 100644 index 00000000..7f337a43 --- /dev/null +++ b/test-sveltekit/src/convex/_generated/server.d.ts @@ -0,0 +1,142 @@ +/* eslint-disable */ +/** + * Generated utilities for implementing server-side Convex query and mutation functions. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { + ActionBuilder, + HttpActionBuilder, + MutationBuilder, + QueryBuilder, + GenericActionCtx, + GenericMutationCtx, + GenericQueryCtx, + GenericDatabaseReader, + GenericDatabaseWriter, +} from "convex/server"; +import type { DataModel } from "./dataModel.js"; + +/** + * Define a query in this Convex app's public API. + * + * This function will be allowed to read your Convex database and will be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export declare const query: QueryBuilder; + +/** + * Define a query that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to read from your Convex database. It will not be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export declare const internalQuery: QueryBuilder; + +/** + * Define a mutation in this Convex app's public API. + * + * This function will be allowed to modify your Convex database and will be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export declare const mutation: MutationBuilder; + +/** + * Define a mutation that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to modify your Convex database. It will not be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export declare const internalMutation: MutationBuilder; + +/** + * Define an action in this Convex app's public API. + * + * An action is a function which can execute any JavaScript code, including non-deterministic + * code and code with side-effects, like calling third-party services. + * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. + * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. + * + * @param func - The action. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped action. Include this as an `export` to name it and make it accessible. + */ +export declare const action: ActionBuilder; + +/** + * Define an action that is only accessible from other Convex functions (but not from the client). + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Include this as an `export` to name it and make it accessible. + */ +export declare const internalAction: ActionBuilder; + +/** + * Define an HTTP action. + * + * This function will be used to respond to HTTP requests received by a Convex + * deployment if the requests matches the path and method where this action + * is routed. Be sure to route your action in `convex/http.js`. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. + */ +export declare const httpAction: HttpActionBuilder; + +/** + * A set of services for use within Convex query functions. + * + * The query context is passed as the first argument to any Convex query + * function run on the server. + * + * This differs from the {@link MutationCtx} because all of the services are + * read-only. + */ +export type QueryCtx = GenericQueryCtx; + +/** + * A set of services for use within Convex mutation functions. + * + * The mutation context is passed as the first argument to any Convex mutation + * function run on the server. + */ +export type MutationCtx = GenericMutationCtx; + +/** + * A set of services for use within Convex action functions. + * + * The action context is passed as the first argument to any Convex action + * function run on the server. + */ +export type ActionCtx = GenericActionCtx; + +/** + * An interface to read from the database within Convex query functions. + * + * The two entry points are {@link DatabaseReader.get}, which fetches a single + * document by its {@link Id}, or {@link DatabaseReader.query}, which starts + * building a query. + */ +export type DatabaseReader = GenericDatabaseReader; + +/** + * An interface to read from and write to the database within Convex mutation + * functions. + * + * Convex guarantees that all writes within a single mutation are + * executed atomically, so you never have to worry about partial writes leaving + * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control) + * for the guarantees Convex provides your functions. + */ +export type DatabaseWriter = GenericDatabaseWriter; diff --git a/test-sveltekit/src/convex/_generated/server.js b/test-sveltekit/src/convex/_generated/server.js new file mode 100644 index 00000000..566d4858 --- /dev/null +++ b/test-sveltekit/src/convex/_generated/server.js @@ -0,0 +1,89 @@ +/* eslint-disable */ +/** + * Generated utilities for implementing server-side Convex query and mutation functions. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { + actionGeneric, + httpActionGeneric, + queryGeneric, + mutationGeneric, + internalActionGeneric, + internalMutationGeneric, + internalQueryGeneric, +} from "convex/server"; + +/** + * Define a query in this Convex app's public API. + * + * This function will be allowed to read your Convex database and will be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export const query = queryGeneric; + +/** + * Define a query that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to read from your Convex database. It will not be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export const internalQuery = internalQueryGeneric; + +/** + * Define a mutation in this Convex app's public API. + * + * This function will be allowed to modify your Convex database and will be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export const mutation = mutationGeneric; + +/** + * Define a mutation that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to modify your Convex database. It will not be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export const internalMutation = internalMutationGeneric; + +/** + * Define an action in this Convex app's public API. + * + * An action is a function which can execute any JavaScript code, including non-deterministic + * code and code with side-effects, like calling third-party services. + * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. + * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. + * + * @param func - The action. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped action. Include this as an `export` to name it and make it accessible. + */ +export const action = actionGeneric; + +/** + * Define an action that is only accessible from other Convex functions (but not from the client). + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Include this as an `export` to name it and make it accessible. + */ +export const internalAction = internalActionGeneric; + +/** + * Define a Convex HTTP action. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object + * as its second. + * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. + */ +export const httpAction = httpActionGeneric; diff --git a/test-sveltekit/convex/README.md b/test-sveltekit/src/lib/convex/README.md similarity index 100% rename from test-sveltekit/convex/README.md rename to test-sveltekit/src/lib/convex/README.md diff --git a/test-sveltekit/src/lib/convex/_generated/api.d.ts b/test-sveltekit/src/lib/convex/_generated/api.d.ts new file mode 100644 index 00000000..adbc4d15 --- /dev/null +++ b/test-sveltekit/src/lib/convex/_generated/api.d.ts @@ -0,0 +1,46 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import type { + ApiFromModules, + FilterApi, + FunctionReference, +} from "convex/server"; +import type * as auth from "../auth.js"; +import type * as helpers from "../helpers.js"; +import type * as http from "../http.js"; +import type * as messages from "../messages.js"; +import type * as tests from "../tests.js"; +import type * as users from "../users.js"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +declare const fullApi: ApiFromModules<{ + auth: typeof auth; + helpers: typeof helpers; + http: typeof http; + messages: typeof messages; + tests: typeof tests; + users: typeof users; +}>; +export declare const api: FilterApi< + typeof fullApi, + FunctionReference +>; +export declare const internal: FilterApi< + typeof fullApi, + FunctionReference +>; diff --git a/test-sveltekit/src/lib/convex/_generated/api.js b/test-sveltekit/src/lib/convex/_generated/api.js new file mode 100644 index 00000000..3f9c482d --- /dev/null +++ b/test-sveltekit/src/lib/convex/_generated/api.js @@ -0,0 +1,22 @@ +/* eslint-disable */ +/** + * Generated `api` utility. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { anyApi } from "convex/server"; + +/** + * A utility for referencing Convex functions in your app's API. + * + * Usage: + * ```js + * const myFunctionReference = api.myModule.myFunction; + * ``` + */ +export const api = anyApi; +export const internal = anyApi; diff --git a/test-sveltekit/src/lib/convex/_generated/dataModel.d.ts b/test-sveltekit/src/lib/convex/_generated/dataModel.d.ts new file mode 100644 index 00000000..8541f319 --- /dev/null +++ b/test-sveltekit/src/lib/convex/_generated/dataModel.d.ts @@ -0,0 +1,60 @@ +/* eslint-disable */ +/** + * Generated data model types. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import type { + DataModelFromSchemaDefinition, + DocumentByName, + TableNamesInDataModel, + SystemTableNames, +} from "convex/server"; +import type { GenericId } from "convex/values"; +import schema from "../schema.js"; + +/** + * The names of all of your Convex tables. + */ +export type TableNames = TableNamesInDataModel; + +/** + * The type of a document stored in Convex. + * + * @typeParam TableName - A string literal type of the table name (like "users"). + */ +export type Doc = DocumentByName< + DataModel, + TableName +>; + +/** + * An identifier for a document in Convex. + * + * Convex documents are uniquely identified by their `Id`, which is accessible + * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids). + * + * Documents can be loaded using `db.get(id)` in query and mutation functions. + * + * IDs are just strings at runtime, but this type can be used to distinguish them from other + * strings when type checking. + * + * @typeParam TableName - A string literal type of the table name (like "users"). + */ +export type Id = + GenericId; + +/** + * A type describing your Convex data model. + * + * This type includes information about what tables you have, the type of + * documents stored in those tables, and the indexes defined on them. + * + * This type is used to parameterize methods like `queryGeneric` and + * `mutationGeneric` to make them type-safe. + */ +export type DataModel = DataModelFromSchemaDefinition; diff --git a/test-sveltekit/src/lib/convex/_generated/server.d.ts b/test-sveltekit/src/lib/convex/_generated/server.d.ts new file mode 100644 index 00000000..7f337a43 --- /dev/null +++ b/test-sveltekit/src/lib/convex/_generated/server.d.ts @@ -0,0 +1,142 @@ +/* eslint-disable */ +/** + * Generated utilities for implementing server-side Convex query and mutation functions. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { + ActionBuilder, + HttpActionBuilder, + MutationBuilder, + QueryBuilder, + GenericActionCtx, + GenericMutationCtx, + GenericQueryCtx, + GenericDatabaseReader, + GenericDatabaseWriter, +} from "convex/server"; +import type { DataModel } from "./dataModel.js"; + +/** + * Define a query in this Convex app's public API. + * + * This function will be allowed to read your Convex database and will be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export declare const query: QueryBuilder; + +/** + * Define a query that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to read from your Convex database. It will not be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export declare const internalQuery: QueryBuilder; + +/** + * Define a mutation in this Convex app's public API. + * + * This function will be allowed to modify your Convex database and will be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export declare const mutation: MutationBuilder; + +/** + * Define a mutation that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to modify your Convex database. It will not be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export declare const internalMutation: MutationBuilder; + +/** + * Define an action in this Convex app's public API. + * + * An action is a function which can execute any JavaScript code, including non-deterministic + * code and code with side-effects, like calling third-party services. + * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. + * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. + * + * @param func - The action. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped action. Include this as an `export` to name it and make it accessible. + */ +export declare const action: ActionBuilder; + +/** + * Define an action that is only accessible from other Convex functions (but not from the client). + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Include this as an `export` to name it and make it accessible. + */ +export declare const internalAction: ActionBuilder; + +/** + * Define an HTTP action. + * + * This function will be used to respond to HTTP requests received by a Convex + * deployment if the requests matches the path and method where this action + * is routed. Be sure to route your action in `convex/http.js`. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. + */ +export declare const httpAction: HttpActionBuilder; + +/** + * A set of services for use within Convex query functions. + * + * The query context is passed as the first argument to any Convex query + * function run on the server. + * + * This differs from the {@link MutationCtx} because all of the services are + * read-only. + */ +export type QueryCtx = GenericQueryCtx; + +/** + * A set of services for use within Convex mutation functions. + * + * The mutation context is passed as the first argument to any Convex mutation + * function run on the server. + */ +export type MutationCtx = GenericMutationCtx; + +/** + * A set of services for use within Convex action functions. + * + * The action context is passed as the first argument to any Convex action + * function run on the server. + */ +export type ActionCtx = GenericActionCtx; + +/** + * An interface to read from the database within Convex query functions. + * + * The two entry points are {@link DatabaseReader.get}, which fetches a single + * document by its {@link Id}, or {@link DatabaseReader.query}, which starts + * building a query. + */ +export type DatabaseReader = GenericDatabaseReader; + +/** + * An interface to read from and write to the database within Convex mutation + * functions. + * + * Convex guarantees that all writes within a single mutation are + * executed atomically, so you never have to worry about partial writes leaving + * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control) + * for the guarantees Convex provides your functions. + */ +export type DatabaseWriter = GenericDatabaseWriter; diff --git a/test-sveltekit/src/lib/convex/_generated/server.js b/test-sveltekit/src/lib/convex/_generated/server.js new file mode 100644 index 00000000..566d4858 --- /dev/null +++ b/test-sveltekit/src/lib/convex/_generated/server.js @@ -0,0 +1,89 @@ +/* eslint-disable */ +/** + * Generated utilities for implementing server-side Convex query and mutation functions. + * + * THIS CODE IS AUTOMATICALLY GENERATED. + * + * To regenerate, run `npx convex dev`. + * @module + */ + +import { + actionGeneric, + httpActionGeneric, + queryGeneric, + mutationGeneric, + internalActionGeneric, + internalMutationGeneric, + internalQueryGeneric, +} from "convex/server"; + +/** + * Define a query in this Convex app's public API. + * + * This function will be allowed to read your Convex database and will be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export const query = queryGeneric; + +/** + * Define a query that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to read from your Convex database. It will not be accessible from the client. + * + * @param func - The query function. It receives a {@link QueryCtx} as its first argument. + * @returns The wrapped query. Include this as an `export` to name it and make it accessible. + */ +export const internalQuery = internalQueryGeneric; + +/** + * Define a mutation in this Convex app's public API. + * + * This function will be allowed to modify your Convex database and will be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export const mutation = mutationGeneric; + +/** + * Define a mutation that is only accessible from other Convex functions (but not from the client). + * + * This function will be allowed to modify your Convex database. It will not be accessible from the client. + * + * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. + * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. + */ +export const internalMutation = internalMutationGeneric; + +/** + * Define an action in this Convex app's public API. + * + * An action is a function which can execute any JavaScript code, including non-deterministic + * code and code with side-effects, like calling third-party services. + * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. + * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. + * + * @param func - The action. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped action. Include this as an `export` to name it and make it accessible. + */ +export const action = actionGeneric; + +/** + * Define an action that is only accessible from other Convex functions (but not from the client). + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument. + * @returns The wrapped function. Include this as an `export` to name it and make it accessible. + */ +export const internalAction = internalActionGeneric; + +/** + * Define a Convex HTTP action. + * + * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object + * as its second. + * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. + */ +export const httpAction = httpActionGeneric; diff --git a/test-sveltekit/convex/auth.config.ts b/test-sveltekit/src/lib/convex/auth.config.ts similarity index 100% rename from test-sveltekit/convex/auth.config.ts rename to test-sveltekit/src/lib/convex/auth.config.ts diff --git a/test-sveltekit/convex/auth.ts b/test-sveltekit/src/lib/convex/auth.ts similarity index 100% rename from test-sveltekit/convex/auth.ts rename to test-sveltekit/src/lib/convex/auth.ts diff --git a/test-sveltekit/convex/helpers.ts b/test-sveltekit/src/lib/convex/helpers.ts similarity index 100% rename from test-sveltekit/convex/helpers.ts rename to test-sveltekit/src/lib/convex/helpers.ts diff --git a/test-sveltekit/convex/http.ts b/test-sveltekit/src/lib/convex/http.ts similarity index 100% rename from test-sveltekit/convex/http.ts rename to test-sveltekit/src/lib/convex/http.ts diff --git a/test-sveltekit/convex/messages.ts b/test-sveltekit/src/lib/convex/messages.ts similarity index 100% rename from test-sveltekit/convex/messages.ts rename to test-sveltekit/src/lib/convex/messages.ts diff --git a/test-sveltekit/convex/schema.ts b/test-sveltekit/src/lib/convex/schema.ts similarity index 100% rename from test-sveltekit/convex/schema.ts rename to test-sveltekit/src/lib/convex/schema.ts diff --git a/test-sveltekit/convex/tests.ts b/test-sveltekit/src/lib/convex/tests.ts similarity index 93% rename from test-sveltekit/convex/tests.ts rename to test-sveltekit/src/lib/convex/tests.ts index f71f80d7..24c7c1b9 100644 --- a/test-sveltekit/convex/tests.ts +++ b/test-sveltekit/src/lib/convex/tests.ts @@ -1,4 +1,4 @@ -import { createAccount } from "../../dist/server/index"; +import { createAccount } from "../../../../dist/server/index"; import { internal } from "./_generated/api"; import { internalAction, internalQuery } from "./_generated/server"; diff --git a/test-sveltekit/convex/tsconfig.json b/test-sveltekit/src/lib/convex/tsconfig.json similarity index 100% rename from test-sveltekit/convex/tsconfig.json rename to test-sveltekit/src/lib/convex/tsconfig.json diff --git a/test-sveltekit/convex/users.ts b/test-sveltekit/src/lib/convex/users.ts similarity index 100% rename from test-sveltekit/convex/users.ts rename to test-sveltekit/src/lib/convex/users.ts From 3ecc5b3b23482775d119177e5ed764349f4406ae Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 13:01:47 +0200 Subject: [PATCH 25/88] Add chat functionality with real-time messaging using Convex --- test-sveltekit/src/components/UserMenu.svelte | 50 ++++++++++++--- .../src/routes/product/+layout.svelte | 35 +++++++++++ .../src/routes/product/+page.server.ts | 24 +++++++ .../src/routes/product/+page.svelte | 17 +++++ .../src/routes/product/Chat/Chat.svelte | 63 +++++++++++++++++++ .../src/routes/product/Chat/ChatIntro.svelte | 6 ++ .../src/routes/product/Chat/Message.svelte | 24 +++++++ .../routes/product/Chat/MessageList.svelte | 24 +++++++ .../src/routes/product/Chat/randomName.ts | 10 +++ 9 files changed, 246 insertions(+), 7 deletions(-) create mode 100644 test-sveltekit/src/routes/product/+layout.svelte create mode 100644 test-sveltekit/src/routes/product/+page.server.ts create mode 100644 test-sveltekit/src/routes/product/+page.svelte create mode 100644 test-sveltekit/src/routes/product/Chat/Chat.svelte create mode 100644 test-sveltekit/src/routes/product/Chat/ChatIntro.svelte create mode 100644 test-sveltekit/src/routes/product/Chat/Message.svelte create mode 100644 test-sveltekit/src/routes/product/Chat/MessageList.svelte create mode 100644 test-sveltekit/src/routes/product/Chat/randomName.ts diff --git a/test-sveltekit/src/components/UserMenu.svelte b/test-sveltekit/src/components/UserMenu.svelte index 6210cc30..b475f626 100644 --- a/test-sveltekit/src/components/UserMenu.svelte +++ b/test-sveltekit/src/components/UserMenu.svelte @@ -1,28 +1,64 @@
- {username} + {@render children()}
+ +
+ {@render children()} + (openState = e.open)} + positioning={{ placement: 'top' }} + triggerBase="btn preset-tonal" + contentBase="card bg-surface-200-800 p-4 space-y-4 max-w-[320px]" + arrow + arrowBackground="!bg-surface-200 dark:!bg-surface-800" + > + {#snippet trigger()}{/snippet} + {#snippet content()} +
{@render children()}
+
+ + {/snippet} +
+
diff --git a/test-sveltekit/src/routes/product/+layout.svelte b/test-sveltekit/src/routes/product/+layout.svelte new file mode 100644 index 00000000..01911451 --- /dev/null +++ b/test-sveltekit/src/routes/product/+layout.svelte @@ -0,0 +1,35 @@ + + + diff --git a/test-sveltekit/src/routes/product/+page.server.ts b/test-sveltekit/src/routes/product/+page.server.ts new file mode 100644 index 00000000..4adc0dd6 --- /dev/null +++ b/test-sveltekit/src/routes/product/+page.server.ts @@ -0,0 +1,24 @@ +import { api } from '../../../convex/_generated/api'; +import { createConvexAuthHooks } from '@convex-dev/auth/sveltekit/server'; +import { redirect, error } from '@sveltejs/kit'; +import type { PageServerLoad } from './$types'; +import { PUBLIC_CONVEX_URL } from '$env/static/public'; + +// Create Convex auth hooks +const { isAuthenticated } = createConvexAuthHooks({ + convexUrl: PUBLIC_CONVEX_URL +}); + +export const load: PageServerLoad = async (event) => { + // Check if the user is authenticated + if (!(await isAuthenticated(event))) { + throw redirect(307, '/signin'); + } + + // The auth token is automatically picked up by the Convex client in the browser + return { + // Return an empty viewer object - the actual data will be fetched client-side + // where Convex client is already configured with auth + viewer: {} + }; +}; diff --git a/test-sveltekit/src/routes/product/+page.svelte b/test-sveltekit/src/routes/product/+page.svelte new file mode 100644 index 00000000..d4f16616 --- /dev/null +++ b/test-sveltekit/src/routes/product/+page.svelte @@ -0,0 +1,17 @@ + + +
+
+ + {viewer.data!.name} +
+ +
diff --git a/test-sveltekit/src/routes/product/Chat/Chat.svelte b/test-sveltekit/src/routes/product/Chat/Chat.svelte new file mode 100644 index 00000000..adc3a524 --- /dev/null +++ b/test-sveltekit/src/routes/product/Chat/Chat.svelte @@ -0,0 +1,63 @@ + + + + {#if messages.data} + {#each messages.data as message} + + {message.body} + + {/each} + {/if} + + +
+
+ + +
+
diff --git a/test-sveltekit/src/routes/product/Chat/ChatIntro.svelte b/test-sveltekit/src/routes/product/Chat/ChatIntro.svelte new file mode 100644 index 00000000..6e607dfb --- /dev/null +++ b/test-sveltekit/src/routes/product/Chat/ChatIntro.svelte @@ -0,0 +1,6 @@ +
+

Chat

+ +
diff --git a/test-sveltekit/src/routes/product/Chat/Message.svelte b/test-sveltekit/src/routes/product/Chat/Message.svelte new file mode 100644 index 00000000..ce193864 --- /dev/null +++ b/test-sveltekit/src/routes/product/Chat/Message.svelte @@ -0,0 +1,24 @@ + + +
  • +
    {authorName}
    +

    + {@render children()} +

    +
  • diff --git a/test-sveltekit/src/routes/product/Chat/MessageList.svelte b/test-sveltekit/src/routes/product/Chat/MessageList.svelte new file mode 100644 index 00000000..d0de222d --- /dev/null +++ b/test-sveltekit/src/routes/product/Chat/MessageList.svelte @@ -0,0 +1,24 @@ + + +
      + {@render children?.()} +
    diff --git a/test-sveltekit/src/routes/product/Chat/randomName.ts b/test-sveltekit/src/routes/product/Chat/randomName.ts new file mode 100644 index 00000000..82ca54f4 --- /dev/null +++ b/test-sveltekit/src/routes/product/Chat/randomName.ts @@ -0,0 +1,10 @@ +const namesList = + "Robert,Linda,Daniel,Anthony,Donald,Paul,Kevin,Brian,Patricia,Jennifer," + + "Elizabeth,William,Richard,Jessica,Lisa,Nancy,Matthew,Ashley,Kimberly," + + "Donna,Kenneth,Melissa"; +const names = namesList.split(","); + +export function randomName(): string { + const picked = names[Math.floor(Math.random() * names.length)]; + return Math.random() > 0.5 ? picked.slice(0, 3) : picked; +} From 4b499df7a01995f4ea7cfad81c2b9337d1114bda Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 13:05:22 +0200 Subject: [PATCH 26/88] Center page --- test-sveltekit/src/routes/+page.svelte | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/test-sveltekit/src/routes/+page.svelte b/test-sveltekit/src/routes/+page.svelte index 1e8ad44c..cc504dde 100644 --- a/test-sveltekit/src/routes/+page.svelte +++ b/test-sveltekit/src/routes/+page.svelte @@ -1,18 +1,16 @@ -

    Welcome to SvelteKit

    -

    Visit svelte.dev/docs/kit to read the documentation

    - -
    +
    {#if isAuthenticated}

    You are authenticated!

    - + Product + {:else}

    You are not authenticated.

    - + Sign In {/if}
    From ae751228ba7edf030790e6db0d31adfdd0725961 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 13:16:11 +0200 Subject: [PATCH 27/88] Add @auth/core --- src/sveltekit/README.md | 20 +++++++++++++------ test-sveltekit/package-lock.json | 34 +++++++++++++++++++++++++++++++- test-sveltekit/package.json | 1 + 3 files changed, 48 insertions(+), 7 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 54d51671..1d9b9368 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -5,11 +5,11 @@ This package provides authentication functionality for SvelteKit applications us ## Installation ```bash -npm install @convex-dev/auth +npm install @convex-dev/auth @auth/core # or -pnpm add @convex-dev/auth +pnpm add @convex-dev/auth @auth/core # or -yarn add @convex-dev/auth +yarn add @convex-dev/auth @auth/core ``` ## Setup @@ -24,7 +24,15 @@ PUBLIC_CONVEX_URL=your_convex_deployment_url For local development, you can also create a `.env.local` file. -### 2. Initialize Auth (Client-side) +### 2. Run the initialization command + +```bash +npx @convex-dev/auth +``` + +This sets up your project for authenticating via the library. + +### 3. Initialize Auth (Client-side) Set up authentication in your root layout: @@ -68,7 +76,7 @@ The `setupConvexAuth` function will: This makes it work seamlessly with different setup patterns. -### 3. Add Auth State in Layout Server +### 4. Add Auth State in Layout Server Load the authentication state in your layout server: @@ -86,7 +94,7 @@ export const load: LayoutServerLoad = async (event) => { }; ``` -### 4. Configure Auth Hooks (Server-side) +### 5. Configure Auth Hooks (Server-side) Create hooks to handle authentication in `src/hooks.server.ts`. diff --git a/test-sveltekit/package-lock.json b/test-sveltekit/package-lock.json index 88f2ab36..3b4fc9dc 100644 --- a/test-sveltekit/package-lock.json +++ b/test-sveltekit/package-lock.json @@ -8,6 +8,7 @@ "name": "test-sveltekit", "version": "0.0.1", "dependencies": { + "@auth/core": "file:../node_modules/@auth/core", "@convex-dev/auth": "file:..", "convex": "file:../node_modules/convex", "convex-svelte": "file:../node_modules/convex-svelte" @@ -55,7 +56,7 @@ "lucia": "^3.2.0", "oauth4webapi": "^3.1.2", "oslo": "^1.1.2", - "path-to-regexp": "^6.3.0", + "path-to-regexp": "^8.2.0", "server-only": "^0.0.1" }, "bin": { @@ -99,6 +100,33 @@ } } }, + "../node_modules/@auth/core": { + "version": "0.37.4", + "license": "ISC", + "dependencies": { + "@panva/hkdf": "^1.2.1", + "jose": "^5.9.6", + "oauth4webapi": "^3.1.1", + "preact": "10.24.3", + "preact-render-to-string": "6.5.11" + }, + "peerDependencies": { + "@simplewebauthn/browser": "^9.0.1", + "@simplewebauthn/server": "^9.0.2", + "nodemailer": "^6.8.0" + }, + "peerDependenciesMeta": { + "@simplewebauthn/browser": { + "optional": true + }, + "@simplewebauthn/server": { + "optional": true + }, + "nodemailer": { + "optional": true + } + } + }, "../node_modules/@sveltejs/kit": { "version": "2.20.5", "dev": true, @@ -258,6 +286,10 @@ "lru-cache": "^10.4.3" } }, + "node_modules/@auth/core": { + "resolved": "../node_modules/@auth/core", + "link": true + }, "node_modules/@babel/code-frame": { "version": "7.26.2", "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", diff --git a/test-sveltekit/package.json b/test-sveltekit/package.json index 029a029d..ba799ac6 100644 --- a/test-sveltekit/package.json +++ b/test-sveltekit/package.json @@ -17,6 +17,7 @@ "test:unit": "vitest" }, "dependencies": { + "@auth/core": "file:../node_modules/@auth/core", "@convex-dev/auth": "file:..", "convex": "file:../node_modules/convex", "convex-svelte": "file:../node_modules/convex-svelte" From f794886226113984f305b13c5df1de1294f9a5e9 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 19 Apr 2025 13:19:13 +0200 Subject: [PATCH 28/88] Remove duplicated files --- test-sveltekit/src/convex/_generated/api.d.ts | 33 ---- test-sveltekit/src/convex/_generated/api.js | 22 --- .../src/convex/_generated/dataModel.d.ts | 58 ------- .../src/convex/_generated/server.d.ts | 142 ------------------ .../src/convex/_generated/server.js | 89 ----------- 5 files changed, 344 deletions(-) delete mode 100644 test-sveltekit/src/convex/_generated/api.d.ts delete mode 100644 test-sveltekit/src/convex/_generated/api.js delete mode 100644 test-sveltekit/src/convex/_generated/dataModel.d.ts delete mode 100644 test-sveltekit/src/convex/_generated/server.d.ts delete mode 100644 test-sveltekit/src/convex/_generated/server.js diff --git a/test-sveltekit/src/convex/_generated/api.d.ts b/test-sveltekit/src/convex/_generated/api.d.ts deleted file mode 100644 index 7d71a015..00000000 --- a/test-sveltekit/src/convex/_generated/api.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-disable */ -/** - * Generated `api` utility. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import type { - ApiFromModules, - FilterApi, - FunctionReference, -} from "convex/server"; - -/** - * A utility for referencing Convex functions in your app's API. - * - * Usage: - * ```js - * const myFunctionReference = api.myModule.myFunction; - * ``` - */ -declare const fullApi: ApiFromModules<{}>; -export declare const api: FilterApi< - typeof fullApi, - FunctionReference ->; -export declare const internal: FilterApi< - typeof fullApi, - FunctionReference ->; diff --git a/test-sveltekit/src/convex/_generated/api.js b/test-sveltekit/src/convex/_generated/api.js deleted file mode 100644 index 3f9c482d..00000000 --- a/test-sveltekit/src/convex/_generated/api.js +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -/** - * Generated `api` utility. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { anyApi } from "convex/server"; - -/** - * A utility for referencing Convex functions in your app's API. - * - * Usage: - * ```js - * const myFunctionReference = api.myModule.myFunction; - * ``` - */ -export const api = anyApi; -export const internal = anyApi; diff --git a/test-sveltekit/src/convex/_generated/dataModel.d.ts b/test-sveltekit/src/convex/_generated/dataModel.d.ts deleted file mode 100644 index fb12533b..00000000 --- a/test-sveltekit/src/convex/_generated/dataModel.d.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* eslint-disable */ -/** - * Generated data model types. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { AnyDataModel } from "convex/server"; -import type { GenericId } from "convex/values"; - -/** - * No `schema.ts` file found! - * - * This generated code has permissive types like `Doc = any` because - * Convex doesn't know your schema. If you'd like more type safety, see - * https://docs.convex.dev/using/schemas for instructions on how to add a - * schema file. - * - * After you change a schema, rerun codegen with `npx convex dev`. - */ - -/** - * The names of all of your Convex tables. - */ -export type TableNames = string; - -/** - * The type of a document stored in Convex. - */ -export type Doc = any; - -/** - * An identifier for a document in Convex. - * - * Convex documents are uniquely identified by their `Id`, which is accessible - * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids). - * - * Documents can be loaded using `db.get(id)` in query and mutation functions. - * - * IDs are just strings at runtime, but this type can be used to distinguish them from other - * strings when type checking. - */ -export type Id = - GenericId; - -/** - * A type describing your Convex data model. - * - * This type includes information about what tables you have, the type of - * documents stored in those tables, and the indexes defined on them. - * - * This type is used to parameterize methods like `queryGeneric` and - * `mutationGeneric` to make them type-safe. - */ -export type DataModel = AnyDataModel; diff --git a/test-sveltekit/src/convex/_generated/server.d.ts b/test-sveltekit/src/convex/_generated/server.d.ts deleted file mode 100644 index 7f337a43..00000000 --- a/test-sveltekit/src/convex/_generated/server.d.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* eslint-disable */ -/** - * Generated utilities for implementing server-side Convex query and mutation functions. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { - ActionBuilder, - HttpActionBuilder, - MutationBuilder, - QueryBuilder, - GenericActionCtx, - GenericMutationCtx, - GenericQueryCtx, - GenericDatabaseReader, - GenericDatabaseWriter, -} from "convex/server"; -import type { DataModel } from "./dataModel.js"; - -/** - * Define a query in this Convex app's public API. - * - * This function will be allowed to read your Convex database and will be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export declare const query: QueryBuilder; - -/** - * Define a query that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to read from your Convex database. It will not be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export declare const internalQuery: QueryBuilder; - -/** - * Define a mutation in this Convex app's public API. - * - * This function will be allowed to modify your Convex database and will be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export declare const mutation: MutationBuilder; - -/** - * Define a mutation that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to modify your Convex database. It will not be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export declare const internalMutation: MutationBuilder; - -/** - * Define an action in this Convex app's public API. - * - * An action is a function which can execute any JavaScript code, including non-deterministic - * code and code with side-effects, like calling third-party services. - * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. - * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. - * - * @param func - The action. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped action. Include this as an `export` to name it and make it accessible. - */ -export declare const action: ActionBuilder; - -/** - * Define an action that is only accessible from other Convex functions (but not from the client). - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped function. Include this as an `export` to name it and make it accessible. - */ -export declare const internalAction: ActionBuilder; - -/** - * Define an HTTP action. - * - * This function will be used to respond to HTTP requests received by a Convex - * deployment if the requests matches the path and method where this action - * is routed. Be sure to route your action in `convex/http.js`. - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. - */ -export declare const httpAction: HttpActionBuilder; - -/** - * A set of services for use within Convex query functions. - * - * The query context is passed as the first argument to any Convex query - * function run on the server. - * - * This differs from the {@link MutationCtx} because all of the services are - * read-only. - */ -export type QueryCtx = GenericQueryCtx; - -/** - * A set of services for use within Convex mutation functions. - * - * The mutation context is passed as the first argument to any Convex mutation - * function run on the server. - */ -export type MutationCtx = GenericMutationCtx; - -/** - * A set of services for use within Convex action functions. - * - * The action context is passed as the first argument to any Convex action - * function run on the server. - */ -export type ActionCtx = GenericActionCtx; - -/** - * An interface to read from the database within Convex query functions. - * - * The two entry points are {@link DatabaseReader.get}, which fetches a single - * document by its {@link Id}, or {@link DatabaseReader.query}, which starts - * building a query. - */ -export type DatabaseReader = GenericDatabaseReader; - -/** - * An interface to read from and write to the database within Convex mutation - * functions. - * - * Convex guarantees that all writes within a single mutation are - * executed atomically, so you never have to worry about partial writes leaving - * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control) - * for the guarantees Convex provides your functions. - */ -export type DatabaseWriter = GenericDatabaseWriter; diff --git a/test-sveltekit/src/convex/_generated/server.js b/test-sveltekit/src/convex/_generated/server.js deleted file mode 100644 index 566d4858..00000000 --- a/test-sveltekit/src/convex/_generated/server.js +++ /dev/null @@ -1,89 +0,0 @@ -/* eslint-disable */ -/** - * Generated utilities for implementing server-side Convex query and mutation functions. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { - actionGeneric, - httpActionGeneric, - queryGeneric, - mutationGeneric, - internalActionGeneric, - internalMutationGeneric, - internalQueryGeneric, -} from "convex/server"; - -/** - * Define a query in this Convex app's public API. - * - * This function will be allowed to read your Convex database and will be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export const query = queryGeneric; - -/** - * Define a query that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to read from your Convex database. It will not be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export const internalQuery = internalQueryGeneric; - -/** - * Define a mutation in this Convex app's public API. - * - * This function will be allowed to modify your Convex database and will be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export const mutation = mutationGeneric; - -/** - * Define a mutation that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to modify your Convex database. It will not be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export const internalMutation = internalMutationGeneric; - -/** - * Define an action in this Convex app's public API. - * - * An action is a function which can execute any JavaScript code, including non-deterministic - * code and code with side-effects, like calling third-party services. - * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. - * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. - * - * @param func - The action. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped action. Include this as an `export` to name it and make it accessible. - */ -export const action = actionGeneric; - -/** - * Define an action that is only accessible from other Convex functions (but not from the client). - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped function. Include this as an `export` to name it and make it accessible. - */ -export const internalAction = internalActionGeneric; - -/** - * Define a Convex HTTP action. - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object - * as its second. - * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. - */ -export const httpAction = httpActionGeneric; From cb8a4242e34c53fd879799041b3345b5d8fc1c53 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sun, 20 Apr 2025 10:41:12 +0200 Subject: [PATCH 29/88] Update convex path --- test-sveltekit/convex.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-sveltekit/convex.json b/test-sveltekit/convex.json index 89700aab..d66f0e19 100644 --- a/test-sveltekit/convex.json +++ b/test-sveltekit/convex.json @@ -1,3 +1,3 @@ { - "functions": "src/convex/" + "functions": "src/lib/convex/" } From d35c3d8f425b5bbee381e054f24f4ec82ff195d1 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sun, 20 Apr 2025 10:59:18 +0200 Subject: [PATCH 30/88] Fix Cookie names --- src/sveltekit/server/handlers.ts | 70 +++++++++++++++++++------------- 1 file changed, 42 insertions(+), 28 deletions(-) diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index c2aba421..c456a5cf 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -4,6 +4,15 @@ import type { RequestEvent, RequestHandler } from "@sveltejs/kit"; import type { ConvexAuthServerState } from "../client.js"; import { json, error } from "@sveltejs/kit"; +// import { env } from "$env/dynamic/public"; + +// We can declare this as a variable that will be undefined by default +// Consumers of the library can configure it via the convexUrl parameter +// SvelteKit apps will have this variable replaced at build time +declare const env: { + [key: `PUBLIC_${string}`]: string | undefined; + PUBLIC_CONVEX_URL: string; +}; // Interface for cookie options interface CookieOptions { @@ -16,8 +25,8 @@ interface CookieOptions { } // Cookie names -const AUTH_TOKEN_COOKIE = "__convex_auth_token"; -const AUTH_REFRESH_TOKEN_COOKIE = "__convex_auth_refresh_token"; +const AUTH_TOKEN_COOKIE = "__convexAuthJWT"; +const AUTH_REFRESH_TOKEN_COOKIE = "__convexAuthRefreshToken"; // Default cookie options const defaultCookieOptions: CookieOptions = { @@ -39,18 +48,22 @@ function logVerbose(message: string, ...args: any[]) { * This allows SvelteKit implementations to automatically use the URL */ function getConvexUrl(): string { - // Try to load from process.env.PUBLIC_CONVEX_URL first - const envUrl = process.env.PUBLIC_CONVEX_URL; - - if (envUrl) { - return envUrl; + // Check for the SvelteKit environment variable (available in SvelteKit apps) + if (typeof env.PUBLIC_CONVEX_URL !== "undefined") { + return env.PUBLIC_CONVEX_URL; + } + + // Try to load from process.env if available in the environment + if ( + typeof process !== "undefined" && + process.env && + process.env.PUBLIC_CONVEX_URL + ) { + return process.env.PUBLIC_CONVEX_URL; } - - // If running in Node.js environment, could try to load from .env file - // but this is usually handled by SvelteKit's config - + throw new Error( - "Convex URL not provided. Either pass convexUrl parameter or set PUBLIC_CONVEX_URL environment variable." + "Convex URL not provided. Either pass convexUrl parameter or set PUBLIC_CONVEX_URL environment variable.", ); } @@ -67,7 +80,9 @@ export function createConvexAuthHandlers({ /** * Get the auth state from cookies */ - async function getAuthState(event: RequestEvent): Promise { + async function getAuthState( + event: RequestEvent, + ): Promise { // Get tokens from cookies const token = event.cookies.get(AUTH_TOKEN_COOKIE) || null; const refreshToken = event.cookies.get(AUTH_REFRESH_TOKEN_COOKIE) || null; @@ -84,16 +99,19 @@ export function createConvexAuthHandlers({ function setAuthCookies( event: RequestEvent, token: string | null, - refreshToken: string | null + refreshToken: string | null, ) { - logVerbose("Setting auth cookies", { token: !!token, refreshToken: !!refreshToken }); - + logVerbose("Setting auth cookies", { + token: !!token, + refreshToken: !!refreshToken, + }); + if (token === null) { event.cookies.delete(AUTH_TOKEN_COOKIE, cookieOptions); } else { - event.cookies.set(AUTH_TOKEN_COOKIE, token, { + event.cookies.set(AUTH_TOKEN_COOKIE, token, { ...cookieOptions, - maxAge: 60 * 60 // 1 hour for the main token + maxAge: 60 * 60, // 1 hour for the main token }); } @@ -102,7 +120,7 @@ export function createConvexAuthHandlers({ } else { event.cookies.set(AUTH_REFRESH_TOKEN_COOKIE, refreshToken, { ...cookieOptions, - maxAge: 60 * 60 * 24 * 30 // 30 days for refresh token + maxAge: 60 * 60 * 24 * 30, // 30 days for refresh token }); } } @@ -114,7 +132,7 @@ export function createConvexAuthHandlers({ async function proxyAuthActionToConvex( event: RequestEvent, action: string, - args: any + args: any, ) { logVerbose("Proxying auth action to Convex", { action, args }); @@ -140,11 +158,7 @@ export function createConvexAuthHandlers({ // Handle authentication results if (result.tokens) { - setAuthCookies( - event, - result.tokens.token, - result.tokens.refreshToken - ); + setAuthCookies(event, result.tokens.token, result.tokens.refreshToken); } else if (result.clearTokens) { setAuthCookies(event, null, null); } @@ -211,10 +225,10 @@ export function createConvexAuthHandlers({ * This is similar to the Next.js convexAuthNextjsServerState function */ export async function convexAuthSvelteKitServerState( - event: RequestEvent + event: RequestEvent, ): Promise { const token = event.cookies.get(AUTH_TOKEN_COOKIE) || null; - + // The server doesn't share the refresh token with the client // for added security - the client has to use the server // endpoint to refresh the token @@ -260,6 +274,6 @@ export function createConvexAuthHooks({ return { ...handlers, - handleAuth + handleAuth, }; } From 7f1d99c8d6939b53697f5f59d73b5a9ec8480f05 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Mon, 21 Apr 2025 19:49:46 +0200 Subject: [PATCH 31/88] Add tsdoc and made the object optional --- src/svelte/client.svelte.ts | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index d2c273e5..da9a4185 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -288,11 +288,23 @@ export function createAuthClient({ throw lastError; }; - const fetchAccessToken = async ({ - forceRefreshToken = false, - }: { - forceRefreshToken: boolean; + /** + * Get an access token from the server using the stored refresh token. + * If the refresh token is invalid, it will be cleared. + * + * If `options.forceRefreshToken` is true, a new access token will always be obtained + * from the server. Otherwise, if an access token is cached, it will be used + * without revalidating it with the server. + * + * @param {object} [options] + * + * @return {Promise} The access token, or null if none is + * available. + */ + const fetchAccessToken = async (options?: { + forceRefreshToken?: boolean; }): Promise => { + const { forceRefreshToken = false } = options ?? {}; logVerbose(`fetchAccessToken forceRefreshToken=${forceRefreshToken}`); // Return the existing token if we have one and aren't forcing a refresh From 0cb2311a040adb0f8e46bad85d1f6709888f175b Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Mon, 21 Apr 2025 20:20:29 +0200 Subject: [PATCH 32/88] Add token getter and fix auth context in SvelteKit with improved type safety --- src/svelte/client.svelte.ts | 1 + src/svelte/index.svelte.ts | 94 +++++++++---------------------------- 2 files changed, 24 insertions(+), 71 deletions(-) diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index da9a4185..4fa08fb5 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -424,6 +424,7 @@ export function createAuthClient({ const authApi = { get isLoading() { return state.isLoading; }, get isAuthenticated() { return isAuthenticated; }, + get token() { return state.token; }, fetchAccessToken, signIn, signOut, diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index 134023dd..c307765b 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -6,17 +6,17 @@ import { ConvexClient, ConvexClientOptions } from "convex/browser"; import { getContext, setContext } from "svelte"; -import { Value } from "convex/values"; -import { - createAuthClient, - getConvexAuthContext, - setConvexAuthContext, -} from "./client.svelte.js"; +import { createAuthClient, setConvexAuthContext, getConvexAuthContext } from "./client.svelte.js"; import { AuthClient } from "./clientType.js"; import { setupConvex } from "convex-svelte"; -// Context key for Convex auth actions -const AUTH_TOKEN_CONTEXT_KEY = "$$_convexAuthToken"; +/** + * Parameters for sign-in methods + */ +type SignInParams = FormData | Record & { + redirectTo?: string; + code?: string; +}; /** * A storage interface for storing and retrieving tokens and other secrets. @@ -121,7 +121,7 @@ export function setupConvexAuth({ */ convexUrl: string; - options?: ConvexClientOptions + options?: ConvexClientOptions; }) { // Client resolution priority: // 1. Client passed directly @@ -159,7 +159,6 @@ export function setupConvexAuth({ ); } - // Create auth client const authClient: AuthClient = { authenticatedCall(action, args) { @@ -189,40 +188,6 @@ export function setupConvexAuth({ // Set auth context setConvexAuthContext(auth); - // Handle token updates reactively - if (typeof window !== "undefined") { - // Set token context reactively with $effect - $effect(() => { - let isMounted = true; - - if (auth.isAuthenticated) { - // Use void to handle the promise without returning it - void (async () => { - try { - const token = await auth.fetchAccessToken({ - forceRefreshToken: false, - }); - if (isMounted) { - setContext(AUTH_TOKEN_CONTEXT_KEY, token); - } - } catch (error) { - console.error("Failed to fetch auth token:", error); - if (isMounted) { - setContext(AUTH_TOKEN_CONTEXT_KEY, null); - } - } - })(); - } else { - setContext(AUTH_TOKEN_CONTEXT_KEY, null); - } - - // Return a cleanup function - return () => { - isMounted = false; - }; - }); - } - return auth; } @@ -256,20 +221,7 @@ export type ConvexAuthActionsContext = { * - `code`: OTP code for email or phone verification, or * (used only in RN) the code from an OAuth flow or magic link URL. */ - params?: - | FormData - | (Record & { - /** - * If provided, customizes the destination the user is - * redirected to at the end of an OAuth flow or the magic link URL. - */ - redirectTo?: string; - /** - * OTP code for email or phone verification, or - * (used only in RN) the code from an OAuth flow or magic link URL. - */ - code?: string; - }), + params?: SignInParams, ): Promise; /** * Sign out the current user, deleting the token from storage. @@ -284,18 +236,18 @@ export type ConvexAuthActionsContext = { /** * Use this function to access all authentication functionality including state, token, and actions. - * + * * ```ts * import { useAuth } from "@convex-dev/auth/svelte"; - * + * * function SomeComponent() { * const { isLoading, isAuthenticated, token, signIn, signOut } = useAuth(); - * + * * // Use authentication state * if (isLoading) { * return

    Loading...

    ; * } - * + * * if (isAuthenticated) { * return ( *
    @@ -304,7 +256,7 @@ export type ConvexAuthActionsContext = { *
    * ); * } - * + * * return ( *
    *

    You need to sign in

    @@ -314,16 +266,16 @@ export type ConvexAuthActionsContext = { * } * ``` */ -export function useAuth(): Omit< - ReturnType, - "fetchAccessToken" -> & { +export function useAuth(): { + isLoading: boolean; + isAuthenticated: boolean; token: string | null; + signIn: (provider: string, params?: SignInParams) => Promise; + signOut: () => Promise; } { try { - // Get the auth client and actions from context + // Get the auth client from context const auth = getConvexAuthContext(); - const token = getContext(AUTH_TOKEN_CONTEXT_KEY) ?? null; if (!auth) { throw new Error("setupConvexAuth must be called before useAuth"); @@ -341,11 +293,11 @@ export function useAuth(): Omit< // Auth token get token() { - return token; + return auth.token; }, // Auth actions - signIn: (...args) => auth.signIn(...args), + signIn: (provider: string, params?: SignInParams) => auth.signIn(provider, params), signOut: () => auth.signOut(), }; } catch (e) { From 08542723fec3d87291502151bb0a8aec25f342ab Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Mon, 21 Apr 2025 21:57:47 +0200 Subject: [PATCH 33/88] Add null checks and refactor auth client initialization for SvelteKit --- src/svelte/client.svelte.ts | 10 +++----- src/sveltekit/client.ts | 25 +++++++++++++++---- src/sveltekit/index.ts | 10 +++----- .../src/routes/product/+page.svelte | 7 ++++-- 4 files changed, 32 insertions(+), 20 deletions(-) diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index 4fa08fb5..50ac3f6e 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -1,7 +1,7 @@ /** * Svelte implementation of Convex Auth client. */ -import { getContext, setContext } from "svelte"; +import { getContext, onMount, setContext } from "svelte"; import type { SignInAction, SignOutAction, @@ -108,11 +108,7 @@ export function createAuthClient({ }; // Load tokens from storage on initialization - $effect(() => { - if (typeof window === "undefined") { - // Skip on server - return; - } + onMount(() => { const loadTokens = async () => { if (serverState?._state) { @@ -234,7 +230,7 @@ export function createAuthClient({ return () => window.removeEventListener("storage", storageListener); }); - // Warning before leaving page during token refresh + // Prevent accidental navigation away from the page during token refresh. $effect(() => { if (typeof window === "undefined") { return; diff --git a/src/sveltekit/client.ts b/src/sveltekit/client.ts index 02fbfa63..12487dc9 100644 --- a/src/sveltekit/client.ts +++ b/src/sveltekit/client.ts @@ -2,8 +2,9 @@ * SvelteKit implementation of Convex Auth client. */ import { invalidateAll } from "$app/navigation"; -import { createAuthClient } from "../svelte/client.svelte.js"; +import { createAuthClient, setConvexAuthContext } from "../svelte/client.svelte.js"; import { AuthClient } from "../svelte/clientType.js"; +import { ConvexClient, ConvexClientOptions } from "convex/browser"; /** * Type definition for the server state from SvelteKit @@ -21,13 +22,17 @@ export function createSvelteKitAuthClient({ serverState, storage = "localStorage", storageNamespace, - verbose, + client, + convexUrl, + options, }: { apiRoute?: string; serverState?: ConvexAuthServerState; storage?: "localStorage" | "inMemory"; storageNamespace?: string; - verbose?: boolean; + client?: ConvexClient; + convexUrl: string; + options?: ConvexClientOptions; }) { // Create SvelteKit-specific auth client const authenticatedCall: AuthClient["authenticatedCall"] = async (action, args) => { @@ -42,11 +47,16 @@ export function createSvelteKitAuthClient({ const authClient: AuthClient = { authenticatedCall, unauthenticatedCall: authenticatedCall, - verbose, + verbose: options?.verbose, }; + // Initialize the Convex client if not provided + if (!client && convexUrl) { + client = new ConvexClient(convexUrl, options); + } + // Create the auth client with SvelteKit-specific config - return createAuthClient({ + const auth = createAuthClient({ client: authClient, serverState, onChange: async () => { @@ -74,6 +84,11 @@ export function createSvelteKitAuthClient({ } }, }); + + // Set the auth context to ensure it's available immediately + setConvexAuthContext(auth); + + return auth; } /** diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts index 1f8600dd..2588b893 100644 --- a/src/sveltekit/index.ts +++ b/src/sveltekit/index.ts @@ -5,7 +5,6 @@ */ import { - setupConvexAuth as setupSvelteConvexAuth, useAuth, type TokenStorage, type ConvexAuthActionsContext @@ -67,16 +66,15 @@ export function setupConvexAuth({ convexUrl: string; options?: ConvexClientOptions }) { - // Initialize the base Svelte auth - setupSvelteConvexAuth({ client, convexUrl, options }); - - // Return the initialized auth client + // Initialize the auth client with SvelteKit-specific configuration return createSvelteKitAuthClient({ apiRoute, serverState, storage, + client, // Pass the client to avoid re-initialization + convexUrl, // Pass the URL for client initialization storageNamespace: storageNamespace ?? convexUrl, - verbose: options?.verbose, + options, // Pass options to configure the client }); } diff --git a/test-sveltekit/src/routes/product/+page.svelte b/test-sveltekit/src/routes/product/+page.svelte index d4f16616..5db60d66 100644 --- a/test-sveltekit/src/routes/product/+page.svelte +++ b/test-sveltekit/src/routes/product/+page.svelte @@ -8,10 +8,13 @@ const viewer = useQuery(api.users.viewer, {}); +{#if viewer.data}
    - {viewer.data!.name} + {viewer.data.name}
    - +
    +{/if} + From bf4799b77e5991970325d4a1a053763010118c1c Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Tue, 22 Apr 2025 13:29:24 +0200 Subject: [PATCH 34/88] Fix signOut --- src/sveltekit/client.ts | 8 ++++---- src/sveltekit/server/handlers.ts | 5 ++++- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/sveltekit/client.ts b/src/sveltekit/client.ts index 12487dc9..1d9bc3a0 100644 --- a/src/sveltekit/client.ts +++ b/src/sveltekit/client.ts @@ -34,8 +34,7 @@ export function createSvelteKitAuthClient({ convexUrl: string; options?: ConvexClientOptions; }) { - // Create SvelteKit-specific auth client - const authenticatedCall: AuthClient["authenticatedCall"] = async (action, args) => { + const call: AuthClient["authenticatedCall"] = async (action, args) => { const params = { action, args }; const response = await fetch(apiRoute, { body: JSON.stringify(params), @@ -45,9 +44,10 @@ export function createSvelteKitAuthClient({ }; const authClient: AuthClient = { - authenticatedCall, - unauthenticatedCall: authenticatedCall, + authenticatedCall: call, + unauthenticatedCall: call, verbose: options?.verbose, + logger: options?.logger, }; // Initialize the Convex client if not provided diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index c456a5cf..e9f6ba48 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -137,6 +137,9 @@ export function createConvexAuthHandlers({ logVerbose("Proxying auth action to Convex", { action, args }); try { + // Ensure args is always an object (needed for signOut which doesn't provide args) + const finalArgs = args === undefined ? {} : args; + // Forward the request to Convex const response = await fetch(`${convexUrl}/api/action`, { method: "POST", @@ -145,7 +148,7 @@ export function createConvexAuthHandlers({ }, body: JSON.stringify({ path: action, - args, + args: finalArgs, }), }); From 4628f0a19bee88822de5312c148a22d788b1828a Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Tue, 22 Apr 2025 16:30:47 +0200 Subject: [PATCH 35/88] Delete convex duplicated files --- test-sveltekit/convex/_generated/api.d.ts | 33 ---- test-sveltekit/convex/_generated/api.js | 22 --- .../convex/_generated/dataModel.d.ts | 58 ------- test-sveltekit/convex/_generated/server.d.ts | 142 ------------------ test-sveltekit/convex/_generated/server.js | 89 ----------- 5 files changed, 344 deletions(-) delete mode 100644 test-sveltekit/convex/_generated/api.d.ts delete mode 100644 test-sveltekit/convex/_generated/api.js delete mode 100644 test-sveltekit/convex/_generated/dataModel.d.ts delete mode 100644 test-sveltekit/convex/_generated/server.d.ts delete mode 100644 test-sveltekit/convex/_generated/server.js diff --git a/test-sveltekit/convex/_generated/api.d.ts b/test-sveltekit/convex/_generated/api.d.ts deleted file mode 100644 index 7d71a015..00000000 --- a/test-sveltekit/convex/_generated/api.d.ts +++ /dev/null @@ -1,33 +0,0 @@ -/* eslint-disable */ -/** - * Generated `api` utility. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import type { - ApiFromModules, - FilterApi, - FunctionReference, -} from "convex/server"; - -/** - * A utility for referencing Convex functions in your app's API. - * - * Usage: - * ```js - * const myFunctionReference = api.myModule.myFunction; - * ``` - */ -declare const fullApi: ApiFromModules<{}>; -export declare const api: FilterApi< - typeof fullApi, - FunctionReference ->; -export declare const internal: FilterApi< - typeof fullApi, - FunctionReference ->; diff --git a/test-sveltekit/convex/_generated/api.js b/test-sveltekit/convex/_generated/api.js deleted file mode 100644 index 3f9c482d..00000000 --- a/test-sveltekit/convex/_generated/api.js +++ /dev/null @@ -1,22 +0,0 @@ -/* eslint-disable */ -/** - * Generated `api` utility. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { anyApi } from "convex/server"; - -/** - * A utility for referencing Convex functions in your app's API. - * - * Usage: - * ```js - * const myFunctionReference = api.myModule.myFunction; - * ``` - */ -export const api = anyApi; -export const internal = anyApi; diff --git a/test-sveltekit/convex/_generated/dataModel.d.ts b/test-sveltekit/convex/_generated/dataModel.d.ts deleted file mode 100644 index fb12533b..00000000 --- a/test-sveltekit/convex/_generated/dataModel.d.ts +++ /dev/null @@ -1,58 +0,0 @@ -/* eslint-disable */ -/** - * Generated data model types. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { AnyDataModel } from "convex/server"; -import type { GenericId } from "convex/values"; - -/** - * No `schema.ts` file found! - * - * This generated code has permissive types like `Doc = any` because - * Convex doesn't know your schema. If you'd like more type safety, see - * https://docs.convex.dev/using/schemas for instructions on how to add a - * schema file. - * - * After you change a schema, rerun codegen with `npx convex dev`. - */ - -/** - * The names of all of your Convex tables. - */ -export type TableNames = string; - -/** - * The type of a document stored in Convex. - */ -export type Doc = any; - -/** - * An identifier for a document in Convex. - * - * Convex documents are uniquely identified by their `Id`, which is accessible - * on the `_id` field. To learn more, see [Document IDs](https://docs.convex.dev/using/document-ids). - * - * Documents can be loaded using `db.get(id)` in query and mutation functions. - * - * IDs are just strings at runtime, but this type can be used to distinguish them from other - * strings when type checking. - */ -export type Id = - GenericId; - -/** - * A type describing your Convex data model. - * - * This type includes information about what tables you have, the type of - * documents stored in those tables, and the indexes defined on them. - * - * This type is used to parameterize methods like `queryGeneric` and - * `mutationGeneric` to make them type-safe. - */ -export type DataModel = AnyDataModel; diff --git a/test-sveltekit/convex/_generated/server.d.ts b/test-sveltekit/convex/_generated/server.d.ts deleted file mode 100644 index 7f337a43..00000000 --- a/test-sveltekit/convex/_generated/server.d.ts +++ /dev/null @@ -1,142 +0,0 @@ -/* eslint-disable */ -/** - * Generated utilities for implementing server-side Convex query and mutation functions. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { - ActionBuilder, - HttpActionBuilder, - MutationBuilder, - QueryBuilder, - GenericActionCtx, - GenericMutationCtx, - GenericQueryCtx, - GenericDatabaseReader, - GenericDatabaseWriter, -} from "convex/server"; -import type { DataModel } from "./dataModel.js"; - -/** - * Define a query in this Convex app's public API. - * - * This function will be allowed to read your Convex database and will be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export declare const query: QueryBuilder; - -/** - * Define a query that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to read from your Convex database. It will not be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export declare const internalQuery: QueryBuilder; - -/** - * Define a mutation in this Convex app's public API. - * - * This function will be allowed to modify your Convex database and will be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export declare const mutation: MutationBuilder; - -/** - * Define a mutation that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to modify your Convex database. It will not be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export declare const internalMutation: MutationBuilder; - -/** - * Define an action in this Convex app's public API. - * - * An action is a function which can execute any JavaScript code, including non-deterministic - * code and code with side-effects, like calling third-party services. - * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. - * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. - * - * @param func - The action. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped action. Include this as an `export` to name it and make it accessible. - */ -export declare const action: ActionBuilder; - -/** - * Define an action that is only accessible from other Convex functions (but not from the client). - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped function. Include this as an `export` to name it and make it accessible. - */ -export declare const internalAction: ActionBuilder; - -/** - * Define an HTTP action. - * - * This function will be used to respond to HTTP requests received by a Convex - * deployment if the requests matches the path and method where this action - * is routed. Be sure to route your action in `convex/http.js`. - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped function. Import this function from `convex/http.js` and route it to hook it up. - */ -export declare const httpAction: HttpActionBuilder; - -/** - * A set of services for use within Convex query functions. - * - * The query context is passed as the first argument to any Convex query - * function run on the server. - * - * This differs from the {@link MutationCtx} because all of the services are - * read-only. - */ -export type QueryCtx = GenericQueryCtx; - -/** - * A set of services for use within Convex mutation functions. - * - * The mutation context is passed as the first argument to any Convex mutation - * function run on the server. - */ -export type MutationCtx = GenericMutationCtx; - -/** - * A set of services for use within Convex action functions. - * - * The action context is passed as the first argument to any Convex action - * function run on the server. - */ -export type ActionCtx = GenericActionCtx; - -/** - * An interface to read from the database within Convex query functions. - * - * The two entry points are {@link DatabaseReader.get}, which fetches a single - * document by its {@link Id}, or {@link DatabaseReader.query}, which starts - * building a query. - */ -export type DatabaseReader = GenericDatabaseReader; - -/** - * An interface to read from and write to the database within Convex mutation - * functions. - * - * Convex guarantees that all writes within a single mutation are - * executed atomically, so you never have to worry about partial writes leaving - * your data in an inconsistent state. See [the Convex Guide](https://docs.convex.dev/understanding/convex-fundamentals/functions#atomicity-and-optimistic-concurrency-control) - * for the guarantees Convex provides your functions. - */ -export type DatabaseWriter = GenericDatabaseWriter; diff --git a/test-sveltekit/convex/_generated/server.js b/test-sveltekit/convex/_generated/server.js deleted file mode 100644 index 566d4858..00000000 --- a/test-sveltekit/convex/_generated/server.js +++ /dev/null @@ -1,89 +0,0 @@ -/* eslint-disable */ -/** - * Generated utilities for implementing server-side Convex query and mutation functions. - * - * THIS CODE IS AUTOMATICALLY GENERATED. - * - * To regenerate, run `npx convex dev`. - * @module - */ - -import { - actionGeneric, - httpActionGeneric, - queryGeneric, - mutationGeneric, - internalActionGeneric, - internalMutationGeneric, - internalQueryGeneric, -} from "convex/server"; - -/** - * Define a query in this Convex app's public API. - * - * This function will be allowed to read your Convex database and will be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export const query = queryGeneric; - -/** - * Define a query that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to read from your Convex database. It will not be accessible from the client. - * - * @param func - The query function. It receives a {@link QueryCtx} as its first argument. - * @returns The wrapped query. Include this as an `export` to name it and make it accessible. - */ -export const internalQuery = internalQueryGeneric; - -/** - * Define a mutation in this Convex app's public API. - * - * This function will be allowed to modify your Convex database and will be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export const mutation = mutationGeneric; - -/** - * Define a mutation that is only accessible from other Convex functions (but not from the client). - * - * This function will be allowed to modify your Convex database. It will not be accessible from the client. - * - * @param func - The mutation function. It receives a {@link MutationCtx} as its first argument. - * @returns The wrapped mutation. Include this as an `export` to name it and make it accessible. - */ -export const internalMutation = internalMutationGeneric; - -/** - * Define an action in this Convex app's public API. - * - * An action is a function which can execute any JavaScript code, including non-deterministic - * code and code with side-effects, like calling third-party services. - * They can be run in Convex's JavaScript environment or in Node.js using the "use node" directive. - * They can interact with the database indirectly by calling queries and mutations using the {@link ActionCtx}. - * - * @param func - The action. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped action. Include this as an `export` to name it and make it accessible. - */ -export const action = actionGeneric; - -/** - * Define an action that is only accessible from other Convex functions (but not from the client). - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument. - * @returns The wrapped function. Include this as an `export` to name it and make it accessible. - */ -export const internalAction = internalActionGeneric; - -/** - * Define a Convex HTTP action. - * - * @param func - The function. It receives an {@link ActionCtx} as its first argument, and a `Request` object - * as its second. - * @returns The wrapped endpoint function. Route a URL path to this function in `convex/http.js`. - */ -export const httpAction = httpActionGeneric; From 59c08dd3938608acc5cc5f5adf2a69effe5d2be1 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Tue, 22 Apr 2025 16:31:11 +0200 Subject: [PATCH 36/88] Update formatting --- test-sveltekit/src/routes/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-sveltekit/src/routes/+page.svelte b/test-sveltekit/src/routes/+page.svelte index cc504dde..4e871004 100644 --- a/test-sveltekit/src/routes/+page.svelte +++ b/test-sveltekit/src/routes/+page.svelte @@ -4,7 +4,7 @@ const { signOut, isAuthenticated } = useAuth(); -
    +
    {#if isAuthenticated}

    You are authenticated!

    Product From ddf5cad1e1379cb64ae1f728f007e334bcf6806d Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Wed, 23 Apr 2025 16:52:00 +0200 Subject: [PATCH 37/88] Add SvelteKit auth server handlers with proxy support and improved token management --- src/svelte/client.svelte.ts | 61 +++---- src/svelte/index.svelte.ts | 55 ++++-- src/sveltekit/client.ts | 12 +- src/sveltekit/env.d.ts | 11 ++ src/sveltekit/server/handlers.ts | 303 ++++++++++++++++++++----------- src/sveltekit/server/index.ts | 65 +++++-- src/sveltekit/server/proxy.ts | 17 ++ src/sveltekit/server/utilts.ts | 145 +++++++++++++++ 8 files changed, 504 insertions(+), 165 deletions(-) create mode 100644 src/sveltekit/env.d.ts create mode 100644 src/sveltekit/server/proxy.ts create mode 100644 src/sveltekit/server/utilts.ts diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index 50ac3f6e..938552ec 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -9,6 +9,7 @@ import type { import { AuthClient } from "./clientType.js"; import type { TokenStorage } from "./index.svelte"; import isNetworkError from "is-network-error"; +import { Value } from "convex/values"; // Retry after this much time, based on the retry number. const RETRY_BACKOFF = [500, 2000]; // In ms @@ -341,56 +342,48 @@ export function createAuthClient({ const signIn = async ( provider: string, - params?: FormData | Record - ): Promise => { + params?: FormData | Record + ) => { logVerbose(`signIn provider=${provider}`); try { // Get verifier if it exists const verifier = (await storageGet(VERIFIER_STORAGE_KEY)) ?? undefined; + await storageRemove(VERIFIER_STORAGE_KEY); - const finalParams = params instanceof FormData ? Object.fromEntries(params.entries()) : params ?? {}; - const response = await client.authenticatedCall( + const result = await client.authenticatedCall( "auth:signIn" as unknown as SignInAction, { provider, params: finalParams, verifier } ); - - if (response.started === true) { - // Redirect flow, need to store verifier - if (response.verifier) { - await storageSet(VERIFIER_STORAGE_KEY, response.verifier); - } - - if (typeof window !== "undefined" && response.redirect) { - window.location.href = response.redirect; - } - - return false; - } else if (!response.redirect) { - // Auth completed silently - if (response.tokens) { - await setToken({ shouldStore: true, tokens: response.tokens }); - return true; - } else { - console.error("No tokens in silent auth response"); - return false; - } - } else { - // Redirect flow - if (response.verifier) { - await storageSet(VERIFIER_STORAGE_KEY, response.verifier); + + if (result.redirect !== undefined) { + const url = new URL(result.redirect); + // For redirect flows (OAuth or magic links) + // Store the verifier for the redirect flow + if (result.verifier) { + await storageSet(VERIFIER_STORAGE_KEY, result.verifier); } if (typeof window !== "undefined") { - window.location.href = response.redirect; + window.location.href = url.toString(); } - return false; + return { signingIn: false, redirect: url }; // User will need to complete the flow + } else if (result.tokens !== undefined) { + // For direct sign-in flows or token refresh + logVerbose(`signed in and got tokens, is null: ${result.tokens === null}`); + await setToken({ shouldStore: true, tokens: result.tokens }); + + // Return success based on whether we got valid tokens + return { signingIn: result.tokens !== null }; } + + // Default case - not signed in + return { signingIn: false }; } catch (e) { console.error("Failed to sign in:", e); throw e; @@ -406,14 +399,18 @@ export function createAuthClient({ await client.authenticatedCall( "auth:signOut" as unknown as SignOutAction ); + } catch (e) { // Ignore any errors, they are usually caused by being // already signed out, which is ok. + if (e instanceof Error) { + logVerbose(`signOut error (ignored): ${e.message}`); + } } // Always clear tokens locally, even if server call failed + logVerbose(`signed out, erasing tokens`); await setToken({ shouldStore: true, tokens: null }); - logVerbose(`signed out, tokens erased`); }; // Expose the auth API diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index c307765b..1dadb79f 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -5,18 +5,24 @@ */ import { ConvexClient, ConvexClientOptions } from "convex/browser"; -import { getContext, setContext } from "svelte"; -import { createAuthClient, setConvexAuthContext, getConvexAuthContext } from "./client.svelte.js"; +import { getContext } from "svelte"; +import { + createAuthClient, + setConvexAuthContext, + getConvexAuthContext, +} from "./client.svelte.js"; import { AuthClient } from "./clientType.js"; import { setupConvex } from "convex-svelte"; /** * Parameters for sign-in methods */ -type SignInParams = FormData | Record & { - redirectTo?: string; - code?: string; -}; +type SignInParams = + | FormData + | (Record & { + redirectTo?: string; + code?: string; + }); /** * A storage interface for storing and retrieving tokens and other secrets. @@ -222,7 +228,24 @@ export type ConvexAuthActionsContext = { * (used only in RN) the code from an OAuth flow or magic link URL. */ params?: SignInParams, - ): Promise; + ): Promise<{ + /** + * Whether the call led to an immediate successful sign-in. + * + * Note that there's a delay between the `signIn` function + * returning and the client performing the handshake with + * the server to confirm the sign-in. + */ + signingIn: boolean; + /** + * If the sign-in started an OAuth flow, this is the URL + * the browser should be redirected to. + * + * Useful in RN for opening the in-app browser to + * this URL. + */ + redirect?: URL; + }>; /** * Sign out the current user, deleting the token from storage. * @@ -236,18 +259,18 @@ export type ConvexAuthActionsContext = { /** * Use this function to access all authentication functionality including state, token, and actions. - * + * * ```ts * import { useAuth } from "@convex-dev/auth/svelte"; - * + * * function SomeComponent() { * const { isLoading, isAuthenticated, token, signIn, signOut } = useAuth(); - * + * * // Use authentication state * if (isLoading) { * return

    Loading...

    ; * } - * + * * if (isAuthenticated) { * return ( *
    @@ -256,7 +279,7 @@ export type ConvexAuthActionsContext = { *
    * ); * } - * + * * return ( *
    *

    You need to sign in

    @@ -270,7 +293,10 @@ export function useAuth(): { isLoading: boolean; isAuthenticated: boolean; token: string | null; - signIn: (provider: string, params?: SignInParams) => Promise; + signIn: (provider: string, params?: SignInParams) => Promise<{ + signingIn: boolean; + redirect?: URL; + }>; signOut: () => Promise; } { try { @@ -297,7 +323,8 @@ export function useAuth(): { }, // Auth actions - signIn: (provider: string, params?: SignInParams) => auth.signIn(provider, params), + signIn: (provider: string, params?: SignInParams) => + auth.signIn(provider, params), signOut: () => auth.signOut(), }; } catch (e) { diff --git a/src/sveltekit/client.ts b/src/sveltekit/client.ts index 1d9bc3a0..fc540e8f 100644 --- a/src/sveltekit/client.ts +++ b/src/sveltekit/client.ts @@ -1,7 +1,7 @@ /** * SvelteKit implementation of Convex Auth client. */ -import { invalidateAll } from "$app/navigation"; +import { invalidateAll, replaceState } from "$app/navigation"; import { createAuthClient, setConvexAuthContext } from "../svelte/client.svelte.js"; import { AuthClient } from "../svelte/clientType.js"; import { ConvexClient, ConvexClientOptions } from "convex/browser"; @@ -51,7 +51,7 @@ export function createSvelteKitAuthClient({ }; // Initialize the Convex client if not provided - if (!client && convexUrl) { + if (!client) { client = new ConvexClient(convexUrl, options); } @@ -80,7 +80,13 @@ export function createSvelteKitAuthClient({ ), replaceURL: (url) => { if (typeof window !== "undefined") { - window.history.replaceState({}, "", url); + try { + // Try using SvelteKit's navigation function first + replaceState(url, {}); + } catch (error) { + // Fall back to standard history API if SvelteKit router isn't ready + window.history.replaceState({}, "", url); + } } }, }); diff --git a/src/sveltekit/env.d.ts b/src/sveltekit/env.d.ts new file mode 100644 index 00000000..adefa421 --- /dev/null +++ b/src/sveltekit/env.d.ts @@ -0,0 +1,11 @@ +/** + * Type declarations for SvelteKit environment variables + * This allows the library to be used without a dev server + */ + +declare module "$env/dynamic/public" { + export const env: { + [key: `PUBLIC_${string}`]: string | undefined; + PUBLIC_CONVEX_URL: string; + }; +} diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index e9f6ba48..f96d0577 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -1,18 +1,19 @@ /** * Server-side handlers for Convex Auth in SvelteKit */ +import cookie from "cookie"; import type { RequestEvent, RequestHandler } from "@sveltejs/kit"; import type { ConvexAuthServerState } from "../client.js"; import { json, error } from "@sveltejs/kit"; -// import { env } from "$env/dynamic/public"; - -// We can declare this as a variable that will be undefined by default -// Consumers of the library can configure it via the convexUrl parameter -// SvelteKit apps will have this variable replaced at build time -declare const env: { - [key: `PUBLIC_${string}`]: string | undefined; - PUBLIC_CONVEX_URL: string; -}; +import { ConvexAuthHooksOptions } from "./index"; +import { shouldProxyAuthAction } from "./proxy.js"; +import { + getConvexUrl, + isCorsRequest, + logVerbose, + setupClient, +} from "./utilts.js"; +import { SignInAction } from "@convex-dev/auth/server"; // Interface for cookie options interface CookieOptions { @@ -36,47 +37,14 @@ const defaultCookieOptions: CookieOptions = { sameSite: "lax", }; -// For debug logging -function logVerbose(message: string, ...args: any[]) { - if (process.env.CONVEX_AUTH_DEBUG === "true") { - console.log(`[ConvexAuth] ${message}`, ...args); - } -} - -/** - * Helper to get the Convex URL from environment variables - * This allows SvelteKit implementations to automatically use the URL - */ -function getConvexUrl(): string { - // Check for the SvelteKit environment variable (available in SvelteKit apps) - if (typeof env.PUBLIC_CONVEX_URL !== "undefined") { - return env.PUBLIC_CONVEX_URL; - } - - // Try to load from process.env if available in the environment - if ( - typeof process !== "undefined" && - process.env && - process.env.PUBLIC_CONVEX_URL - ) { - return process.env.PUBLIC_CONVEX_URL; - } - - throw new Error( - "Convex URL not provided. Either pass convexUrl parameter or set PUBLIC_CONVEX_URL environment variable.", - ); -} - /** * Create server-side handlers for SvelteKit */ export function createConvexAuthHandlers({ convexUrl = getConvexUrl(), - cookieOptions = defaultCookieOptions, -}: { - convexUrl?: string; - cookieOptions?: CookieOptions; -} = {}) { + cookieConfig = defaultCookieOptions, + verbose = false, +}: ConvexAuthHooksOptions = {}) { /** * Get the auth state from cookies */ @@ -97,31 +65,59 @@ export function createConvexAuthHandlers({ * Set auth cookies */ function setAuthCookies( - event: RequestEvent, + response: Response, token: string | null, refreshToken: string | null, ) { - logVerbose("Setting auth cookies", { - token: !!token, - refreshToken: !!refreshToken, - }); + logVerbose( + `Setting auth cookies { token: ${!!token}, refreshToken: ${!!refreshToken} }`, + verbose, + ); if (token === null) { - event.cookies.delete(AUTH_TOKEN_COOKIE, cookieOptions); + // To delete a cookie, we need to set it with an expired date/max-age + response.headers.append( + "set-cookie", + cookie.serialize(AUTH_TOKEN_COOKIE, "", { + ...cookieConfig, + maxAge: 0, // Setting max-age to 0 tells the browser to delete it immediately + expires: new Date(0), // Setting an expired date as backup + }) + ); } else { - event.cookies.set(AUTH_TOKEN_COOKIE, token, { - ...cookieOptions, - maxAge: 60 * 60, // 1 hour for the main token - }); + response.headers.append( + "set-cookie", + cookie.serialize(AUTH_TOKEN_COOKIE, token, { + ...cookieConfig, + maxAge: + cookieConfig.maxAge === undefined + ? 60 * 60 // 1 hour for the main token + : cookieConfig.maxAge, + }), + ); } if (refreshToken === null) { - event.cookies.delete(AUTH_REFRESH_TOKEN_COOKIE, cookieOptions); + // To delete a cookie, we need to set it with an expired date/max-age + response.headers.append( + "set-cookie", + cookie.serialize(AUTH_REFRESH_TOKEN_COOKIE, "", { + ...cookieConfig, + maxAge: 0, // Setting max-age to 0 tells the browser to delete it immediately + expires: new Date(0), // Setting an expired date as backup + }) + ); } else { - event.cookies.set(AUTH_REFRESH_TOKEN_COOKIE, refreshToken, { - ...cookieOptions, - maxAge: 60 * 60 * 24 * 30, // 30 days for refresh token - }); + response.headers.append( + "set-cookie", + cookie.serialize(AUTH_REFRESH_TOKEN_COOKIE, refreshToken, { + ...cookieConfig, + maxAge: + cookieConfig.maxAge === undefined + ? 60 * 60 * 24 * 30 // 30 days for refresh token + : cookieConfig.maxAge, + }), + ); } } @@ -131,45 +127,145 @@ export function createConvexAuthHandlers({ */ async function proxyAuthActionToConvex( event: RequestEvent, - action: string, + action: any, args: any, ) { - logVerbose("Proxying auth action to Convex", { action, args }); + logVerbose( + `Proxying auth action to Convex { action: ${action}, args: ${JSON.stringify({ + ...args, + refreshToken: args?.refreshToken ? '[redacted]' : undefined, + })} }`, + verbose, + ); + + if (isCorsRequest(event)) { + return new Response("Invalid origin", { status: 403 }); + } - try { - // Ensure args is always an object (needed for signOut which doesn't provide args) - const finalArgs = args === undefined ? {} : args; + if (action !== "auth:signIn" && action !== "auth:signOut") { + logVerbose(`Invalid action ${action}, returning 400`, verbose); + return new Response("Invalid action", { status: 400 }); + } - // Forward the request to Convex - const response = await fetch(`${convexUrl}/api/action`, { - method: "POST", - headers: { - "Content-Type": "application/json", - }, - body: JSON.stringify({ - path: action, - args: finalArgs, - }), - }); + let token: string | undefined; + + if (action === "auth:signIn" && args.refreshToken !== undefined) { + // The client has a dummy refreshToken, the real one is only stored in cookies + const refreshToken = event.cookies.get(AUTH_REFRESH_TOKEN_COOKIE); + if (refreshToken === null) { + console.error( + "Convex Auth: Unexpected missing refreshToken cookie during client refresh", + ); + return json({ tokens: null }); + } + args.refreshToken = refreshToken; + } else { + // Make sure the proxy is authenticated if the client is, + // important for signOut and any other logic working with existing sessions + token = event.cookies.get(AUTH_TOKEN_COOKIE) ?? undefined; + } - if (!response.ok) { - throw new Error(`Failed to proxy auth action: ${response.statusText}`); + // Add verifier from cookie if we're processing a code verification and verifier wasn't already provided + if (action === "auth:signIn" && + args.params?.code !== undefined && + !args.verifier) { + const verifier = event.cookies.get("verifier"); + if (verifier) { + args.verifier = verifier; } + } - const result = await response.json(); - logVerbose("Proxy result", result); + logVerbose( + `Fetching action ${action} with args ${JSON.stringify({ + ...args, + refreshToken: args?.refreshToken ? "[redacted]" : undefined, + })}`, + verbose, + ); + + if (action === "auth:signIn") { + let result: SignInAction["_returnType"]; + // Do not require auth when refreshing tokens or validating a code since they + // are steps in the auth flow + const clientOptions: { url: string; token?: string } = { url: convexUrl }; + if (!(args.refreshToken !== undefined || args.params?.code !== undefined)) { + clientOptions.token = token; + } - // Handle authentication results - if (result.tokens) { - setAuthCookies(event, result.tokens.token, result.tokens.refreshToken); - } else if (result.clearTokens) { - setAuthCookies(event, null, null); + try { + const client = setupClient(clientOptions); + result = await client.action(action, args); + } catch (error) { + console.error(`Hit error while running \`auth:signIn\`:`); + console.error(error); + logVerbose(`Clearing auth cookies`, verbose); + const response = json(null); + setAuthCookies(response, null, null); + return response; } - return result; - } catch (e) { - console.error("Error proxying auth action:", e); - throw error(500, "Error proxying auth action to Convex"); + if (result.redirect !== undefined) { + const { redirect } = result; + const response = json({ redirect }); + if (result.verifier) { + response.headers.append( + "set-cookie", + cookie.serialize("verifier", result.verifier, { + ...cookieConfig, + maxAge: cookieConfig?.maxAge, + }) + ); + } + logVerbose(`Redirecting to ${redirect}`, verbose); + return response; + } else if (result.tokens !== undefined) { + // The server doesn't share the refresh token with the client + // for added security - the client has to use the server + // endpoint to refresh the token + logVerbose( + result.tokens === null + ? `No tokens returned, clearing auth cookies` + : `Setting auth cookies with returned tokens`, + verbose, + ); + + const response = json({ + tokens: + result.tokens !== null + ? { token: result.tokens.token, refreshToken: "dummy" } + : null, + }); + + if (result.tokens !== null) { + setAuthCookies( + response, + result.tokens.token, + result.tokens.refreshToken, + ); + } else { + setAuthCookies(response, null, null); + } + + return response; + } + return json(result); + } else { + // Handle signOut + try { + const client = setupClient({ + url: convexUrl, + token + }); + await client.action(action, args); + } catch (error) { + console.error(`Hit error while running \`auth:signOut\`:`); + console.error(error); + } + + logVerbose(`Clearing auth cookies`, verbose); + const response = json(null); + setAuthCookies(response, null, null); + return response; } } @@ -179,8 +275,7 @@ export function createConvexAuthHandlers({ */ const handleAuthAction: RequestHandler = async (event) => { try { - const body = await event.request.json(); - const { action, args } = body; + const { action, args } = await event.request.json(); // Only allow auth-related actions to be proxied if (!action.startsWith("auth:")) { @@ -188,7 +283,7 @@ export function createConvexAuthHandlers({ } const result = await proxyAuthActionToConvex(event, action, args); - return json(result); + return result; } catch (e) { console.error("Error in auth action handler:", e); throw error(500, "Error processing auth action"); @@ -254,21 +349,27 @@ interface HandleArgs { export function createConvexAuthHooks({ convexUrl = getConvexUrl(), apiRoute = "/api/auth", - cookieOptions, -}: { - convexUrl?: string; - apiRoute?: string; - cookieOptions?: CookieOptions; -} = {}) { - const handlers = createConvexAuthHandlers({ convexUrl, cookieOptions }); + cookieConfig, + verbose = false, +}: ConvexAuthHooksOptions = {}) { + const handlers = createConvexAuthHandlers({ convexUrl, cookieConfig, verbose }); /** * Request handler for the hooks.server.ts handle function */ async function handleAuth({ event, resolve }: HandleArgs) { + logVerbose( + `Begin middleware for request with URL ${event.url.toString()}`, + verbose, + ); // If this is the auth API route, handle the auth action - if (event.url.pathname === apiRoute && event.request.method === "POST") { - return handlers.handleAuthAction(event); + if (shouldProxyAuthAction(event, apiRoute)) { + logVerbose( + `Proxying auth action to Convex, path matches ${apiRoute} with or without trailing slash`, + verbose, + ); + const result = await handlers.handleAuthAction(event); + return result; } // For other routes, just continue diff --git a/src/sveltekit/server/index.ts b/src/sveltekit/server/index.ts index ebe02aed..3203b92b 100644 --- a/src/sveltekit/server/index.ts +++ b/src/sveltekit/server/index.ts @@ -1,27 +1,62 @@ /** * Server-side handlers for Convex Auth in SvelteKit */ -import { - createConvexAuthHandlers, +import { + createConvexAuthHandlers, createConvexAuthHooks, - convexAuthSvelteKitServerState -} from './handlers.js'; -import { - createRouteMatcher, - type RouteMatcherParam, - type RouteMatcherFn -} from './routeMatcher.js'; + convexAuthSvelteKitServerState, +} from "./handlers.js"; +import { + createRouteMatcher, + type RouteMatcherParam, + type RouteMatcherFn, +} from "./routeMatcher.js"; + +/** + * Options for the `createConvexAuthHooks` function. + */ +export type ConvexAuthHooksOptions = { + /** + * The URL of the Convex deployment to use for authentication. + * + * Defaults to `process.env.NEXT_PUBLIC_CONVEX_URL`. + */ + convexUrl?: string; + /** + * You can customize the route path that handles authentication + * actions via this option and the `apiRoute` prop of `ConvexAuthNextjsProvider`. + * + * Defaults to `/api/auth`. + */ + apiRoute?: string; + /** + * The cookie config to use for the auth cookies. + * + * `maxAge` is the number of seconds the cookie will be valid for. If this is not set, the cookie will be a session cookie. + * + * See [MDN Web Docs](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies#defining_the_lifetime_of_a_cookie) + * for more information. + */ + cookieConfig?: { + path?: string; + httpOnly?: boolean; + secure?: boolean; + maxAge?: number; + sameSite?: "strict" | "lax" | "none"; + domain?: string; + }; + /** + * Turn on debugging logs. + */ + verbose?: boolean; +}; // Export server handlers export { createConvexAuthHandlers, createConvexAuthHooks, - convexAuthSvelteKitServerState + convexAuthSvelteKitServerState, }; // Export route matchers (equivalent to NextJS implementation) -export { - createRouteMatcher, - type RouteMatcherParam, - type RouteMatcherFn -}; +export { createRouteMatcher, type RouteMatcherParam, type RouteMatcherFn }; diff --git a/src/sveltekit/server/proxy.ts b/src/sveltekit/server/proxy.ts new file mode 100644 index 00000000..ed483215 --- /dev/null +++ b/src/sveltekit/server/proxy.ts @@ -0,0 +1,17 @@ +import { RequestEvent } from "@sveltejs/kit"; + +export function shouldProxyAuthAction(event: RequestEvent, apiRoute: string) { + // Handle both with and without trailing slash since this could be configured either way. + // https://nextjs.org/docs/app/api-reference/next-config-js/trailingSlash + const requestUrl = event.url; + if (apiRoute.endsWith("/")) { + return ( + requestUrl.pathname === apiRoute || + requestUrl.pathname === apiRoute.slice(0, -1) + ); + } else { + return ( + requestUrl.pathname === apiRoute || requestUrl.pathname === apiRoute + "/" + ); + } +} diff --git a/src/sveltekit/server/utilts.ts b/src/sveltekit/server/utilts.ts new file mode 100644 index 00000000..ada35b41 --- /dev/null +++ b/src/sveltekit/server/utilts.ts @@ -0,0 +1,145 @@ +import { env } from "$env/dynamic/public"; +import { RequestEvent } from "@sveltejs/kit"; +import { ConvexHttpClient } from "convex/browser"; + +// For debug logging +export function logVerbose(message: string, verbose: boolean) { + if (verbose) { + console.debug( + `[verbose] ${new Date().toISOString()} [ConvexAuthSvelteKit] ${message}`, + ); + } +} + +// TODO: Move this to convex-auth +/** + * Options to {@link preloadQuery}, {@link fetchQuery}, {@link fetchMutation} and {@link fetchAction}. + */ +export type SveltekitOptions = { + /** + * The JWT-encoded OpenID Connect authentication token to use for the function call. + */ + token?: string; + /** + * The URL of the Convex deployment to use for the function call. + * Defaults to `process.env.NEXT_PUBLIC_CONVEX_URL`. + */ + url?: string; + + /** + * @internal + */ + adminToken?: string; + /** + * Skip validating that the Convex deployment URL looks like + * `https://happy-animal-123.convex.cloud` or localhost. + * + * This can be useful if running a self-hosted Convex backend that uses a different + * URL. + * + * The default value is `false` + */ + skipConvexDeploymentUrlCheck?: boolean; +}; + +export function setupClient(options?: SveltekitOptions) { + const client = new ConvexHttpClient( + getConvexUrl(options?.url, options?.skipConvexDeploymentUrlCheck ?? false), + ); + if (options?.token !== undefined) { + client.setAuth(options.token); + } +// TODO: Somehow .adminToken and .setFetchOptions are not available in ConvexHttpClient although it is in the nextjs version +// if (options.adminToken !== undefined) { +// client.setAdminAuth(options.adminToken); +// } +// client.setFetchOptions({ cache: "no-store" }); + return client; +} + +/** + * Helper to get the Convex URL from environment variables + * This allows SvelteKit implementations to automatically use the URL + */ +export function getConvexUrl( + deploymentUrl?: string, + skipConvexDeploymentUrlCheck?: boolean, +): string { + let url = deploymentUrl; + // Check for the SvelteKit environment variable (available in SvelteKit apps) + if (!url && typeof env.PUBLIC_CONVEX_URL !== "undefined") { + url = env.PUBLIC_CONVEX_URL; + } + + // Try to load from process.env if available in the environment + if ( + !url && + typeof process !== "undefined" && + process.env && + process.env.PUBLIC_CONVEX_URL + ) { + url = process.env.PUBLIC_CONVEX_URL; + } + + if (!url) { + throw new Error( + "Convex URL not provided. Either pass convexUrl parameter or set PUBLIC_CONVEX_URL environment variable.", + ); + } + + if (!skipConvexDeploymentUrlCheck) { + validateDeploymentUrl(url); + } + return url; +} + +export function validateDeploymentUrl(deploymentUrl: string) { + // TODO: react native is not relevant in sveltekit (But maybe in svelte native), so eventually we need to adjust this section + // Don't use things like `new URL(deploymentUrl).hostname` since these aren't + // supported by React Native's JS environment + if (typeof deploymentUrl === "undefined") { + throw new Error( + `Client created with undefined deployment address. If you used an environment variable, check that it's set.`, + ); + } + if (typeof deploymentUrl !== "string") { + throw new Error( + `Invalid deployment address: found ${deploymentUrl as any}".`, + ); + } + if ( + !(deploymentUrl.startsWith("http:") || deploymentUrl.startsWith("https:")) + ) { + throw new Error( + `Invalid deployment address: Must start with "https://" or "http://". Found "${deploymentUrl}".`, + ); + } + + // Most clients should connect to ".convex.cloud". But we also support localhost and + // custom custom. We validate the deployment url is a valid url, which is the most + // common failure pattern. + try { + new URL(deploymentUrl); + } catch { + throw new Error( + `Invalid deployment address: "${deploymentUrl}" is not a valid URL. If you believe this URL is correct, use the \`skipConvexDeploymentUrlCheck\` option to bypass this.`, + ); + } + + // If a user uses .convex.site, this is very likely incorrect. + if (deploymentUrl.endsWith(".convex.site")) { + throw new Error( + `Invalid deployment address: "${deploymentUrl}" ends with .convex.site, which is used for HTTP Actions. Convex deployment URLs typically end with .convex.cloud? If you believe this URL is correct, use the \`skipConvexDeploymentUrlCheck\` option to bypass this.`, + ); + } +} + +export function isCorsRequest(event: RequestEvent) { + const origin = event.request.headers.get("Origin"); + const originURL = origin ? new URL(origin) : null; + return ( + originURL !== null && + (originURL.host !== event.request.headers.get("Host") || + originURL.protocol !== new URL(event.request.url).protocol) + ); +} From d1a289a0ffa0faf174aa30daf27ea09e1b7c0611 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 24 Apr 2025 15:49:38 +0200 Subject: [PATCH 38/88] Remove unused imports from product page server handler --- test-sveltekit/src/routes/product/+page.server.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test-sveltekit/src/routes/product/+page.server.ts b/test-sveltekit/src/routes/product/+page.server.ts index 4adc0dd6..3ea17d50 100644 --- a/test-sveltekit/src/routes/product/+page.server.ts +++ b/test-sveltekit/src/routes/product/+page.server.ts @@ -1,6 +1,5 @@ -import { api } from '../../../convex/_generated/api'; import { createConvexAuthHooks } from '@convex-dev/auth/sveltekit/server'; -import { redirect, error } from '@sveltejs/kit'; +import { redirect } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; import { PUBLIC_CONVEX_URL } from '$env/static/public'; From a1fde73cbc67532ad441c9af6e7f05fc225e61aa Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 24 Apr 2025 16:18:33 +0200 Subject: [PATCH 39/88] Refactor client setup and improve auth initialization flow --- src/svelte/client.svelte.ts | 186 ++++++++++++++++++++++++------------ src/svelte/index.svelte.ts | 38 +------- src/sveltekit/client.ts | 16 +++- 3 files changed, 138 insertions(+), 102 deletions(-) diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index 938552ec..98a42589 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -10,6 +10,8 @@ import { AuthClient } from "./clientType.js"; import type { TokenStorage } from "./index.svelte"; import isNetworkError from "is-network-error"; import { Value } from "convex/values"; +import { setupConvex } from "convex-svelte"; +import { ConvexClient, ConvexClientOptions } from "convex/browser"; // Retry after this much time, based on the retry number. const RETRY_BACKOFF = [500, 2000]; // In ms @@ -49,7 +51,7 @@ export function createAuthClient({ const state = $state({ token: serverState?._state.token ?? null, isLoading: serverState?._state.token === null, - isRefreshingToken: false + isRefreshingToken: false, }); const isAuthenticated = $derived(state.token !== null); @@ -64,8 +66,8 @@ export function createAuthClient({ // Create storage helpers with namespace const { storageSet, storageGet, storageRemove } = useNamespacedStorage( - storage, - storageNamespace + storage, + storageNamespace, ); // Token management @@ -73,11 +75,11 @@ export function createAuthClient({ args: | { shouldStore: true; tokens: { token: string; refreshToken: string } } | { shouldStore: false; tokens: { token: string } } - | { shouldStore: boolean; tokens: null } + | { shouldStore: boolean; tokens: null }, ) => { const wasAuthenticated = state.token !== null; let newToken: string | null; - + if (args.tokens === null) { state.token = null; if (args.shouldStore) { @@ -92,25 +94,27 @@ export function createAuthClient({ const { refreshToken } = args.tokens; await storageSet(JWT_STORAGE_KEY, value); await storageSet(REFRESH_TOKEN_STORAGE_KEY, refreshToken); - + // Store server state fetch time if (serverState && !state.isRefreshingToken) { - await storageSet(SERVER_STATE_FETCH_TIME_STORAGE_KEY, `${serverState._timeFetched}`); + await storageSet( + SERVER_STATE_FETCH_TIME_STORAGE_KEY, + `${serverState._timeFetched}`, + ); } } newToken = value; } - + if (wasAuthenticated !== (newToken !== null)) { await onChange?.(); } - + state.isLoading = false; }; // Load tokens from storage on initialization onMount(() => { - const loadTokens = async () => { if (serverState?._state) { // Use server state @@ -153,34 +157,34 @@ export function createAuthClient({ if (typeof window === "undefined") { return; } - + const url = new URL(window.location.href); const code = url.searchParams.get("code"); - + if (code) { logVerbose("found code in URL, removing"); url.searchParams.delete("code"); await replaceURL( - url.pathname + url.search + (url.hash ? url.hash : "") + url.pathname + url.search + (url.hash ? url.hash : ""), ); - + // Get verifier from storage const verifier = await storageGet(VERIFIER_STORAGE_KEY); await storageRemove(VERIFIER_STORAGE_KEY); - + logVerbose(`verifying code, have verifier: ${!!verifier}`); try { const response = await verifyCode({ code, verifier: verifier ?? undefined, }); - + // Extract tokens from the response if (response.tokens) { // If tokens is available in the response - await setToken({ - shouldStore: true, - tokens: response.tokens + await setToken({ + shouldStore: true, + tokens: response.tokens, }); logVerbose("signed in with code from URL using tokens object"); } else { @@ -189,7 +193,7 @@ export function createAuthClient({ state.isLoading = false; return; } - + logVerbose("signed in with code from URL"); } catch (e) { console.error("Failed to verify code from URL:", e); @@ -218,7 +222,7 @@ export function createAuthClient({ if (event.key === storageKey(JWT_STORAGE_KEY, storageNamespace)) { const value = event.newValue; logVerbose(`synced access token, is null: ${value === null}`); - + // Update our state without writing back to storage void setToken({ shouldStore: false, @@ -231,7 +235,7 @@ export function createAuthClient({ return () => window.removeEventListener("storage", storageListener); }); - // Prevent accidental navigation away from the page during token refresh. + // Prevent accidental navigation away from the page during token refresh. $effect(() => { if (typeof window === "undefined") { return; @@ -240,7 +244,7 @@ export function createAuthClient({ const beforeUnloadListener = (e: BeforeUnloadEvent) => { if (state.isRefreshingToken) { e.preventDefault(); - const confirmationMessage = + const confirmationMessage = "Are you sure you want to leave? Your changes may not be saved."; e.returnValue = confirmationMessage; return confirmationMessage; @@ -248,18 +252,19 @@ export function createAuthClient({ }; window.addEventListener("beforeunload", beforeUnloadListener); - return () => window.removeEventListener("beforeunload", beforeUnloadListener); + return () => + window.removeEventListener("beforeunload", beforeUnloadListener); }); // Auth methods const verifyCode = async ( - args: { code: string; verifier?: string } | { refreshToken: string } + args: { code: string; verifier?: string } | { refreshToken: string }, ) => { let lastError; // Retry the call if it fails due to a network error. - // This is especially common in mobile apps where an app is backgrounded - // while making a call and hits a network error, but will succeed with a - // retry once the app is brought to the foreground. + // This is especially common in mobile apps where an app is backgrounded + // while making a call and hits a network error, but will succeed with a + // retry once the app is brought to the foreground. let retry = 0; while (retry < RETRY_BACKOFF.length) { try { @@ -267,7 +272,7 @@ export function createAuthClient({ "auth:signIn" as unknown as SignInAction, "code" in args ? { params: { code: args.code }, verifier: args.verifier } - : args + : args, ); } catch (e) { lastError = e; @@ -277,7 +282,7 @@ export function createAuthClient({ const wait = RETRY_BACKOFF[retry] + RETRY_JITTER * Math.random(); retry++; logVerbose( - `verifyCode failed with network error, retry ${retry} of ${RETRY_BACKOFF.length} in ${wait}ms` + `verifyCode failed with network error, retry ${retry} of ${RETRY_BACKOFF.length} in ${wait}ms`, ); await new Promise((resolve) => setTimeout(resolve, wait)); } @@ -303,7 +308,7 @@ export function createAuthClient({ }): Promise => { const { forceRefreshToken = false } = options ?? {}; logVerbose(`fetchAccessToken forceRefreshToken=${forceRefreshToken}`); - + // Return the existing token if we have one and aren't forcing a refresh if (state.token !== null && !forceRefreshToken) { return state.token; @@ -311,7 +316,7 @@ export function createAuthClient({ try { state.isRefreshingToken = true; - + // Get the refresh token from storage const refreshToken = await storageGet(REFRESH_TOKEN_STORAGE_KEY); if (!refreshToken) { @@ -320,9 +325,11 @@ export function createAuthClient({ logVerbose("using refresh token to get new access token"); const response = await verifyCode({ refreshToken }); - + if (response.tokens) { - logVerbose(`got new access token, is null: ${response.tokens.token === null}`); + logVerbose( + `got new access token, is null: ${response.tokens.token === null}`, + ); await setToken({ shouldStore: true, tokens: response.tokens }); return response.tokens.token; } else { @@ -331,7 +338,7 @@ export function createAuthClient({ } } catch (e) { console.error("Failed to refresh token:", e); - + // Clear tokens on failure await setToken({ shouldStore: true, tokens: null }); return null; @@ -342,22 +349,23 @@ export function createAuthClient({ const signIn = async ( provider: string, - params?: FormData | Record + params?: FormData | Record, ) => { logVerbose(`signIn provider=${provider}`); - + try { // Get verifier if it exists const verifier = (await storageGet(VERIFIER_STORAGE_KEY)) ?? undefined; await storageRemove(VERIFIER_STORAGE_KEY); - - const finalParams = params instanceof FormData - ? Object.fromEntries(params.entries()) - : params ?? {}; - + + const finalParams = + params instanceof FormData + ? Object.fromEntries(params.entries()) + : (params ?? {}); + const result = await client.authenticatedCall( "auth:signIn" as unknown as SignInAction, - { provider, params: finalParams, verifier } + { provider, params: finalParams, verifier }, ); if (result.redirect !== undefined) { @@ -367,21 +375,23 @@ export function createAuthClient({ if (result.verifier) { await storageSet(VERIFIER_STORAGE_KEY, result.verifier); } - + if (typeof window !== "undefined") { window.location.href = url.toString(); } - + return { signingIn: false, redirect: url }; // User will need to complete the flow } else if (result.tokens !== undefined) { // For direct sign-in flows or token refresh - logVerbose(`signed in and got tokens, is null: ${result.tokens === null}`); + logVerbose( + `signed in and got tokens, is null: ${result.tokens === null}`, + ); await setToken({ shouldStore: true, tokens: result.tokens }); - + // Return success based on whether we got valid tokens return { signingIn: result.tokens !== null }; } - + // Default case - not signed in return { signingIn: false }; } catch (e) { @@ -392,14 +402,13 @@ export function createAuthClient({ const signOut = async (): Promise => { logVerbose("signOut"); - + try { // This can fail if the backend is unavailable, that's ok we will // still sign out on the client. await client.authenticatedCall( - "auth:signOut" as unknown as SignOutAction + "auth:signOut" as unknown as SignOutAction, ); - } catch (e) { // Ignore any errors, they are usually caused by being // already signed out, which is ok. @@ -407,7 +416,7 @@ export function createAuthClient({ logVerbose(`signOut error (ignored): ${e.message}`); } } - + // Always clear tokens locally, even if server call failed logVerbose(`signed out, erasing tokens`); await setToken({ shouldStore: true, tokens: null }); @@ -415,9 +424,15 @@ export function createAuthClient({ // Expose the auth API const authApi = { - get isLoading() { return state.isLoading; }, - get isAuthenticated() { return isAuthenticated; }, - get token() { return state.token; }, + get isLoading() { + return state.isLoading; + }, + get isAuthenticated() { + return isAuthenticated; + }, + get token() { + return state.token; + }, fetchAccessToken, signIn, signOut, @@ -433,7 +448,7 @@ export function useAuth() { const authClient = getContext(AUTH_CONTEXT_KEY); if (!authClient) { throw new Error( - "No ConvexAuth client found in context. Did you forget to use createAuthProvider?" + "No ConvexAuth client found in context. Did you forget to use createAuthProvider?", ); } return authClient; @@ -442,7 +457,9 @@ export function useAuth() { /** * Set the Convex Auth client in the context */ -export function setConvexAuthContext(authClient: ReturnType) { +export function setConvexAuthContext( + authClient: ReturnType, +) { setContext(AUTH_CONTEXT_KEY, authClient); return authClient; } @@ -467,7 +484,7 @@ function storageKey(key: string, namespace: string): string { function createInMemoryStorage(): TokenStorage { // Create a closure around the map to maintain state const map = new Map(); - + return { getItem: (key) => map.get(key) ?? null, setItem: (key, value) => { @@ -482,13 +499,16 @@ function createInMemoryStorage(): TokenStorage { /** * Helper to create namespaced storage functions */ -function useNamespacedStorage(persistentStorage: TokenStorage | null, namespace: string) { +function useNamespacedStorage( + persistentStorage: TokenStorage | null, + namespace: string, +) { // Use either provided storage or create in-memory storage const storage = persistentStorage ?? createInMemoryStorage(); - + // Normalize namespace to alphanumeric only (for compatibility with RN) const normalizedNamespace = namespace.replace(/[^a-zA-Z0-9]/g, ""); - + const storageGet = async (key: string): Promise => { try { const value = await storage.getItem(storageKey(key, normalizedNamespace)); @@ -521,7 +541,7 @@ function useNamespacedStorage(persistentStorage: TokenStorage | null, namespace: // In the browser, executes the callback as the only tab / frame at a time. export async function browserMutex( key: string, - callback: () => Promise + callback: () => Promise, ): Promise { if (typeof window === "undefined") { return callback(); @@ -606,3 +626,45 @@ async function manualMutex( }); return outerPromise; } + +export const setupConvexClient = ( + convexUrl: string, + options?: ConvexClientOptions, +) => { + // Client resolution priority: + // 1. Client from context + // 2. Try to create one if setupConvex is available + + let client: ConvexClient | null = null; + + // Try to get client from context + try { + client = getContext("$$_convexClient"); + } catch (e) { + // Context not available or no client in context + } + + // If no client and convexUrl is provided, try to create one using setupConvex + if (!client && convexUrl) { + try { + setupConvex(convexUrl, options); + // After setting up, try to get the client from context + try { + client = getContext("$$_convexClient"); + } catch (e) { + // Context not available after setup + } + } catch (e) { + console.warn("Failed to create Convex client:", e); + } + } + + // If we still don't have a client, throw an error + if (!client) { + throw new Error( + "No ConvexClient was provided. Either pass one to setupConvexAuth or call setupConvex() first.", + ); + } + + return client; +}; diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index 1dadb79f..d73e66b8 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -5,14 +5,13 @@ */ import { ConvexClient, ConvexClientOptions } from "convex/browser"; -import { getContext } from "svelte"; import { createAuthClient, setConvexAuthContext, getConvexAuthContext, + setupConvexClient, } from "./client.svelte.js"; import { AuthClient } from "./clientType.js"; -import { setupConvex } from "convex-svelte"; /** * Parameters for sign-in methods @@ -129,40 +128,9 @@ export function setupConvexAuth({ options?: ConvexClientOptions; }) { - // Client resolution priority: - // 1. Client passed directly - // 2. Client from context - // 3. Try to create one if setupConvex is available - - // If no client provided, try to get from context - if (!client) { - try { - client = getContext("$$_convexClient"); - } catch (e) { - // Context not available or no client in context - } - } - - // If still no client and convexUrl is provided, try to create one using setupConvex - if (!client && convexUrl) { - try { - setupConvex(convexUrl, options); - // After setting up, try to get the client from context - try { - client = getContext("$$_convexClient"); - } catch (e) { - // Context not available after setup - } - } catch (e) { - console.warn("Failed to create Convex client:", e); - } - } - - // If we still don't have a client, throw an error + if (!client) { - throw new Error( - "No ConvexClient was provided. Either pass one to setupConvexAuth or call setupConvex() first.", - ); + client = setupConvexClient(convexUrl, options); } // Create auth client diff --git a/src/sveltekit/client.ts b/src/sveltekit/client.ts index fc540e8f..b098071d 100644 --- a/src/sveltekit/client.ts +++ b/src/sveltekit/client.ts @@ -2,7 +2,11 @@ * SvelteKit implementation of Convex Auth client. */ import { invalidateAll, replaceState } from "$app/navigation"; -import { createAuthClient, setConvexAuthContext } from "../svelte/client.svelte.js"; +import { + createAuthClient, + setConvexAuthContext, + setupConvexClient, +} from "../svelte/client.svelte.js"; import { AuthClient } from "../svelte/clientType.js"; import { ConvexClient, ConvexClientOptions } from "convex/browser"; @@ -52,7 +56,7 @@ export function createSvelteKitAuthClient({ // Initialize the Convex client if not provided if (!client) { - client = new ConvexClient(convexUrl, options); + setupConvexClient(convexUrl, options); } // Create the auth client with SvelteKit-specific config @@ -75,8 +79,10 @@ export function createSvelteKitAuthClient({ storageNamespace: storageNamespace ?? requireEnv( - typeof process !== "undefined" ? process.env.PUBLIC_CONVEX_URL : undefined, - "PUBLIC_CONVEX_URL" + typeof process !== "undefined" + ? process.env.PUBLIC_CONVEX_URL + : undefined, + "PUBLIC_CONVEX_URL", ), replaceURL: (url) => { if (typeof window !== "undefined") { @@ -93,7 +99,7 @@ export function createSvelteKitAuthClient({ // Set the auth context to ensure it's available immediately setConvexAuthContext(auth); - + return auth; } From 476e14576f6bbc3c57a708c84fa6a0789916aeb6 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 24 Apr 2025 16:30:59 +0200 Subject: [PATCH 40/88] Formatted --- test-sveltekit/src/routes/+layout.svelte | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test-sveltekit/src/routes/+layout.svelte b/test-sveltekit/src/routes/+layout.svelte index 04312201..9503941f 100644 --- a/test-sveltekit/src/routes/+layout.svelte +++ b/test-sveltekit/src/routes/+layout.svelte @@ -1,12 +1,15 @@ {@render children()} From 59a4017f535048a77a7bf452856a7856d265e4ab Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 24 Apr 2025 16:34:55 +0200 Subject: [PATCH 41/88] Refactor auth usage --- test-sveltekit/src/routes/+page.svelte | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test-sveltekit/src/routes/+page.svelte b/test-sveltekit/src/routes/+page.svelte index 4e871004..bbc45514 100644 --- a/test-sveltekit/src/routes/+page.svelte +++ b/test-sveltekit/src/routes/+page.svelte @@ -1,14 +1,14 @@
    - {#if isAuthenticated} + {#if auth.isAuthenticated}

    You are authenticated!

    Product - + {:else}

    You are not authenticated.

    Sign In From 48a570d33817b3bcfaa09b41aca0ec4e40be90ff Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 24 Apr 2025 16:38:30 +0200 Subject: [PATCH 42/88] update GitHub sign-in redirect to home page --- test-sveltekit/src/routes/signin/+page.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-sveltekit/src/routes/signin/+page.svelte b/test-sveltekit/src/routes/signin/+page.svelte index 2566b80b..931011ba 100644 --- a/test-sveltekit/src/routes/signin/+page.svelte +++ b/test-sveltekit/src/routes/signin/+page.svelte @@ -10,7 +10,7 @@

    Sign in or create an account

    - {#if env.PUBLIC_E2E_TEST} From 2a25f4c895bd199ee38f8f59fdfea3c95cee0bba Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 24 Apr 2025 16:57:56 +0200 Subject: [PATCH 43/88] Update store import from $app/stores to $app/state --- test-sveltekit/src/routes/product/+layout.svelte | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/test-sveltekit/src/routes/product/+layout.svelte b/test-sveltekit/src/routes/product/+layout.svelte index 01911451..05a49e9e 100644 --- a/test-sveltekit/src/routes/product/+layout.svelte +++ b/test-sveltekit/src/routes/product/+layout.svelte @@ -1,5 +1,5 @@
    @@ -7,7 +7,7 @@ - + {@render children?.()}
    From f8f81c275f7a73a773c4f5278864f2da026d1a71 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 26 Apr 2025 13:11:07 +0200 Subject: [PATCH 45/88] Fix auth token fetching by setting auth client on Convex client initialization --- src/svelte/index.svelte.ts | 2 ++ src/sveltekit/client.ts | 4 +++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index d73e66b8..dd903c15 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -159,6 +159,8 @@ export function setupConvexAuth({ }, }); + client.setAuth(auth.fetchAccessToken) + // Set auth context setConvexAuthContext(auth); diff --git a/src/sveltekit/client.ts b/src/sveltekit/client.ts index b098071d..6f0b30bd 100644 --- a/src/sveltekit/client.ts +++ b/src/sveltekit/client.ts @@ -56,7 +56,7 @@ export function createSvelteKitAuthClient({ // Initialize the Convex client if not provided if (!client) { - setupConvexClient(convexUrl, options); + client = setupConvexClient(convexUrl, { disabled: false, ...options }); } // Create the auth client with SvelteKit-specific config @@ -97,6 +97,8 @@ export function createSvelteKitAuthClient({ }, }); + client.setAuth(auth.fetchAccessToken); + // Set the auth context to ensure it's available immediately setConvexAuthContext(auth); From 36a00b309c4c77286c4a8537ee23d8105308f4bd Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sun, 27 Apr 2025 16:08:02 +0200 Subject: [PATCH 46/88] Make convexUrl optional and use PUBLIC_CONVEX_URL env var as fallback --- src/svelte/client.svelte.ts | 2 +- src/sveltekit/client.ts | 33 ++++++++++-------------- src/sveltekit/index.ts | 2 +- test-sveltekit/src/routes/+layout.svelte | 2 -- 4 files changed, 15 insertions(+), 24 deletions(-) diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index 98a42589..7d0de1da 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -645,7 +645,7 @@ export const setupConvexClient = ( } // If no client and convexUrl is provided, try to create one using setupConvex - if (!client && convexUrl) { + if (!client) { try { setupConvex(convexUrl, options); // After setting up, try to get the client from context diff --git a/src/sveltekit/client.ts b/src/sveltekit/client.ts index 6f0b30bd..bb2b6b4f 100644 --- a/src/sveltekit/client.ts +++ b/src/sveltekit/client.ts @@ -2,6 +2,7 @@ * SvelteKit implementation of Convex Auth client. */ import { invalidateAll, replaceState } from "$app/navigation"; +import { env } from "$env/dynamic/public"; import { createAuthClient, setConvexAuthContext, @@ -35,9 +36,18 @@ export function createSvelteKitAuthClient({ storage?: "localStorage" | "inMemory"; storageNamespace?: string; client?: ConvexClient; - convexUrl: string; + convexUrl?: string; options?: ConvexClientOptions; }) { + const url = + convexUrl ?? + env.PUBLIC_CONVEX_URL ?? + (() => { + throw new Error( + "No Convex URL provided. Either pass convexUrl parameter or set PUBLIC_CONVEX_URL environment variable.", + ); + })(); + const call: AuthClient["authenticatedCall"] = async (action, args) => { const params = { action, args }; const response = await fetch(apiRoute, { @@ -56,7 +66,7 @@ export function createSvelteKitAuthClient({ // Initialize the Convex client if not provided if (!client) { - client = setupConvexClient(convexUrl, { disabled: false, ...options }); + client = setupConvexClient(url, { disabled: false, ...options }); } // Create the auth client with SvelteKit-specific config @@ -76,14 +86,7 @@ export function createSvelteKitAuthClient({ : storage === "inMemory" ? null : window.localStorage, - storageNamespace: - storageNamespace ?? - requireEnv( - typeof process !== "undefined" - ? process.env.PUBLIC_CONVEX_URL - : undefined, - "PUBLIC_CONVEX_URL", - ), + storageNamespace: storageNamespace ?? url, replaceURL: (url) => { if (typeof window !== "undefined") { try { @@ -104,13 +107,3 @@ export function createSvelteKitAuthClient({ return auth; } - -/** - * Validate that required environment variables are present - */ -function requireEnv(value: string | undefined, name: string): string { - if (value === undefined) { - throw new Error(`Missing environment variable \`${name}\``); - } - return value; -} diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts index 2588b893..22ddca43 100644 --- a/src/sveltekit/index.ts +++ b/src/sveltekit/index.ts @@ -63,7 +63,7 @@ export function setupConvexAuth({ * The url of your Convex deployment, often provided * by an environment variable. E.g. `https://small-mouse-123.convex.cloud`. */ - convexUrl: string; + convexUrl?: string; options?: ConvexClientOptions }) { // Initialize the auth client with SvelteKit-specific configuration diff --git a/test-sveltekit/src/routes/+layout.svelte b/test-sveltekit/src/routes/+layout.svelte index 34dbb123..9c3a142d 100644 --- a/test-sveltekit/src/routes/+layout.svelte +++ b/test-sveltekit/src/routes/+layout.svelte @@ -1,6 +1,5 @@
    - {@render children()} - -
    - -
    - {@render children()} (openState = e.open)} positioning={{ placement: 'top' }} - triggerBase="btn preset-tonal" + triggerBase="btn" contentBase="card bg-surface-200-800 p-4 space-y-4 max-w-[320px]" arrow arrowBackground="!bg-surface-200 dark:!bg-surface-800" > - {#snippet trigger()}{/snippet} + {#snippet trigger()} + + {/snippet} {#snippet content()} -
    {@render children()}
    +
    {data.name}

    - + {/snippet}
    diff --git a/test-sveltekit/src/routes/product/+page.svelte b/test-sveltekit/src/routes/product/+page.svelte index 5db60d66..55461c0b 100644 --- a/test-sveltekit/src/routes/product/+page.svelte +++ b/test-sveltekit/src/routes/product/+page.svelte @@ -12,7 +12,7 @@
    - {viewer.data.name} +
    From 06290d3e8da5fefdbbd28c9466e6848cfe862db0 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Wed, 30 Apr 2025 10:59:01 +0200 Subject: [PATCH 57/88] Fix import paths --- test-sveltekit/src/{routes/product => lib}/Chat/Chat.svelte | 0 .../src/{routes/product => lib}/Chat/ChatIntro.svelte | 2 +- .../src/{routes/product => lib}/Chat/Message.svelte | 0 .../src/{routes/product => lib}/Chat/MessageList.svelte | 0 .../src/{routes/product => lib}/Chat/randomName.ts | 0 test-sveltekit/src/{components => lib}/UserMenu.svelte | 4 ---- test-sveltekit/src/lib/index.ts | 1 - test-sveltekit/src/routes/product/+page.svelte | 6 +++--- 8 files changed, 4 insertions(+), 9 deletions(-) rename test-sveltekit/src/{routes/product => lib}/Chat/Chat.svelte (100%) rename test-sveltekit/src/{routes/product => lib}/Chat/ChatIntro.svelte (75%) rename test-sveltekit/src/{routes/product => lib}/Chat/Message.svelte (100%) rename test-sveltekit/src/{routes/product => lib}/Chat/MessageList.svelte (100%) rename test-sveltekit/src/{routes/product => lib}/Chat/randomName.ts (100%) rename test-sveltekit/src/{components => lib}/UserMenu.svelte (96%) delete mode 100644 test-sveltekit/src/lib/index.ts diff --git a/test-sveltekit/src/routes/product/Chat/Chat.svelte b/test-sveltekit/src/lib/Chat/Chat.svelte similarity index 100% rename from test-sveltekit/src/routes/product/Chat/Chat.svelte rename to test-sveltekit/src/lib/Chat/Chat.svelte diff --git a/test-sveltekit/src/routes/product/Chat/ChatIntro.svelte b/test-sveltekit/src/lib/Chat/ChatIntro.svelte similarity index 75% rename from test-sveltekit/src/routes/product/Chat/ChatIntro.svelte rename to test-sveltekit/src/lib/Chat/ChatIntro.svelte index 6e607dfb..18ffe673 100644 --- a/test-sveltekit/src/routes/product/Chat/ChatIntro.svelte +++ b/test-sveltekit/src/lib/Chat/ChatIntro.svelte @@ -1,6 +1,6 @@

    Chat

    -
    diff --git a/test-sveltekit/src/routes/product/Chat/Message.svelte b/test-sveltekit/src/lib/Chat/Message.svelte similarity index 100% rename from test-sveltekit/src/routes/product/Chat/Message.svelte rename to test-sveltekit/src/lib/Chat/Message.svelte diff --git a/test-sveltekit/src/routes/product/Chat/MessageList.svelte b/test-sveltekit/src/lib/Chat/MessageList.svelte similarity index 100% rename from test-sveltekit/src/routes/product/Chat/MessageList.svelte rename to test-sveltekit/src/lib/Chat/MessageList.svelte diff --git a/test-sveltekit/src/routes/product/Chat/randomName.ts b/test-sveltekit/src/lib/Chat/randomName.ts similarity index 100% rename from test-sveltekit/src/routes/product/Chat/randomName.ts rename to test-sveltekit/src/lib/Chat/randomName.ts diff --git a/test-sveltekit/src/components/UserMenu.svelte b/test-sveltekit/src/lib/UserMenu.svelte similarity index 96% rename from test-sveltekit/src/components/UserMenu.svelte rename to test-sveltekit/src/lib/UserMenu.svelte index 6bbd6b6f..54845713 100644 --- a/test-sveltekit/src/components/UserMenu.svelte +++ b/test-sveltekit/src/lib/UserMenu.svelte @@ -30,10 +30,6 @@ } let openState = $state(false); - - function popoverClose() { - openState = false; - }
    diff --git a/test-sveltekit/src/lib/index.ts b/test-sveltekit/src/lib/index.ts deleted file mode 100644 index 856f2b6c..00000000 --- a/test-sveltekit/src/lib/index.ts +++ /dev/null @@ -1 +0,0 @@ -// place files you want to import through the `$lib` alias in this folder. diff --git a/test-sveltekit/src/routes/product/+page.svelte b/test-sveltekit/src/routes/product/+page.svelte index 55461c0b..e48435ea 100644 --- a/test-sveltekit/src/routes/product/+page.svelte +++ b/test-sveltekit/src/routes/product/+page.svelte @@ -1,8 +1,8 @@ - {@render children()} +{@render children()} ``` The `setupConvexAuth` function will: @@ -86,11 +81,11 @@ import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; import type { LayoutServerLoad } from './$types'; // Create auth handlers - convexUrl is automatically detected from environment -const { loadAuthState } = createConvexAuthHandlers(); +const { getAuthState } = createConvexAuthHandlers(); // Export load function to provide auth state to layout export const load: LayoutServerLoad = async (event) => { - return loadAuthState(event); + return { authState: await getAuthState(event) }; }; ``` @@ -124,9 +119,10 @@ Use authentication in your pages: {#if isLoading} @@ -203,7 +199,7 @@ const isPublicRoute = createRouteMatcher([ ]); // Create auth hooks -const { handleAuth, convexAuth } = createConvexAuthHooks(); +const { handleAuth, isAuthenticated: isAuthenticatedPromise } = createConvexAuthHooks(); // Custom handle function for auth-first pattern const authFirstPattern: Handle = async ({ event, resolve }) => { @@ -213,8 +209,7 @@ const authFirstPattern: Handle = async ({ event, resolve }) => { } // For all other routes, check authentication - const isAuthenticated = await convexAuth.isAuthenticated(event); - + const isAuthenticated = await isAuthenticatedPromise(event); if (!isAuthenticated) { // Store the original URL for redirect after login const returnUrl = encodeURIComponent(event.url.pathname + event.url.search); @@ -252,11 +247,14 @@ const isProtectedRoute = createRouteMatcher([ '/profile/*path', ]); +// Create auth hooks +const { handleAuth, isAuthenticated: isAuthenticatedPromise } = createConvexAuthHooks(); + // Custom handle function for public-first pattern const publicFirstPattern: Handle = async ({ event, resolve }) => { // Check auth only for protected routes if (isProtectedRoute(event.url.pathname)) { - const isAuthenticated = await convexAuth.isAuthenticated(event); + const isAuthenticated = await isAuthenticatedPromise(event); if (!isAuthenticated) { // Store the original URL for redirect after login @@ -288,7 +286,7 @@ Protect individual pages in their `+page.server.ts`: import { redirect } from '@sveltejs/kit'; import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; -const { isAuthenticated } = createConvexAuthHandlers(); +const { isAuthenticated: isAuthenticatedPromise } = createConvexAuthHandlers(); export async function load(event) { if (!(await isAuthenticated(event))) { @@ -308,7 +306,7 @@ export async function load(event) { ```html {#if isLoading} @@ -355,61 +354,6 @@ export async function load(event) { {/if} ``` -## Advanced Usage - -### Manual Token Handling - -```html - -``` - -### Alternative: Custom API Endpoint - -If you prefer to handle auth requests with a dedicated endpoint (instead of using the hooks approach), create a file at `src/routes/api/auth/+server.ts`: - -```typescript -// src/routes/api/auth/+server.ts -import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; -import type { RequestHandler } from '@sveltejs/kit'; - -// Create auth handlers -const { handleAuthAction } = createConvexAuthHandlers(); - -// Export POST handler for auth requests -export const POST: RequestHandler = handleAuthAction; -``` - -When using this approach, make sure to update your Auth Provider to use the same API route: - -```ts -setupConvexAuth({ serverState: data.authState, apiRoute: "/api/auth" }); -``` - -## Troubleshooting - -### Common Issues - -1. **Auth Tokens Not Persisting**: Ensure cookie options are configured correctly, especially `secure` and `sameSite`. - -2. **CORS Errors**: If your Convex backend is on a different domain, you may need to configure CORS. - -3. **TypeScript Errors with `$env/static/public`**: Make sure you have run your SvelteKit app at least once to generate the proper type definitions. - ### Debug Mode Enable debug logging by setting an environment variable: diff --git a/test-sveltekit/src/hooks.server.ts b/test-sveltekit/src/hooks.server.ts index 180a03d4..ba0d96be 100644 --- a/test-sveltekit/src/hooks.server.ts +++ b/test-sveltekit/src/hooks.server.ts @@ -13,7 +13,7 @@ const { handleAuth, isAuthenticated: isAuthenticatedPromise } = createConvexAuth const authFirstPattern: Handle = async ({ event, resolve }) => { const isAuthenticated = await isAuthenticatedPromise(event); - + if (isSignInPage(event.url.pathname) && isAuthenticated) { redirect(307, '/product'); } diff --git a/test-sveltekit/src/routes/+page.svelte b/test-sveltekit/src/routes/+page.svelte index bbc45514..b80effb4 100644 --- a/test-sveltekit/src/routes/+page.svelte +++ b/test-sveltekit/src/routes/+page.svelte @@ -1,14 +1,15 @@
    - {#if auth.isAuthenticated} + {#if isAuthenticated}

    You are authenticated!

    Product - + {:else}

    You are not authenticated.

    Sign In From c714b396822f287f4266c078427ac9db9308dd32 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Wed, 30 Apr 2025 14:51:19 +0200 Subject: [PATCH 61/88] Update readme --- src/sveltekit/README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 5247f3dc..97311869 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -64,10 +64,10 @@ Set up authentication in your root layout: {@render children()} ``` -The `setupConvexAuth` function will: +The `setupConvexAuth` function will try to create a Convex client in the following order: 1. Use a client you provide directly (if any) 2. Look for a client in Svelte context (if available) -3. Create a new client automatically (if needed and not disabled) +3. Create a new client automatically This makes it work seamlessly with different setup patterns. From dfd83b0a2356a94e042976a007ebe8f62df654ff Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Wed, 30 Apr 2025 15:11:30 +0200 Subject: [PATCH 62/88] Refactor auth proxy logic --- src/sveltekit/server/handlers.ts | 158 +---------------------------- src/sveltekit/server/proxy.ts | 169 +++++++++++++++++++++++++++++++ 2 files changed, 171 insertions(+), 156 deletions(-) diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index e7825996..46bb2485 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -3,22 +3,17 @@ */ import type { RequestEvent } from "@sveltejs/kit"; import type { ConvexAuthServerState } from "../client.js"; -import { json } from "@sveltejs/kit"; import { ConvexAuthHooksOptions } from "./index"; -import { shouldProxyAuthAction } from "./proxy.js"; +import { shouldProxyAuthAction, proxyAuthActionToConvex } from "./proxy.js"; import { getConvexUrl, - isCorsRequest, logVerbose, setupClient, } from "./utils.js"; -import { SignInAction } from "@convex-dev/auth/server"; import { AUTH_TOKEN_COOKIE, AUTH_REFRESH_TOKEN_COOKIE, - AUTH_VERIFIER_COOKIE, setAuthCookies, - setVerifierCookie, defaultCookieOptions, } from "./cookies"; import { IsAuthenticatedQuery } from "../../server/implementation/index.js"; @@ -50,154 +45,6 @@ export function createConvexAuthHandlers({ }; } - /** - * Proxy an auth action to Convex - * Used to forward authentication requests to Convex - */ - async function proxyAuthActionToConvex(event: RequestEvent) { - const { action, args } = await event.request.json(); - logVerbose( - `Proxying auth action to Convex { action: ${action}, args: ${JSON.stringify( - { - ...args, - refreshToken: args?.refreshToken ? "[redacted]" : undefined, - }, - )} }`, - verbose, - ); - - if (isCorsRequest(event.request)) { - return new Response("Invalid origin", { status: 403 }); - } - - if (action !== "auth:signIn" && action !== "auth:signOut") { - logVerbose(`Invalid action ${action}, returning 400`, verbose); - return new Response("Invalid action", { status: 400 }); - } - - let token: string | undefined; - - if (action === "auth:signIn" && args.refreshToken !== undefined) { - // The client has a dummy refreshToken, the real one is only stored in cookies - const refreshToken = event.cookies.get(AUTH_REFRESH_TOKEN_COOKIE); - if (refreshToken === null) { - console.error( - "Convex Auth: Unexpected missing refreshToken cookie during client refresh", - ); - return json({ tokens: null }); - } - args.refreshToken = refreshToken; - } else { - // Make sure the proxy is authenticated if the client is, - // important for signOut and any other logic working with existing sessions - token = event.cookies.get(AUTH_TOKEN_COOKIE) ?? undefined; - } - - // Add verifier from cookie if we're processing a code verification and verifier wasn't already provided - if ( - action === "auth:signIn" && - args.params?.code !== undefined && - !args.verifier - ) { - const verifier = event.cookies.get(AUTH_VERIFIER_COOKIE); - if (verifier) { - args.verifier = verifier; - } - } - - logVerbose( - `Fetching action ${action} with args ${JSON.stringify({ - ...args, - refreshToken: args?.refreshToken ? "[redacted]" : undefined, - })}`, - verbose, - ); - - if (action === "auth:signIn") { - let result: SignInAction["_returnType"]; - // Do not require auth when refreshing tokens or validating a code since they - // are steps in the auth flow - const clientOptions: { url: string; token?: string } = { url: convexUrl }; - if ( - !(args.refreshToken !== undefined || args.params?.code !== undefined) - ) { - clientOptions.token = token; - } - - try { - const client = setupClient(clientOptions); - result = await client.action(action, args); - } catch (error) { - console.error(`Hit error while running \`auth:signIn\`:`); - console.error(error); - logVerbose(`Clearing auth cookies`, verbose); - const response = json(null); - setAuthCookies(response, null, null, cookieConfig, verbose); - return response; - } - - if (result.redirect !== undefined) { - const { redirect } = result; - const response = json({ redirect }); - if (result.verifier) { - // Set the verifier cookie for OAuth PKCE flow - setVerifierCookie(response, result.verifier, cookieConfig, verbose); - } - logVerbose(`Redirecting to ${redirect}`, verbose); - return response; - } else if (result.tokens !== undefined) { - // The server doesn't share the refresh token with the client - // for added security - the client has to use the server - // endpoint to refresh the token - logVerbose( - result.tokens === null - ? `No tokens returned, clearing auth cookies` - : `Setting auth cookies with returned tokens`, - verbose, - ); - - const response = json({ - tokens: - result.tokens !== null - ? { token: result.tokens.token, refreshToken: "dummy" } - : null, - }); - - if (result.tokens !== null) { - setAuthCookies( - response, - result.tokens.token, - result.tokens.refreshToken, - cookieConfig, - verbose, - ); - } else { - setAuthCookies(response, null, null, cookieConfig, verbose); - } - - return response; - } - return json(result); - } else { - // Handle signOut - try { - const client = setupClient({ - url: convexUrl, - token, - }); - await client.action(action, args); - } catch (error) { - console.error(`Hit error while running \`auth:signOut\`:`); - console.error(error); - } - - logVerbose(`Clearing auth cookies`, verbose); - const response = json(null); - setAuthCookies(response, null, null, cookieConfig, verbose); - return response; - } - } - /** * Check if the client is authenticated with Convex */ @@ -231,7 +78,6 @@ export function createConvexAuthHandlers({ return { getAuthState, - proxyAuthActionToConvex, isAuthenticated, }; } @@ -284,7 +130,7 @@ export function createConvexAuthHooks({ `Proxying auth action to Convex, path matches ${apiRoute} with or without trailing slash`, verbose, ); - const result = await handlers.proxyAuthActionToConvex(event); + const result = await proxyAuthActionToConvex(event, convexUrl, cookieConfig, verbose); return result; } logVerbose( diff --git a/src/sveltekit/server/proxy.ts b/src/sveltekit/server/proxy.ts index ed483215..fe26896a 100644 --- a/src/sveltekit/server/proxy.ts +++ b/src/sveltekit/server/proxy.ts @@ -1,4 +1,20 @@ import { RequestEvent } from "@sveltejs/kit"; +import { json } from "@sveltejs/kit"; +import { SignInAction } from "@convex-dev/auth/server"; +import { + AUTH_TOKEN_COOKIE, + AUTH_REFRESH_TOKEN_COOKIE, + AUTH_VERIFIER_COOKIE, + setAuthCookies, + setVerifierCookie, + defaultCookieOptions +} from "./cookies"; +import { + getConvexUrl, + isCorsRequest, + logVerbose, + setupClient +} from "./utils.js"; export function shouldProxyAuthAction(event: RequestEvent, apiRoute: string) { // Handle both with and without trailing slash since this could be configured either way. @@ -15,3 +31,156 @@ export function shouldProxyAuthAction(event: RequestEvent, apiRoute: string) { ); } } + +/** + * Proxy an auth action to Convex + * Used to forward authentication requests to Convex + */ +export async function proxyAuthActionToConvex( + event: RequestEvent, + convexUrl = getConvexUrl(), + cookieConfig = defaultCookieOptions, + verbose = false +) { + const { action, args } = await event.request.json(); + logVerbose( + `Proxying auth action to Convex { action: ${action}, args: ${JSON.stringify( + { + ...args, + refreshToken: args?.refreshToken ? "[redacted]" : undefined, + }, + )} }`, + verbose, + ); + + if (isCorsRequest(event.request)) { + return new Response("Invalid origin", { status: 403 }); + } + + if (action !== "auth:signIn" && action !== "auth:signOut") { + logVerbose(`Invalid action ${action}, returning 400`, verbose); + return new Response("Invalid action", { status: 400 }); + } + + let token: string | undefined; + + if (action === "auth:signIn" && args.refreshToken !== undefined) { + // The client has a dummy refreshToken, the real one is only stored in cookies + const refreshToken = event.cookies.get(AUTH_REFRESH_TOKEN_COOKIE); + if (refreshToken === null) { + console.error( + "Convex Auth: Unexpected missing refreshToken cookie during client refresh", + ); + return json({ tokens: null }); + } + args.refreshToken = refreshToken; + } else { + // Make sure the proxy is authenticated if the client is, + // important for signOut and any other logic working with existing sessions + token = event.cookies.get(AUTH_TOKEN_COOKIE) ?? undefined; + } + + // Add verifier from cookie if we're processing a code verification and verifier wasn't already provided + if ( + action === "auth:signIn" && + args.params?.code !== undefined && + !args.verifier + ) { + const verifier = event.cookies.get(AUTH_VERIFIER_COOKIE); + if (verifier) { + args.verifier = verifier; + } + } + + logVerbose( + `Fetching action ${action} with args ${JSON.stringify({ + ...args, + refreshToken: args?.refreshToken ? "[redacted]" : undefined, + })}`, + verbose, + ); + + if (action === "auth:signIn") { + let result: SignInAction["_returnType"]; + // Do not require auth when refreshing tokens or validating a code since they + // are steps in the auth flow + const clientOptions: { url: string; token?: string } = { url: convexUrl }; + if ( + !(args.refreshToken !== undefined || args.params?.code !== undefined) + ) { + clientOptions.token = token; + } + + try { + const client = setupClient(clientOptions); + result = await client.action(action, args); + } catch (error) { + console.error(`Hit error while running \`auth:signIn\`:`); + console.error(error); + logVerbose(`Clearing auth cookies`, verbose); + const response = json(null); + setAuthCookies(response, null, null, cookieConfig, verbose); + return response; + } + + if (result.redirect !== undefined) { + const { redirect } = result; + const response = json({ redirect }); + if (result.verifier) { + // Set the verifier cookie for OAuth PKCE flow + setVerifierCookie(response, result.verifier, cookieConfig, verbose); + } + logVerbose(`Redirecting to ${redirect}`, verbose); + return response; + } else if (result.tokens !== undefined) { + // The server doesn't share the refresh token with the client + // for added security - the client has to use the server + // endpoint to refresh the token + logVerbose( + result.tokens === null + ? `No tokens returned, clearing auth cookies` + : `Setting auth cookies with returned tokens`, + verbose, + ); + + const response = json({ + tokens: + result.tokens !== null + ? { token: result.tokens.token, refreshToken: "dummy" } + : null, + }); + + if (result.tokens !== null) { + setAuthCookies( + response, + result.tokens.token, + result.tokens.refreshToken, + cookieConfig, + verbose, + ); + } else { + setAuthCookies(response, null, null, cookieConfig, verbose); + } + + return response; + } + return json(result); + } else { + // Handle signOut + try { + const client = setupClient({ + url: convexUrl, + token, + }); + await client.action(action, args); + } catch (error) { + console.error(`Hit error while running \`auth:signOut\`:`); + console.error(error); + } + + logVerbose(`Clearing auth cookies`, verbose); + const response = json(null); + setAuthCookies(response, null, null, cookieConfig, verbose); + return response; + } +} From 5a670abd8a437db3ceb23456ba7dfc5a07a54f78 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Wed, 30 Apr 2025 15:13:37 +0200 Subject: [PATCH 63/88] Remove unused variables --- src/sveltekit/server/handlers.ts | 32 +++++++++++++++----------------- 1 file changed, 15 insertions(+), 17 deletions(-) diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index 46bb2485..67670818 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -5,11 +5,7 @@ import type { RequestEvent } from "@sveltejs/kit"; import type { ConvexAuthServerState } from "../client.js"; import { ConvexAuthHooksOptions } from "./index"; import { shouldProxyAuthAction, proxyAuthActionToConvex } from "./proxy.js"; -import { - getConvexUrl, - logVerbose, - setupClient, -} from "./utils.js"; +import { getConvexUrl, logVerbose, setupClient } from "./utils.js"; import { AUTH_TOKEN_COOKIE, AUTH_REFRESH_TOKEN_COOKIE, @@ -24,11 +20,7 @@ import { handleAuthenticationInRequest } from "./request.js"; */ export function createConvexAuthHandlers({ convexUrl = getConvexUrl(), - cookieConfig: cookieConfigOverride, - verbose = false, }: ConvexAuthHooksOptions = {}) { - const cookieConfig = cookieConfigOverride ?? defaultCookieOptions; - /** * Get the auth state from cookies */ @@ -100,11 +92,7 @@ export function createConvexAuthHooks({ }: ConvexAuthHooksOptions = {}) { const cookieConfig = cookieConfigOverride ?? defaultCookieOptions; - const handlers = createConvexAuthHandlers({ - convexUrl, - cookieConfig, - verbose, - }); + const handlers = createConvexAuthHandlers({ convexUrl }); /** * Request handler for the hooks.server.ts handle function @@ -130,7 +118,12 @@ export function createConvexAuthHooks({ `Proxying auth action to Convex, path matches ${apiRoute} with or without trailing slash`, verbose, ); - const result = await proxyAuthActionToConvex(event, convexUrl, cookieConfig, verbose); + const result = await proxyAuthActionToConvex( + event, + convexUrl, + cookieConfig, + verbose, + ); return result; } logVerbose( @@ -139,7 +132,12 @@ export function createConvexAuthHooks({ ); // Refresh tokens, handle code query param - const authResult = await handleAuthenticationInRequest(event, { convexUrl, apiRoute, cookieConfig, verbose }); + const authResult = await handleAuthenticationInRequest(event, { + convexUrl, + apiRoute, + cookieConfig, + verbose, + }); // If redirecting, proceed, the middleware will run again on next request if (authResult.kind === "redirect") { @@ -164,7 +162,7 @@ export function createConvexAuthHooks({ authResult.refreshTokens.token, authResult.refreshTokens.refreshToken, cookieConfig, - verbose + verbose, ); } else { setAuthCookies(response, null, null, cookieConfig, verbose); From d0ec0b622514d7ae6ead095d7b9ff72789eae52c Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Wed, 30 Apr 2025 15:27:50 +0200 Subject: [PATCH 64/88] Remov server imports from client sveltekit --- src/sveltekit/index.ts | 22 ---------------------- src/sveltekit/server/handlers.ts | 1 + 2 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts index 45e4839e..7259bb61 100644 --- a/src/sveltekit/index.ts +++ b/src/sveltekit/index.ts @@ -91,25 +91,3 @@ export type { ConvexAuthActionsContext, ConvexAuthServerState }; - -/** - * Create server-side handlers for SvelteKit. - * This provides utilities to work with Convex Auth in SvelteKit. - * - * Usage in hooks.server.ts: - * ```ts - * import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; - * import { PUBLIC_CONVEX_URL } from '$env/static/public'; - * - * const { getAuthState } = createConvexAuthHandlers({ - * convexUrl: PUBLIC_CONVEX_URL, - * }); - * - * export async function handle({ event, resolve }) { - * // Add auth state to event.locals - * event.locals.authState = await getAuthState(event); - * return resolve(event); - * } - * ``` - */ -export { createConvexAuthHandlers } from "./server/handlers.js"; diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index 67670818..bd1e098b 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -17,6 +17,7 @@ import { handleAuthenticationInRequest } from "./request.js"; /** * Create server-side handlers for SvelteKit + * Use this in your server hooks files (+layout.server.ts, +page.server.ts, server.ts, etc.) */ export function createConvexAuthHandlers({ convexUrl = getConvexUrl(), From e721656c3aa4164a0f2f3bfe2af90c8d9feee49f Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Wed, 30 Apr 2025 15:51:21 +0200 Subject: [PATCH 65/88] Use $state for authState in SvelteKit auth setup --- src/sveltekit/README.md | 4 +++- test-sveltekit/src/routes/+layout.svelte | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 97311869..ec521404 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -43,9 +43,11 @@ Set up authentication in your root layout: // Import data from +layout.server.ts let { children, data } = $props(); + + let authState = $state(data.authState); // Set up authentication (automatically initializes Convex client) - setupConvexAuth({ serverState: data.authState }); + setupConvexAuth({ serverState: authState }); // Alternatively, you have these options: diff --git a/test-sveltekit/src/routes/+layout.svelte b/test-sveltekit/src/routes/+layout.svelte index 9c3a142d..074ec6cd 100644 --- a/test-sveltekit/src/routes/+layout.svelte +++ b/test-sveltekit/src/routes/+layout.svelte @@ -5,8 +5,10 @@ let { children, data } = $props(); + let authState = $state(data.authState); + setupConvexAuth({ - serverState: data.authState, + serverState: authState, options: { verbose: true } From cca57189359afa333ff3e11f3b71a1bdf2c6fc79 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Wed, 30 Apr 2025 17:14:48 +0200 Subject: [PATCH 66/88] Add e2e tests for auth flows and expose fetchAccessToken --- src/svelte/index.svelte.ts | 2 + test-sveltekit/e2e/README.md | 37 +++++++++++++++++++ test-sveltekit/e2e/demo.test.ts | 6 --- test-sveltekit/e2e/invalid-auth.spec.ts | 36 ++++++++++++++++++ .../e2e/route-handler-with-auth.spec.ts | 33 +++++++++++++++++ test-sveltekit/e2e/signin.spec.ts | 27 ++++++++++++++ test-sveltekit/e2e/signout.spec.ts | 15 ++++++++ test-sveltekit/src/routes/+page.svelte | 2 +- 8 files changed, 151 insertions(+), 7 deletions(-) create mode 100644 test-sveltekit/e2e/README.md delete mode 100644 test-sveltekit/e2e/demo.test.ts create mode 100644 test-sveltekit/e2e/invalid-auth.spec.ts create mode 100644 test-sveltekit/e2e/route-handler-with-auth.spec.ts create mode 100644 test-sveltekit/e2e/signin.spec.ts create mode 100644 test-sveltekit/e2e/signout.spec.ts diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index dd903c15..e1b5132b 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -263,6 +263,7 @@ export function useAuth(): { isLoading: boolean; isAuthenticated: boolean; token: string | null; + fetchAccessToken: () => Promise; signIn: (provider: string, params?: SignInParams) => Promise<{ signingIn: boolean; redirect?: URL; @@ -291,6 +292,7 @@ export function useAuth(): { get token() { return auth.token; }, + fetchAccessToken: () => auth.fetchAccessToken(), // Auth actions signIn: (provider: string, params?: SignInParams) => diff --git a/test-sveltekit/e2e/README.md b/test-sveltekit/e2e/README.md new file mode 100644 index 00000000..b582e9dd --- /dev/null +++ b/test-sveltekit/e2e/README.md @@ -0,0 +1,37 @@ +# Run the e2e tests + +## The mostly automated way + +After an `npm install` at the root of this repo and an `npm install` in test-sveltekit, run `npm test` in test-sveltekit. +This tests against the most recently published official binary. + +## The more manual way + +The following instructions require some pre-work, but once you've done the first couple steps once +you can skip to running the test command at the end. + +1. Clone [convex-backend](https://github.com/get-convex/convex-backend) + +1. Follow the instructions in its [README](https://github.com/get-convex/convex-backend/blob/main/README.md) to get it building + +1. From the `test-sveltekit` directory, run: + +``` +CONVEX_LOCAL_BACKEND_PATH=/path/to/your/convex-backend npm run test +``` + +## The most manual way + +You'll need manage your own Convex deployment to follow these instructions. + +1. Set up your Convex deployment for auth ([instructions](https://labs.convex.dev/auth/setup/manual)) + +1. Create a test user + + `npx convex run tests:init` + +1. Set up the secret on a Convex backend matching the one in `.env.test`: + + `npx convex env set AUTH_E2E_TEST_SECRET ` + +1. Run `playwright test` diff --git a/test-sveltekit/e2e/demo.test.ts b/test-sveltekit/e2e/demo.test.ts deleted file mode 100644 index 9985ce11..00000000 --- a/test-sveltekit/e2e/demo.test.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { expect, test } from '@playwright/test'; - -test('home page has expected h1', async ({ page }) => { - await page.goto('/'); - await expect(page.locator('h1')).toBeVisible(); -}); diff --git a/test-sveltekit/e2e/invalid-auth.spec.ts b/test-sveltekit/e2e/invalid-auth.spec.ts new file mode 100644 index 00000000..1e5f0679 --- /dev/null +++ b/test-sveltekit/e2e/invalid-auth.spec.ts @@ -0,0 +1,36 @@ +import { test } from "@playwright/test"; +import { SignJWT } from "jose"; + +test("invalid auth cookie redirects to signin page", async ({ + page, + context, +}) => { + // Create a fake JWT that's otherwise valid. + const expirationTime = new Date( + Date.now() + 12 * 60 * 60 * 1000, // 12 hours in the future + ); + const jwt = await new SignJWT({ + sub: "blahblahblah", + }) + .setProtectedHeader({ alg: "HS256" }) + .setIssuedAt() + .setIssuer("https://example.com") + .setAudience("convex") + .setExpirationTime(expirationTime) + .sign(new TextEncoder().encode("")); + + // Set cookies for the fake JWT and a junk refresh token too. + await context.addCookies([ + { name: "__convexAuthJWT", value: jwt, path: "/", domain: "127.0.0.1" }, + { + name: "__convexAuthRefreshToken", + value: "foobar", + path: "/", + domain: "127.0.0.1", + }, + ]); + + // An attempt to go to a protected route should redirect to sign-in. + await page.goto("/product"); + await page.waitForURL("/signin"); +}); diff --git a/test-sveltekit/e2e/route-handler-with-auth.spec.ts b/test-sveltekit/e2e/route-handler-with-auth.spec.ts new file mode 100644 index 00000000..b97ac1a5 --- /dev/null +++ b/test-sveltekit/e2e/route-handler-with-auth.spec.ts @@ -0,0 +1,33 @@ +import { test, expect, Page } from "@playwright/test"; + +test("route handler returns 403 when not authenticated", async ({ page }) => { + const response = await page.goto("/api/"); + + expect(response).not.toBeNull(); + expect(response?.status()).toBe(403); +}); + +test("route handler returns 200 when authenticated", async ({ page }) => { + await signIn(page); + + + const response = await page.goto("/api/"); + + expect(response).not.toBeNull(); + expect(response?.status()).toBe(200); + + await signOut(page); +}); + +async function signIn(page: Page) { + await page.goto("/signin"); + await page.getByLabel("Secret").fill(process.env.AUTH_E2E_TEST_SECRET!); + await page.getByRole("button").getByText("Sign in with secret").click(); + await page.waitForURL("/product"); +} + +async function signOut(page: Page) { + await page.goto("/product"); + await page.getByRole("button", { name: "user menu" }).click(); + await page.getByRole("menuitem").getByText("Sign out").click(); +} \ No newline at end of file diff --git a/test-sveltekit/e2e/signin.spec.ts b/test-sveltekit/e2e/signin.spec.ts new file mode 100644 index 00000000..80d2598b --- /dev/null +++ b/test-sveltekit/e2e/signin.spec.ts @@ -0,0 +1,27 @@ +import { test, expect } from "@playwright/test"; + +test("signin fails correctly", async ({ page }) => { + await page.goto("/"); + + await page.getByRole("link").getByText("Get Started").first().click(); + + await page.waitForURL("/signin"); + + await page + .getByLabel("Secret") + .fill( + "for the love of all mighty please don't set this as the secret value", + ); + + // Record the alert message + let message = ""; + page.on("dialog", (dialog) => { + message = dialog.message(); + void dialog.accept(); + }); + + await page.getByRole("button").getByText("Sign in with secret").click(); + + // Need to wait for the dialog to appear, it's async + await expect.poll(async () => message).toBe("Invalid secret"); +}); diff --git a/test-sveltekit/e2e/signout.spec.ts b/test-sveltekit/e2e/signout.spec.ts new file mode 100644 index 00000000..e4138d8b --- /dev/null +++ b/test-sveltekit/e2e/signout.spec.ts @@ -0,0 +1,15 @@ +import { test } from "@playwright/test"; + +test("signout works", async ({ page }) => { + await page.goto("/signin"); + + // await page.getByRole("link").getByText("Get Started").first().click(); + + await page.getByLabel("Secret").fill(process.env.AUTH_E2E_TEST_SECRET!); + + await page.getByRole("button").getByText("Sign in with secret").click(); + + await page.getByRole("button", { name: "user menu" }).click(); + + await page.getByRole("menuitem").getByText("Sign out").click(); +}); diff --git a/test-sveltekit/src/routes/+page.svelte b/test-sveltekit/src/routes/+page.svelte index b80effb4..b9030831 100644 --- a/test-sveltekit/src/routes/+page.svelte +++ b/test-sveltekit/src/routes/+page.svelte @@ -12,6 +12,6 @@ {:else}

    You are not authenticated.

    - Sign In + Get Started {/if}
    From 7db12fc601ad0cd73f1e5361ba8c3e39671a626c Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 1 May 2025 11:47:31 +0200 Subject: [PATCH 67/88] Refactor auth state handling to use getter function instead of direct state access --- src/svelte/client.svelte.ts | 27 ++++++++--------- src/svelte/index.svelte.ts | 8 +++++ src/sveltekit/{client.ts => client.svelte.ts} | 29 +++++++++++-------- src/sveltekit/index.ts | 11 +++---- src/sveltekit/server/handlers.ts | 2 +- src/sveltekit/server/index.ts | 2 +- src/sveltekit/server/utils.ts | 2 +- test-sveltekit/src/routes/+layout.svelte | 4 +-- .../src/routes/product/+page.svelte | 15 +++++----- 9 files changed, 54 insertions(+), 46 deletions(-) rename src/sveltekit/{client.ts => client.svelte.ts} (84%) diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index 3af5780e..8cf11d58 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -7,7 +7,7 @@ import type { SignOutAction, } from "../server/implementation/index.js"; import { AuthClient } from "./clientType.js"; -import type { TokenStorage } from "./index.svelte"; +import type { ConvexAuthServerState, TokenStorage } from "./index.svelte"; import isNetworkError from "is-network-error"; import { Value } from "convex/values"; import { setupConvex } from "convex-svelte"; @@ -31,17 +31,14 @@ const AUTH_CONTEXT_KEY = "$$_convexAuth"; */ export function createAuthClient({ client, - serverState, + getServerState, onChange, storage, storageNamespace, replaceURL, }: { client: AuthClient; - serverState?: { - _state: { token: string | null; refreshToken: string | null }; - _timeFetched: number; - }; + getServerState?: () => ConvexAuthServerState; onChange?: () => Promise; storage: TokenStorage | null; storageNamespace: string; @@ -51,9 +48,9 @@ export function createAuthClient({ // Initialize state with reactive variables const state = $state({ - token: serverState?._state.token ?? null, - refreshToken: serverState?._state.refreshToken ?? null, - isLoading: serverState?._state.token === null, + token: getServerState?.()._state.token ?? null, + refreshToken: getServerState?.()._state.refreshToken ?? null, + isLoading: getServerState?.()._state.token === null, isRefreshingToken: false, }); const isAuthenticated = $derived(state.token !== null); @@ -101,10 +98,10 @@ export function createAuthClient({ await storageSet(REFRESH_TOKEN_STORAGE_KEY, refreshToken); // Store server state fetch time - if (serverState && !state.isRefreshingToken) { + if (getServerState && !state.isRefreshingToken) { await storageSet( SERVER_STATE_FETCH_TIME_STORAGE_KEY, - `${serverState._timeFetched}`, + `${getServerState()._timeFetched}`, ); } } @@ -121,19 +118,19 @@ export function createAuthClient({ // Load tokens from storage on initialization $effect(() => { const loadTokens = async () => { - if (serverState?._state) { + if (getServerState?.()._state) { // Check if the server state is newer than what we have in localStorage const storedTimeFetched = await storageGet(SERVER_STATE_FETCH_TIME_STORAGE_KEY); - const serverIsNewer = !storedTimeFetched || serverState._timeFetched > +storedTimeFetched; + const serverIsNewer = !storedTimeFetched || getServerState()._timeFetched > +storedTimeFetched; if (serverIsNewer) { // Server state is newer, use it - const { token, refreshToken } = serverState._state; + const { token, refreshToken } = getServerState()._state; // Save the server fetch time await storageSet( SERVER_STATE_FETCH_TIME_STORAGE_KEY, - serverState._timeFetched.toString() + getServerState()._timeFetched.toString() ); logVerbose(`Using server state tokens (newer than storage), null? ${token === null || refreshToken === null}`); diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index e1b5132b..480812f4 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -54,6 +54,14 @@ export interface TokenStorage { removeItem: (key: string) => void | Promise; } +/** + * Type definition for the server state + */ +export type ConvexAuthServerState = { + _state: { token: string | null; refreshToken: string | null }; + _timeFetched: number; +}; + /** * Initialize Convex Auth for Svelte. * diff --git a/src/sveltekit/client.ts b/src/sveltekit/client.svelte.ts similarity index 84% rename from src/sveltekit/client.ts rename to src/sveltekit/client.svelte.ts index a288dc5a..3477d7e8 100644 --- a/src/sveltekit/client.ts +++ b/src/sveltekit/client.svelte.ts @@ -10,21 +10,15 @@ import { } from "../svelte/client.svelte.js"; import { AuthClient } from "../svelte/clientType.js"; import { ConvexClient, ConvexClientOptions } from "convex/browser"; - -/** - * Type definition for the server state from SvelteKit - */ -export type ConvexAuthServerState = { - _state: { token: string | null; refreshToken: string | null }; - _timeFetched: number; -}; +import { ConvexAuthServerState } from "../svelte/index.svelte"; +import { logVerbose } from "./server/utils.js"; /** * Create a Convex Auth client for SvelteKit */ export function createSvelteKitAuthClient({ apiRoute = "/api/auth", - serverState, + getServerState: getServerState, storage = "localStorage", storageNamespace, client, @@ -32,7 +26,7 @@ export function createSvelteKitAuthClient({ options, }: { apiRoute?: string; - serverState: ConvexAuthServerState; + getServerState: () => ConvexAuthServerState; storage?: "localStorage" | "inMemory"; storageNamespace?: string; client?: ConvexClient; @@ -72,8 +66,9 @@ export function createSvelteKitAuthClient({ // Create the auth client with SvelteKit-specific config const auth = createAuthClient({ client: authClient, - serverState, + getServerState, onChange: async () => { + console.log("\n**onChange invalidateAll**\n"); // Invalidate SvelteKit data on auth changes await invalidateAll(); }, @@ -111,7 +106,17 @@ export function createSvelteKitAuthClient({ }, }); - client.setAuth(auth.fetchAccessToken); + $effect(() => { + const s = getServerState(); // fresh each invalidation + logVerbose( + `Update convex client setAuth to ${s._state.token ? "Authenticated" : "Unauthenticated"}`, + options?.verbose, + ); + + if (s._state.token) { + client.setAuth(auth.fetchAccessToken); + } + }); // Set the auth context to ensure it's available immediately setConvexAuthContext(auth); diff --git a/src/sveltekit/index.ts b/src/sveltekit/index.ts index 7259bb61..c645ce64 100644 --- a/src/sveltekit/index.ts +++ b/src/sveltekit/index.ts @@ -7,11 +7,12 @@ import { useAuth, type TokenStorage, - type ConvexAuthActionsContext + type ConvexAuthActionsContext, + type ConvexAuthServerState } from "../svelte/index.svelte"; import { ConvexClient, ConvexClientOptions } from "convex/browser"; -import { createSvelteKitAuthClient, type ConvexAuthServerState } from "./client"; +import { createSvelteKitAuthClient } from "./client.svelte"; /** * Initialize Convex Auth for SvelteKit. @@ -39,7 +40,7 @@ import { createSvelteKitAuthClient, type ConvexAuthServerState } from "./client" export function setupConvexAuth({ client, apiRoute = "/api/auth", - serverState, + getServerState: getServerState, storage = "localStorage", storageNamespace, convexUrl, @@ -54,7 +55,7 @@ export function setupConvexAuth({ /** API route to use for auth requests */ apiRoute?: string; /** Server-provided authentication state */ - serverState: ConvexAuthServerState; + getServerState: () => ConvexAuthServerState; /** Storage type to use */ storage?: "localStorage" | "inMemory"; /** Storage namespace for auth tokens */ @@ -69,7 +70,7 @@ export function setupConvexAuth({ // Initialize the auth client with SvelteKit-specific configuration return createSvelteKitAuthClient({ apiRoute, - serverState, + getServerState, storage, client, // Pass the client to avoid re-initialization convexUrl, // Pass the URL for client initialization diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index bd1e098b..3852a8af 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -2,7 +2,6 @@ * Server-side handlers for Convex Auth in SvelteKit */ import type { RequestEvent } from "@sveltejs/kit"; -import type { ConvexAuthServerState } from "../client.js"; import { ConvexAuthHooksOptions } from "./index"; import { shouldProxyAuthAction, proxyAuthActionToConvex } from "./proxy.js"; import { getConvexUrl, logVerbose, setupClient } from "./utils.js"; @@ -14,6 +13,7 @@ import { } from "./cookies"; import { IsAuthenticatedQuery } from "../../server/implementation/index.js"; import { handleAuthenticationInRequest } from "./request.js"; +import { ConvexAuthServerState } from "../../svelte/index.svelte.js"; /** * Create server-side handlers for SvelteKit diff --git a/src/sveltekit/server/index.ts b/src/sveltekit/server/index.ts index 175791c8..84886c99 100644 --- a/src/sveltekit/server/index.ts +++ b/src/sveltekit/server/index.ts @@ -10,8 +10,8 @@ import { type RouteMatcherParam, type RouteMatcherFn, } from "./routeMatcher.js"; -import type { ConvexAuthServerState } from "../client.js"; import type { CookieOptions } from "./cookies.js"; +import { ConvexAuthServerState } from "../../svelte/index.svelte.js"; /** * Options for the createConvexAuthHandlers and createConvexAuthHooks functions diff --git a/src/sveltekit/server/utils.ts b/src/sveltekit/server/utils.ts index e8ead17d..95cfdf20 100644 --- a/src/sveltekit/server/utils.ts +++ b/src/sveltekit/server/utils.ts @@ -2,7 +2,7 @@ import { env } from "$env/dynamic/public"; import { ConvexHttpClient } from "convex/browser"; // For debug logging -export function logVerbose(message: string, verbose: boolean) { +export function logVerbose(message: string, verbose: boolean = false) { if (verbose) { console.debug( `[verbose] ${new Date().toISOString()} [ConvexAuthSvelteKit] ${message}`, diff --git a/test-sveltekit/src/routes/+layout.svelte b/test-sveltekit/src/routes/+layout.svelte index 074ec6cd..9257f3a1 100644 --- a/test-sveltekit/src/routes/+layout.svelte +++ b/test-sveltekit/src/routes/+layout.svelte @@ -5,10 +5,8 @@ let { children, data } = $props(); - let authState = $state(data.authState); - setupConvexAuth({ - serverState: authState, + serverState: () => data.authState, options: { verbose: true } diff --git a/test-sveltekit/src/routes/product/+page.svelte b/test-sveltekit/src/routes/product/+page.svelte index e48435ea..0c8b6727 100644 --- a/test-sveltekit/src/routes/product/+page.svelte +++ b/test-sveltekit/src/routes/product/+page.svelte @@ -9,12 +9,11 @@ {#if viewer.data} -
    -
    - - -
    - -
    +
    +
    + + +
    + +
    {/if} - From 2db898f825c11a96bfce41f6179459c6a6fd598e Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 1 May 2025 11:50:58 +0200 Subject: [PATCH 68/88] Fix auth setup by renaming serverState param to getServerState --- test-sveltekit/src/routes/+layout.svelte | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-sveltekit/src/routes/+layout.svelte b/test-sveltekit/src/routes/+layout.svelte index 9257f3a1..a21440c0 100644 --- a/test-sveltekit/src/routes/+layout.svelte +++ b/test-sveltekit/src/routes/+layout.svelte @@ -6,7 +6,7 @@ let { children, data } = $props(); setupConvexAuth({ - serverState: () => data.authState, + getServerState: () => data.authState, options: { verbose: true } From a094e6d0da8d8e8096300123bf581e8a9520a2d9 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 1 May 2025 12:35:25 +0200 Subject: [PATCH 69/88] Refactor auth client to use options.verbose for logging and pass options through --- src/svelte/client.svelte.ts | 9 +++++---- src/svelte/index.svelte.ts | 1 + src/sveltekit/client.svelte.ts | 1 + 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index 8cf11d58..40ad2129 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -36,6 +36,7 @@ export function createAuthClient({ storage, storageNamespace, replaceURL, + options, }: { client: AuthClient; getServerState?: () => ConvexAuthServerState; @@ -43,6 +44,7 @@ export function createAuthClient({ storage: TokenStorage | null; storageNamespace: string; replaceURL: (relativeUrl: string) => void | Promise; + options?: ConvexClientOptions; }) { @@ -56,10 +58,9 @@ export function createAuthClient({ const isAuthenticated = $derived(state.token !== null); // Debug logging - const verbose: boolean = client.verbose ?? false; const logVerbose = (message: string) => { - if (verbose) { - console.debug(`${new Date().toISOString()} ${message}`); + if (options?.verbose) { + console.log(`${new Date().toISOString()} ${message}`); client.logger?.logVerbose(message); } }; @@ -84,8 +85,8 @@ export function createAuthClient({ state.token = null; state.refreshToken = null; if (args.shouldStore) { - await storageRemove(JWT_STORAGE_KEY); await storageRemove(REFRESH_TOKEN_STORAGE_KEY); + await storageRemove(JWT_STORAGE_KEY); } newToken = null; } else { diff --git a/src/svelte/index.svelte.ts b/src/svelte/index.svelte.ts index 480812f4..6de64381 100644 --- a/src/svelte/index.svelte.ts +++ b/src/svelte/index.svelte.ts @@ -165,6 +165,7 @@ export function setupConvexAuth({ // Handle auth state changes // This is a hook for implementations to use }, + options, }); client.setAuth(auth.fetchAccessToken) diff --git a/src/sveltekit/client.svelte.ts b/src/sveltekit/client.svelte.ts index 3477d7e8..1be04c68 100644 --- a/src/sveltekit/client.svelte.ts +++ b/src/sveltekit/client.svelte.ts @@ -104,6 +104,7 @@ export function createSvelteKitAuthClient({ // Start retry attempts after a short delay setTimeout(() => attemptSvelteKitNavigation(), 50); }, + options, }); $effect(() => { From 95724856951b91bcc60eb8e951907e636edb5333 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 1 May 2025 19:57:38 +0200 Subject: [PATCH 70/88] Update auth setup to use function for server state instead of $state variable --- src/sveltekit/README.md | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index ec521404..88f087c6 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -43,24 +43,22 @@ Set up authentication in your root layout: // Import data from +layout.server.ts let { children, data } = $props(); - - let authState = $state(data.authState); // Set up authentication (automatically initializes Convex client) - setupConvexAuth({ serverState: authState }); + setupConvexAuth({ serverState: () => data.authState }); // Alternatively, you have these options: // Option 1: Provide a custom Convex URL // setupConvexAuth({ - // serverState: data.authState, + // serverState: () => data.authState, // convexUrl: "https://your-convex-deployment.convex.cloud" // }); // Option 2: Provide your own ConvexClient instance // import { ConvexClient } from "convex/browser"; // const client = new ConvexClient("https://your-deployment.convex.cloud"); - // setupConvexAuth({ serverState: data.authState, client }); + // setupConvexAuth({ serverState: () => data.authState, client }); {@render children()} From 77f5f2a1543d955b53825ff0bc23727dc8ffa722 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 1 May 2025 20:18:03 +0200 Subject: [PATCH 71/88] Add mutex to prevent concurrent token refreshes across browser tabs --- src/svelte/client.svelte.ts | 112 +++++++++++++++++++++++------------- 1 file changed, 72 insertions(+), 40 deletions(-) diff --git a/src/svelte/client.svelte.ts b/src/svelte/client.svelte.ts index 40ad2129..a15c78d4 100644 --- a/src/svelte/client.svelte.ts +++ b/src/svelte/client.svelte.ts @@ -46,8 +46,6 @@ export function createAuthClient({ replaceURL: (relativeUrl: string) => void | Promise; options?: ConvexClientOptions; }) { - - // Initialize state with reactive variables const state = $state({ token: getServerState?.()._state.token ?? null, @@ -121,27 +119,34 @@ export function createAuthClient({ const loadTokens = async () => { if (getServerState?.()._state) { // Check if the server state is newer than what we have in localStorage - const storedTimeFetched = await storageGet(SERVER_STATE_FETCH_TIME_STORAGE_KEY); - const serverIsNewer = !storedTimeFetched || getServerState()._timeFetched > +storedTimeFetched; - + const storedTimeFetched = await storageGet( + SERVER_STATE_FETCH_TIME_STORAGE_KEY, + ); + const serverIsNewer = + !storedTimeFetched || + getServerState()._timeFetched > +storedTimeFetched; + if (serverIsNewer) { // Server state is newer, use it const { token, refreshToken } = getServerState()._state; - + // Save the server fetch time await storageSet( SERVER_STATE_FETCH_TIME_STORAGE_KEY, - getServerState()._timeFetched.toString() + getServerState()._timeFetched.toString(), ); - - logVerbose(`Using server state tokens (newer than storage), null? ${token === null || refreshToken === null}`); - + + logVerbose( + `Using server state tokens (newer than storage), null? ${token === null || refreshToken === null}`, + ); + // Apply the tokens await setToken({ shouldStore: true, - tokens: token === null || refreshToken === null - ? null - : { token, refreshToken } + tokens: + token === null || refreshToken === null + ? null + : { token, refreshToken }, }); } else { // localStorage has newer data, load from there @@ -150,11 +155,11 @@ export function createAuthClient({ } return; } - + // No server state, try localStorage await loadFromStorage(); }; - + // Helper to load from storage const loadFromStorage = async () => { try { @@ -343,40 +348,67 @@ export function createAuthClient({ // Return the existing token if we have one and aren't forcing a refresh if (state.token !== null && !forceRefreshToken) { + logVerbose(`returning existing token, is null: ${state.token === null}`); return state.token; } - try { - state.isRefreshingToken = true; - - // Get the refresh token from storage - const refreshToken = await storageGet(REFRESH_TOKEN_STORAGE_KEY); - if (!refreshToken) { - return null; - } + // From here on, we need to potentially refresh the token. + // We use a mutex to ensure only one tab/window attempts the refresh. - logVerbose("using refresh token to get new access token"); - const response = await verifyCode({ refreshToken }); + const tokenBeforeLockAquisition = state.token; - if (response.tokens) { + return await browserMutex(REFRESH_TOKEN_STORAGE_KEY, async () => { + const tokenAfterLockAquisition = state.token; + // Another tab or frame might have refreshed the token while we waited for the lock. + if (tokenAfterLockAquisition !== tokenBeforeLockAquisition) { logVerbose( - `got new access token, is null: ${response.tokens.token === null}`, + `returning synced token, is null: ${tokenAfterLockAquisition === null}`, ); - await setToken({ shouldStore: true, tokens: response.tokens }); - return response.tokens.token; - } else { - logVerbose("no tokens in refresh token response"); - return null; + return tokenAfterLockAquisition; } - } catch (e) { - console.error("Failed to refresh token:", e); - // Clear tokens on failure - await setToken({ shouldStore: true, tokens: null }); - return null; - } finally { - state.isRefreshingToken = false; - } + // We hold the lock, proceed with refreshing the token. + try { + state.isRefreshingToken = true; + + // Get the refresh token from storage + const refreshToken = await storageGet(REFRESH_TOKEN_STORAGE_KEY); + if (!refreshToken) { + logVerbose("no refresh token found in storage"); + // Ensure token state is null if no refresh token exists + if (state.token !== null) { + await setToken({ shouldStore: true, tokens: null }); + } + return null; + } + + logVerbose("using refresh token to get new access token"); + const response = await verifyCode({ refreshToken }); + + if (response.tokens) { + logVerbose( + `retrieved tokens, is null: ${response.tokens.token === null}`, + ); + await setToken({ shouldStore: true, tokens: response.tokens }); + return response.tokens.token; + } else { + logVerbose( + "no tokens in refresh token response, clearing stored tokens", + ); + // Clear tokens if refresh failed but didn't throw + await setToken({ shouldStore: true, tokens: null }); + return null; + } + } catch (e) { + console.error("Failed to refresh token:", e); + + // Clear tokens on failure + await setToken({ shouldStore: true, tokens: null }); + return null; + } finally { + state.isRefreshingToken = false; + } + }); }; const signIn = async ( From 8d2f456feca087ca3e9f7e4738a9b2a2f1db885b Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Thu, 1 May 2025 21:04:36 +0200 Subject: [PATCH 72/88] Add E2E tests and route handler for auth with improved test config and user menu --- test-sveltekit/e2e/route-handler-with-auth.spec.ts | 4 ++-- test-sveltekit/e2e/signout.spec.ts | 10 +++------- test-sveltekit/package.json | 4 +++- test-sveltekit/playwright.config.ts | 7 +++++++ test-sveltekit/src/lib/UserMenu.svelte | 1 + test-sveltekit/src/routes/api/+server.ts | 11 +++++++++++ 6 files changed, 27 insertions(+), 10 deletions(-) create mode 100644 test-sveltekit/src/routes/api/+server.ts diff --git a/test-sveltekit/e2e/route-handler-with-auth.spec.ts b/test-sveltekit/e2e/route-handler-with-auth.spec.ts index b97ac1a5..872e36a2 100644 --- a/test-sveltekit/e2e/route-handler-with-auth.spec.ts +++ b/test-sveltekit/e2e/route-handler-with-auth.spec.ts @@ -28,6 +28,6 @@ async function signIn(page: Page) { async function signOut(page: Page) { await page.goto("/product"); - await page.getByRole("button", { name: "user menu" }).click(); - await page.getByRole("menuitem").getByText("Sign out").click(); + await page.locator("#user-menu-trigger").click(); + await page.getByRole("button").getByText("Sign out").click(); } \ No newline at end of file diff --git a/test-sveltekit/e2e/signout.spec.ts b/test-sveltekit/e2e/signout.spec.ts index e4138d8b..dfc3e652 100644 --- a/test-sveltekit/e2e/signout.spec.ts +++ b/test-sveltekit/e2e/signout.spec.ts @@ -2,14 +2,10 @@ import { test } from "@playwright/test"; test("signout works", async ({ page }) => { await page.goto("/signin"); - - // await page.getByRole("link").getByText("Get Started").first().click(); - await page.getByLabel("Secret").fill(process.env.AUTH_E2E_TEST_SECRET!); - await page.getByRole("button").getByText("Sign in with secret").click(); + await page.waitForURL("/product"); - await page.getByRole("button", { name: "user menu" }).click(); - - await page.getByRole("menuitem").getByText("Sign out").click(); + await page.locator("#user-menu-trigger").click(); + await page.getByRole("button").getByText("Sign out").click(); }); diff --git a/test-sveltekit/package.json b/test-sveltekit/package.json index ba799ac6..8639be29 100644 --- a/test-sveltekit/package.json +++ b/test-sveltekit/package.json @@ -4,7 +4,9 @@ "version": "0.0.1", "type": "module", "scripts": { - "dev": "vite dev", + "dev": "npm-run-all --parallel dev:frontend dev:backend", + "dev:frontend": "vite dev", + "dev:backend": "convex dev", "build": "vite build", "preview": "vite preview", "prepare": "svelte-kit sync || echo ''", diff --git a/test-sveltekit/playwright.config.ts b/test-sveltekit/playwright.config.ts index f6c81af8..ae226450 100644 --- a/test-sveltekit/playwright.config.ts +++ b/test-sveltekit/playwright.config.ts @@ -1,5 +1,12 @@ import { defineConfig } from '@playwright/test'; +/** + * Read environment variables from file. + * https://github.com/motdotla/dotenv + */ +import dotenv from "dotenv"; +dotenv.config({ path: '.env.local' }); + export default defineConfig({ webServer: { command: 'npm run build && npm run preview', diff --git a/test-sveltekit/src/lib/UserMenu.svelte b/test-sveltekit/src/lib/UserMenu.svelte index 54845713..90ab4894 100644 --- a/test-sveltekit/src/lib/UserMenu.svelte +++ b/test-sveltekit/src/lib/UserMenu.svelte @@ -41,6 +41,7 @@ contentBase="card bg-surface-200-800 p-4 space-y-4 max-w-[320px]" arrow arrowBackground="!bg-surface-200 dark:!bg-surface-800" + ids={{trigger: "user-menu-trigger"}} > {#snippet trigger()} diff --git a/test-sveltekit/src/routes/api/+server.ts b/test-sveltekit/src/routes/api/+server.ts new file mode 100644 index 00000000..8593718f --- /dev/null +++ b/test-sveltekit/src/routes/api/+server.ts @@ -0,0 +1,11 @@ +import { json } from '@sveltejs/kit'; +import type { RequestHandler } from './$types'; +import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; + +const { isAuthenticated: isAuthenticatedPromise } = createConvexAuthHandlers(); + +export const GET: RequestHandler = async (event) => { + const isAuthenticated = await isAuthenticatedPromise(event); + // return new Response(); + return json({ someData: isAuthenticated }, { status: isAuthenticated ? 200 : 403 }); +}; From de48649fa10d25fe2a7182f3640156b58c97126d Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 3 May 2025 11:37:46 +0200 Subject: [PATCH 73/88] Update middleware to updated routematcher --- test-nextjs/middleware.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-nextjs/middleware.ts b/test-nextjs/middleware.ts index 770be7ec..8b3eb562 100644 --- a/test-nextjs/middleware.ts +++ b/test-nextjs/middleware.ts @@ -5,7 +5,7 @@ import { } from "@convex-dev/auth/nextjs/server"; const isSignInPage = createRouteMatcher(["/signin"]); -const isProtectedRoute = createRouteMatcher(["/product(.*)"]); +const isProtectedRoute = createRouteMatcher(["/product/*path"]); export default convexAuthNextjsMiddleware(async (request, { convexAuth }) => { if (isSignInPage(request) && (await convexAuth.isAuthenticated())) { From b72fd568bf1f712a75139a7f6ae88159e5a083e9 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 3 May 2025 11:40:21 +0200 Subject: [PATCH 74/88] Update dependencies: cookie, Next.js, Svelte, TypeScript and dev tools --- package-lock.json | 3933 ++++++++++++++++++--------------- package.json | 18 +- test-nextjs/package-lock.json | 123 +- 3 files changed, 2297 insertions(+), 1777 deletions(-) diff --git a/package-lock.json b/package-lock.json index bf28d551..b9af02d2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,7 @@ "version": "0.0.82", "license": "Apache-2.0", "dependencies": { - "cookie": "^1.0.1", + "cookie": "^1.0.2", "is-network-error": "^1.1.0", "jose": "^5.2.2", "jwt-decode": "^4.0.0", @@ -25,8 +25,8 @@ "devDependencies": { "@commander-js/extra-typings": "^12.1.0", "@edge-runtime/vm": "^3.2.0", - "@sveltejs/kit": "^2.16.0", - "@sveltejs/vite-plugin-svelte": "^5.0.0", + "@sveltejs/kit": "^2.20.8", + "@sveltejs/vite-plugin-svelte": "^5.0.3", "@types/inquirer": "^9.0.7", "@types/node": "20.6.0", "@types/react": "^18.3.12", @@ -37,17 +37,17 @@ "dotenv": "^16.4.5", "eslint": "8.49.0", "inquirer": "^9.2.22", - "next": "^15.0.3", + "next": "^15.3.1", "npm-run-all": "^4.1.5", "react-dom": "^18.3.1", "shelljs": "^0.8.5", - "svelte": "^5.0.0", - "svelte-check": "^4.0.0", + "svelte": "^5.28.2", + "svelte-check": "^4.1.7", "tsup": "^8.0.1", - "typescript": "^5.5.2", + "typescript": "^5.8.3", "valibot": "^0.35.0", - "vite": "^6.3.1", - "vitest": "^1.6.0" + "vite": "^6.3.4", + "vitest": "^1.6.1" }, "peerDependencies": { "@auth/core": "^0.37.0", @@ -1229,92 +1229,12 @@ "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", "dev": true }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.33.5.tgz", - "integrity": "sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.33.5.tgz", - "integrity": "sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.0.4.tgz", - "integrity": "sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.0.4.tgz", - "integrity": "sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.0.5.tgz", - "integrity": "sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==", + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.1.0.tgz", + "integrity": "sha512-tiXxFZFbhnkWE2LA8oQj7KYR+bWBkiV2nilRldT7bqoEZ4HiDOcePr9wVDAZPi/Id5fT1oY9iGnDq20cwUz8lQ==", "cpu": [ - "arm" + "ppc64" ], "dev": true, "license": "LGPL-3.0-or-later", @@ -1326,415 +1246,123 @@ "url": "https://opencollective.com/libvips" } }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.0.4.tgz", - "integrity": "sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/figures": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.11.tgz", + "integrity": "sha512-eOg92lvrn/aRUqbxRyvpEWnrvRuTYRifixHkYVpJiygTgVSBIHDqLh0SrMQXkafvULg3ck11V7xvR+zcgvpHFw==", "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "license": "MIT", + "engines": { + "node": ">=18" } }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.0.4.tgz", - "integrity": "sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==", - "cpu": [ - "s390x" - ], + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" } }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.0.4.tgz", - "integrity": "sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==", - "cpu": [ - "x64" - ], + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], + "engines": { + "node": ">=12" + }, "funding": { - "url": "https://opencollective.com/libvips" + "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.0.4.tgz", - "integrity": "sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==", - "cpu": [ - "arm64" - ], + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], + "engines": { + "node": ">=12" + }, "funding": { - "url": "https://opencollective.com/libvips" + "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.0.4.tgz", - "integrity": "sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" - } + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.33.5.tgz", - "integrity": "sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==", - "cpu": [ - "arm" - ], + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=12" }, "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.0.5" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.33.5.tgz", - "integrity": "sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==", - "cpu": [ - "arm64" - ], + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "ansi-regex": "^6.0.1" + }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=12" }, "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.0.4" + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.33.5.tgz", - "integrity": "sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==", - "cpu": [ - "s390x" - ], + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + "node": ">=12" }, "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.0.4" + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.33.5.tgz", - "integrity": "sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==", - "cpu": [ - "x64" - ], + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "license": "MIT", + "dependencies": { + "@sinclair/typebox": "^0.27.8" }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.33.5.tgz", - "integrity": "sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4" - } - }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.33.5.tgz", - "integrity": "sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.0.4" - } - }, - "node_modules/@img/sharp-wasm32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.33.5.tgz", - "integrity": "sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", - "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.2.0" - }, - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-wasm32/node_modules/@emnapi/runtime": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.3.1.tgz", - "integrity": "sha512-kEBmG8KyqtxJZv+ygbEim+KCGtIq1fC22Ms3S4ziXmYKm8uyoLX0MHONVKwp+9opg390VaKRNt4a7A9NwmpNhw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.33.5.tgz", - "integrity": "sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.33.5.tgz", - "integrity": "sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "Apache-2.0 AND LGPL-3.0-or-later", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - } - }, - "node_modules/@inquirer/figures": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-1.0.2.tgz", - "integrity": "sha512-4F1MBwVr3c/m4bAUef6LgkvBfSjzwH+OfldgHqcuacWwSUetFebM2wi58WfG9uk1rR98U6GwLed4asLJbwdV5w==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "dev": true, - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "dev": true, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "dev": true - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "dev": true, - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "dev": true, - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/@jest/schemas": { - "version": "29.6.3", - "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", - "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", - "dev": true, - "dependencies": { - "@sinclair/typebox": "^0.27.8" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, "node_modules/@jridgewell/gen-mapping": { @@ -1794,212 +1422,76 @@ } }, "node_modules/@next/env": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/env/-/env-15.0.3.tgz", - "integrity": "sha512-t9Xy32pjNOvVn2AS+Utt6VmyrshbpfUMhIjFO60gI58deSo/KgLOp31XZ4O+kY/Is8WAGYwA5gR7kOb1eORDBA==", + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@next/env/-/env-15.3.1.tgz", + "integrity": "sha512-cwK27QdzrMblHSn9DZRV+DQscHXRuJv6MydlJRpFSqJWZrTYMLzKDeyueJNN9MGd8NNiUKzDQADAf+dMLXX7YQ==", "dev": true, "license": "MIT" }, - "node_modules/@next/swc-darwin-arm64": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.3.tgz", - "integrity": "sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==", + "node_modules/@node-rs/argon2": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2/-/argon2-1.7.0.tgz", + "integrity": "sha512-zfULc+/tmcWcxn+nHkbyY8vP3+MpEqKORbszt4UkpqZgBgDAAIYvuDN/zukfTgdmo6tmJKKVfzigZOPk4LlIog==", + "engines": { + "node": ">= 10" + }, + "optionalDependencies": { + "@node-rs/argon2-android-arm-eabi": "1.7.0", + "@node-rs/argon2-android-arm64": "1.7.0", + "@node-rs/argon2-darwin-arm64": "1.7.0", + "@node-rs/argon2-darwin-x64": "1.7.0", + "@node-rs/argon2-freebsd-x64": "1.7.0", + "@node-rs/argon2-linux-arm-gnueabihf": "1.7.0", + "@node-rs/argon2-linux-arm64-gnu": "1.7.0", + "@node-rs/argon2-linux-arm64-musl": "1.7.0", + "@node-rs/argon2-linux-x64-gnu": "1.7.0", + "@node-rs/argon2-linux-x64-musl": "1.7.0", + "@node-rs/argon2-wasm32-wasi": "1.7.0", + "@node-rs/argon2-win32-arm64-msvc": "1.7.0", + "@node-rs/argon2-win32-ia32-msvc": "1.7.0", + "@node-rs/argon2-win32-x64-msvc": "1.7.0" + } + }, + "node_modules/@node-rs/argon2-android-arm-eabi": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm-eabi/-/argon2-android-arm-eabi-1.7.0.tgz", + "integrity": "sha512-udDqkr5P9E+wYX1SZwAVPdyfYvaF4ry9Tm+R9LkfSHbzWH0uhU6zjIwNRp7m+n4gx691rk+lqqDAIP8RLKwbhg==", "cpu": [ - "arm64" + "arm" ], - "dev": true, - "license": "MIT", "optional": true, "os": [ - "darwin" + "android" ], "engines": { "node": ">= 10" } }, - "node_modules/@next/swc-darwin-x64": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.3.tgz", - "integrity": "sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==", + "node_modules/@node-rs/argon2-android-arm64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm64/-/argon2-android-arm64-1.7.0.tgz", + "integrity": "sha512-s9j/G30xKUx8WU50WIhF0fIl1EdhBGq0RQ06lEhZ0Gi0ap8lhqbE2Bn5h3/G2D1k0Dx+yjeVVNmt/xOQIRG38A==", "cpu": [ - "x64" + "arm64" ], - "dev": true, - "license": "MIT", "optional": true, "os": [ - "darwin" + "android" ], "engines": { "node": ">= 10" } }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.3.tgz", - "integrity": "sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==", + "node_modules/@node-rs/argon2-darwin-arm64": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-arm64/-/argon2-darwin-arm64-1.7.0.tgz", + "integrity": "sha512-ZIz4L6HGOB9U1kW23g+m7anGNuTZ0RuTw0vNp3o+2DWpb8u8rODq6A8tH4JRL79S+Co/Nq608m9uackN2pe0Rw==", "cpu": [ "arm64" ], - "dev": true, - "license": "MIT", "optional": true, "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.3.tgz", - "integrity": "sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.3.tgz", - "integrity": "sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.3.tgz", - "integrity": "sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.3.tgz", - "integrity": "sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "15.0.3", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.3.tgz", - "integrity": "sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/argon2": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/argon2/-/argon2-1.7.0.tgz", - "integrity": "sha512-zfULc+/tmcWcxn+nHkbyY8vP3+MpEqKORbszt4UkpqZgBgDAAIYvuDN/zukfTgdmo6tmJKKVfzigZOPk4LlIog==", - "engines": { - "node": ">= 10" - }, - "optionalDependencies": { - "@node-rs/argon2-android-arm-eabi": "1.7.0", - "@node-rs/argon2-android-arm64": "1.7.0", - "@node-rs/argon2-darwin-arm64": "1.7.0", - "@node-rs/argon2-darwin-x64": "1.7.0", - "@node-rs/argon2-freebsd-x64": "1.7.0", - "@node-rs/argon2-linux-arm-gnueabihf": "1.7.0", - "@node-rs/argon2-linux-arm64-gnu": "1.7.0", - "@node-rs/argon2-linux-arm64-musl": "1.7.0", - "@node-rs/argon2-linux-x64-gnu": "1.7.0", - "@node-rs/argon2-linux-x64-musl": "1.7.0", - "@node-rs/argon2-wasm32-wasi": "1.7.0", - "@node-rs/argon2-win32-arm64-msvc": "1.7.0", - "@node-rs/argon2-win32-ia32-msvc": "1.7.0", - "@node-rs/argon2-win32-x64-msvc": "1.7.0" - } - }, - "node_modules/@node-rs/argon2-android-arm-eabi": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm-eabi/-/argon2-android-arm-eabi-1.7.0.tgz", - "integrity": "sha512-udDqkr5P9E+wYX1SZwAVPdyfYvaF4ry9Tm+R9LkfSHbzWH0uhU6zjIwNRp7m+n4gx691rk+lqqDAIP8RLKwbhg==", - "cpu": [ - "arm" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/argon2-android-arm64": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/argon2-android-arm64/-/argon2-android-arm64-1.7.0.tgz", - "integrity": "sha512-s9j/G30xKUx8WU50WIhF0fIl1EdhBGq0RQ06lEhZ0Gi0ap8lhqbE2Bn5h3/G2D1k0Dx+yjeVVNmt/xOQIRG38A==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@node-rs/argon2-darwin-arm64": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/@node-rs/argon2-darwin-arm64/-/argon2-darwin-arm64-1.7.0.tgz", - "integrity": "sha512-ZIz4L6HGOB9U1kW23g+m7anGNuTZ0RuTw0vNp3o+2DWpb8u8rODq6A8tH4JRL79S+Co/Nq608m9uackN2pe0Rw==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" + "darwin" ], "engines": { "node": ">= 10" @@ -2760,7 +2252,8 @@ "version": "0.27.8", "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.8.tgz", "integrity": "sha512-+Fj43pSMwJs4KRrH/938Uf+uAELIgVBmQzg/q1YG10djyfA3TnrU8N8XzqCh/okZdszqBQTZf96idMfE5lnwTA==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/@sveltejs/acorn-typescript": { "version": "1.0.5", @@ -2772,9 +2265,9 @@ } }, "node_modules/@sveltejs/kit": { - "version": "2.20.5", - "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.20.5.tgz", - "integrity": "sha512-zT/97KvVUo19jEGZa972ls7KICjPCB53j54TVxnEFT5VEwL16G+YFqRVwJbfxh7AmS7/Ptr1rKF7Qt4FBMDNlw==", + "version": "2.20.8", + "resolved": "https://registry.npmjs.org/@sveltejs/kit/-/kit-2.20.8.tgz", + "integrity": "sha512-ep9qTxL7WALhfm0kFecL3VHeuNew8IccbYGqv5TqL/KSqWRKzEgDG8blNlIu1CkLTTua/kHjI+f5T8eCmWIxKw==", "dev": true, "license": "MIT", "dependencies": { @@ -2860,13 +2353,13 @@ "license": "Apache-2.0" }, "node_modules/@swc/helpers": { - "version": "0.5.13", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.13.tgz", - "integrity": "sha512-UoKGxQ3r5kYI9dALKJapMmuK+1zWM/H17Z1+iwnNmzcJRnfFuevZs375TA5rW31pu4BS4NoSy1fRsexDXfWn5w==", + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", "dev": true, "license": "Apache-2.0", "dependencies": { - "tslib": "^2.4.0" + "tslib": "^2.8.0" } }, "node_modules/@tybys/wasm-util": { @@ -3138,13 +2631,14 @@ } }, "node_modules/@vitest/expect": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.0.tgz", - "integrity": "sha512-ixEvFVQjycy/oNgHjqsL6AZCDduC+tflRluaHIzKIsdbzkLn2U/iBnVeJwB6HsIjQBdfMR8Z0tRxKUsvFJEeWQ==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-1.6.1.tgz", + "integrity": "sha512-jXL+9+ZNIJKruofqXuuTClf44eSpcHlgj3CiuNihUF3Ioujtmc0zIa3UJOW5RjDK1YLBJZnWBlPuqhYycLioog==", "dev": true, + "license": "MIT", "dependencies": { - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", + "@vitest/spy": "1.6.1", + "@vitest/utils": "1.6.1", "chai": "^4.3.10" }, "funding": { @@ -3152,12 +2646,13 @@ } }, "node_modules/@vitest/runner": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.0.tgz", - "integrity": "sha512-P4xgwPjwesuBiHisAVz/LSSZtDjOTPYZVmNAnpHHSR6ONrf8eCJOFRvUwdHn30F5M1fxhqtl7QZQUk2dprIXAg==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-1.6.1.tgz", + "integrity": "sha512-3nSnYXkVkf3mXFfE7vVyPmi3Sazhb/2cfZGGs0JRzFsPFvAMBEcrweV1V1GsrstdXeKCTXlJbvnQwGWgEIHmOA==", "dev": true, + "license": "MIT", "dependencies": { - "@vitest/utils": "1.6.0", + "@vitest/utils": "1.6.1", "p-limit": "^5.0.0", "pathe": "^1.1.1" }, @@ -3170,6 +2665,7 @@ "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-5.0.0.tgz", "integrity": "sha512-/Eaoq+QyLSiXQ4lyYV23f14mZRQcXnxfHrN0vCai+ak9G0pp9iEQukIIZq5NccEvwRB8PUnZT0KsOoDCINS1qQ==", "dev": true, + "license": "MIT", "dependencies": { "yocto-queue": "^1.0.0" }, @@ -3181,10 +2677,11 @@ } }, "node_modules/@vitest/runner/node_modules/yocto-queue": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", - "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.1.tgz", + "integrity": "sha512-AyeEbWOu/TAXdxlV9wmGcR0+yh2j3vYPGOECcIj2S7MkrLyC7ne+oye2BKTItt0ii2PHk4cDy+95+LshzbXnGg==", "dev": true, + "license": "MIT", "engines": { "node": ">=12.20" }, @@ -3193,10 +2690,11 @@ } }, "node_modules/@vitest/snapshot": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.0.tgz", - "integrity": "sha512-+Hx43f8Chus+DCmygqqfetcAZrDJwvTj0ymqjQq4CvmpKFSTVteEOBzCusu1x2tt4OJcvBflyHUE0DZSLgEMtQ==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-1.6.1.tgz", + "integrity": "sha512-WvidQuWAzU2p95u8GAKlRMqMyN1yOJkGHnx3M1PL9Raf7AQ1kwLKg04ADlCa3+OXUZE7BceOhVZiuWAbzCKcUQ==", "dev": true, + "license": "MIT", "dependencies": { "magic-string": "^0.30.5", "pathe": "^1.1.1", @@ -3206,37 +2704,12 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/snapshot/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@vitest/snapshot/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/@vitest/spy": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.0.tgz", - "integrity": "sha512-leUTap6B/cqi/bQkXUu6bQV5TZPx7pmMBKBQiI0rJA8c3pB56ZsaTbREnF7CJfmvAS4V2cXIBAh/3rVwrrCYgw==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-1.6.1.tgz", + "integrity": "sha512-MGcMmpGkZebsMZhbQKkAf9CX5zGvjkBTqf8Zx3ApYWXr3wG+QvEu2eXWfnIIWYSJExIp4V9FCKDEeygzkYrXMw==", "dev": true, + "license": "MIT", "dependencies": { "tinyspy": "^2.2.0" }, @@ -3245,10 +2718,11 @@ } }, "node_modules/@vitest/utils": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.0.tgz", - "integrity": "sha512-21cPiuGMoMZwiOHa2i4LXkMkMkCGzA+MVFV70jRwHo95dL4x/ts5GZhML1QWuy7yfp3WzK3lRvZi3JnXTYqrBw==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-1.6.1.tgz", + "integrity": "sha512-jOrrUvXM4Av9ZWiG1EajNto0u96kWAhJ1LmPmJhXXQx/32MecEKd10pOLYgS2BQx1TgkGhloPU1ArDW2vvaY6g==", "dev": true, + "license": "MIT", "dependencies": { "diff-sequences": "^29.6.3", "estree-walker": "^3.0.3", @@ -3259,32 +2733,6 @@ "url": "https://opencollective.com/vitest" } }, - "node_modules/@vitest/utils/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@vitest/utils/node_modules/pretty-format": { - "version": "29.7.0", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", - "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", - "dev": true, - "dependencies": { - "@jest/schemas": "^29.6.3", - "ansi-styles": "^5.0.0", - "react-is": "^18.0.0" - }, - "engines": { - "node": "^14.15.0 || ^16.10.0 || >=18.0.0" - } - }, "node_modules/acorn": { "version": "8.14.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", @@ -3398,6 +2846,19 @@ "node": ">= 8" } }, + "node_modules/anymatch/node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -3414,13 +2875,14 @@ } }, "node_modules/array-buffer-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", - "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", + "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", - "is-array-buffer": "^3.0.4" + "call-bound": "^1.0.3", + "is-array-buffer": "^3.0.5" }, "engines": { "node": ">= 0.4" @@ -3445,19 +2907,19 @@ } }, "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.3.tgz", - "integrity": "sha512-bMxMKAjg13EBSVscxTaYA4mRc5t1UAXa2kXiGTNfZ079HIWXEkKmkgFrh/nJqamaLSrXO5H4WFFkPEaLJWbs3A==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", + "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", "dev": true, + "license": "MIT", "dependencies": { "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", - "es-abstract": "^1.22.3", - "es-errors": "^1.2.1", - "get-intrinsic": "^1.2.3", - "is-array-buffer": "^3.0.4", - "is-shared-array-buffer": "^1.0.2" + "es-abstract": "^1.23.5", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", + "is-array-buffer": "^3.0.4" }, "engines": { "node": ">= 0.4" @@ -3471,10 +2933,21 @@ "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, + "node_modules/async-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", + "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -3630,16 +3103,16 @@ } }, "node_modules/call-bind": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", - "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.8.tgz", + "integrity": "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==", "dev": true, + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", "get-intrinsic": "^1.2.4", - "set-function-length": "^1.2.1" + "set-function-length": "^1.2.2" }, "engines": { "node": ">= 0.4" @@ -3648,19 +3121,50 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, "engines": { - "node": ">=6" + "node": ">= 0.4" } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001642", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", - "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001642", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001642.tgz", + "integrity": "sha512-3XQ0DoRgLijXJErLSl+bLnJ+Et4KqV1PY6JJBGAFlsNsz31zeAIncyeZfLCabHK/jtSh+671RM9YMldxjUPZtA==", "dev": true, "funding": [ { @@ -3678,10 +3182,11 @@ ] }, "node_modules/chai": { - "version": "4.4.1", - "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", - "integrity": "sha512-13sOfMv2+DWduEU+/xbun3LScLoqN17nBeTLUsmDfKdoiC1fr0n9PU4guu4AhRcOVFk/sW8LyZWHuhWtQZiF+g==", + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.5.0.tgz", + "integrity": "sha512-RITGBfijLkBddZvnn8jdqoTypxvqbOLYQkGGxXzeFjVHvudaPw0HNFD9x928/eUwYWd2dPCugVqspGALTZZQKw==", "dev": true, + "license": "MIT", "dependencies": { "assertion-error": "^1.1.0", "check-error": "^1.0.3", @@ -3689,7 +3194,7 @@ "get-func-name": "^2.0.2", "loupe": "^2.3.6", "pathval": "^1.1.1", - "type-detect": "^4.0.8" + "type-detect": "^4.1.0" }, "engines": { "node": ">=4" @@ -3733,6 +3238,7 @@ "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", "dev": true, + "license": "MIT", "dependencies": { "get-func-name": "^2.0.2" }, @@ -3969,10 +3475,11 @@ "dev": true }, "node_modules/confbox": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.7.tgz", - "integrity": "sha512-uJcB/FKZtBMCJpK8MQji6bJHgu1tixKPxRLeGkNzBoOZzpnZUJm0jm2/sBDWcuBx1dYgxV4JU+g5hmNxCyAmdA==", - "dev": true + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.1.8.tgz", + "integrity": "sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==", + "dev": true, + "license": "MIT" }, "node_modules/convex": { "version": "1.23.0", @@ -4050,11 +3557,22 @@ "node": ">=18" } }, - "node_modules/core-util-is": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", - "dev": true + "node_modules/convex/node_modules/@esbuild/android-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.25.1.tgz", + "integrity": "sha512-dp+MshLYux6j/JjdqVLnMglQlFu+MuVeNrmT5nk6q07wNhCdSnB7QZj+7G8VMUGh1q+vj2Bq8kRsuyA00I/k+Q==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "peer": true, + "engines": { + "node": ">=18" + } }, "node_modules/convex/node_modules/@esbuild/android-arm64": { "version": "0.25.1", @@ -4073,240 +3591,238 @@ "node": ">=18" } }, - "node_modules/cspell": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/cspell/-/cspell-8.17.2.tgz", - "integrity": "sha512-y+INkxDa+M9f+gsyyMLjKh1tF20r2g5Gn22peSRJglrNLQtmDuRtDT9vyDHANXZcH5g6pHDnENQu/+P2Tiyu8Q==", - "dev": true, - "dependencies": { - "@cspell/cspell-json-reporter": "8.17.2", - "@cspell/cspell-pipe": "8.17.2", - "@cspell/cspell-types": "8.17.2", - "@cspell/dynamic-import": "8.17.2", - "@cspell/url": "8.17.2", - "chalk": "^5.4.1", - "chalk-template": "^1.1.0", - "commander": "^13.0.0", - "cspell-dictionary": "8.17.2", - "cspell-gitignore": "8.17.2", - "cspell-glob": "8.17.2", - "cspell-io": "8.17.2", - "cspell-lib": "8.17.2", - "fast-json-stable-stringify": "^2.1.0", - "file-entry-cache": "^9.1.0", - "get-stdin": "^9.0.0", - "semver": "^7.6.3", - "tinyglobby": "^0.2.10" - }, - "bin": { - "cspell": "bin.mjs", - "cspell-esm": "bin.mjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-config-lib": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.17.2.tgz", - "integrity": "sha512-g08lRd/smLk2je0j7HlCjdDa0dSTyI2oRP3gScWlsyXjb4NSr9qO0Wzyn5BfPgrqFdS/z4dXbHe+tnLQZCt9iQ==", - "dev": true, - "dependencies": { - "@cspell/cspell-types": "8.17.2", - "comment-json": "^4.2.5", - "yaml": "^2.7.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-dictionary": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.17.2.tgz", - "integrity": "sha512-2JC9RRsZruCs3AHId/8X63fSxDoF94dleRp8y/dXS9LIX7NruofohUJwzc/3tlgzCWWdaek1RXhO5xaYX74QtA==", - "dev": true, - "dependencies": { - "@cspell/cspell-pipe": "8.17.2", - "@cspell/cspell-types": "8.17.2", - "cspell-trie-lib": "8.17.2", - "fast-equals": "^5.2.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-gitignore": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.17.2.tgz", - "integrity": "sha512-zCTTN30zV96LkZmUDrLamEHpLLUGohKglKJ4iXoHQC8pDU3xTsV2qzeCQjM9SEmU3VbE1TzWq+vj0fslasv6pA==", - "dev": true, - "dependencies": { - "@cspell/url": "8.17.2", - "cspell-glob": "8.17.2", - "cspell-io": "8.17.2", - "find-up-simple": "^1.0.0" - }, - "bin": { - "cspell-gitignore": "bin.mjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-glob": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.17.2.tgz", - "integrity": "sha512-MTgrWX12oY8Pq/M3PEYCTHwD6w6l+DPtBWm958nhR4dboUbwi/3KfqCtdorkhnuClqLDQuuZHp0uGBXB4cdQrw==", - "dev": true, - "dependencies": { - "@cspell/url": "8.17.2", - "micromatch": "^4.0.8" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-grammar": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.17.2.tgz", - "integrity": "sha512-Asg5XRvrg2yHCvBwzARBPSwI4P5/unN+bKBlxqFazHgR72WJE+ASeobfUNfGi/RxJA2+m0hO91oYtvq6LfK52w==", - "dev": true, - "dependencies": { - "@cspell/cspell-pipe": "8.17.2", - "@cspell/cspell-types": "8.17.2" - }, - "bin": { - "cspell-grammar": "bin.mjs" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-io": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.17.2.tgz", - "integrity": "sha512-IUdhbO6gsWYiM2dgudFJQTfnFCDYjLOqal3SxH5o8oOWeu5iIZ+s3N8E1odz0L5zF2Go7zDQSKvPr7Y9OOoRfw==", - "dev": true, - "dependencies": { - "@cspell/cspell-service-bus": "8.17.2", - "@cspell/url": "8.17.2" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-lib": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.17.2.tgz", - "integrity": "sha512-ZgkTvGh9FO+R3v5TaTqlrJEylWyZhNOzbtrQ5W35Hb3tZ9IJJklxjlcGe+gbFsjGi56kLj6c5L2NR7YX/Fdu5Q==", - "dev": true, - "dependencies": { - "@cspell/cspell-bundled-dicts": "8.17.2", - "@cspell/cspell-pipe": "8.17.2", - "@cspell/cspell-resolver": "8.17.2", - "@cspell/cspell-types": "8.17.2", - "@cspell/dynamic-import": "8.17.2", - "@cspell/filetypes": "8.17.2", - "@cspell/strong-weak-map": "8.17.2", - "@cspell/url": "8.17.2", - "clear-module": "^4.1.2", - "comment-json": "^4.2.5", - "cspell-config-lib": "8.17.2", - "cspell-dictionary": "8.17.2", - "cspell-glob": "8.17.2", - "cspell-grammar": "8.17.2", - "cspell-io": "8.17.2", - "cspell-trie-lib": "8.17.2", - "env-paths": "^3.0.0", - "fast-equals": "^5.2.2", - "gensequence": "^7.0.0", - "import-fresh": "^3.3.0", - "resolve-from": "^5.0.0", - "vscode-languageserver-textdocument": "^1.0.12", - "vscode-uri": "^3.0.8", - "xdg-basedir": "^5.1.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-lib/node_modules/resolve-from": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", - "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell-trie-lib": { - "version": "8.17.2", - "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.17.2.tgz", - "integrity": "sha512-Bw9q8EWFihkQGo8fNdfkUqYOTsC161+wrQxR7m74K4bKEmQgm0mS0sLHKUwxEOZVGGLmIw9dMQl+8WnTgqOaMQ==", - "dev": true, - "dependencies": { - "@cspell/cspell-pipe": "8.17.2", - "@cspell/cspell-types": "8.17.2", - "gensequence": "^7.0.0" - }, - "engines": { - "node": ">=18" - } - }, - "node_modules/cspell/node_modules/commander": { - "version": "13.0.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-13.0.0.tgz", - "integrity": "sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==", - "dev": true, - "engines": { - "node": ">=18" - } - }, - "node_modules/convex/node_modules/@esbuild/linux-riscv64": { + "node_modules/convex/node_modules/@esbuild/android-x64": { "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", - "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.25.1.tgz", + "integrity": "sha512-GCj6WfUtNldqUzYkN/ITtlhwQqGWu9S45vUXs7EIYf+7rCiiqH9bCloatO9VhxsL0Pji+PF4Lz2XXCES+Q8hDw==", "cpu": [ - "riscv64" + "x64" ], "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], "peer": true, "engines": { "node": ">=18" } }, - "node_modules/convex/node_modules/@esbuild/linux-s390x": { + "node_modules/convex/node_modules/@esbuild/darwin-arm64": { "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", - "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.25.1.tgz", + "integrity": "sha512-5hEZKPf+nQjYoSr/elb62U19/l1mZDdqidGfmFutVUjjUZrOazAtwK+Kr+3y0C/oeJfLlxo9fXb1w7L+P7E4FQ==", "cpu": [ - "s390x" + "arm64" ], "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], "peer": true, "engines": { "node": ">=18" } }, - "node_modules/convex/node_modules/@esbuild/linux-x64": { + "node_modules/convex/node_modules/@esbuild/darwin-x64": { "version": "0.25.1", - "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", - "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.25.1.tgz", + "integrity": "sha512-hxVnwL2Dqs3fM1IWq8Iezh0cX7ZGdVhbTfnOy5uURtao5OIVCEyj9xIzemDi7sRvKsuSdtCAhMKarxqtlyVyfA==", "cpu": [ "x64" ], "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/freebsd-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.25.1.tgz", + "integrity": "sha512-1MrCZs0fZa2g8E+FUo2ipw6jw5qqQiH+tERoS5fAfKnRx6NXH31tXBKI3VpmLijLH6yriMZsxJtaXUyFt/8Y4A==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/freebsd-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.25.1.tgz", + "integrity": "sha512-0IZWLiTyz7nm0xuIs0q1Y3QWJC52R8aSXxe40VUxm6BB1RNmkODtW6LHvWRrGiICulcX7ZvyH6h5fqdLu4gkww==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-arm": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.25.1.tgz", + "integrity": "sha512-NdKOhS4u7JhDKw9G3cY6sWqFcnLITn6SqivVArbzIaf3cemShqfLGHYMx8Xlm/lBit3/5d7kXvriTUGa5YViuQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-arm64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.25.1.tgz", + "integrity": "sha512-jaN3dHi0/DDPelk0nLcXRm1q7DNJpjXy7yWaWvbfkPvI+7XNSc/lDOnCLN7gzsyzgu6qSAmgSvP9oXAhP973uQ==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-ia32": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.25.1.tgz", + "integrity": "sha512-OJykPaF4v8JidKNGz8c/q1lBO44sQNUQtq1KktJXdBLn1hPod5rE/Hko5ugKKZd+D2+o1a9MFGUEIUwO2YfgkQ==", + "cpu": [ + "ia32" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-loong64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.25.1.tgz", + "integrity": "sha512-nGfornQj4dzcq5Vp835oM/o21UMlXzn79KobKlcs3Wz9smwiifknLy4xDCLUU0BWp7b/houtdrgUz7nOGnfIYg==", + "cpu": [ + "loong64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-mips64el": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.25.1.tgz", + "integrity": "sha512-1osBbPEFYwIE5IVB/0g2X6i1qInZa1aIoj1TdL4AaAb55xIIgbg8Doq6a5BzYWgr+tEcDzYH67XVnTmUzL+nXg==", + "cpu": [ + "mips64el" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-ppc64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.25.1.tgz", + "integrity": "sha512-/6VBJOwUf3TdTvJZ82qF3tbLuWsscd7/1w+D9LH0W/SqUgM5/JJD0lrJ1fVIfZsqB6RFmLCe0Xz3fmZc3WtyVg==", + "cpu": [ + "ppc64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-riscv64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.25.1.tgz", + "integrity": "sha512-nSut/Mx5gnilhcq2yIMLMe3Wl4FK5wx/o0QuuCLMtmJn+WeWYoEGDN1ipcN72g1WHsnIbxGXd4i/MF0gTcuAjQ==", + "cpu": [ + "riscv64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-s390x": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.25.1.tgz", + "integrity": "sha512-cEECeLlJNfT8kZHqLarDBQso9a27o2Zd2AQ8USAEoGtejOrCYHNtKP8XQhMDJMtthdF4GBmjR2au3x1udADQQQ==", + "cpu": [ + "s390x" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/convex/node_modules/@esbuild/linux-x64": { + "version": "0.25.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.25.1.tgz", + "integrity": "sha512-xbfUhu/gnvSEg+EGovRc+kjBAkrvtk38RlerAzQxvMzlB4fXpCFCeUAYzJvrnhFtdeyVCDANSjJvOvGYoeKzFA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" ], "peer": true, "engines": { @@ -4491,9 +4007,10 @@ } }, "node_modules/cookie": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.1.tgz", - "integrity": "sha512-Xd8lFX4LM9QEEwxQpF9J9NTUh8pmdJO0cyRJhFiDoLTk2eH8FXlRv2IFGYVadZpqI3j8fhNrSdKCeYPxiAhLXw==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.0.2.tgz", + "integrity": "sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==", + "license": "MIT", "engines": { "node": ">=18" } @@ -4501,7 +4018,8 @@ "node_modules/core-util-is": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", - "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==" + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true }, "node_modules/cross-spawn": { "version": "7.0.6", @@ -4521,6 +4039,7 @@ "version": "8.17.2", "resolved": "https://registry.npmjs.org/cspell/-/cspell-8.17.2.tgz", "integrity": "sha512-y+INkxDa+M9f+gsyyMLjKh1tF20r2g5Gn22peSRJglrNLQtmDuRtDT9vyDHANXZcH5g6pHDnENQu/+P2Tiyu8Q==", + "dev": true, "dependencies": { "@cspell/cspell-json-reporter": "8.17.2", "@cspell/cspell-pipe": "8.17.2", @@ -4556,6 +4075,7 @@ "version": "8.17.2", "resolved": "https://registry.npmjs.org/cspell-config-lib/-/cspell-config-lib-8.17.2.tgz", "integrity": "sha512-g08lRd/smLk2je0j7HlCjdDa0dSTyI2oRP3gScWlsyXjb4NSr9qO0Wzyn5BfPgrqFdS/z4dXbHe+tnLQZCt9iQ==", + "dev": true, "dependencies": { "@cspell/cspell-types": "8.17.2", "comment-json": "^4.2.5", @@ -4569,6 +4089,7 @@ "version": "8.17.2", "resolved": "https://registry.npmjs.org/cspell-dictionary/-/cspell-dictionary-8.17.2.tgz", "integrity": "sha512-2JC9RRsZruCs3AHId/8X63fSxDoF94dleRp8y/dXS9LIX7NruofohUJwzc/3tlgzCWWdaek1RXhO5xaYX74QtA==", + "dev": true, "dependencies": { "@cspell/cspell-pipe": "8.17.2", "@cspell/cspell-types": "8.17.2", @@ -4583,6 +4104,7 @@ "version": "8.17.2", "resolved": "https://registry.npmjs.org/cspell-gitignore/-/cspell-gitignore-8.17.2.tgz", "integrity": "sha512-zCTTN30zV96LkZmUDrLamEHpLLUGohKglKJ4iXoHQC8pDU3xTsV2qzeCQjM9SEmU3VbE1TzWq+vj0fslasv6pA==", + "dev": true, "dependencies": { "@cspell/url": "8.17.2", "cspell-glob": "8.17.2", @@ -4600,6 +4122,7 @@ "version": "8.17.2", "resolved": "https://registry.npmjs.org/cspell-glob/-/cspell-glob-8.17.2.tgz", "integrity": "sha512-MTgrWX12oY8Pq/M3PEYCTHwD6w6l+DPtBWm958nhR4dboUbwi/3KfqCtdorkhnuClqLDQuuZHp0uGBXB4cdQrw==", + "dev": true, "dependencies": { "@cspell/url": "8.17.2", "micromatch": "^4.0.8" @@ -4612,6 +4135,7 @@ "version": "8.17.2", "resolved": "https://registry.npmjs.org/cspell-grammar/-/cspell-grammar-8.17.2.tgz", "integrity": "sha512-Asg5XRvrg2yHCvBwzARBPSwI4P5/unN+bKBlxqFazHgR72WJE+ASeobfUNfGi/RxJA2+m0hO91oYtvq6LfK52w==", + "dev": true, "dependencies": { "@cspell/cspell-pipe": "8.17.2", "@cspell/cspell-types": "8.17.2" @@ -4627,6 +4151,7 @@ "version": "8.17.2", "resolved": "https://registry.npmjs.org/cspell-io/-/cspell-io-8.17.2.tgz", "integrity": "sha512-IUdhbO6gsWYiM2dgudFJQTfnFCDYjLOqal3SxH5o8oOWeu5iIZ+s3N8E1odz0L5zF2Go7zDQSKvPr7Y9OOoRfw==", + "dev": true, "dependencies": { "@cspell/cspell-service-bus": "8.17.2", "@cspell/url": "8.17.2" @@ -4639,6 +4164,7 @@ "version": "8.17.2", "resolved": "https://registry.npmjs.org/cspell-lib/-/cspell-lib-8.17.2.tgz", "integrity": "sha512-ZgkTvGh9FO+R3v5TaTqlrJEylWyZhNOzbtrQ5W35Hb3tZ9IJJklxjlcGe+gbFsjGi56kLj6c5L2NR7YX/Fdu5Q==", + "dev": true, "dependencies": { "@cspell/cspell-bundled-dicts": "8.17.2", "@cspell/cspell-pipe": "8.17.2", @@ -4673,6 +4199,7 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, "engines": { "node": ">=8" } @@ -4681,6 +4208,7 @@ "version": "8.17.2", "resolved": "https://registry.npmjs.org/cspell-trie-lib/-/cspell-trie-lib-8.17.2.tgz", "integrity": "sha512-Bw9q8EWFihkQGo8fNdfkUqYOTsC161+wrQxR7m74K4bKEmQgm0mS0sLHKUwxEOZVGGLmIw9dMQl+8WnTgqOaMQ==", + "dev": true, "dependencies": { "@cspell/cspell-pipe": "8.17.2", "@cspell/cspell-types": "8.17.2", @@ -4694,6 +4222,7 @@ "version": "13.0.0", "resolved": "https://registry.npmjs.org/commander/-/commander-13.0.0.tgz", "integrity": "sha512-oPYleIY8wmTVzkvQq10AEok6YcTC4sRUBl8F9gVuwchGVUCTbl/vhLTaQqutuuySYOsu8YTgV+OxKc/8Yvx+mQ==", + "dev": true, "engines": { "node": ">=18" } @@ -4714,12 +4243,10 @@ "version": "5.0.0", "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz", "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==", + "dev": true, "dependencies": { - "flatted": "^3.3.1", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=18" + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" } }, "node_modules/csstype": { @@ -4729,14 +4256,15 @@ "dev": true }, "node_modules/data-view-buffer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", - "integrity": "sha512-0lht7OugA5x3iJLOWFhWK/5ehONdprk0ISXqVFn/NFrDu+cuc8iADFrGQz5BnRK7LLU3JmkbXSxaqX+/mXYtUA==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", + "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -4746,29 +4274,31 @@ } }, "node_modules/data-view-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.1.tgz", - "integrity": "sha512-4J7wRJD3ABAzr8wP+OcIcqq2dlUKp4DVflx++hs5h5ZKydWMI6/D/fAot+yh6g2tHh8fLFTvNOaVN357NvSrOQ==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", + "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" + "is-data-view": "^1.0.2" }, "engines": { "node": ">= 0.4" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/inspect-js" } }, "node_modules/data-view-byte-offset": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.0.tgz", - "integrity": "sha512-t/Ygsytq+R995EJ5PZlD4Cu56sWa8InXySaViRzw9apusqsOO2bQP+SbYzAhR0pFKoB+43lYy8rWban9JSuXnA==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", + "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", "is-data-view": "^1.0.1" }, @@ -4798,10 +4328,11 @@ } }, "node_modules/deep-eql": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", - "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", "dev": true, + "license": "MIT", "dependencies": { "type-detect": "^4.0.0" }, @@ -4894,6 +4425,7 @@ "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.6.3.tgz", "integrity": "sha512-EjePK1srD3P08o2j4f0ExnylqRs5B9tJjcp9t1krH2qRi8CCdsYfwe9JgSLurFBWwq4uOlipzfk5fHNvwFKr8Q==", "dev": true, + "license": "MIT", "engines": { "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } @@ -4934,6 +4466,21 @@ "url": "https://dotenvx.com" } }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", @@ -4950,6 +4497,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "dev": true, "engines": { "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, @@ -4967,57 +4515,63 @@ } }, "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "version": "1.23.9", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.9.tgz", + "integrity": "sha512-py07lI0wjxAC/DcfK1S6G7iANonniZwTISvdPzk9hzeH0IZIshbuuFxLIU96OyF89Yb9hiqWn8M/bY83KY5vzA==", "dev": true, + "license": "MIT", "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", + "array-buffer-byte-length": "^1.0.2", + "arraybuffer.prototype.slice": "^1.0.4", "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "data-view-buffer": "^1.0.2", + "data-view-byte-length": "^1.0.2", + "data-view-byte-offset": "^1.0.1", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", + "es-set-tostringtag": "^2.1.0", + "es-to-primitive": "^1.3.0", + "function.prototype.name": "^1.1.8", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.0", + "get-symbol-description": "^1.1.0", + "globalthis": "^1.0.4", + "gopd": "^1.2.0", "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", + "has-proto": "^1.2.0", + "has-symbols": "^1.1.0", "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", + "internal-slot": "^1.1.0", + "is-array-buffer": "^3.0.5", "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", + "is-data-view": "^1.0.2", + "is-regex": "^1.2.1", + "is-shared-array-buffer": "^1.0.4", + "is-string": "^1.1.1", + "is-typed-array": "^1.1.15", + "is-weakref": "^1.1.0", + "math-intrinsics": "^1.1.0", + "object-inspect": "^1.13.3", "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", + "object.assign": "^4.1.7", + "own-keys": "^1.0.1", + "regexp.prototype.flags": "^1.5.3", + "safe-array-concat": "^1.1.3", + "safe-push-apply": "^1.0.0", + "safe-regex-test": "^1.1.0", + "set-proto": "^1.0.0", + "string.prototype.trim": "^1.2.10", + "string.prototype.trimend": "^1.0.9", "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" + "typed-array-buffer": "^1.0.3", + "typed-array-byte-length": "^1.0.3", + "typed-array-byte-offset": "^1.0.4", + "typed-array-length": "^1.0.7", + "unbox-primitive": "^1.1.0", + "which-typed-array": "^1.1.18" }, "engines": { "node": ">= 0.4" @@ -5027,13 +4581,11 @@ } }, "node_modules/es-define-property": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", - "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.2.4" - }, + "license": "MIT", "engines": { "node": ">= 0.4" } @@ -5048,10 +4600,11 @@ } }, "node_modules/es-object-atoms": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.0.0.tgz", - "integrity": "sha512-MZ4iQ6JwHOBQjahnjwaC1ZtIBH+2ohjamzAO3oaHcXYup7qxjF2fixyH+Q71voWHeOkI2q/TnJao/KfXYIZWbw==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", + "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0" }, @@ -5060,28 +4613,31 @@ } }, "node_modules/es-set-tostringtag": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.0.3.tgz", - "integrity": "sha512-3T8uNMC3OQTHkFUsFq8r/BwAXLHvU/9O9mE0fBc/MY5iq/8H7ncvO947LmYA6ldWw9Uh8Yhf25zu6n7nML5QWQ==", + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", + "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", "dev": true, + "license": "MIT", "dependencies": { - "get-intrinsic": "^1.2.4", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.6", "has-tostringtag": "^1.0.2", - "hasown": "^2.0.1" + "hasown": "^2.0.2" }, "engines": { "node": ">= 0.4" } }, "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.0.tgz", + "integrity": "sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" + "is-callable": "^1.2.7", + "is-date-object": "^1.0.5", + "is-symbol": "^1.0.4" }, "engines": { "node": ">= 0.4" @@ -5257,11 +4813,12 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, - "node_modules/cspell/node_modules/flat-cache": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-5.0.0.tgz", - "integrity": "sha512-JrqFmyUl2PnPi1OvLyTVHnQvwQ0S+e6lGSwu8OkAZlSaNIZciTY2H/cOOROxsBA1m/LZNHDsqAgDZt6akWcjsQ==", + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "dev": true, + "license": "MIT", "dependencies": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -5340,12 +4897,13 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, "bin": { "esparse": "bin/esparse.js", "esvalidate": "bin/esvalidate.js" }, "engines": { - "node": ">=4" + "node": ">=8" } }, "node_modules/esquery": { @@ -5395,6 +4953,7 @@ "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", "dev": true, + "license": "MIT", "dependencies": { "@types/estree": "^1.0.0" } @@ -5455,8 +5014,9 @@ "version": "5.2.2", "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz", "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==", + "dev": true, "engines": { - "node": ">=6.0.0" + "node": ">= 4" } }, "node_modules/fast-glob": { @@ -5490,7 +5050,8 @@ "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true }, "node_modules/fast-levenshtein": { "version": "2.0.6", @@ -5504,13 +5065,15 @@ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", "dev": true, "dependencies": { - "reusify": "^1.0.4" - } + "once": "^1.3.0", + "wrappy": "1" + } }, "node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "dev": true, "license": "MIT", "peerDependencies": { "picomatch": "^3 || ^4" @@ -5537,11 +5100,26 @@ "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, "dependencies": { - "to-regex-range": "^5.0.1" + "@inquirer/figures": "^1.0.2", + "@ljharb/through": "^2.3.13", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" }, "engines": { - "node": ">=8" + "node": ">=18" } }, "node_modules/find-up": { @@ -5564,11 +5142,9 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==", + "dev": true, "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">= 0.10" } }, "node_modules/flat-cache": { @@ -5588,15 +5164,23 @@ "node_modules/flatted": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==" + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "dev": true }, "node_modules/for-each": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", - "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==", + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", + "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", "dev": true, + "license": "MIT", "dependencies": { - "is-callable": "^1.1.3" + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" } }, "node_modules/foreground-child": { @@ -5639,80 +5223,17 @@ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", "dev": true }, - "node_modules/env-paths": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", - "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.23.3", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.23.3.tgz", - "integrity": "sha512-e+HfNH61Bj1X9/jLc5v1owaLYuHdeHHSQlkhCBiTK8rBvKaULl/beGMxwrMXjpYrv4pz22BlY570vVePA2ho4A==", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", "dev": true, - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "arraybuffer.prototype.slice": "^1.0.3", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "data-view-buffer": "^1.0.1", - "data-view-byte-length": "^1.0.1", - "data-view-byte-offset": "^1.0.0", - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-set-tostringtag": "^2.0.3", - "es-to-primitive": "^1.2.1", - "function.prototype.name": "^1.1.6", - "get-intrinsic": "^1.2.4", - "get-symbol-description": "^1.0.2", - "globalthis": "^1.0.3", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.0.3", - "has-symbols": "^1.0.3", - "hasown": "^2.0.2", - "internal-slot": "^1.0.7", - "is-array-buffer": "^3.0.4", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.1", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.1.4", - "is-shared-array-buffer": "^1.0.3", - "is-string": "^1.0.7", - "is-typed-array": "^1.1.13", - "is-weakref": "^1.0.2", - "object-inspect": "^1.13.1", - "object-keys": "^1.1.1", - "object.assign": "^4.1.5", - "regexp.prototype.flags": "^1.5.2", - "safe-array-concat": "^1.1.2", - "safe-regex-test": "^1.0.3", - "string.prototype.trim": "^1.2.9", - "string.prototype.trimend": "^1.0.8", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.2", - "typed-array-byte-length": "^1.0.1", - "typed-array-byte-offset": "^1.0.2", - "typed-array-length": "^1.0.6", - "unbox-primitive": "^1.0.2", - "which-typed-array": "^1.1.15" - }, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } @@ -5727,15 +5248,18 @@ } }, "node_modules/function.prototype.name": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.6.tgz", - "integrity": "sha512-Z5kx79swU5P27WEayXM1tBi5Ze/lbIyiNgU3qyXUOf9b2rgXYyF9Dy9Cx+IQv/Lc8WCG6L82zwUPpSS9hGehIg==", + "version": "1.1.8", + "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.1.8.tgz", + "integrity": "sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "define-properties": "^1.2.0", - "es-abstract": "^1.22.1", - "functions-have-names": "^1.2.3" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "define-properties": "^1.2.1", + "functions-have-names": "^1.2.3", + "hasown": "^2.0.2", + "is-callable": "^1.2.7" }, "engines": { "node": ">= 0.4" @@ -5749,6 +5273,7 @@ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", "dev": true, + "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -5757,8 +5282,9 @@ "version": "7.0.0", "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-7.0.0.tgz", "integrity": "sha512-47Frx13aZh01afHJTB3zTtKIlFI6vWY+MYCN9Qpew6i52rfKjnhCF/l1YlC8UmEMvvntZZ6z4PiCcmyuedR2aQ==", + "dev": true, "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, "node_modules/get-func-name": { @@ -5766,21 +5292,28 @@ "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } }, "node_modules/get-intrinsic": { - "version": "1.2.4", - "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", - "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", "dev": true, + "license": "MIT", "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", - "has-proto": "^1.0.1", - "has-symbols": "^1.0.3", - "hasown": "^2.0.0" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -5789,12 +5322,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/get-stdin": { "version": "9.0.0", "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", + "dev": true, "engines": { - "node": ">=12" + "node": ">=16" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5813,14 +5361,15 @@ } }, "node_modules/get-symbol-description": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.2.tgz", - "integrity": "sha512-g0QYk1dZBxGwk+Ngc+ltRH2IBp2f7zBkBMBJZCDerh6EhlhSR6+9irMCuT/09zD6qkarHUSn529sK/yL4S27mg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", + "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4" + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -5888,11 +5437,12 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "dev": true, "dependencies": { "ini": "4.1.1" }, "engines": { - "node": ">=18" + "node": ">=8" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" @@ -5950,12 +5500,13 @@ } }, "node_modules/gopd": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", - "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", "dev": true, - "dependencies": { - "get-intrinsic": "^1.1.3" + "license": "MIT", + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -5991,17 +5542,13 @@ "node": ">=8" } }, - "node_modules/esprima": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", - "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "node_modules/has-own-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", + "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", "dev": true, - "bin": { - "esparse": "bin/esparse.js", - "esvalidate": "bin/esvalidate.js" - }, "engines": { - "node": ">=8" + "node": ">=10" } }, "node_modules/has-property-descriptors": { @@ -6017,10 +5564,14 @@ } }, "node_modules/has-proto": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", - "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", + "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.0" + }, "engines": { "node": ">= 0.4" }, @@ -6029,10 +5580,11 @@ } }, "node_modules/has-symbols": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", - "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6114,11 +5666,12 @@ } ] }, - "node_modules/fast-equals": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/fast-equals/-/fast-equals-5.2.2.tgz", - "integrity": "sha512-V7/RktU11J3I36Nwq2JnZEM7tNm17eBJz+u25qdxBZeCKiX6BkVSZQjwWIr+IobgnZy+ag73tTZgZi7tr0LrBw==", + "node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", "dev": true, + "license": "MIT", "engines": { "node": ">= 4" } @@ -6127,21 +5680,23 @@ "version": "3.3.0", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" + "mlly": "^1.4.2", + "pkg-types": "^1.0.3" }, "engines": { - "node": ">=6" + "node": ">=14" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/sponsors/antfu" } }, "node_modules/import-meta-resolve": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", + "dev": true, "funding": { "type": "github", "url": "https://github.com/sponsors/wooorm" @@ -6156,23 +5711,13 @@ "node": ">=0.8.19" } }, - "node_modules/fast-json-stable-stringify": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", - "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", - "dev": true - }, - "node_modules/fast-levenshtein": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", - "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", - "dev": true - }, - "node_modules/fastq": { - "version": "1.17.1", - "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz", - "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==", + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", "dev": true, + "license": "ISC", "dependencies": { "once": "^1.3.0", "wrappy": "1" @@ -6188,67 +5733,70 @@ "version": "4.1.1", "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "dev": true, "engines": { "node": "^14.17.0 || ^16.13.0 || >=18.0.0" } }, - "node_modules/fill-range": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", - "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "node_modules/inquirer": { + "version": "9.3.7", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.3.7.tgz", + "integrity": "sha512-LJKFHCSeIRq9hanN14IlOtPSTe3lNES7TYDTE2xxdAy1LS5rYphajK1qtwvj3YmQXvvk0U2Vbmcni8P9EIQW9w==", "dev": true, + "license": "MIT", "dependencies": { - "@inquirer/figures": "^1.0.2", - "@ljharb/through": "^2.3.13", + "@inquirer/figures": "^1.0.3", "ansi-escapes": "^4.3.2", - "chalk": "^5.3.0", - "cli-cursor": "^3.1.0", "cli-width": "^4.1.0", "external-editor": "^3.1.0", - "lodash": "^4.17.21", "mute-stream": "1.0.0", "ora": "^5.4.1", "run-async": "^3.0.0", "rxjs": "^7.8.1", "string-width": "^4.2.3", "strip-ansi": "^6.0.1", - "wrap-ansi": "^6.2.0" + "wrap-ansi": "^6.2.0", + "yoctocolors-cjs": "^2.1.2" }, "engines": { "node": ">=18" } }, "node_modules/internal-slot": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz", - "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", + "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", "dev": true, + "license": "MIT", "dependencies": { "es-errors": "^1.3.0", - "hasown": "^2.0.0", - "side-channel": "^1.0.4" + "hasown": "^2.0.2", + "side-channel": "^1.1.0" }, "engines": { "node": ">= 0.4" } }, - "node_modules/find-up-simple": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/find-up-simple/-/find-up-simple-1.0.0.tgz", - "integrity": "sha512-q7Us7kcjj2VMePAa02hDAF6d+MzsdsAWEwYyOpwUtlerRBkOEPBCRZrAV4XfcSN8fHAgaD0hP7miwoay6DCprw==", + "node_modules/interpret": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.4.0.tgz", + "integrity": "sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.10" } }, "node_modules/is-array-buffer": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", - "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", + "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "get-intrinsic": "^1.2.1" + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" }, "engines": { "node": ">= 0.4" @@ -6257,19 +5805,44 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/flatted": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", - "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", - "dev": true + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-async-function": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", + "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "async-function": "^1.0.0", + "call-bound": "^1.0.3", + "get-proto": "^1.0.1", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } }, "node_modules/is-bigint": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", - "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", + "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", "dev": true, + "license": "MIT", "dependencies": { - "has-bigints": "^1.0.1" + "has-bigints": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6288,13 +5861,14 @@ } }, "node_modules/is-boolean-object": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", - "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", + "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -6328,11 +5902,14 @@ } }, "node_modules/is-data-view": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.1.tgz", - "integrity": "sha512-AHkaJrsUVW6wq6JS8y3JnM/GJF/9cf+k20+iDzlSaJrinEo5+7vRiteOSwBhHRiAyQATN1AmY4hwzxJKPmYf+w==", + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", + "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", "dev": true, + "license": "MIT", "dependencies": { + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", "is-typed-array": "^1.1.13" }, "engines": { @@ -6343,12 +5920,14 @@ } }, "node_modules/is-date-object": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", - "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", + "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -6357,15 +5936,32 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/gensequence": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/gensequence/-/gensequence-7.0.0.tgz", - "integrity": "sha512-47Frx13aZh01afHJTB3zTtKIlFI6vWY+MYCN9Qpew6i52rfKjnhCF/l1YlC8UmEMvvntZZ6z4PiCcmyuedR2aQ==", + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, + "node_modules/is-finalizationregistry": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", + "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-fullwidth-code-point": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", @@ -6375,6 +5971,25 @@ "node": ">=8" } }, + "node_modules/is-generator-function": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.0.tgz", + "integrity": "sha512-nPUB5km40q9e8UfN/Zc24eLlzdSf9OfKByBw9CIdw4H1giPMeA0OIJvbchsCu4npfI2QcMVBsGEBHKZ7wLTWmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-glob": { "version": "4.0.3", "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", @@ -6396,11 +6011,12 @@ "node": ">=8" } }, - "node_modules/is-negative-zero": { + "node_modules/is-map": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", + "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", + "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6408,11 +6024,11 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/get-stdin": { - "version": "9.0.0", - "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-9.0.0.tgz", - "integrity": "sha512-dVKBjfWisLAicarI2Sf+JuBE/DghV4UzNAVe9yhEJuzeREd3JhOTE9cUaJTeSa77fsbQUK3pcOpJfM59+VKZaA==", - "dev": true, + "node_modules/is-network-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-network-error/-/is-network-error-1.1.0.tgz", + "integrity": "sha512-tUdRRAnhT+OtCZR/LxZelH/C7QtjtFrTu5tXCA8pl55eTUElUHT+GPYV8MBMBvea/j+NxQqVt3LbWMRir7Gx9g==", + "license": "MIT", "engines": { "node": ">=16" }, @@ -6420,21 +6036,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "engines": { - "node": ">=0.12.0" - } - }, "node_modules/is-number-object": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", - "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", + "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -6462,14 +6072,30 @@ } }, "node_modules/is-regex": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", - "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", + "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2", - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.2", + "gopd": "^1.2.0", + "has-tostringtag": "^1.0.2", + "hasown": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-set": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", + "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "dev": true, + "license": "MIT", "engines": { "node": ">= 0.4" }, @@ -6478,12 +6104,13 @@ } }, "node_modules/is-shared-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz", - "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", + "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7" + "call-bound": "^1.0.3" }, "engines": { "node": ">= 0.4" @@ -6492,14 +6119,12 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/global-directory": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/global-directory/-/global-directory-4.0.1.tgz", - "integrity": "sha512-wHTUcDUoZ1H5/0iVqEudYW4/kAlN5cZ3j/bXn0Dpbizl9iaUVeWSHqiOjsgk6OW2bkLclbBjzewBz6weQ1zA2Q==", + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", "dev": true, - "dependencies": { - "ini": "4.1.1" - }, + "license": "MIT", "engines": { "node": ">=8" }, @@ -6508,12 +6133,14 @@ } }, "node_modules/is-string": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", - "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", + "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", "dev": true, + "license": "MIT", "dependencies": { - "has-tostringtag": "^1.0.0" + "call-bound": "^1.0.3", + "has-tostringtag": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -6523,12 +6150,15 @@ } }, "node_modules/is-symbol": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", - "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", + "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", "dev": true, + "license": "MIT", "dependencies": { - "has-symbols": "^1.0.2" + "call-bound": "^1.0.2", + "has-symbols": "^1.1.0", + "safe-regex-test": "^1.1.0" }, "engines": { "node": ">= 0.4" @@ -6538,12 +6168,13 @@ } }, "node_modules/is-typed-array": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.13.tgz", - "integrity": "sha512-uZ25/bUAlUY5fR4OKT4rZQEBrzQWYV9ZJYGGsUmEJ6thodVJ1HX64ePQ6Z0qPWP+m+Uq6e9UugrE38jeYsDSMw==", + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", + "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", "dev": true, + "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.14" + "which-typed-array": "^1.1.16" }, "engines": { "node": ">= 0.4" @@ -6564,13 +6195,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/is-weakmap": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", + "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-weakref": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", - "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", + "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.2" + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -6580,7 +6245,8 @@ "version": "2.0.5", "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/isexe": { "version": "2.0.0", @@ -6614,11 +6280,12 @@ "url": "https://github.com/sponsors/panva" } }, - "node_modules/has-own-prop": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/has-own-prop/-/has-own-prop-2.0.0.tgz", - "integrity": "sha512-Pq0h+hvsVm6dDEa8x82GnLSYHOzNDt7f0ddFa3FqcQlgzEiptPqL+XrOJNavjOzSYiYWIrgeVYYgGlLmnxwilQ==", + "node_modules/joycon": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/joycon/-/joycon-3.1.1.tgz", + "integrity": "sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==", "dev": true, + "license": "MIT", "engines": { "node": ">=10" } @@ -6641,11 +6308,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==" - }, "node_modules/json-parse-better-errors": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", @@ -6669,15 +6331,29 @@ "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", "engines": { - "node": ">=18" + "node": ">=0.10.0" } }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, "dependencies": { - "json-buffer": "3.0.1" + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/keyv/node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" } }, "node_modules/kleur": { @@ -6745,14 +6421,15 @@ "node": "^12.20.0 || ^14.13.1 || >=16.0.0" } }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "node_modules/local-pkg": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/local-pkg/-/local-pkg-0.5.1.tgz", + "integrity": "sha512-9rrA30MRRP3gBD3HTGnC6cDFpaE1kVDWxWgqWJUN0RvDNAo+Nz/9GxB+nHOH0ifbVFy0hSA1V6vFDvnx54lTEQ==", "dev": true, + "license": "MIT", "dependencies": { - "mlly": "^1.4.2", - "pkg-types": "^1.0.3" + "mlly": "^1.7.3", + "pkg-types": "^1.2.1" }, "engines": { "node": ">=14" @@ -6761,15 +6438,11 @@ "url": "https://github.com/sponsors/antfu" } }, - "node_modules/import-meta-resolve": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/import-meta-resolve/-/import-meta-resolve-4.1.0.tgz", - "integrity": "sha512-I6fiaX09Xivtk+THaMfAwnA3MVA5Big1WHF1Dfx9hFuvNIWpXnorlkzhcQf6ehrqQiiZECRt1poOAkPmer3ruw==", - "dev": true, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wooorm" - } + "node_modules/locate-character": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz", + "integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==", + "license": "MIT" }, "node_modules/locate-path": { "version": "6.0.0", @@ -6798,14 +6471,12 @@ "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, - "node_modules/ini": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.1.tgz", - "integrity": "sha512-QQnnxNyfvmHFIsj7gkPcYymR8Jdw/o7mp5ZFihxn6h8Ci6fh3Dx4E1gPjpQEpIuPo9XVNY/ZUwh4BPMjGyL01g==", + "node_modules/lodash.sortby": { + "version": "4.7.0", + "resolved": "https://registry.npmjs.org/lodash.sortby/-/lodash.sortby-4.7.0.tgz", + "integrity": "sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==", "dev": true, - "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" - } + "license": "MIT" }, "node_modules/log-symbols": { "version": "4.1.0", @@ -6889,6 +6560,7 @@ "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", "dev": true, + "license": "MIT", "dependencies": { "get-func-name": "^2.0.1" } @@ -6919,6 +6591,16 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, "node_modules/memfs": { "version": "3.5.3", "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", @@ -6968,18 +6650,20 @@ "version": "4.0.8", "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" }, "engines": { - "node": ">=8.6" + "node": ">=0.10.0" } }, "node_modules/micromatch/node_modules/picomatch": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, "license": "MIT", "engines": { "node": ">=8.6" @@ -7022,17 +6706,25 @@ } }, "node_modules/mlly": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.0.tgz", - "integrity": "sha512-U9SDaXGEREBYQgfejV97coK0UL1r+qnF2SyO9A3qcI8MzKnsIFKHNVEkrDyNncQTKQQumsasmeq84eNMdBfsNQ==", + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/mlly/-/mlly-1.7.4.tgz", + "integrity": "sha512-qmdSIPC4bDJXgZTCR7XosJiNKySV7O215tsPtDN9iEO/7q/76b/ijtgRu/+epFXSJhijtTCCGp3DWS549P3xKw==", "dev": true, + "license": "MIT", "dependencies": { - "acorn": "^8.11.3", - "pathe": "^1.1.2", - "pkg-types": "^1.1.0", - "ufo": "^1.5.3" + "acorn": "^8.14.0", + "pathe": "^2.0.1", + "pkg-types": "^1.3.0", + "ufo": "^1.5.4" } }, + "node_modules/mlly/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/mri": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/mri/-/mri-1.2.0.tgz", @@ -7066,78 +6758,625 @@ "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", "dev": true, "engines": { - "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/mz": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", + "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "dev": true, + "dependencies": { + "any-promise": "^1.0.0", + "object-assign": "^4.0.1", + "thenify-all": "^1.0.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.8", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", + "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true, + "license": "MIT" + }, + "node_modules/next": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/next/-/next-15.3.1.tgz", + "integrity": "sha512-8+dDV0xNLOgHlyBxP1GwHGVaNXsmp+2NhZEYrXr24GWLHtt27YrBPbPuHvzlhi7kZNYjeJNR93IF5zfFu5UL0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@next/env": "15.3.1", + "@swc/counter": "0.1.3", + "@swc/helpers": "0.5.15", + "busboy": "1.6.0", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.4.31", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, + "engines": { + "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "15.3.1", + "@next/swc-darwin-x64": "15.3.1", + "@next/swc-linux-arm64-gnu": "15.3.1", + "@next/swc-linux-arm64-musl": "15.3.1", + "@next/swc-linux-x64-gnu": "15.3.1", + "@next/swc-linux-x64-musl": "15.3.1", + "@next/swc-win32-arm64-msvc": "15.3.1", + "@next/swc-win32-x64-msvc": "15.3.1", + "sharp": "^0.34.1" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.41.2", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } + } + }, + "node_modules/next/node_modules/@emnapi/runtime": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.4.3.tgz", + "integrity": "sha512-pBPWdu6MLKROBX05wSNKcNb++m5Er+KQ9QkB+WVM+pW2Kx9hoSrVTnu3BdkI5eBLZoKu/J6mW/B6i6bJB2ytXQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/next/node_modules/@img/sharp-darwin-arm64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.34.1.tgz", + "integrity": "sha512-pn44xgBtgpEbZsu+lWf2KNb6OAf70X68k+yk69Ic2Xz11zHR/w24/U49XT7AeRwJ0Px+mhALhU5LPci1Aymk7A==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.1.0" + } + }, + "node_modules/next/node_modules/@img/sharp-darwin-x64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.34.1.tgz", + "integrity": "sha512-VfuYgG2r8BpYiOUN+BfYeFo69nP/MIwAtSJ7/Zpxc5QF3KS22z8Pvg3FkrSFJBPNQ7mmcUcYQFBmEQp7eu1F8Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.1.0" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.1.0.tgz", + "integrity": "sha512-HZ/JUmPwrJSoM4DIQPv/BfNh9yrOA8tlBbqbLz4JZ5uew2+o22Ik+tHQJcih7QJuSa0zo5coHTfD5J8inqj9DA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.1.0.tgz", + "integrity": "sha512-Xzc2ToEmHN+hfvsl9wja0RlnXEgpKNmftriQp6XzY/RaSfwD9th+MSh0WQKzUreLKKINb3afirxW7A0fz2YWuQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "darwin" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.1.0.tgz", + "integrity": "sha512-s8BAd0lwUIvYCJyRdFqvsj+BJIpDBSxs6ivrOPm/R7piTs5UIwY5OjXrP2bqXC9/moGsyRa37eYWYCOGVXxVrA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.1.0.tgz", + "integrity": "sha512-IVfGJa7gjChDET1dK9SekxFFdflarnUB8PwW8aGwEoF3oAsSDuNUTYS+SKDOyOJxQyDC1aPFMuRYLoDInyV9Ew==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.1.0.tgz", + "integrity": "sha512-xukSwvhguw7COyzvmjydRb3x/09+21HykyapcZchiCUkTThEQEOMtBj9UhkaBRLuBrgLFzQ2wbxdeCCJW/jgJA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.1.0.tgz", + "integrity": "sha512-yRj2+reB8iMg9W5sULM3S74jVS7zqSzHG3Ol/twnAAkAhnGQnpjj6e4ayUz7V+FpKypwgs82xbRdYtchTTUB+Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.1.0.tgz", + "integrity": "sha512-jYZdG+whg0MDK+q2COKbYidaqW/WTz0cc1E+tMAusiDygrM4ypmSCjOJPmFTvHHJ8j/6cAGyeDWZOsK06tP33w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.1.0.tgz", + "integrity": "sha512-wK7SBdwrAiycjXdkPnGCPLjYb9lD4l6Ze2gSdAGVZrEL05AOUJESWU2lhlC+Ffn5/G+VKuSm6zzbQSzFX/P65A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "LGPL-3.0-or-later", + "optional": true, + "os": [ + "linux" + ], + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-linux-arm": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.34.1.tgz", + "integrity": "sha512-anKiszvACti2sGy9CirTlNyk7BjjZPiML1jt2ZkTdcvpLU1YH6CXwRAZCA2UmRXnhiIftXQ7+Oh62Ji25W72jA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.1.0" + } + }, + "node_modules/next/node_modules/@img/sharp-linux-arm64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.34.1.tgz", + "integrity": "sha512-kX2c+vbvaXC6vly1RDf/IWNXxrlxLNpBVWkdpRq5Ka7OOKj6nr66etKy2IENf6FtOgklkg9ZdGpEu9kwdlcwOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.1.0" + } + }, + "node_modules/next/node_modules/@img/sharp-linux-s390x": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.34.1.tgz", + "integrity": "sha512-7s0KX2tI9mZI2buRipKIw2X1ufdTeaRgwmRabt5bi9chYfhur+/C1OXg3TKg/eag1W+6CCWLVmSauV1owmRPxA==", + "cpu": [ + "s390x" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.1.0" + } + }, + "node_modules/next/node_modules/@img/sharp-linux-x64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.34.1.tgz", + "integrity": "sha512-wExv7SH9nmoBW3Wr2gvQopX1k8q2g5V5Iag8Zk6AVENsjwd+3adjwxtp3Dcu2QhOXr8W9NusBU6XcQUohBZ5MA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.1.0" + } + }, + "node_modules/next/node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.34.1.tgz", + "integrity": "sha512-DfvyxzHxw4WGdPiTF0SOHnm11Xv4aQexvqhRDAoD00MzHekAj9a/jADXeXYCDFH/DzYruwHbXU7uz+H+nWmSOQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.1.0" + } + }, + "node_modules/next/node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.34.1.tgz", + "integrity": "sha512-pax/kTR407vNb9qaSIiWVnQplPcGU8LRIJpDT5o8PdAx5aAA7AS3X9PS8Isw1/WfqgQorPotjrZL3Pqh6C5EBg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.1.0" + } + }, + "node_modules/next/node_modules/@img/sharp-wasm32": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.34.1.tgz", + "integrity": "sha512-YDybQnYrLQfEpzGOQe7OKcyLUCML4YOXl428gOOzBgN6Gw0rv8dpsJ7PqTHxBnXnwXr8S1mYFSLSa727tpz0xg==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "optional": true, + "dependencies": { + "@emnapi/runtime": "^1.4.0" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-win32-ia32": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.34.1.tgz", + "integrity": "sha512-WKf/NAZITnonBf3U1LfdjoMgNO5JYRSlhovhRhMxXVdvWYveM4kM3L8m35onYIdh75cOMCo1BexgVQcCDzyoWw==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@img/sharp-win32-x64": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.34.1.tgz", + "integrity": "sha512-hw1iIAHpNE8q3uMIRCgGOeDoz9KtFNarFLQclLxr/LK1VBkj8nby18RjFvr6aP7USRYAjTZW6yisnBWMX571Tw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND LGPL-3.0-or-later", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + } + }, + "node_modules/next/node_modules/@next/swc-darwin-arm64": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.3.1.tgz", + "integrity": "sha512-hjDw4f4/nla+6wysBL07z52Gs55Gttp5Bsk5/8AncQLJoisvTBP0pRIBK/B16/KqQyH+uN4Ww8KkcAqJODYH3w==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/next/node_modules/@next/swc-darwin-x64": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.3.1.tgz", + "integrity": "sha512-q+aw+cJ2ooVYdCEqZVk+T4Ni10jF6Fo5DfpEV51OupMaV5XL6pf3GCzrk6kSSZBsMKZtVC1Zm/xaNBFpA6bJ2g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/next/node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.3.1.tgz", + "integrity": "sha512-wBQ+jGUI3N0QZyWmmvRHjXjTWFy8o+zPFLSOyAyGFI94oJi+kK/LIZFJXeykvgXUk1NLDAEFDZw/NVINhdk9FQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/next/node_modules/@next/swc-linux-arm64-musl": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.3.1.tgz", + "integrity": "sha512-IIxXEXRti/AulO9lWRHiCpUUR8AR/ZYLPALgiIg/9ENzMzLn3l0NSxVdva7R/VDcuSEBo0eGVCe3evSIHNz0Hg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/next/node_modules/@next/swc-linux-x64-gnu": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.3.1.tgz", + "integrity": "sha512-bfI4AMhySJbyXQIKH5rmLJ5/BP7bPwuxauTvVEiJ/ADoddaA9fgyNNCcsbu9SlqfHDoZmfI6g2EjzLwbsVTr5A==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/mz": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/mz/-/mz-2.7.0.tgz", - "integrity": "sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==", + "node_modules/next/node_modules/@next/swc-linux-x64-musl": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.3.1.tgz", + "integrity": "sha512-FeAbR7FYMWR+Z+M5iSGytVryKHiAsc0x3Nc3J+FD5NVbD5Mqz7fTSy8CYliXinn7T26nDMbpExRUI/4ekTvoiA==", + "cpu": [ + "x64" + ], "dev": true, - "dependencies": { - "any-promise": "^1.0.0", - "object-assign": "^4.0.1", - "thenify-all": "^1.0.0" + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/nanoid": { - "version": "3.3.8", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.8.tgz", - "integrity": "sha512-WNLf5Sd8oZxOm+TzppcYk8gVOgP+l58xNy58D0nbUnOxOWRWvlcCV4kUF7ltmI6PsrLl/BgKEyS4mqsGChFN0w==", + "node_modules/next/node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.3.1.tgz", + "integrity": "sha512-yP7FueWjphQEPpJQ2oKmshk/ppOt+0/bB8JC8svPUZNy0Pi3KbPx2Llkzv1p8CoQa+D2wknINlJpHf3vtChVBw==", + "cpu": [ + "arm64" + ], "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } + "license": "MIT", + "optional": true, + "os": [ + "win32" ], - "bin": { - "nanoid": "bin/nanoid.cjs" - }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">= 10" } }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "node_modules/next/node_modules/@next/swc-win32-x64-msvc": { + "version": "15.3.1", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.3.1.tgz", + "integrity": "sha512-3PMvF2zRJAifcRNni9uMk/gulWfWS+qVI/pagd+4yLF5bcXPZPPH2xlYRYOsUjmCJOXSTAC2PjRzbhsRzR2fDQ==", + "cpu": [ + "x64" + ], "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^18.18.0 || ^19.8.0 || >= 20.0.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "15.0.3", - "@next/swc-darwin-x64": "15.0.3", - "@next/swc-linux-arm64-gnu": "15.0.3", - "@next/swc-linux-arm64-musl": "15.0.3", - "@next/swc-linux-x64-gnu": "15.0.3", - "@next/swc-linux-x64-musl": "15.0.3", - "@next/swc-win32-arm64-msvc": "15.0.3", - "@next/swc-win32-x64-msvc": "15.0.3", - "sharp": "^0.33.5" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.41.2", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-66855b96-20241106", - "react-dom": "^18.2.0 || 19.0.0-rc-66855b96-20241106", - "sass": "^1.3.0" - }, - "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@playwright/test": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - }, - "sass": { - "optional": true - } + "node": ">= 10" } }, "node_modules/next/node_modules/postcss": { @@ -7168,6 +7407,48 @@ "node": "^10 || ^12 || >=14" } }, + "node_modules/next/node_modules/sharp": { + "version": "0.34.1", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.34.1.tgz", + "integrity": "sha512-1j0w61+eVxu7DawFJtnfYcvSv6qPFvfTaqzTQ2BLknVhHTwGS8sc63ZBF4rzkWMBVKybo4S5OBtDdZahh2A1xg==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "color": "^4.2.3", + "detect-libc": "^2.0.3", + "semver": "^7.7.1" + }, + "engines": { + "node": "^18.17.0 || ^20.3.0 || >=21.0.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.34.1", + "@img/sharp-darwin-x64": "0.34.1", + "@img/sharp-libvips-darwin-arm64": "1.1.0", + "@img/sharp-libvips-darwin-x64": "1.1.0", + "@img/sharp-libvips-linux-arm": "1.1.0", + "@img/sharp-libvips-linux-arm64": "1.1.0", + "@img/sharp-libvips-linux-ppc64": "1.1.0", + "@img/sharp-libvips-linux-s390x": "1.1.0", + "@img/sharp-libvips-linux-x64": "1.1.0", + "@img/sharp-libvips-linuxmusl-arm64": "1.1.0", + "@img/sharp-libvips-linuxmusl-x64": "1.1.0", + "@img/sharp-linux-arm": "0.34.1", + "@img/sharp-linux-arm64": "0.34.1", + "@img/sharp-linux-s390x": "0.34.1", + "@img/sharp-linux-x64": "0.34.1", + "@img/sharp-linuxmusl-arm64": "0.34.1", + "@img/sharp-linuxmusl-x64": "0.34.1", + "@img/sharp-wasm32": "0.34.1", + "@img/sharp-win32-ia32": "0.34.1", + "@img/sharp-win32-x64": "0.34.1" + } + }, "node_modules/nice-try": { "version": "1.0.5", "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", @@ -7209,6 +7490,7 @@ "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", "dev": true, + "license": "MIT", "dependencies": { "ansi-styles": "^3.2.1", "chalk": "^2.4.1", @@ -7329,43 +7611,22 @@ "node": ">=0.10.0" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "dev": true - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "dev": true - }, - "node_modules/json-stable-stringify-without-jsonify": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", - "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", - "dev": true - }, - "node_modules/jwt-decode": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/jwt-decode/-/jwt-decode-4.0.0.tgz", - "integrity": "sha512-+KJGIyHgkGuIq3IEBNftfhW/LfWhXUIY6OmyVWjliu5KH1y0fw7VQ8YndE2O4qZdMSd9SqbnC8GOcZEy0Om7sA==", + "node_modules/npm-run-all/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", "engines": { "node": ">=0.10.0" } }, - "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "node_modules/npm-run-all/node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", "dev": true, + "license": "MIT", "dependencies": { "has-flag": "^3.0.0" }, @@ -7416,10 +7677,14 @@ } }, "node_modules/object-inspect": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", - "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "version": "1.13.4", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -7434,14 +7699,17 @@ } }, "node_modules/object.assign": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz", - "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", + "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.5", + "call-bind": "^1.0.8", + "call-bound": "^1.0.3", "define-properties": "^1.2.1", - "has-symbols": "^1.0.3", + "es-object-atoms": "^1.0.0", + "has-symbols": "^1.1.0", "object-keys": "^1.1.1" }, "engines": { @@ -7582,6 +7850,24 @@ "@node-rs/bcrypt": "1.9.0" } }, + "node_modules/own-keys": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.1.tgz", + "integrity": "sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-intrinsic": "^1.2.6", + "object-keys": "^1.1.1", + "safe-push-apply": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -7612,17 +7898,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, "node_modules/parse-json": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", @@ -7645,15 +7920,12 @@ "node": ">=8" } }, - "node_modules/micromatch": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", - "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", "dev": true, - "dependencies": { - "braces": "^3.0.3", - "picomatch": "^2.3.1" - }, + "license": "MIT", "engines": { "node": ">=0.10.0" } @@ -7711,13 +7983,15 @@ "version": "1.1.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", "dev": true, + "license": "MIT", "engines": { "node": "*" } @@ -7732,6 +8006,7 @@ "version": "4.0.2", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -7771,16 +8046,24 @@ } }, "node_modules/pkg-types": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.1.1.tgz", - "integrity": "sha512-ko14TjmDuQJ14zsotODv7dBlwxKhUKQEhuhmbqo1uCi9BB0Z2alo/wAXg6q1dTR5TyuqYyWhjtfe/Tsh+X28jQ==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-1.3.1.tgz", + "integrity": "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==", "dev": true, + "license": "MIT", "dependencies": { - "confbox": "^0.1.7", - "mlly": "^1.7.0", - "pathe": "^1.1.2" + "confbox": "^0.1.8", + "mlly": "^1.7.4", + "pathe": "^2.0.1" } }, + "node_modules/pkg-types/node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -7900,6 +8183,34 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -7960,7 +8271,8 @@ "version": "18.3.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", - "dev": true + "dev": true, + "license": "MIT" }, "node_modules/read-pkg": { "version": "3.0.0", @@ -8039,16 +8351,42 @@ "node": ">= 0.10" } }, + "node_modules/reflect.getprototypeof": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", + "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.8", + "define-properties": "^1.2.1", + "es-abstract": "^1.23.9", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.7", + "get-proto": "^1.0.1", + "which-builtin-type": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/regexp.prototype.flags": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz", - "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==", + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", + "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bind": "^1.0.8", "define-properties": "^1.2.1", "es-errors": "^1.3.0", - "set-function-name": "^2.0.1" + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "set-function-name": "^2.0.2" }, "engines": { "node": ">= 0.4" @@ -8061,8 +8399,12 @@ "version": "1.6.1", "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "dev": true, "engines": { - "node": ">=0.10" + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, "node_modules/resolve": { @@ -8082,14 +8424,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "engines": { - "node": ">=4" - } - }, "node_modules/restore-cursor": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", @@ -8103,16 +8437,6 @@ "node": ">=8" } }, - "node_modules/reusify": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", - "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", - "dev": true, - "engines": { - "iojs": ">=1.0.0", - "node": ">=0.10.0" - } - }, "node_modules/rimraf": { "version": "3.0.2", "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", @@ -8224,14 +8548,16 @@ } }, "node_modules/safe-array-concat": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", - "integrity": "sha512-vj6RsCsWBCf19jIeHEfkRMw8DPiBb+DMXklQ/1SGDHOMlHdPUkZXFQ2YdplS23zESTijAcurb1aSgJA3AgMu1Q==", + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.3.tgz", + "integrity": "sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", - "get-intrinsic": "^1.2.4", - "has-symbols": "^1.0.3", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "get-intrinsic": "^1.2.6", + "has-symbols": "^1.1.0", "isarray": "^2.0.5" }, "engines": { @@ -8261,15 +8587,33 @@ } ] }, + "node_modules/safe-push-apply": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", + "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "isarray": "^2.0.5" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/safe-regex-test": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.3.tgz", - "integrity": "sha512-CdASjNJPvRa7roO6Ra/gLYBTzYzzPyyBXxIMdGW3USQLyjWEls2RgW5UBTXaQVp+OrpeCK3bLem8smtmheoRuw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", + "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.6", + "call-bound": "^1.0.2", "es-errors": "^1.3.0", - "is-regex": "^1.1.4" + "is-regex": "^1.2.1" }, "engines": { "node": ">= 0.4" @@ -8294,9 +8638,10 @@ } }, "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "version": "7.7.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.1.tgz", + "integrity": "sha512-hlq8tAfn0m/61p4BVRcPzIGr6LKiMwo4VM6dGi6pt4qcRkmNzTcWq6eCEjEh+qXjkMDvPlOFFSGwQjoEa6gyMA==", + "dev": true, "license": "ISC", "bin": { "semver": "bin/semver.js" @@ -8339,6 +8684,7 @@ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", "dev": true, + "license": "MIT", "dependencies": { "define-data-property": "^1.1.4", "es-errors": "^1.3.0", @@ -8349,54 +8695,19 @@ "node": ">= 0.4" } }, - "node_modules/sharp": { - "version": "0.33.5", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.33.5.tgz", - "integrity": "sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==", + "node_modules/set-proto": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", + "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", "dev": true, - "hasInstallScript": true, - "license": "Apache-2.0", - "optional": true, + "license": "MIT", "dependencies": { - "color": "^4.2.3", - "detect-libc": "^2.0.3", - "semver": "^7.6.3" + "dunder-proto": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.0.0" }, "engines": { - "node": "^18.17.0 || ^20.3.0 || >=21.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.33.5", - "@img/sharp-darwin-x64": "0.33.5", - "@img/sharp-libvips-darwin-arm64": "1.0.4", - "@img/sharp-libvips-darwin-x64": "1.0.4", - "@img/sharp-libvips-linux-arm": "1.0.5", - "@img/sharp-libvips-linux-arm64": "1.0.4", - "@img/sharp-libvips-linux-s390x": "1.0.4", - "@img/sharp-libvips-linux-x64": "1.0.4", - "@img/sharp-libvips-linuxmusl-arm64": "1.0.4", - "@img/sharp-libvips-linuxmusl-x64": "1.0.4", - "@img/sharp-linux-arm": "0.33.5", - "@img/sharp-linux-arm64": "0.33.5", - "@img/sharp-linux-s390x": "0.33.5", - "@img/sharp-linux-x64": "0.33.5", - "@img/sharp-linuxmusl-arm64": "0.33.5", - "@img/sharp-linuxmusl-x64": "0.33.5", - "@img/sharp-wasm32": "0.33.5", - "@img/sharp-win32-ia32": "0.33.5", - "@img/sharp-win32-x64": "0.33.5" + "node": ">= 0.4" } }, "node_modules/shebang-command": { @@ -8447,15 +8758,73 @@ } }, "node_modules/side-channel": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", - "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", + "integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.4", - "object-inspect": "^1.13.1" + "object-inspect": "^1.13.3", + "side-channel-list": "^1.0.0", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz", + "integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" }, "engines": { "node": ">= 0.4" @@ -8495,13 +8864,16 @@ "license": "MIT", "optional": true }, - "node_modules/picomatch": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", - "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "node_modules/sirv": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.1.tgz", + "integrity": "sha512-FoqMu0NCGBLCcAkS1qA+XJIQTR6/JHfQXl+uGteNCQ76T91DMUjPa9xfmeqMY3z80nLSg9yQmNjK0Px6RWsH/A==", "dev": true, - "engines": { - "node": ">=8.6" + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" }, "engines": { "node": ">=18" @@ -8673,15 +9045,19 @@ } }, "node_modules/string.prototype.trim": { - "version": "1.2.9", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.9.tgz", - "integrity": "sha512-klHuCNxiMZ8MlsOihJhJEBJAiMVqU3Z2nEXWfWnIqjN0gEFS9J9+IxKozWWtQGcgoa1WUZzLjKPTr4ZHNFTFxw==", + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.10.tgz", + "integrity": "sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", + "define-data-property": "^1.1.4", "define-properties": "^1.2.1", - "es-abstract": "^1.23.0", - "es-object-atoms": "^1.0.0" + "es-abstract": "^1.23.5", + "es-object-atoms": "^1.0.0", + "has-property-descriptors": "^1.0.2" }, "engines": { "node": ">= 0.4" @@ -8691,15 +9067,20 @@ } }, "node_modules/string.prototype.trimend": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.8.tgz", - "integrity": "sha512-p73uL5VCHCO2BZZ6krwwQE3kCzM7NKmis8S//xEC6fQonchbum4eP6kR4DLEjQFO3Wnj3Fuo8NM0kOSjVdHjZQ==", + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.9.tgz", + "integrity": "sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", + "call-bound": "^1.0.2", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0" }, + "engines": { + "node": ">= 0.4" + }, "funding": { "url": "https://github.com/sponsors/ljharb" } @@ -8764,11 +9145,12 @@ "node": ">=6" } }, - "node_modules/repeat-string": { - "version": "1.6.1", - "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", - "integrity": "sha512-PV0dzCYDNfRi1jCDbJzpW7jNNDRuCOG/jI5ctQcGKt/clZD+YcPS3yIlWuTJMmESC8aevCFmWJy5wjAFgNqN6w==", + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", "dev": true, + "license": "MIT", "engines": { "node": ">=8" }, @@ -8807,26 +9189,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">= 12.0.0" - }, - "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" - }, - "peerDependenciesMeta": { - "@babel/core": { - "optional": true - }, - "babel-plugin-macros": { - "optional": true - } - } - }, "node_modules/sucrase": { "version": "3.35.0", "resolved": "https://registry.npmjs.org/sucrase/-/sucrase-3.35.0.tgz", @@ -8920,9 +9282,9 @@ } }, "node_modules/svelte": { - "version": "5.26.2", - "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.26.2.tgz", - "integrity": "sha512-e2TEcGK2YKVwDWYy5OsptVclYgDvfY1E/8IzPiOq63uG/GDo/j5VUYTC9EinQNraoZalbMWN+5f5TYC1QlAqOw==", + "version": "5.28.2", + "resolved": "https://registry.npmjs.org/svelte/-/svelte-5.28.2.tgz", + "integrity": "sha512-FbWBxgWOpQfhKvoGJv/TFwzqb4EhJbwCD17dB0tEpQiw1XyUEKZJtgm4nA4xq3LLsMo7hu5UY/BOFmroAxKTMg==", "license": "MIT", "dependencies": { "@ampproject/remapping": "^2.3.0", @@ -8945,9 +9307,9 @@ } }, "node_modules/svelte-check": { - "version": "4.1.6", - "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.1.6.tgz", - "integrity": "sha512-P7w/6tdSfk3zEVvfsgrp3h3DFC75jCdZjTQvgGJtjPORs1n7/v2VMPIoty3PWv7jnfEm3x0G/p9wH4pecTb0Wg==", + "version": "4.1.7", + "resolved": "https://registry.npmjs.org/svelte-check/-/svelte-check-4.1.7.tgz", + "integrity": "sha512-1jX4BzXrQJhC/Jt3SqYf6Ntu//vmfc6VWp07JkRfK2nn+22yIblspVUo96gzMkg0Zov8lQicxhxsMzOctwcMQQ==", "dev": true, "license": "MIT", "dependencies": { @@ -8984,15 +9346,12 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/semver": { - "version": "7.6.3", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.3.tgz", - "integrity": "sha512-oVekP1cKtI+CTDvHWYFUcMtsK/00wmAEfyqKfNdARm8u1wNVhSgaX7A8d4UuIlUI5e84iEwOhs7ZPYRmzU9U6A==", + "node_modules/svelte-check/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" - }, + "license": "MIT", "engines": { "node": ">= 14.18.0" }, @@ -9035,12 +9394,13 @@ "dev": true }, "node_modules/tinyglobby": { - "version": "0.2.12", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.12.tgz", - "integrity": "sha512-qkf4trmKSIiMTs/E63cxH+ojC2unam7rJ0WrauAzpT3ECNTxGRMlaXxVbfxMUC/w0LaYk6jQ4y/nGR9uBO3tww==", + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.13.tgz", + "integrity": "sha512-mEwzpUgrLySlveBwEVDMKk5B57bhLPYovRfPAXD5gA/98Opn0rCDj3GtLwFvCvH5RK9uPCExUROW5NjDwvqkxw==", + "dev": true, "license": "MIT", "dependencies": { - "fdir": "^6.4.3", + "fdir": "^6.4.4", "picomatch": "^4.0.2" }, "engines": { @@ -9064,6 +9424,7 @@ "resolved": "https://registry.npmjs.org/tinyspy/-/tinyspy-2.2.1.tgz", "integrity": "sha512-KYad6Vy5VDWV4GH3fjpseMQ/XU2BhIYP7Vzd0LG44qRWm/Yt2WCOTicFdvmgo6gWaqooMQCawTtILVQJupKu7A==", "dev": true, + "license": "MIT", "engines": { "node": ">=14.0.0" } @@ -9080,17 +9441,6 @@ "node": ">=0.6.0" } }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dependencies": { - "is-number": "^7.0.0" - }, - "engines": { - "node": ">=8.0" - } - }, "node_modules/totalist": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", @@ -9129,10 +9479,11 @@ "dev": true }, "node_modules/tslib": { - "version": "2.6.2", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", - "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", - "devOptional": true + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "devOptional": true, + "license": "0BSD" }, "node_modules/tsup": { "version": "8.0.2", @@ -9595,10 +9946,11 @@ } }, "node_modules/type-detect": { - "version": "4.0.8", - "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", - "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", "dev": true, + "license": "MIT", "engines": { "node": ">=4" } @@ -9616,30 +9968,32 @@ } }, "node_modules/typed-array-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.2.tgz", - "integrity": "sha512-gEymJYKZtKXzzBzM4jqa9w6Q1Jjm7x2d+sh19AdsD4wqnMPDYyvwpsIc2Q/835kHuo3BEQ7CjelGhfTsoBb2MQ==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", + "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bound": "^1.0.3", "es-errors": "^1.3.0", - "is-typed-array": "^1.1.13" + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" } }, "node_modules/typed-array-byte-length": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.1.tgz", - "integrity": "sha512-3iMJ9q0ao7WE9tWcaYKIptkNBuOIcZCCT0d4MRvuuH88fEoEH62IuQe0OtraD3ebQEoTRk8XCBoknUNc1Y67pw==", + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", + "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", "dev": true, + "license": "MIT", "dependencies": { - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.14" }, "engines": { "node": ">= 0.4" @@ -9649,60 +10003,41 @@ } }, "node_modules/typed-array-byte-offset": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.2.tgz", - "integrity": "sha512-Ous0vodHa56FviZucS2E63zkgtgrACj7omjwd/8lTEMEPFFyjfixMZ1ZXenpgCFBBt4EC1J2XsyVS2gkG0eTFA==", + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.4.tgz", + "integrity": "sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", + "call-bind": "^1.0.8", "for-each": "^0.3.3", - "gopd": "^1.0.1", - "has-proto": "^1.0.3", - "is-typed-array": "^1.1.13" + "gopd": "^1.2.0", + "has-proto": "^1.2.0", + "is-typed-array": "^1.1.15", + "reflect.getprototypeof": "^1.0.9" }, "engines": { - "node": ">=0.8" - } - }, - "node_modules/tinybench": { - "version": "2.8.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.8.0.tgz", - "integrity": "sha512-1/eK7zUnIklz4JUUlL+658n58XO2hHLQfSk1Zf2LKieUjxidN16eKFEoDEfjHc3ohofSSqK3X5yO6VGb6iW8Lw==", - "dev": true - }, - "node_modules/tinyglobby": { - "version": "0.2.10", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.10.tgz", - "integrity": "sha512-Zc+8eJlFMvgatPZTl6A9L/yht8QqdmUNtURHaKZLmKBE12hNPSrqNkUp2cs3M/UKmNVVAMFQYSjYIVHDjW5zew==", - "dev": true, - "dependencies": { - "fdir": "^6.4.2", - "picomatch": "^4.0.2" + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/tinyglobby/node_modules/fdir": { - "version": "6.4.3", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.3.tgz", - "integrity": "sha512-PMXmW2y1hDDfTSRc9gaXIuCCRpuoz3Kaz8cUelp3smouvfT632ozg2vrT6lJsHKKOF59YLbOGfAWGUcKEfRMQw==", + "node_modules/typed-array-length": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.7.tgz", + "integrity": "sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==", "dev": true, - "peerDependencies": { - "picomatch": "^3 || ^4" + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "for-each": "^0.3.3", + "gopd": "^1.0.1", + "is-typed-array": "^1.1.13", + "possible-typed-array-names": "^1.0.0", + "reflect.getprototypeof": "^1.0.6" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } - } - }, - "node_modules/tinyglobby/node_modules/picomatch": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", - "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", - "dev": true, "engines": { "node": ">= 0.4" }, @@ -9711,10 +10046,11 @@ } }, "node_modules/typescript": { - "version": "5.5.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.5.3.tgz", - "integrity": "sha512-/hreyEujaB0w76zKo6717l3L0o/qEUtRgdvUBvlkhoWeOVMjMuHNHk0BRBzikzuGDqNmPQbg5ifMEqsHLiIUcQ==", + "version": "5.8.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz", + "integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==", "dev": true, + "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -9724,30 +10060,26 @@ } }, "node_modules/ufo": { - "version": "1.5.3", - "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.5.3.tgz", - "integrity": "sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==", - "dev": true + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/ufo/-/ufo-1.6.1.tgz", + "integrity": "sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==", + "dev": true, + "license": "MIT" }, "node_modules/unbox-primitive": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", - "integrity": "sha512-61pPlCD9h51VoreyJ0BReideM3MDKMKnh6+V9L08331ipq6Q8OFXZYiqP6n/tbHx4s5I9uRhcye6BrbkizkBDw==", + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", + "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", "dev": true, + "license": "MIT", "dependencies": { - "os-tmpdir": "~1.0.2" + "call-bound": "^1.0.3", + "has-bigints": "^1.0.2", + "has-symbols": "^1.1.0", + "which-boxed-primitive": "^1.1.1" }, "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/to-regex-range": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", - "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", - "dev": true, - "dependencies": { - "is-number": "^7.0.0" + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" @@ -9785,18 +10117,18 @@ } }, "node_modules/vite": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.1.tgz", - "integrity": "sha512-kkzzkqtMESYklo96HKKPE5KKLkC1amlsqt+RjFMlX2AvbRB/0wghap19NdBxxwGZ+h/C6DLCrcEphPIItlGrRQ==", + "version": "6.3.4", + "resolved": "https://registry.npmjs.org/vite/-/vite-6.3.4.tgz", + "integrity": "sha512-BiReIiMS2fyFqbqNT/Qqt4CVITDU9M9vE+DKcVAsB+ZV0wvTKd+3hMbkpxz1b+NmEDMegpVbisKiAZOnvO92Sw==", "dev": true, "license": "MIT", "dependencies": { "esbuild": "^0.25.0", - "fdir": "^6.4.3", + "fdir": "^6.4.4", "picomatch": "^4.0.2", "postcss": "^8.5.3", "rollup": "^4.34.9", - "tinyglobby": "^0.2.12" + "tinyglobby": "^0.2.13" }, "bin": { "vite": "bin/vite.js" @@ -9860,10 +10192,11 @@ } }, "node_modules/vite-node": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.0.tgz", - "integrity": "sha512-de6HJgzC+TFzOu0NTC4RAIsyf/DY/ibWDYQUcuEA84EMHhcefTUGkjFHKKEJhQN4A+6I0u++kr3l36ZF2d7XRw==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-1.6.1.tgz", + "integrity": "sha512-YAXkfvGtuTzwWbDSACdJSg4A4DZiAqckWe90Zapc/sEX3XvHcw1NdurM/6od8J207tSDqNbSsgdCacBgvJKFuA==", "dev": true, + "license": "MIT", "dependencies": { "cac": "^6.7.14", "debug": "^4.3.4", @@ -10312,9 +10645,9 @@ } }, "node_modules/vite-node/node_modules/vite": { - "version": "5.4.18", - "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.18.tgz", - "integrity": "sha512-1oDcnEp3lVyHCuQ2YFelM4Alm2o91xNoMncRm1U7S+JdYfYOvbiGZ3/CxGttrOu2M/KcGz7cRC2DoNUA6urmMA==", + "version": "5.4.19", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.4.19.tgz", + "integrity": "sha512-qO3aKv3HoQC8QKiNSTuUM1l9o/XX3+c+VTgLHbJWHZGeTPVAg2XwazI9UWzoxjIJCGCV2zU60uqMzjeLZuULqA==", "dev": true, "license": "MIT", "dependencies": { @@ -10391,16 +10724,17 @@ } }, "node_modules/vitest": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.0.tgz", - "integrity": "sha512-H5r/dN06swuFnzNFhq/dnz37bPXnq8xB2xB5JOVk8K09rUtoeNN+LHWkoQ0A/i3hvbUKKcCei9KpbxqHMLhLLA==", + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-1.6.1.tgz", + "integrity": "sha512-Ljb1cnSJSivGN0LqXd/zmDbWEM0RNNg2t1QW/XUhYl/qPqyu7CsqeWtqQXHVaJsecLPuDoak2oJcZN2QoRIOag==", "dev": true, + "license": "MIT", "dependencies": { - "@vitest/expect": "1.6.0", - "@vitest/runner": "1.6.0", - "@vitest/snapshot": "1.6.0", - "@vitest/spy": "1.6.0", - "@vitest/utils": "1.6.0", + "@vitest/expect": "1.6.1", + "@vitest/runner": "1.6.1", + "@vitest/snapshot": "1.6.1", + "@vitest/spy": "1.6.1", + "@vitest/utils": "1.6.1", "acorn-walk": "^8.3.2", "chai": "^4.3.10", "debug": "^4.3.4", @@ -10414,7 +10748,7 @@ "tinybench": "^2.5.1", "tinypool": "^0.8.3", "vite": "^5.0.0", - "vite-node": "1.6.0", + "vite-node": "1.6.1", "why-is-node-running": "^2.2.2" }, "bin": { @@ -10429,8 +10763,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || >=20.0.0", - "@vitest/browser": "1.6.0", - "@vitest/ui": "1.6.0", + "@vitest/browser": "1.6.1", + "@vitest/ui": "1.6.1", "happy-dom": "*", "jsdom": "*" }, @@ -11116,31 +11450,85 @@ } }, "node_modules/which-boxed-primitive": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", + "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-bigint": "^1.1.0", + "is-boolean-object": "^1.2.1", + "is-number-object": "^1.1.1", + "is-string": "^1.1.1", + "is-symbol": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-builtin-type": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", + "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "function.prototype.name": "^1.1.6", + "has-tostringtag": "^1.0.2", + "is-async-function": "^2.0.0", + "is-date-object": "^1.1.0", + "is-finalizationregistry": "^1.1.0", + "is-generator-function": "^1.0.10", + "is-regex": "^1.2.1", + "is-weakref": "^1.0.2", + "isarray": "^2.0.5", + "which-boxed-primitive": "^1.1.0", + "which-collection": "^1.0.2", + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-collection": { "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", - "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", + "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", "dev": true, + "license": "MIT", "dependencies": { - "is-bigint": "^1.0.1", - "is-boolean-object": "^1.1.0", - "is-number-object": "^1.0.4", - "is-string": "^1.0.5", - "is-symbol": "^1.0.3" + "is-map": "^2.0.3", + "is-set": "^2.0.3", + "is-weakmap": "^2.0.2", + "is-weakset": "^2.0.3" + }, + "engines": { + "node": ">= 0.4" }, "funding": { "url": "https://github.com/sponsors/ljharb" } }, "node_modules/which-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.15.tgz", - "integrity": "sha512-oV0jmFtUky6CXfkqehVvBP/LSWJ2sy4vWMioiENyJLePrBO/yKyV9OyJySfAKosh+RYkIl5zJCNZ8/4JncrpdA==", + "version": "1.1.19", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.19.tgz", + "integrity": "sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==", "dev": true, + "license": "MIT", "dependencies": { "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.7", - "for-each": "^0.3.3", - "gopd": "^1.0.1", + "call-bind": "^1.0.8", + "call-bound": "^1.0.4", + "for-each": "^0.3.5", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", "has-tostringtag": "^1.0.2" }, "engines": { @@ -11315,6 +11703,19 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/yoctocolors-cjs": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yoctocolors-cjs/-/yoctocolors-cjs-2.1.2.tgz", + "integrity": "sha512-cYVsTjKl8b+FrnidjibDWskAv7UKOfcwaVZdp/it9n1s9fU3IkgDbhdIRKCW4JDsAlECJY0ytoVPT3sK6kideA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/zimmerframe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/zimmerframe/-/zimmerframe-1.1.2.tgz", diff --git a/package.json b/package.json index 81a02b7c..6c52f5f6 100644 --- a/package.json +++ b/package.json @@ -77,7 +77,7 @@ } }, "dependencies": { - "cookie": "^1.0.1", + "cookie": "^1.0.2", "is-network-error": "^1.1.0", "jose": "^5.2.2", "jwt-decode": "^4.0.0", @@ -105,6 +105,8 @@ "devDependencies": { "@commander-js/extra-typings": "^12.1.0", "@edge-runtime/vm": "^3.2.0", + "@sveltejs/kit": "^2.20.8", + "@sveltejs/vite-plugin-svelte": "^5.0.3", "@types/inquirer": "^9.0.7", "@types/node": "20.6.0", "@types/react": "^18.3.12", @@ -115,18 +117,16 @@ "dotenv": "^16.4.5", "eslint": "8.49.0", "inquirer": "^9.2.22", - "next": "^15.0.3", - "@sveltejs/kit": "^2.16.0", - "@sveltejs/vite-plugin-svelte": "^5.0.0", - "svelte": "^5.0.0", - "svelte-check": "^4.0.0", + "next": "^15.3.1", "npm-run-all": "^4.1.5", "react-dom": "^18.3.1", "shelljs": "^0.8.5", + "svelte": "^5.28.2", + "svelte-check": "^4.1.7", "tsup": "^8.0.1", - "typescript": "^5.5.2", + "typescript": "^5.8.3", "valibot": "^0.35.0", - "vitest": "^1.6.0", - "vite": "^6.3.1" + "vite": "^6.3.4", + "vitest": "^1.6.1" } } diff --git a/test-nextjs/package-lock.json b/test-nextjs/package-lock.json index c94bc5ea..3863e8ed 100644 --- a/test-nextjs/package-lock.json +++ b/test-nextjs/package-lock.json @@ -45,14 +45,13 @@ "license": "Apache-2.0", "dependencies": { "cookie": "^1.0.1", - "cspell": "^8.17.2", "is-network-error": "^1.1.0", "jose": "^5.2.2", "jwt-decode": "^4.0.0", "lucia": "^3.2.0", "oauth4webapi": "^3.1.2", "oslo": "^1.1.2", - "path-to-regexp": "^6.3.0", + "path-to-regexp": "^8.2.0", "server-only": "^0.0.1" }, "bin": { @@ -5867,6 +5866,126 @@ "funding": { "url": "https://github.com/sponsors/sindresorhus" } + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-15.0.3.tgz", + "integrity": "sha512-s3Q/NOorCsLYdCKvQlWU+a+GeAd3C8Rb3L1YnetsgwXzhc3UTWrtQpB/3eCjFOdGUj5QmXfRak12uocd1ZiiQw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-darwin-x64": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-15.0.3.tgz", + "integrity": "sha512-Zxl/TwyXVZPCFSf0u2BNj5sE0F2uR6iSKxWpq4Wlk/Sv9Ob6YCKByQTkV2y6BCic+fkabp9190hyrDdPA/dNrw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-15.0.3.tgz", + "integrity": "sha512-T5+gg2EwpsY3OoaLxUIofmMb7ohAUlcNZW0fPQ6YAutaWJaxt1Z1h+8zdl4FRIOr5ABAAhXtBcpkZNwUcKI2fw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-arm64-musl": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-15.0.3.tgz", + "integrity": "sha512-WkAk6R60mwDjH4lG/JBpb2xHl2/0Vj0ZRu1TIzWuOYfQ9tt9NFsIinI1Epma77JVgy81F32X/AeD+B2cBu/YQA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-gnu": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-15.0.3.tgz", + "integrity": "sha512-gWL/Cta1aPVqIGgDb6nxkqy06DkwJ9gAnKORdHWX1QBbSZZB+biFYPFti8aKIQL7otCE1pjyPaXpFzGeG2OS2w==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-linux-x64-musl": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-15.0.3.tgz", + "integrity": "sha512-QQEMwFd8r7C0GxQS62Zcdy6GKx999I/rTO2ubdXEe+MlZk9ZiinsrjwoiBL5/57tfyjikgh6GOU2WRQVUej3UA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-15.0.3.tgz", + "integrity": "sha512-9TEp47AAd/ms9fPNgtgnT7F3M1Hf7koIYYWCMQ9neOwjbVWJsHZxrFbI3iEDJ8rf1TDGpmHbKxXf2IFpAvheIQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } + }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "15.0.3", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-15.0.3.tgz", + "integrity": "sha512-VNAz+HN4OGgvZs6MOoVfnn41kBzT+M+tB+OK4cww6DNyWS6wKaDpaAm/qLeOUbnMh0oVx1+mg0uoYARF69dJyA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" + } } } } From 8fca45c23353ff1a5ae19811a716d618d0ed7a66 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 3 May 2025 12:12:23 +0200 Subject: [PATCH 75/88] Upgrade shelljs to 0.9.2 and valibot to 1.0.0 --- package-lock.json | 200 +++++++++++++++++++++++++++++++++++++++++++--- package.json | 4 +- 2 files changed, 192 insertions(+), 12 deletions(-) diff --git a/package-lock.json b/package-lock.json index b9af02d2..5fde225d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -40,12 +40,12 @@ "next": "^15.3.1", "npm-run-all": "^4.1.5", "react-dom": "^18.3.1", - "shelljs": "^0.8.5", + "shelljs": "^0.9.2", "svelte": "^5.28.2", "svelte-check": "^4.1.7", "tsup": "^8.0.1", "typescript": "^5.8.3", - "valibot": "^0.35.0", + "valibot": "^1.0.0", "vite": "^6.3.4", "vitest": "^1.6.1" }, @@ -4493,6 +4493,16 @@ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", "dev": true }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "once": "^1.4.0" + } + }, "node_modules/env-paths": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", @@ -7868,6 +7878,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/p-finally": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", + "integrity": "sha512-LICb2p9CB7FS+0eR1oqWnHhp0FljGLZCWBE9aix0Uye9W8LTQPwMTYVGWQWIw9RdQiDg4+epXQODwIYJtSJaow==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, "node_modules/p-limit": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", @@ -8211,6 +8231,17 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/pump": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz", + "integrity": "sha512-tUPXtzlGM8FE3P0ZL6DVs/3P58k9nk8/jZeQCurTJylQA8qFYzHFfhBJkuqyE0FifOsQ0uKWekiZ5g8wtr28cw==", + "dev": true, + "license": "MIT", + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", @@ -8741,22 +8772,152 @@ } }, "node_modules/shelljs": { - "version": "0.8.5", - "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.8.5.tgz", - "integrity": "sha512-TiwcRcrkhHvbrZbnRcFYMLl30Dfov3HKqzp5tO5b4pt6G/SezKcYhmDg15zXVBswHmctSAQKznqNW2LO5tTDow==", + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/shelljs/-/shelljs-0.9.2.tgz", + "integrity": "sha512-S3I64fEiKgTZzKCC46zT/Ib9meqofLrQVbpSswtjFfAVDW+AZ54WTnAM/3/yENoxz/V1Cy6u3kiiEbQ4DNphvw==", "dev": true, + "license": "BSD-3-Clause", "dependencies": { - "glob": "^7.0.0", + "execa": "^1.0.0", + "fast-glob": "^3.3.2", "interpret": "^1.0.0", "rechoir": "^0.6.2" }, "bin": { "shjs": "bin/shjs" }, + "engines": { + "node": ">=18" + } + }, + "node_modules/shelljs/node_modules/cross-spawn": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.6.tgz", + "integrity": "sha512-VqCUuhcd1iB+dsv8gxPttb5iZh/D0iubSP21g36KXdEuf6I5JiioesUVjpCdHV9MZRUfVFlvwtIUyPfxo5trtw==", + "dev": true, + "license": "MIT", + "dependencies": { + "nice-try": "^1.0.4", + "path-key": "^2.0.1", + "semver": "^5.5.0", + "shebang-command": "^1.2.0", + "which": "^1.2.9" + }, + "engines": { + "node": ">=4.8" + } + }, + "node_modules/shelljs/node_modules/execa": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz", + "integrity": "sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA==", + "dev": true, + "license": "MIT", + "dependencies": { + "cross-spawn": "^6.0.0", + "get-stream": "^4.0.0", + "is-stream": "^1.1.0", + "npm-run-path": "^2.0.0", + "p-finally": "^1.0.0", + "signal-exit": "^3.0.0", + "strip-eof": "^1.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/shelljs/node_modules/get-stream": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz", + "integrity": "sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/shelljs/node_modules/is-stream": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz", + "integrity": "sha512-uQPm8kcs47jx38atAcWTVxyltQYoPT68y9aWYdV6yWXSyW8mzSat0TL6CiWdZeCdF3KrAvpVtnHbTv4RN+rqdQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shelljs/node_modules/npm-run-path": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz", + "integrity": "sha512-lJxZYlT4DW/bRUtFh1MQIWqmLwQfAxnqWG4HhEdjMlkrJYnJn0Jrr2u3mgxqaWsdiBc76TYkTG/mhrnYTuzfHw==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^2.0.0" + }, "engines": { "node": ">=4" } }, + "node_modules/shelljs/node_modules/path-key": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", + "integrity": "sha512-fEHGKCSmUSDPv4uoj8AlD+joPlq3peND+HRYyxFz4KPw4z926S/b8rIuFs2FYJg3BwsxJf6A9/3eIdLaYC+9Dw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/shelljs/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/shelljs/node_modules/shebang-command": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", + "integrity": "sha512-EV3L1+UQWGor21OmnvojK36mhg+TyIKDh3iFBKBohr5xeXIhNBcx8oWdgkTEEQ+BEFFYdLRuqMfd5L84N1V5Vg==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^1.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shelljs/node_modules/shebang-regex": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", + "integrity": "sha512-wpoSFAxys6b2a2wHZ1XpDSgD7N9iVjg29Ph9uV/uaP9Ex/KXlkTZTeddxDPSYQpgvzKLGJke2UU0AzoGCjNIvQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/shelljs/node_modules/which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "which": "bin/which" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -9136,6 +9297,16 @@ "node": ">=4" } }, + "node_modules/strip-eof": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz", + "integrity": "sha512-7FCwGGmx8mD5xQd3RPUvnSpUXHM3BWuzjtpD4TXsfcZ9EL4azvVVUscFYwD9nx8Kh+uCBC00XBtAykoMHwTh8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", @@ -10101,10 +10272,19 @@ "dev": true }, "node_modules/valibot": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/valibot/-/valibot-0.35.0.tgz", - "integrity": "sha512-+i2aCRkReTrd5KBN/dW2BrPOvFnU5LXTV2xjZnjnqUIO8YUx6P2+MgRrkwF2FhkexgyKq/NIZdPdknhHf5A/Ww==", - "dev": true + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.0.0.tgz", + "integrity": "sha512-1Hc0ihzWxBar6NGeZv7fPLY0QuxFMyxwYR2sF1Blu7Wq7EnremwY2W02tit2ij2VJT8HcSkHAQqmFfl77f73Yw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } }, "node_modules/validate-npm-package-license": { "version": "3.0.4", diff --git a/package.json b/package.json index 6c52f5f6..c07c8981 100644 --- a/package.json +++ b/package.json @@ -120,12 +120,12 @@ "next": "^15.3.1", "npm-run-all": "^4.1.5", "react-dom": "^18.3.1", - "shelljs": "^0.8.5", + "shelljs": "^0.9.2", "svelte": "^5.28.2", "svelte-check": "^4.1.7", "tsup": "^8.0.1", "typescript": "^5.8.3", - "valibot": "^0.35.0", + "valibot": "^1.0.0", "vite": "^6.3.4", "vitest": "^1.6.1" } From 6614c7c3cd2583e450c63826f1e52df0886c6b4f Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 3 May 2025 12:42:29 +0200 Subject: [PATCH 76/88] rename login to sign in README --- src/sveltekit/README.md | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 88f087c6..a8d21930 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -156,8 +156,8 @@ const { isAuthenticated } = createConvexAuthHandlers(); export const load: PageServerLoad = async (event) => { // Check if user is authenticated if (!(await isAuthenticated(event))) { - // Redirect to login if not authenticated - throw redirect(302, '/login'); + // Redirect to signin if not authenticated + throw redirect(302, '/signin'); } // Return data for authenticated users @@ -175,7 +175,7 @@ export const load: PageServerLoad = async (event) => { Most routes require authentication except for a few public ones ```ts const isPublicRoute = createRouteMatcher([ - '/login', + '/signin', '/register', '/about', ]); @@ -191,7 +191,7 @@ import { } from '@convex-dev/auth/sveltekit/server'; const isPublicRoute = createRouteMatcher([ - '/login', + '/signin', '/register', '/about', // Note: No need to add '/api/auth' here as the handleAuth middleware @@ -211,9 +211,9 @@ const authFirstPattern: Handle = async ({ event, resolve }) => { // For all other routes, check authentication const isAuthenticated = await isAuthenticatedPromise(event); if (!isAuthenticated) { - // Store the original URL for redirect after login + // Store the original URL for redirect after signin const returnUrl = encodeURIComponent(event.url.pathname + event.url.search); - return redirect(307, `/login?redirectTo=${returnUrl}`); + return redirect(307, `/signin?redirectTo=${returnUrl}`); } // User is authenticated, continue to next handler @@ -257,9 +257,9 @@ const publicFirstPattern: Handle = async ({ event, resolve }) => { const isAuthenticated = await isAuthenticatedPromise(event); if (!isAuthenticated) { - // Store the original URL for redirect after login + // Store the original URL for redirect after signin const returnUrl = encodeURIComponent(event.url.pathname + event.url.search); - return redirect(307, `/login?redirectTo=${returnUrl}`); + return redirect(307, `/signin?redirectTo=${returnUrl}`); } } @@ -290,7 +290,7 @@ const { isAuthenticated: isAuthenticatedPromise } = createConvexAuthHandlers(); export async function load(event) { if (!(await isAuthenticated(event))) { - throw redirect(302, '/login?redirectTo=' + event.url.pathname); + throw redirect(302, '/signin?redirectTo=' + event.url.pathname); } return { From 63e6832121aa32ee1e97ecd12f585f62b3d99c2f Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sat, 3 May 2025 13:22:50 +0200 Subject: [PATCH 77/88] Fix createRouteMatcher input --- test-nextjs/middleware.ts | 2 +- test-sveltekit/src/hooks.server.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/test-nextjs/middleware.ts b/test-nextjs/middleware.ts index 8b3eb562..09df2f5a 100644 --- a/test-nextjs/middleware.ts +++ b/test-nextjs/middleware.ts @@ -5,7 +5,7 @@ import { } from "@convex-dev/auth/nextjs/server"; const isSignInPage = createRouteMatcher(["/signin"]); -const isProtectedRoute = createRouteMatcher(["/product/*path"]); +const isProtectedRoute = createRouteMatcher(["/product", "/product/*rest"]); export default convexAuthNextjsMiddleware(async (request, { convexAuth }) => { if (isSignInPage(request) && (await convexAuth.isAuthenticated())) { diff --git a/test-sveltekit/src/hooks.server.ts b/test-sveltekit/src/hooks.server.ts index ba0d96be..2a05243a 100644 --- a/test-sveltekit/src/hooks.server.ts +++ b/test-sveltekit/src/hooks.server.ts @@ -4,7 +4,7 @@ import { PUBLIC_CONVEX_URL } from '$env/static/public'; import { redirect, type Handle } from '@sveltejs/kit'; const isSignInPage = createRouteMatcher('/signin'); -const isProtectedRoute = createRouteMatcher('/product/*path'); +const isProtectedRoute = createRouteMatcher(['/product', '/product/*path']); const { handleAuth, isAuthenticated: isAuthenticatedPromise } = createConvexAuthHooks({ convexUrl: PUBLIC_CONVEX_URL, From 0d274fcda4f06129780241212c3f12c17f1f7b42 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sun, 4 May 2025 16:16:48 +0200 Subject: [PATCH 78/88] Implement server-side rendering with initial data for chat and viewer --- test-sveltekit/src/lib/Chat/Chat.svelte | 42 ++++++++----------- test-sveltekit/src/lib/UserMenu.svelte | 22 +++++----- .../src/routes/product/+page.server.ts | 33 +++++++-------- .../src/routes/product/+page.svelte | 8 ++-- 4 files changed, 49 insertions(+), 56 deletions(-) diff --git a/test-sveltekit/src/lib/Chat/Chat.svelte b/test-sveltekit/src/lib/Chat/Chat.svelte index adc3a524..8011e464 100644 --- a/test-sveltekit/src/lib/Chat/Chat.svelte +++ b/test-sveltekit/src/lib/Chat/Chat.svelte @@ -4,23 +4,30 @@ import type { Id } from '$lib/convex/_generated/dataModel'; import Message from './Message.svelte'; import MessageList from './MessageList.svelte'; - + interface Props { - viewer: Id<'users'>; + viewerId: Id<'users'>; + initialMessages?: { + author: string; + _id: Id<'messages'>; + _creationTime: number; + userId: Id<'users'>; + body: string; + }[]; } - let { viewer }: Props = $props(); + let { viewerId, initialMessages }: Props = $props(); const client = useConvexClient(); - + let newMessageText = $state(''); - - const messages = useQuery(api.messages.list, {}); - + + const messages = useQuery(api.messages.list, {}, () => ({ initialData: initialMessages })); + async function handleSubmit(event: Event) { event.preventDefault(); if (newMessageText.trim() === '') return; - + try { await client.mutation(api.messages.send, { body: newMessageText }); newMessageText = ''; @@ -33,11 +40,7 @@ {#if messages.data} {#each messages.data as message} - + {message.body} {/each} @@ -46,17 +49,8 @@
    - -
    diff --git a/test-sveltekit/src/lib/UserMenu.svelte b/test-sveltekit/src/lib/UserMenu.svelte index 90ab4894..a11cafb7 100644 --- a/test-sveltekit/src/lib/UserMenu.svelte +++ b/test-sveltekit/src/lib/UserMenu.svelte @@ -7,20 +7,20 @@ import type { Id } from '$lib/convex/_generated/dataModel.js'; interface Props { - data: { + viewer: { _id: Id<'users'>; _creationTime: number; - name?: string | undefined | undefined; - email?: string | undefined | undefined; - phone?: string | undefined | undefined; - image?: string | undefined | undefined; - emailVerificationTime?: number | undefined | undefined; - phoneVerificationTime?: number | undefined | undefined; - isAnonymous?: boolean | undefined | undefined; + name?: string; + email?: string; + phone?: string; + image?: string; + emailVerificationTime?: number; + phoneVerificationTime?: number; + isAnonymous?: boolean; }; } - let { data }: Props = $props(); + let { viewer }: Props = $props(); const { signOut } = useAuth(); @@ -44,10 +44,10 @@ ids={{trigger: "user-menu-trigger"}} > {#snippet trigger()} - + {/snippet} {#snippet content()} -
    {data.name}
    +
    {viewer.name}

    {/snippet} diff --git a/test-sveltekit/src/routes/product/+page.server.ts b/test-sveltekit/src/routes/product/+page.server.ts index 3ea17d50..6e00bbcd 100644 --- a/test-sveltekit/src/routes/product/+page.server.ts +++ b/test-sveltekit/src/routes/product/+page.server.ts @@ -1,23 +1,20 @@ -import { createConvexAuthHooks } from '@convex-dev/auth/sveltekit/server'; -import { redirect } from '@sveltejs/kit'; import type { PageServerLoad } from './$types'; +import { ConvexHttpClient } from 'convex/browser'; import { PUBLIC_CONVEX_URL } from '$env/static/public'; +import { api } from '$lib/convex/_generated/api.js'; +import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; -// Create Convex auth hooks -const { isAuthenticated } = createConvexAuthHooks({ - convexUrl: PUBLIC_CONVEX_URL -}); +export const load = (async (event) => { + const auth = await createConvexAuthHandlers(); + const state = await auth.getAuthState(event); -export const load: PageServerLoad = async (event) => { - // Check if the user is authenticated - if (!(await isAuthenticated(event))) { - throw redirect(307, '/signin'); - } - - // The auth token is automatically picked up by the Convex client in the browser - return { - // Return an empty viewer object - the actual data will be fetched client-side - // where Convex client is already configured with auth - viewer: {} + const client = new ConvexHttpClient(PUBLIC_CONVEX_URL); + client.setAuth(state._state.token!) + + const viewer = await client.query(api.users.viewer, {}); + const messages = await client.query(api.messages.list, {}); + return { + viewer, + messages }; -}; +}) satisfies PageServerLoad; \ No newline at end of file diff --git a/test-sveltekit/src/routes/product/+page.svelte b/test-sveltekit/src/routes/product/+page.svelte index 0c8b6727..54a4d55b 100644 --- a/test-sveltekit/src/routes/product/+page.svelte +++ b/test-sveltekit/src/routes/product/+page.svelte @@ -5,15 +5,17 @@ import UserMenu from '$lib/UserMenu.svelte'; import { useQuery } from 'convex-svelte'; - const viewer = useQuery(api.users.viewer, {}); + let { data } = $props(); + + const viewer = useQuery(api.users.viewer, {}, () => ({initialData: data.viewer})); {#if viewer.data}
    - +
    - +
    {/if} From 497322c85dab653bc5e0ce00fb7e1c9902761c88 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sun, 4 May 2025 16:29:45 +0200 Subject: [PATCH 79/88] Add createConvexHttpClient helper to create authenticated HTTP clients in SvelteKit --- src/sveltekit/server/handlers.ts | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/sveltekit/server/handlers.ts b/src/sveltekit/server/handlers.ts index 3852a8af..fd45e6e6 100644 --- a/src/sveltekit/server/handlers.ts +++ b/src/sveltekit/server/handlers.ts @@ -14,6 +14,7 @@ import { import { IsAuthenticatedQuery } from "../../server/implementation/index.js"; import { handleAuthenticationInRequest } from "./request.js"; import { ConvexAuthServerState } from "../../svelte/index.svelte.js"; +import { ConvexHttpClient, ConvexClientOptions } from "convex/browser"; /** * Create server-side handlers for SvelteKit @@ -69,9 +70,31 @@ export function createConvexAuthHandlers({ } } + /** + * Create a Convex HTTP client. + * + * Returns an authenticated HTTP client if the user is signed in, + * otherwise returns an unauthenticated HTTP client. + */ + async function createConvexHttpClient( + event: RequestEvent, + options?: { + skipConvexDeploymentUrlCheck?: boolean; + logger?: ConvexClientOptions["logger"]; + }, + ) { + const token = event.cookies.get(AUTH_TOKEN_COOKIE); + const client = new ConvexHttpClient(convexUrl, options); + if (token) { + client.setAuth(token); + } + return client; + } + return { getAuthState, isAuthenticated, + createConvexHttpClient, }; } From 0965f6146a0d748fc6fa75595c91360324a38632 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sun, 4 May 2025 16:32:47 +0200 Subject: [PATCH 80/88] Simplify auth client creation by using createConvexHttpClient helper --- test-sveltekit/src/routes/product/+page.server.ts | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/test-sveltekit/src/routes/product/+page.server.ts b/test-sveltekit/src/routes/product/+page.server.ts index 6e00bbcd..c5c3e538 100644 --- a/test-sveltekit/src/routes/product/+page.server.ts +++ b/test-sveltekit/src/routes/product/+page.server.ts @@ -1,16 +1,11 @@ import type { PageServerLoad } from './$types'; -import { ConvexHttpClient } from 'convex/browser'; -import { PUBLIC_CONVEX_URL } from '$env/static/public'; import { api } from '$lib/convex/_generated/api.js'; import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; export const load = (async (event) => { - const auth = await createConvexAuthHandlers(); - const state = await auth.getAuthState(event); + const { createConvexHttpClient} = await createConvexAuthHandlers(); + const client = await createConvexHttpClient(event); - const client = new ConvexHttpClient(PUBLIC_CONVEX_URL); - client.setAuth(state._state.token!) - const viewer = await client.query(api.users.viewer, {}); const messages = await client.query(api.messages.list, {}); return { From 24cd72598980c46083b7734fc1a6964b83afc881 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sun, 4 May 2025 16:48:24 +0200 Subject: [PATCH 81/88] Add docs for making authenticated server and client requests --- src/sveltekit/README.md | 123 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index a8d21930..56df1184 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -2,6 +2,30 @@ This package provides authentication functionality for SvelteKit applications using Convex as a backend. It includes both client-side components and server-side utilities for a complete authentication solution. +## Table of Contents + +- [Installation](#installation) +- [Setup](#setup) + - [1. Environment Variables](#1-environment-variables) + - [2. Run the initialization command](#2-run-the-initialization-command) + - [3. Initialize Auth (Client-side)](#3-initialize-auth-client-side) + - [4. Add Auth State in Layout Server](#4-add-auth-state-in-layout-server) + - [5. Configure Auth Hooks (Server-side)](#5-configure-auth-hooks-server-side) +- [Usage](#usage) + - [Pages (`+page.svelte`)](#pages-pagesvelte) + - [Page Server (`+page.server.ts`)](#page-server-pageserverts) +- [Protecting Routes](#protecting-routes) + - [Option 1: Using Hooks (App-wide Protection) (Recommended)](#option-1-using-hooks-app-wide-protection-recommended) + - [Option 2: Using Page Server Load (Page-level Protection)](#option-2-using-page-server-load-page-level-protection) +- [Authentication Actions](#authentication-actions) + - [Sign In](#sign-in) + - [Sign Out](#sign-out) + - [Check Auth State](#check-auth-state) +- [Debug Mode](#debug-mode) +- [Making Authenticated Requests](#making-authenticated-requests) + - [Server-side Requests](#server-side-requests) + - [Client-side Requests](#client-side-requests) + ## Installation ```bash @@ -363,3 +387,102 @@ CONVEX_AUTH_DEBUG=true ``` This will output detailed logs about auth operations to help with troubleshooting. + +## Making Authenticated Requests + +One of the key benefits of Convex Auth is the ability to make authenticated requests to your Convex backend. This section explains how to perform authenticated requests both on the server and client sides. + +### Server-side Requests + +The `createConvexHttpClient` function provided by the server handlers allows you to create an authenticated HTTP client for making server-side requests to your Convex backend. + +```ts +// src/routes/some-page/+page.server.ts +import type { PageServerLoad } from './$types'; +import { api } from '$lib/convex/_generated/api.js'; +import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; + +export const load = (async (event) => { + const { createConvexHttpClient } = createConvexAuthHandlers(); + + // Create an authenticated HTTP client + // If the user is authenticated, this client will have the auth token + // If not, it will be an unauthenticated client + const client = await createConvexHttpClient(event); + + // Make authenticated queries to your Convex backend + const viewer = await client.query(api.users.viewer, {}); + + return { viewer }; +}) satisfies PageServerLoad; +``` + +The `createConvexHttpClient` function automatically: +- Creates a Convex HTTP client using the Convex URL (automatically detected from environment variables) +- Sets the authentication token if the user is signed in +- Returns an unauthenticated client if the user is not signed in + +You can then use this client to make authenticated queries and mutations to your Convex backend. + +### Client-side Requests + +On the client side, you can use the Convex Svelte integration to make authenticated requests. The authentication is handled automatically when you set up Convex Auth as described in the setup section. + +```html + + + +{#if viewer.data} +
    +

    Welcome, {viewer.data.name}!

    + + +
    + + +
    +
    +{/if} +``` + +This approach: +- Uses `useQuery` from Convex Svelte to make authenticated queries +- Leverages server-side data as initial data for a smoother user experience +- Uses `useConvexClient()` to get the Convex client for making mutations +- Calls `client.mutation()` directly to execute mutations + +By combining server-side and client-side authenticated requests, you can create a seamless authentication experience while optimizing for performance and user experience. From 76b18985b72eba572fae1a6364e1f6bf674d0595 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sun, 4 May 2025 16:53:54 +0200 Subject: [PATCH 82/88] Remove debug mode section from SvelteKit auth documentation --- src/sveltekit/README.md | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 56df1184..24306346 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -378,16 +378,6 @@ export async function load(event) { {/if} ``` -### Debug Mode - -Enable debug logging by setting an environment variable: - -``` -CONVEX_AUTH_DEBUG=true -``` - -This will output detailed logs about auth operations to help with troubleshooting. - ## Making Authenticated Requests One of the key benefits of Convex Auth is the ability to make authenticated requests to your Convex backend. This section explains how to perform authenticated requests both on the server and client sides. From b791b736cee6d132fcdce9f37f4c6016c4b5ff53 Mon Sep 17 00:00:00 2001 From: Micha Mailaender Date: Sun, 4 May 2025 17:16:25 +0200 Subject: [PATCH 83/88] Reorganize auth docs with clearer sections and improved code examples --- src/sveltekit/README.md | 413 +++++++++++++++++----------------------- 1 file changed, 175 insertions(+), 238 deletions(-) diff --git a/src/sveltekit/README.md b/src/sveltekit/README.md index 24306346..7ae9658d 100644 --- a/src/sveltekit/README.md +++ b/src/sveltekit/README.md @@ -12,19 +12,15 @@ This package provides authentication functionality for SvelteKit applications us - [4. Add Auth State in Layout Server](#4-add-auth-state-in-layout-server) - [5. Configure Auth Hooks (Server-side)](#5-configure-auth-hooks-server-side) - [Usage](#usage) - - [Pages (`+page.svelte`)](#pages-pagesvelte) - - [Page Server (`+page.server.ts`)](#page-server-pageserverts) -- [Protecting Routes](#protecting-routes) - - [Option 1: Using Hooks (App-wide Protection) (Recommended)](#option-1-using-hooks-app-wide-protection-recommended) - - [Option 2: Using Page Server Load (Page-level Protection)](#option-2-using-page-server-load-page-level-protection) -- [Authentication Actions](#authentication-actions) - - [Sign In](#sign-in) - - [Sign Out](#sign-out) - - [Check Auth State](#check-auth-state) -- [Debug Mode](#debug-mode) -- [Making Authenticated Requests](#making-authenticated-requests) - - [Server-side Requests](#server-side-requests) - - [Client-side Requests](#client-side-requests) + - [Authentication UI](#authentication-ui) + - [User Login/Logout Components](#user-loginlogout-components) + - [Checking Auth State](#checking-auth-state) + - [Data Operations](#data-operations) + - [Making Authenticated Requests (Client-side)](#making-authenticated-requests-client-side) + - [Making Authenticated Requests (Server-side)](#making-authenticated-requests-server-side) +- [Route Protection](#route-protection) + - [Option 1: App-wide Protection (Using Hooks) *Recommended*](#option-1-app-wide-protection-using-hooks) + - [Option 2: Page-level Protection (Using Page Server Load)](#option-2-page-level-protection-using-page-server-load) ## Installation @@ -132,12 +128,13 @@ export const handle = sequence( ); ``` - ## Usage -### Pages (`+page.svelte`) +### Authentication UI + +#### User Login/Logout Components -Use authentication in your pages: +The following example shows how to create a simple login/logout component: ```html @@ -153,179 +150,17 @@ Use authentication in your pages:

    Loading authentication state...

    {:else if isAuthenticated}

    Welcome, authenticated user!

    - + {:else}

    Please sign in

    -
    {/if} ``` -### Page Server (`+page.server.ts`) - -Use auth state in page server load functions: - -```ts -// src/routes/profile/+page.server.ts -import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; -import { redirect } from '@sveltejs/kit'; -import type { PageServerLoad } from './$types'; - -// Create auth handlers -const { isAuthenticated } = createConvexAuthHandlers(); - -// Protect routes at the page level -export const load: PageServerLoad = async (event) => { - // Check if user is authenticated - if (!(await isAuthenticated(event))) { - // Redirect to signin if not authenticated - throw redirect(302, '/signin'); - } - - // Return data for authenticated users - return { - user: { /* user data */ } - }; -}; -``` - -## Protecting Routes - -### Option 1: Using Hooks (App-wide Protection) (Recommended) - -#### Example 1: Auth-first approach (whitelist pattern) -Most routes require authentication except for a few public ones -```ts -const isPublicRoute = createRouteMatcher([ - '/signin', - '/register', - '/about', -]); -``` - -```ts -// src/hooks.server.ts -import { sequence } from '@sveltejs/kit/hooks'; -import { redirect, type Handle } from '@sveltejs/kit'; -import { - createConvexAuthHooks, - createRouteMatcher -} from '@convex-dev/auth/sveltekit/server'; - -const isPublicRoute = createRouteMatcher([ - '/signin', - '/register', - '/about', - // Note: No need to add '/api/auth' here as the handleAuth middleware - // will process those requests before this middleware runs -]); - -// Create auth hooks -const { handleAuth, isAuthenticated: isAuthenticatedPromise } = createConvexAuthHooks(); - -// Custom handle function for auth-first pattern -const authFirstPattern: Handle = async ({ event, resolve }) => { - // Skip auth check for public routes - if (isPublicRoute(event.url.pathname)) { - return; - } - - // For all other routes, check authentication - const isAuthenticated = await isAuthenticatedPromise(event); - if (!isAuthenticated) { - // Store the original URL for redirect after signin - const returnUrl = encodeURIComponent(event.url.pathname + event.url.search); - return redirect(307, `/signin?redirectTo=${returnUrl}`); - } - - // User is authenticated, continue to next handler - return resolve(event); -} -``` - -#### Example 2: Public-first approach (blacklist pattern) - Most routes are public, only protect specific areas -```ts -const isProtectedRoute = createRouteMatcher([ - '/admin/*path', - '/dashboard/*path', - '/profile/*path', -]); -``` - - -```ts -// src/hooks.server.ts -import { sequence } from '@sveltejs/kit/hooks'; -import { redirect, type Handle } from '@sveltejs/kit'; -import { - createConvexAuthHooks, - createRouteMatcher -} from '@convex-dev/auth/sveltekit/server'; - -const isProtectedRoute = createRouteMatcher([ - '/admin/*path', - '/dashboard/*path', - '/profile/*path', -]); - -// Create auth hooks -const { handleAuth, isAuthenticated: isAuthenticatedPromise } = createConvexAuthHooks(); - -// Custom handle function for public-first pattern -const publicFirstPattern: Handle = async ({ event, resolve }) => { - // Check auth only for protected routes - if (isProtectedRoute(event.url.pathname)) { - const isAuthenticated = await isAuthenticatedPromise(event); - - if (!isAuthenticated) { - // Store the original URL for redirect after signin - const returnUrl = encodeURIComponent(event.url.pathname + event.url.search); - return redirect(307, `/signin?redirectTo=${returnUrl}`); - } - } - - // All other routes are public, or user is authenticated - return resolve(event); -} - -// Choose which pattern to use based on your app's needs -// and apply hooks in sequence -export const handle = sequence( - handleAuth, // Handle auth API requests - // authFirstPattern, // Uncomment to use auth-first pattern - publicFirstPattern, // Comment out if using auth-first pattern - // Your other custom handlers... -); -``` - -### Option 2: Using Page Server Load (Page-level Protection) - -Protect individual pages in their `+page.server.ts`: - -```ts -// src/routes/protected/+page.server.ts -import { redirect } from '@sveltejs/kit'; -import { createConvexAuthHandlers } from '@convex-dev/auth/sveltekit/server'; - -const { isAuthenticated: isAuthenticatedPromise } = createConvexAuthHandlers(); - -export async function load(event) { - if (!(await isAuthenticated(event))) { - throw redirect(302, '/signin?redirectTo=' + event.url.pathname); - } - - return { - // Page data here - }; -} -``` - -## Authentication Actions - -### Sign In +For email/password authentication: ```html ``` -### Sign Out +#### Checking Auth State -```html - -``` - -### Check Auth State +You can check the authentication state to conditionally render components: ```html
    -