diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 75a166c1fd..843e1648b7 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -25,7 +25,7 @@ jobs: id: playwright-cache with: path: ~/.cache/ms-playwright - key: ${{ runner.os }}-playwright-${{ hashFiles('**/pnpm-lock.yaml') }} + key: ${{ runner.os }}-playwright-${{ hashFiles('**/bun.lock') }} restore-keys: | ${{ runner.os }}-playwright- diff --git a/.github/workflows/production.yml b/.github/workflows/production.yml new file mode 100644 index 0000000000..71d7dc2981 --- /dev/null +++ b/.github/workflows/production.yml @@ -0,0 +1,108 @@ +name: Production deployment + +on: + workflow_dispatch: + release: + types: [published] + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + +env: + ENVIRONMENT: production + PROJECT: cloud + APPLICATION: cloud + DECLARATIVE_OWNER: appwrite-labs + DECLARATIVE_REPOSITORY: application-configuration + DECLARATIVE_ALIAS: cloud-console + IMAGE_NAME: appwrite/console-cloud + TAG: ${{ github.event.release.tag_name || github.sha }} + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set up QEMU + uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 + - name: Log in to Docker Hub + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push Docker image + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ env.IMAGE_NAME }}:${{ env.TAG }} + build-args: | + "PUBLIC_CONSOLE_MODE=cloud" + "PUBLIC_CONSOLE_FEATURE_FLAGS=" + "PUBLIC_APPWRITE_MULTI_REGION=true" + "PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS=false" + "PUBLIC_GROWTH_ENDPOINT=${{ vars.VITE_APPWRITE_GROWTH_ENDPOINT }}" + "PUBLIC_STRIPE_KEY=${{ secrets.PUBLIC_STRIPE_KEY }}" + "PUBLIC_CONSOLE_FINGERPRINT_KEY=${{ secrets.PUBLIC_CONSOLE_FINGERPRINT_KEY }}" + "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" + "SENTRY_RELEASE=${{ github.event.release.tag_name }}" + + deploy: + needs: build + runs-on: ubuntu-latest + # Shared across the staging and production workflows so their deploy + # jobs never push to application-configuration at the same time. + concurrency: + group: declarative-deploy + cancel-in-progress: false + steps: + - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} + id: app-token + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2 + with: + app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} + private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} + owner: ${{ env.DECLARATIVE_OWNER }} + repositories: ${{ env.DECLARATIVE_REPOSITORY }} + + - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} + token: ${{ steps.app-token.outputs.token }} + # Don't leave the write-capable token in .git/config for later steps. + persist-credentials: false + + - name: Update image tag + run: yq -i '.[strenv(DECLARATIVE_ALIAS)].image.tag = strenv(TAG)' ${{ env.PROJECT }}/${{ env.ENVIRONMENT }}/${{ env.APPLICATION }}/default.yaml + + - name: Open pull request + # The release author reviews; falls back to the dispatcher for + # manual runs. The PR author is the GitHub App bot, so requesting + # the release author as reviewer is always allowed. + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + REVIEWER: ${{ github.event.release.author.login || github.actor }} + BRANCH: deploy/console-${{ env.TAG }} + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add ${{ env.PROJECT }}/${{ env.ENVIRONMENT }}/${{ env.APPLICATION }}/default.yaml + if git diff --cached --quiet; then + echo "No changes to commit" + exit 0 + fi + git checkout -b "$BRANCH" + git commit -m "chore(${{ env.ENVIRONMENT }}): console image tag to ${{ env.TAG }}" + git push "https://x-access-token:${GH_TOKEN}@github.com/${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }}.git" "$BRANCH" + gh pr create \ + --base main \ + --head "$BRANCH" \ + --reviewer "$REVIEWER" \ + --title "chore(${{ env.ENVIRONMENT }}): console image tag to ${{ env.TAG }}" \ + --body "Promotes \`${{ env.IMAGE_NAME }}:${{ env.TAG }}\` to production. Requested by @$REVIEWER." diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 2c16db7ac1..534b86bf00 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -5,88 +5,6 @@ on: types: [published] jobs: - publish-cloud: - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Set up QEMU - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - name: Log in to Docker Hub - uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 - with: - username: ${{ vars.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 - with: - images: appwrite/console-cloud - tags: | - type=semver,pattern={{major}}.{{minor}}.{{patch}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - - name: Build and push Docker image - id: push - uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 - with: - context: . - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - build-args: | - "PUBLIC_CONSOLE_MODE=cloud" - "PUBLIC_CONSOLE_FEATURE_FLAGS=" - "PUBLIC_APPWRITE_MULTI_REGION=true" - "PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS=false" - "PUBLIC_GROWTH_ENDPOINT=${{ secrets.PUBLIC_GROWTH_ENDPOINT }}" - "PUBLIC_STRIPE_KEY=${{ secrets.PUBLIC_STRIPE_KEY }}" - "PUBLIC_CONSOLE_FINGERPRINT_KEY=${{ secrets.PUBLIC_CONSOLE_FINGERPRINT_KEY }}" - "SENTRY_AUTH_TOKEN=${{ secrets.SENTRY_AUTH_TOKEN }}" - "SENTRY_RELEASE=${{ github.event.release.tag_name }}" - publish-cloud-stage: - runs-on: ubuntu-latest - steps: - - name: Checkout the repo - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - - name: Set up QEMU - uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 - - name: Set up Docker Buildx - uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 - - name: Log in to Docker Hub - uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 - with: - username: ${{ vars.DOCKERHUB_USERNAME }} - password: ${{ secrets.DOCKERHUB_TOKEN }} - - name: Extract metadata (tags, labels) for Docker - id: meta - uses: docker/metadata-action@030e881283bb7a6894de51c315a6bfe6a94e05cf # v6.0.0 - with: - images: appwrite/console-cloud-stage - tags: | - type=semver,pattern={{major}}.{{minor}}.{{patch}} - type=semver,pattern={{major}}.{{minor}} - type=semver,pattern={{major}} - - name: Build and push Docker image - id: push - uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 - with: - context: . - push: true - platforms: linux/amd64,linux/arm64 - tags: ${{ steps.meta.outputs.tags }} - labels: ${{ steps.meta.outputs.labels }} - build-args: | - "PUBLIC_CONSOLE_MODE=cloud" - "PUBLIC_CONSOLE_FEATURE_FLAGS=" - "PUBLIC_APPWRITE_MULTI_REGION=true" - "PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS=false" - "PUBLIC_GROWTH_ENDPOINT=${{ secrets.PUBLIC_GROWTH_ENDPOINT }}" - "PUBLIC_STRIPE_KEY=${{ secrets.PUBLIC_STRIPE_KEY_STAGE }}" - "PUBLIC_CONSOLE_FINGERPRINT_KEY=${{ secrets.PUBLIC_CONSOLE_FINGERPRINT_KEY_STAGE }}" publish-self-hosted: runs-on: ubuntu-latest steps: @@ -124,7 +42,7 @@ jobs: "PUBLIC_APPWRITE_MULTI_REGION=false" "PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS=true" "PUBLIC_CONSOLE_FEATURE_FLAGS=" - "PUBLIC_GROWTH_ENDPOINT=${{ secrets.PUBLIC_GROWTH_ENDPOINT }}" + "PUBLIC_GROWTH_ENDPOINT=${{ vars.VITE_APPWRITE_GROWTH_ENDPOINT }}" publish-cloud-no-regions: runs-on: ubuntu-latest @@ -165,4 +83,4 @@ jobs: "PUBLIC_CONSOLE_FEATURE_FLAGS=" "PUBLIC_STRIPE_KEY=${{ secrets.PUBLIC_STRIPE_KEY_STAGE }}" "PUBLIC_CONSOLE_FINGERPRINT_KEY=${{ secrets.PUBLIC_CONSOLE_FINGERPRINT_KEY_STAGE }}" - "PUBLIC_GROWTH_ENDPOINT=${{ secrets.PUBLIC_GROWTH_ENDPOINT }}" + "PUBLIC_GROWTH_ENDPOINT=${{ vars.VITE_APPWRITE_GROWTH_ENDPOINT }}" diff --git a/.github/workflows/staging.yml b/.github/workflows/staging.yml new file mode 100644 index 0000000000..b7dc185d13 --- /dev/null +++ b/.github/workflows/staging.yml @@ -0,0 +1,96 @@ +name: Staging deployment + +on: + workflow_dispatch: + push: + branches: + - main + +concurrency: + group: ${{ github.workflow }} + cancel-in-progress: false + +env: + ENVIRONMENT: staging + PROJECT: cloud + APPLICATION: cloud + DECLARATIVE_OWNER: appwrite-labs + DECLARATIVE_REPOSITORY: application-configuration + DECLARATIVE_ALIAS: cloud-console + IMAGE_NAME: appwrite/console-cloud-stage + TAG: ${{ github.sha }} + +jobs: + build: + environment: staging + runs-on: ubuntu-latest + steps: + - name: Checkout the repo + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Set up QEMU + uses: docker/setup-qemu-action@ce360397dd3f832beb865e1373c09c0e9f86d70a # v4.0.0 + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@4d04d5d9486b7bd6fa91e7baf45bbb4f8b9deedd # v4.0.0 + - name: Log in to Docker Hub + uses: docker/login-action@4907a6ddec9925e35a0a9e82d7399ccc52663121 # v4.1.0 + with: + username: ${{ vars.DOCKERHUB_USERNAME }} + password: ${{ secrets.DOCKERHUB_TOKEN }} + - name: Build and push Docker image + uses: docker/build-push-action@bcafcacb16a39f128d818304e6c9c0c18556b85f # v7.1.0 + with: + context: . + push: true + platforms: linux/amd64,linux/arm64 + tags: ${{ env.IMAGE_NAME }}:${{ env.TAG }} + build-args: | + "PUBLIC_CONSOLE_MODE=cloud" + "PUBLIC_CONSOLE_FEATURE_FLAGS=" + "PUBLIC_APPWRITE_MULTI_REGION=true" + "PUBLIC_CONSOLE_MOCK_AI_SUGGESTIONS=false" + "PUBLIC_GROWTH_ENDPOINT=${{ vars.VITE_APPWRITE_GROWTH_ENDPOINT }}" + "PUBLIC_STRIPE_KEY=${{ secrets.PUBLIC_STRIPE_KEY_STAGE }}" + "PUBLIC_CONSOLE_FINGERPRINT_KEY=${{ secrets.PUBLIC_CONSOLE_FINGERPRINT_KEY_STAGE }}" + + deploy: + needs: build + runs-on: ubuntu-latest + # Shared across the staging and production workflows so their deploy + # jobs never push to application-configuration at the same time. + concurrency: + group: declarative-deploy + cancel-in-progress: false + steps: + - name: Get token for ${{ env.DECLARATIVE_REPOSITORY }} + id: app-token + uses: actions/create-github-app-token@fee1f7d63c2ff003460e3d139729b119787bc349 # v2 + with: + app-id: ${{ vars.DECLARATIVE_DEPLOYMENT_GITHUB_APP_ID }} + private-key: ${{ secrets.DECLARATIVE_DEPLOYMENT_GITHUB_APP_PRIVATE_KEY }} + owner: ${{ env.DECLARATIVE_OWNER }} + repositories: ${{ env.DECLARATIVE_REPOSITORY }} + + - name: Checkout ${{ env.DECLARATIVE_REPOSITORY }} + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + with: + repository: ${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }} + token: ${{ steps.app-token.outputs.token }} + # Don't leave the write-capable token in .git/config for later steps. + persist-credentials: false + + - name: Update image tag + run: yq -i '.[strenv(DECLARATIVE_ALIAS)].image.tag = strenv(TAG)' ${{ env.PROJECT }}/${{ env.ENVIRONMENT }}/${{ env.APPLICATION }}/default.yaml + + - name: Commit and push + env: + GH_TOKEN: ${{ steps.app-token.outputs.token }} + run: | + git config user.name "github-actions[bot]" + git config user.email "github-actions[bot]@users.noreply.github.com" + git add ${{ env.PROJECT }}/${{ env.ENVIRONMENT }}/${{ env.APPLICATION }}/default.yaml + if git diff --cached --quiet; then + echo "No changes to commit" + else + git commit -m "chore(${{ env.ENVIRONMENT }}): console image tag to ${{ env.TAG }}" + git push "https://x-access-token:${GH_TOKEN}@github.com/${{ env.DECLARATIVE_OWNER }}/${{ env.DECLARATIVE_REPOSITORY }}.git" HEAD:main + fi diff --git a/.gitignore b/.gitignore index acc78571f0..69a75d2ccb 100644 --- a/.gitignore +++ b/.gitignore @@ -11,6 +11,7 @@ node_modules !.env.example test-results/ playwright-report/ +.playwright-mcp/ vite.config.js.timestamp-* vite.config.ts.timestamp-* diff --git a/bun.lock b/bun.lock index a8194ed8ea..798c00a88a 100644 --- a/bun.lock +++ b/bun.lock @@ -6,103 +6,109 @@ "name": "@appwrite/console", "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "^12.2.0", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@ed09983", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", "@appwrite.io/pink-legacy": "^1.0.3", "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@8dcaa17", - "@codemirror/autocomplete": "^6.19.0", - "@codemirror/commands": "^6.9.0", - "@codemirror/language": "^6.11.3", - "@codemirror/lint": "^6.9.0", - "@codemirror/search": "^6.5.11", - "@codemirror/state": "^6.5.2", - "@codemirror/view": "^6.38.6", + "@codemirror/autocomplete": "^6.20.2", + "@codemirror/commands": "^6.10.3", + "@codemirror/language": "^6.12.3", + "@codemirror/lint": "^6.9.6", + "@codemirror/search": "^6.7.0", + "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.43.0", "@faker-js/faker": "^9.9.0", - "@lezer/highlight": "^1.2.1", - "@plausible-analytics/tracker": "^0.4.4", + "@lezer/highlight": "^1.2.3", + "@plausible-analytics/tracker": "^0.4.5", "@popperjs/core": "^2.11.8", - "@sentry/sveltekit": "^8.55.1", + "@sentry/sveltekit": "^8.55.2", "@stripe/stripe-js": "^3.5.0", - "@threlte/core": "^8.5.2", - "@threlte/extras": "^9.13.0", - "ai": "^6.0.138", + "@threlte/core": "^8.5.16", + "@threlte/extras": "^9.20.1", + "ai": "^6.0.194", "analytics": "^0.8.19", "codemirror-json5": "^1.0.3", "cron-parser": "^4.9.0", - "dayjs": "^1.11.20", + "dayjs": "^1.11.21", "deep-equal": "^2.2.3", + "dompurify": "^3.4.12", "echarts": "^5.6.0", "flatted": "^3.4.2", "ignore": "^6.0.2", "json5": "^2.2.3", - "nanoid": "^5.1.7", + "nanoid": "^3.3.18", "nanotar": "^0.3.0", "pretty-bytes": "^6.1.1", "remarkable": "^2.0.1", - "svelte-confetti": "^1.4.0", "three": "^0.181.2", "tippy.js": "^6.3.7", }, "devDependencies": { "@eslint/compat": "^1.4.1", "@eslint/js": "^9.39.4", - "@lezer/common": "^1.5.0", + "@lezer/common": "^1.5.2", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", - "@playwright/test": "^1.58.2", + "@playwright/test": "^1.60.0", "@sveltejs/adapter-static": "^3.0.10", - "@sveltejs/kit": "^2.57.1", + "@sveltejs/kit": "^2.61.1", "@sveltejs/vite-plugin-svelte": "^5.1.1", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/svelte": "^5.3.1", "@testing-library/user-event": "^14.6.1", "@types/deep-equal": "^1.0.4", + "@types/dompurify": "^3.2.0", "@types/remarkable": "^2.0.8", "@types/three": "^0.182.0", - "@typescript-eslint/eslint-plugin": "^8.57.2", - "@typescript-eslint/parser": "^8.57.2", - "@vitest/ui": "^3.2.4", + "@typescript-eslint/eslint-plugin": "^8.60.1", + "@typescript-eslint/parser": "^8.60.1", + "@vitest/ui": "^4.1.8", "color": "^5.0.3", "eslint": "^9.39.4", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-svelte": "^3.16.0", + "eslint-plugin-svelte": "^3.19.0", "globals": "^16.5.0", "jsdom": "^26.1.0", "kleur": "^4.1.5", - "prettier": "^3.8.1", - "prettier-plugin-svelte": "^3.5.1", - "sass": "^1.98.0", - "svelte": "^5.55.0", - "svelte-check": "^4.4.5", - "svelte-preprocess": "^6.0.3", + "prettier": "^3.8.3", + "prettier-plugin-svelte": "^3.5.2", + "sass": "^1.100.0", + "svelte": "^5.56.1", + "svelte-check": "^4.5.0", + "svelte-preprocess": "^6.0.5", "svelte-sequential-preprocessor": "^2.0.3", - "tldts": "^7.0.27", + "tldts": "^7.4.2", "tslib": "^2.8.1", "typescript": "^5.9.3", - "typescript-eslint": "^8.57.2", + "typescript-eslint": "^8.60.1", "vite": "^7.3.1", - "vitest": "^3.2.4", + "vitest": "^4.1.8", }, }, }, "overrides": { - "brace-expansion": ">=5.0.5", + "brace-expansion": ">=5.0.9", "cookie": "^0.7.0", + "devalue": "^5.8.1", "flatted": "^3.4.2", - "immutable": "^5.1.5", + "immutable": "^5.1.8", + "js-yaml": "^4.3.1", "minimatch": "10.2.3", + "nanoid": "^3.3.18", "picomatch": "^4.0.4", + "postcss": "^8.5.18", "vite": "npm:rolldown-vite@latest", + "ws": "^8.21.0", "yaml": "^1.10.3", }, "packages": { "@adobe/css-tools": ["@adobe/css-tools@4.4.4", "", {}, "sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg=="], - "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.80", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21", "@vercel/oidc": "3.1.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-uM7kpZB5l977lW7+2X1+klBUxIZQ78+1a9jHlaHFEzcOcmmslTl3sdP0QqfuuBcO0YBM2gwOiqVdp8i4TRQYcw=="], + "@ai-sdk/gateway": ["@ai-sdk/gateway@3.0.122", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "@vercel/oidc": "3.2.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-U1k2fk7cSH/tS5CZ3ujROiUCOLFwkzb792OqR/Org8Mfm27dKSIdRZG4ZuJUifT8alUWa61IoaRu4foXKlP5TQ=="], - "@ai-sdk/provider": ["@ai-sdk/provider@3.0.8", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ=="], + "@ai-sdk/provider": ["@ai-sdk/provider@3.0.10", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-Q3BZ27qfpYqnCYGvE3vt+Qi6LGOF9R5Nmzn+9JoM1lCRsD9mYaIhfJLkSunN48nfGXJ6n+XNV0J/XVpqGQl7Dw=="], "@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@2.1.13", "", { "dependencies": { "@ai-sdk/provider": "1.0.11", "eventsource-parser": "^3.0.0", "nanoid": "^3.3.8", "secure-json-parse": "^2.7.0" }, "peerDependencies": { "zod": "^3.0.0" }, "optionalPeers": ["zod"] }, "sha512-kLjqsfOdONr6DGcGEntFYM1niXz1H05vyZNf9OAzK+KKKc64izyP4/q/9HX7W4+6g8hm6BnmKxu8vkr6FSOqDg=="], @@ -124,15 +130,15 @@ "@analytics/type-utils": ["@analytics/type-utils@0.6.4", "", {}, "sha512-Ou1gQxFakOWLcPnbFVsrPb8g1wLLUZYYJXDPjHkG07+5mustGs5yqACx42UAu4A6NszNN6Z5gGxhyH45zPWRxw=="], - "@appwrite.io/console": ["@appwrite.io/console@12.2.0", "", { "dependencies": { "json-bigint": "1.0.0" } }, "sha512-kv5CS/pWlSkLzG1mPctUr5fMdisZRrkOYStIvAaNPHv+bl/wFCZMMoRoiPGlBpw2NKwTddGFkkQvHq8GbxehNA=="], + "@appwrite.io/console": ["@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@ed09983", { "dependencies": { "json-bigint": "1.0.0" } }], "@appwrite.io/pink-icons": ["@appwrite.io/pink-icons@0.25.0", "", {}, "sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q=="], - "@appwrite.io/pink-icons-svelte": ["@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", { "peerDependencies": { "svelte": "^4.0.0" } }, "sha512-2HYl/CC2OlfZIR7LzbLXuSPBn0iNkjbnxpaeGCkZ7UNZ/hFeSeeWjDJqTBMdZ8+X95uuZqHx62XPTiE/svuSXQ=="], + "@appwrite.io/pink-icons-svelte": ["@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", { "peerDependencies": { "svelte": "^4.0.0" } }], "@appwrite.io/pink-legacy": ["@appwrite.io/pink-legacy@1.0.3", "", { "dependencies": { "@appwrite.io/pink-icons": "1.0.0", "the-new-css-reset": "^1.11.2" } }, "sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ=="], - "@appwrite.io/pink-svelte": ["@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@8dcaa17", { "dependencies": { "@appwrite.io/pink-icons-svelte": "2.0.0-RC.1", "@floating-ui/dom": "^1.6.13", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", "@tanstack/svelte-virtual": "^3.13.10", "ansicolor": "^2.0.3", "d3": "^7.9.0", "fuse.js": "^7.1.0", "pretty-bytes": "^6.1.1", "shiki": "^1.18.0", "svelte-motion": "^0.12.2", "svelte-sonner": "^0.3.28" }, "peerDependencies": { "svelte": "^4.0.0" } }, "sha512-rw3zXN7/cUciCnhj0FR8M0H5Db+LYYMaKtPxvOAIMxNTBmStzU8kTw6grqIvdtFu9vybIsjKtIwm9QLHpNDBjA=="], + "@appwrite.io/pink-svelte": ["@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@8dcaa17", { "dependencies": { "@appwrite.io/pink-icons-svelte": "2.0.0-RC.1", "@floating-ui/dom": "^1.6.13", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", "@tanstack/svelte-virtual": "^3.13.10", "ansicolor": "^2.0.3", "d3": "^7.9.0", "fuse.js": "^7.1.0", "pretty-bytes": "^6.1.1", "shiki": "^1.18.0", "svelte-motion": "^0.12.2", "svelte-sonner": "^0.3.28" }, "peerDependencies": { "svelte": "^4.0.0" } }], "@asamuzakjp/css-color": ["@asamuzakjp/css-color@3.2.0", "", { "dependencies": { "@csstools/css-calc": "^2.1.3", "@csstools/css-color-parser": "^3.0.9", "@csstools/css-parser-algorithms": "^3.0.4", "@csstools/css-tokenizer": "^3.0.3", "lru-cache": "^10.4.3" } }, "sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw=="], @@ -170,19 +176,19 @@ "@babel/types": ["@babel/types@7.29.0", "", { "dependencies": { "@babel/helper-string-parser": "^7.27.1", "@babel/helper-validator-identifier": "^7.28.5" } }, "sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A=="], - "@codemirror/autocomplete": ["@codemirror/autocomplete@6.20.1", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-1cvg3Vz1dSSToCNlJfRA2WSI4ht3K+WplO0UMOgmUYPivCyy2oueZY6Lx7M9wThm7SDUBViRmuT+OG/i8+ON9A=="], + "@codemirror/autocomplete": ["@codemirror/autocomplete@6.20.2", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.17.0", "@lezer/common": "^1.0.0" } }, "sha512-G5FPkgIiLjOgZMjqVjvuKQ1rGPtHogLldJr33eFJdVLtmwY+giGrlv/ewljLz6b9BSQLkjxuwBc6g6omDM+YxQ=="], "@codemirror/commands": ["@codemirror/commands@6.10.3", "", { "dependencies": { "@codemirror/language": "^6.0.0", "@codemirror/state": "^6.6.0", "@codemirror/view": "^6.27.0", "@lezer/common": "^1.1.0" } }, "sha512-JFRiqhKu+bvSkDLI+rUhJwSxQxYb759W5GBezE8Uc8mHLqC9aV/9aTC7yJSqCtB3F00pylrLCwnyS91Ap5ej4Q=="], "@codemirror/language": ["@codemirror/language@6.12.3", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.23.0", "@lezer/common": "^1.5.0", "@lezer/highlight": "^1.0.0", "@lezer/lr": "^1.0.0", "style-mod": "^4.0.0" } }, "sha512-QwCZW6Tt1siP37Jet9Tb02Zs81TQt6qQrZR2H+eGMcFsL1zMrk2/b9CLC7/9ieP1fjIUMgviLWMmgiHoJrj+ZA=="], - "@codemirror/lint": ["@codemirror/lint@6.9.5", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.35.0", "crelt": "^1.0.5" } }, "sha512-GElsbU9G7QT9xXhpUg1zWGmftA/7jamh+7+ydKRuT0ORpWS3wOSP0yT1FOlIZa7mIJjpVPipErsyvVqB9cfTFA=="], + "@codemirror/lint": ["@codemirror/lint@6.9.6", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.42.0", "crelt": "^1.0.5" } }, "sha512-6Kp7r6XfCi/D/5sdXieMfg9pJU1bUEx96WITuLU6ESaKizCz0QHFMjY/TaFSbigDdEAIgi93itLBIUETP4oK+A=="], - "@codemirror/search": ["@codemirror/search@6.6.0", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.37.0", "crelt": "^1.0.5" } }, "sha512-koFuNXcDvyyotWcgOnZGmY7LZqEOXZaaxD/j6n18TCLx2/9HieZJ5H6hs1g8FiRxBD0DNfs0nXn17g872RmYdw=="], + "@codemirror/search": ["@codemirror/search@6.7.0", "", { "dependencies": { "@codemirror/state": "^6.0.0", "@codemirror/view": "^6.37.0", "crelt": "^1.0.5" } }, "sha512-ZvGm99wc/s2cITtMT15LFdn8aH/aS+V+DqyGq/N5ZlV5vWtH+nILvC2nw0zX7ByNoHHDZ2IxxdW38O0tc5nVHg=="], "@codemirror/state": ["@codemirror/state@6.6.0", "", { "dependencies": { "@marijn/find-cluster-break": "^1.0.0" } }, "sha512-4nbvra5R5EtiCzr9BTHiTLc+MLXK2QGiAVYMyi8PkQd3SR+6ixar/Q/01Fa21TBIDOZXgeWV4WppsQolSreAPQ=="], - "@codemirror/view": ["@codemirror/view@6.41.1", "", { "dependencies": { "@codemirror/state": "^6.6.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-ToDnWKbBnke+ZLrP6vgTTDScGi5H37YYuZGniQaBzxMVdtCxMrslsmtnOvbPZk4RX9bvkQqnWR/WS/35tJA0qg=="], + "@codemirror/view": ["@codemirror/view@6.43.0", "", { "dependencies": { "@codemirror/state": "^6.6.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-V7ZCLQO3Jus9hzh2jVCCPW3mO4IBMr43O37PqSUYautJSnnJF41YlgLw21x0fLJTYvJ+Vkm6Gp+qKGH9pltgXA=="], "@csstools/color-helpers": ["@csstools/color-helpers@5.1.0", "", {}, "sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA=="], @@ -364,9 +370,9 @@ "@parcel/watcher-win32-x64": ["@parcel/watcher-win32-x64@2.5.6", "", { "os": "win32", "cpu": "x64" }, "sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw=="], - "@plausible-analytics/tracker": ["@plausible-analytics/tracker@0.4.4", "", {}, "sha512-fz0NOYUEYXtg1TBaPEEvtcBq3FfmLFuTe1VZw4M8sTWX129br5dguu3M15+plOQnc181ShYe67RfwhKgK89VnA=="], + "@plausible-analytics/tracker": ["@plausible-analytics/tracker@0.4.5", "", {}, "sha512-6BfAGejXY+YA3Cw6LYT2Zpn4hTxDtPQAawFsYUsQCOg78wIS5C4deAGXTfJffa5VleMWITv5lpJ/EYuQBl1tPA=="], - "@playwright/test": ["@playwright/test@1.58.2", "", { "dependencies": { "playwright": "1.58.2" }, "bin": { "playwright": "cli.js" } }, "sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA=="], + "@playwright/test": ["@playwright/test@1.60.0", "", { "dependencies": { "playwright": "1.60.0" }, "bin": { "playwright": "cli.js" } }, "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag=="], "@polka/url": ["@polka/url@1.0.0-next.29", "", {}, "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww=="], @@ -402,17 +408,17 @@ "@rolldown/pluginutils": ["@rolldown/pluginutils@1.0.0-beta.53", "", {}, "sha512-vENRlFU4YbrwVqNDZ7fLvy+JR1CRkyr01jhSiDpE1u6py3OMzQfztQU2jxykW3ALNxO4kSlqIDeYyD0Y9RcQeQ=="], - "@sentry-internal/browser-utils": ["@sentry-internal/browser-utils@8.55.1", "", { "dependencies": { "@sentry/core": "8.55.1" } }, "sha512-SipXiwVhJrxzy3/4kf+YIFmpYlLKtGSRD+er7SBCcuSBtv31Fee8IXMDvk+bq24gRXxyjOLUmT//GGXjy2LL6w=="], + "@sentry-internal/browser-utils": ["@sentry-internal/browser-utils@8.55.2", "", { "dependencies": { "@sentry/core": "8.55.2" } }, "sha512-GnKod+gL/Y+1FUM/RGV8q6le1CoyiGbT40MitEK7eVwWe+bfTRq1gN7ioupyHFMUg1RlQkDQ4/sENmio/uow5A=="], - "@sentry-internal/feedback": ["@sentry-internal/feedback@8.55.1", "", { "dependencies": { "@sentry/core": "8.55.1" } }, "sha512-9iFHaT/ijtzB0ffZhXMnt2rPNIXO/dDiCL1G1Bc55rQMPXgawR9AIaAWciyqQjYcbL1DDOhWbzdVqB+kVs5gXw=="], + "@sentry-internal/feedback": ["@sentry-internal/feedback@8.55.2", "", { "dependencies": { "@sentry/core": "8.55.2" } }, "sha512-XQy//NWbL0mLLM5w8wNDWMNpXz39VUyW2397dUrH8++kR63WhUVAvTOtL0o0GMVadSAzl1b08oHP9zSUNFQwcg=="], - "@sentry-internal/replay": ["@sentry-internal/replay@8.55.1", "", { "dependencies": { "@sentry-internal/browser-utils": "8.55.1", "@sentry/core": "8.55.1" } }, "sha512-XaX6r8pXeX47rfiQrSQUwkgxHsDkOKzIT++zfTwrmveVlYSqAhp3x+AKhxAXGmKG62wlmAKQz54GJKcG4cgyKQ=="], + "@sentry-internal/replay": ["@sentry-internal/replay@8.55.2", "", { "dependencies": { "@sentry-internal/browser-utils": "8.55.2", "@sentry/core": "8.55.2" } }, "sha512-+W43Z697EVe/OgpGW07B773sa8xO1UbpnW0Cr+E+3FMDb6ZbXlaBUoagPTUkkQPdwBe35SDh6r8y2M3EOPGbxg=="], - "@sentry-internal/replay-canvas": ["@sentry-internal/replay-canvas@8.55.1", "", { "dependencies": { "@sentry-internal/replay": "8.55.1", "@sentry/core": "8.55.1" } }, "sha512-2sKRu96Qe70y6TiYdYbwkhg4um2prgzH/ZJRItuoSEAjPjoFYYlP+1qjE2CcBw4RPS8/PimV7SFheSaeZs2GCw=="], + "@sentry-internal/replay-canvas": ["@sentry-internal/replay-canvas@8.55.2", "", { "dependencies": { "@sentry-internal/replay": "8.55.2", "@sentry/core": "8.55.2" } }, "sha512-P/jGiuR7dRLG9IzD/463fLgiibyYceauav/9prRG0ZxJm1AtuO02OKball2Fs3bbzdzwHCTlcsUuL2ivDF4b5A=="], "@sentry/babel-plugin-component-annotate": ["@sentry/babel-plugin-component-annotate@2.22.6", "", {}, "sha512-V2g1Y1I5eSe7dtUVMBvAJr8BaLRr4CLrgNgtPaZyMT4Rnps82SrZ5zqmEkLXPumlXhLUWR6qzoMNN2u+RXVXfQ=="], - "@sentry/browser": ["@sentry/browser@8.55.1", "", { "dependencies": { "@sentry-internal/browser-utils": "8.55.1", "@sentry-internal/feedback": "8.55.1", "@sentry-internal/replay": "8.55.1", "@sentry-internal/replay-canvas": "8.55.1", "@sentry/core": "8.55.1" } }, "sha512-OEn2eg8h3Mr7BmBGQ28BqbWehYA/NklZ0pAZB1FypPPl+kMd85AbaRdGTnaSjgmpc8bKbBO64edq4Y14sbCs5w=="], + "@sentry/browser": ["@sentry/browser@8.55.2", "", { "dependencies": { "@sentry-internal/browser-utils": "8.55.2", "@sentry-internal/feedback": "8.55.2", "@sentry-internal/replay": "8.55.2", "@sentry-internal/replay-canvas": "8.55.2", "@sentry/core": "8.55.2" } }, "sha512-xHuPIEKhx9zw5quWvv4YgZprnwoVMCfxIhmOIf6KJ9iizyUHeUDcKpLS59xERroqwX4RpvK+l/27AZu4zfZlzQ=="], "@sentry/bundler-plugin-core": ["@sentry/bundler-plugin-core@2.22.6", "", { "dependencies": { "@babel/core": "^7.18.5", "@sentry/babel-plugin-component-annotate": "2.22.6", "@sentry/cli": "^2.36.1", "dotenv": "^16.3.1", "find-up": "^5.0.0", "glob": "^9.3.2", "magic-string": "0.30.8", "unplugin": "1.0.1" } }, "sha512-1esQdgSUCww9XAntO4pr7uAM5cfGhLsgTK9MEwAKNfvpMYJi9NUTYa3A7AZmdA8V6107Lo4OD7peIPrDRbaDCg=="], @@ -434,15 +440,15 @@ "@sentry/cli-win32-x64": ["@sentry/cli-win32-x64@2.58.5", "", { "os": "win32", "cpu": "x64" }, "sha512-IZf+XIMiQwj+5NzqbOQfywlOitmCV424Vtf9c+ep61AaVScUFD1TSrQbOcJJv5xGxhlxNOMNgMeZhdexdzrKZg=="], - "@sentry/core": ["@sentry/core@8.55.1", "", {}, "sha512-0ea+yDOgaijR3ba2al1QZxY0bZ9MBZq2a0G+2A0uCBpBkiXnpLFGVAo9UAlEikN1C4M8ROZYiuFU7yZCqacgLQ=="], + "@sentry/core": ["@sentry/core@8.55.2", "", {}, "sha512-YlEBwybUcOQ/KjMHDmof1vwweVnBtBxYlQp7DE3fOdtW4pqqdHWTnTntQs4VgYfxzjJYgtkd9LHlGtg8qy+JVQ=="], - "@sentry/node": ["@sentry/node@8.55.1", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1", "@opentelemetry/core": "^1.30.1", "@opentelemetry/instrumentation": "^0.57.1", "@opentelemetry/instrumentation-amqplib": "^0.46.0", "@opentelemetry/instrumentation-connect": "0.43.0", "@opentelemetry/instrumentation-dataloader": "0.16.0", "@opentelemetry/instrumentation-express": "0.47.0", "@opentelemetry/instrumentation-fastify": "0.44.1", "@opentelemetry/instrumentation-fs": "0.19.0", "@opentelemetry/instrumentation-generic-pool": "0.43.0", "@opentelemetry/instrumentation-graphql": "0.47.0", "@opentelemetry/instrumentation-hapi": "0.45.1", "@opentelemetry/instrumentation-http": "0.57.1", "@opentelemetry/instrumentation-ioredis": "0.47.0", "@opentelemetry/instrumentation-kafkajs": "0.7.0", "@opentelemetry/instrumentation-knex": "0.44.0", "@opentelemetry/instrumentation-koa": "0.47.0", "@opentelemetry/instrumentation-lru-memoizer": "0.44.0", "@opentelemetry/instrumentation-mongodb": "0.51.0", "@opentelemetry/instrumentation-mongoose": "0.46.0", "@opentelemetry/instrumentation-mysql": "0.45.0", "@opentelemetry/instrumentation-mysql2": "0.45.0", "@opentelemetry/instrumentation-nestjs-core": "0.44.0", "@opentelemetry/instrumentation-pg": "0.50.0", "@opentelemetry/instrumentation-redis-4": "0.46.0", "@opentelemetry/instrumentation-tedious": "0.18.0", "@opentelemetry/instrumentation-undici": "0.10.0", "@opentelemetry/resources": "^1.30.1", "@opentelemetry/sdk-trace-base": "^1.30.1", "@opentelemetry/semantic-conventions": "^1.28.0", "@prisma/instrumentation": "5.22.0", "@sentry/core": "8.55.1", "@sentry/opentelemetry": "8.55.1", "import-in-the-middle": "^1.11.2" } }, "sha512-s8ydn/OxZFIxc9Fvt23gJkrXkCvPnUu2bDKwjQBCx0M1b4DdNdp4FaimT6B9reya7buj+tsNkZAoT11KqFhG/g=="], + "@sentry/node": ["@sentry/node@8.55.2", "", { "dependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1", "@opentelemetry/core": "^1.30.1", "@opentelemetry/instrumentation": "^0.57.1", "@opentelemetry/instrumentation-amqplib": "^0.46.0", "@opentelemetry/instrumentation-connect": "0.43.0", "@opentelemetry/instrumentation-dataloader": "0.16.0", "@opentelemetry/instrumentation-express": "0.47.0", "@opentelemetry/instrumentation-fastify": "0.44.1", "@opentelemetry/instrumentation-fs": "0.19.0", "@opentelemetry/instrumentation-generic-pool": "0.43.0", "@opentelemetry/instrumentation-graphql": "0.47.0", "@opentelemetry/instrumentation-hapi": "0.45.1", "@opentelemetry/instrumentation-http": "0.57.1", "@opentelemetry/instrumentation-ioredis": "0.47.0", "@opentelemetry/instrumentation-kafkajs": "0.7.0", "@opentelemetry/instrumentation-knex": "0.44.0", "@opentelemetry/instrumentation-koa": "0.47.0", "@opentelemetry/instrumentation-lru-memoizer": "0.44.0", "@opentelemetry/instrumentation-mongodb": "0.51.0", "@opentelemetry/instrumentation-mongoose": "0.46.0", "@opentelemetry/instrumentation-mysql": "0.45.0", "@opentelemetry/instrumentation-mysql2": "0.45.0", "@opentelemetry/instrumentation-nestjs-core": "0.44.0", "@opentelemetry/instrumentation-pg": "0.50.0", "@opentelemetry/instrumentation-redis-4": "0.46.0", "@opentelemetry/instrumentation-tedious": "0.18.0", "@opentelemetry/instrumentation-undici": "0.10.0", "@opentelemetry/resources": "^1.30.1", "@opentelemetry/sdk-trace-base": "^1.30.1", "@opentelemetry/semantic-conventions": "^1.28.0", "@prisma/instrumentation": "5.22.0", "@sentry/core": "8.55.2", "@sentry/opentelemetry": "8.55.2", "import-in-the-middle": "^1.11.2" } }, "sha512-x3Whryb4TytiIhH9ABLVuASfBvwA50v6PpJYvq0Y9dUMi9Eb0cfuqvRCB3e+oVntZHQpnXor2U/gRBIdG2jp4w=="], - "@sentry/opentelemetry": ["@sentry/opentelemetry@8.55.1", "", { "dependencies": { "@sentry/core": "8.55.1" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1", "@opentelemetry/core": "^1.30.1", "@opentelemetry/instrumentation": "^0.57.1", "@opentelemetry/sdk-trace-base": "^1.30.1", "@opentelemetry/semantic-conventions": "^1.28.0" } }, "sha512-ipiM/k3Hzt8visoBfkDb4AQBWHkJeou3SjoPec7NlDabH/Jj8x6VlK5Hex4z+WOv99rRy+5MUtga/CZnOjvh0A=="], + "@sentry/opentelemetry": ["@sentry/opentelemetry@8.55.2", "", { "dependencies": { "@sentry/core": "8.55.2" }, "peerDependencies": { "@opentelemetry/api": "^1.9.0", "@opentelemetry/context-async-hooks": "^1.30.1", "@opentelemetry/core": "^1.30.1", "@opentelemetry/instrumentation": "^0.57.1", "@opentelemetry/sdk-trace-base": "^1.30.1", "@opentelemetry/semantic-conventions": "^1.28.0" } }, "sha512-pbhXi4cS1W4l392yEfIx3UD28OYAl9JkYOmh/Cpm6cPTtRMPxi3hWeujGbcXV9T/RkWYjqd+JdUDJjqsWSww9A=="], - "@sentry/svelte": ["@sentry/svelte@8.55.1", "", { "dependencies": { "@sentry/browser": "8.55.1", "@sentry/core": "8.55.1", "magic-string": "^0.30.0" }, "peerDependencies": { "svelte": "3.x || 4.x || 5.x" } }, "sha512-INuwEscDDkHY3rnZyYiRCBtI8vz9qkTprTpegMC01W7mWE2vh9bNft8V/c41una8m8m6JLREy+1eYRvd/uDr3A=="], + "@sentry/svelte": ["@sentry/svelte@8.55.2", "", { "dependencies": { "@sentry/browser": "8.55.2", "@sentry/core": "8.55.2", "magic-string": "^0.30.0" }, "peerDependencies": { "svelte": "3.x || 4.x || 5.x" } }, "sha512-q5aN6lwYiReZcwQfzIQyipBVtfu5ZmE237ivKiTp1VZqPetWLZO4PMWzP9kzG+lz1OIdRhEGm6GBvJi4NBS/9A=="], - "@sentry/sveltekit": ["@sentry/sveltekit@8.55.1", "", { "dependencies": { "@sentry/core": "8.55.1", "@sentry/node": "8.55.1", "@sentry/opentelemetry": "8.55.1", "@sentry/svelte": "8.55.1", "@sentry/vite-plugin": "2.22.6", "magic-string": "0.30.7", "magicast": "0.2.8", "sorcery": "1.0.0" }, "peerDependencies": { "@sveltejs/kit": "1.x || 2.x", "vite": "*" }, "optionalPeers": ["vite"] }, "sha512-Kt05HMaWvbtvUYFF5gmZmNBY2Wn1kJnyTXDjYusTxsAtM9RfU05UbOSqedBcOqhSALohZUwHA4/QO3lqgXEsAg=="], + "@sentry/sveltekit": ["@sentry/sveltekit@8.55.2", "", { "dependencies": { "@sentry/core": "8.55.2", "@sentry/node": "8.55.2", "@sentry/opentelemetry": "8.55.2", "@sentry/svelte": "8.55.2", "@sentry/vite-plugin": "2.22.6", "magic-string": "0.30.7", "magicast": "0.2.8", "sorcery": "1.0.0" }, "peerDependencies": { "@sveltejs/kit": "1.x || 2.x", "vite": "*" }, "optionalPeers": ["vite"] }, "sha512-ypl/St8erGso2z2IBLiRv9nRdH1HQ3rXDaI71mkj9PjUhcdiC7k7COFUs6j8knmgPIsRc7ByU23vsfotyCxFvA=="], "@sentry/vite-plugin": ["@sentry/vite-plugin@2.22.6", "", { "dependencies": { "@sentry/bundler-plugin-core": "2.22.6", "unplugin": "1.0.1" } }, "sha512-zIieP1VLWQb3wUjFJlwOAoaaJygJhXeUoGd0e/Ha2RLb2eW2S+4gjf6y6NqyY71tZ74LYVZKg/4prB6FAZSMXQ=="], @@ -464,11 +470,11 @@ "@stripe/stripe-js": ["@stripe/stripe-js@3.5.0", "", {}, "sha512-pKS3wZnJoL1iTyGBXAvCwduNNeghJHY6QSRSNNvpYnrrQrLZ6Owsazjyynu0e0ObRgks0i7Rv+pe2M7/MBTZpQ=="], - "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.9", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA=="], + "@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.10", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-4WfKk68eTih+MiJD4fSbxN7E8kVBmTMPWHUPYjvl2N0rMs53YLTT8/YjKU5Dtnz5LqDjl7LEw4U7lXR2W3J5WA=="], "@sveltejs/adapter-static": ["@sveltejs/adapter-static@3.0.10", "", { "peerDependencies": { "@sveltejs/kit": "^2.0.0" } }, "sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew=="], - "@sveltejs/kit": ["@sveltejs/kit@2.57.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/cookie": "^0.6.0", "acorn": "^8.14.1", "cookie": "^0.6.0", "devalue": "^5.6.4", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "set-cookie-parser": "^3.0.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": "^5.3.3 || ^6.0.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" }, "optionalPeers": ["@opentelemetry/api", "typescript"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-VRdSbB96cI1EnRh09CqmnQqP/YJvET5buj8S6k7CxaJqBJD4bw4fRKDjcarAj/eX9k2eHifQfDH8NtOh+ZxxPw=="], + "@sveltejs/kit": ["@sveltejs/kit@2.61.1", "", { "dependencies": { "@standard-schema/spec": "^1.0.0", "@sveltejs/acorn-typescript": "^1.0.9", "@types/cookie": "^0.6.0", "acorn": "^8.16.0", "cookie": "^0.6.0", "devalue": "^5.8.1", "esm-env": "^1.2.2", "kleur": "^4.1.5", "magic-string": "^0.30.5", "mrmime": "^2.0.0", "set-cookie-parser": "^3.0.0", "sirv": "^3.0.0" }, "peerDependencies": { "@opentelemetry/api": "^1.0.0", "@sveltejs/vite-plugin-svelte": "^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0", "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": "^5.3.3 || ^6.0.0", "vite": "^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0" }, "optionalPeers": ["@opentelemetry/api", "typescript"], "bin": { "svelte-kit": "svelte-kit.js" } }, "sha512-Ny8s1SR1TyQS2hD2Rvw0XKzU2Nw1eUF52dTb6T2bdcgz7wSC+Nyb5IwjWYlR4b2dvbbR5NJDiQwHg3rnNseghg=="], "@sveltejs/vite-plugin-svelte": ["@sveltejs/vite-plugin-svelte@5.1.1", "", { "dependencies": { "@sveltejs/vite-plugin-svelte-inspector": "^4.0.1", "debug": "^4.4.1", "deepmerge": "^4.3.1", "kleur": "^4.1.5", "magic-string": "^0.30.17", "vitefu": "^1.0.6" }, "peerDependencies": { "svelte": "^5.0.0", "vite": "^6.0.0" } }, "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ=="], @@ -492,9 +498,9 @@ "@threejs-kit/instanced-sprite-mesh": ["@threejs-kit/instanced-sprite-mesh@2.5.1", "", { "dependencies": { "diet-sprite": "^0.0.1", "earcut": "^2.2.4", "maath": "^0.10.7", "three-instanced-uniforms-mesh": "^0.52.4", "troika-three-utils": "^0.52.4" }, "peerDependencies": { "three": ">=0.170.0" } }, "sha512-pmt1ALRhbHhCJQTj2FuthH6PeLIeaM4hOuS2JO3kWSwlnvx/9xuUkjFR3JOi/myMqsH7pSsLIROSaBxDfttjeA=="], - "@threlte/core": ["@threlte/core@8.5.2", "", { "dependencies": { "mitt": "^3.0.1" }, "peerDependencies": { "svelte": ">=5", "three": ">=0.160" } }, "sha512-noxIsYlEYRFBo0U3T8Z4PWkfe23VCDxaHIlSzSWlOlBgd+mhKrhyM8lFmeznmZQS78z4obkWUJeYxx/jauD+rw=="], + "@threlte/core": ["@threlte/core@8.5.16", "", { "peerDependencies": { "svelte": ">=5", "three": ">=0.160" } }, "sha512-+aa9Zgz0/Qat82H0hTm1pTEtS2BIP1Nfu7pKaei+3+TvDqER0YnZ4hdgI9fYU9Z5r1lrzY3JxMyrdISp4B0kfw=="], - "@threlte/extras": ["@threlte/extras@9.13.0", "", { "dependencies": { "@threejs-kit/instanced-sprite-mesh": "^2.5.1", "camera-controls": "^3.1.2", "three-mesh-bvh": "^0.9.1", "three-perf": "^1.0.11", "three-viewport-gizmo": "^2.2.0", "troika-three-text": "^0.52.4" }, "peerDependencies": { "svelte": ">=5", "three": ">=0.160" } }, "sha512-fHt5VcOoXyBT+wuytRHlKa1SUxNEI15L/kpudVWE9Z0G+U5TWIf01mt0BdQBGJOqwVJYxwFzRJQxfS2/kLAl9Q=="], + "@threlte/extras": ["@threlte/extras@9.20.1", "", { "dependencies": { "@threejs-kit/instanced-sprite-mesh": "^2.5.1", "camera-controls": "^3.1.2", "three-mesh-bvh": "^0.9.1", "three-perf": "^1.0.11", "three-viewport-gizmo": "^2.2.0", "troika-three-text": "^0.52.4" }, "peerDependencies": { "svelte": ">=5", "three": ">=0.160" } }, "sha512-eWfTKw0IjZIaWlqD4B3+63iBsOFGxgSt3pitvo4ar6KgEjIyMR68X/CP64sBTDxwrsDDy0+vKEVGnX9mM0KPtA=="], "@tweenjs/tween.js": ["@tweenjs/tween.js@23.1.3", "", {}, "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA=="], @@ -514,6 +520,8 @@ "@types/dlv": ["@types/dlv@1.1.5", "", {}, "sha512-JHOWNfiWepAhfwlSw17kiWrWrk6od2dEQgHltJw9AS0JPFoLZJBge5+Dnil2NfdjAvJ/+vGSX60/BRW20PpUXw=="], + "@types/dompurify": ["@types/dompurify@3.2.0", "", { "dependencies": { "dompurify": "*" } }, "sha512-Fgg31wv9QbLDA0SpTOXO3MaxySc4DKGLi8sna4/Utjo4r3ZRPdCt4UQee8BWr+Q5z21yifghREPJGYaEOEIACg=="], + "@types/estree": ["@types/estree@1.0.8", "", {}, "sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w=="], "@types/hast": ["@types/hast@3.0.4", "", { "dependencies": { "@types/unist": "*" } }, "sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ=="], @@ -550,45 +558,45 @@ "@types/webxr": ["@types/webxr@0.5.24", "", {}, "sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg=="], - "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.57.2", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.57.2", "@typescript-eslint/type-utils": "8.57.2", "@typescript-eslint/utils": "8.57.2", "@typescript-eslint/visitor-keys": "8.57.2", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.57.2", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w=="], + "@typescript-eslint/eslint-plugin": ["@typescript-eslint/eslint-plugin@8.60.1", "", { "dependencies": { "@eslint-community/regexpp": "^4.12.2", "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/type-utils": "8.60.1", "@typescript-eslint/utils": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1", "ignore": "^7.0.5", "natural-compare": "^1.4.0", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "@typescript-eslint/parser": "^8.60.1", "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-JQ4S5GB0tfjO8BuJ4fcX+HodkzJjYBV+7OJ+wLygaX7OGQ7FudyHL4NSCA6ob+w3Yn+5MkKIozOwQhXeM7opVg=="], - "@typescript-eslint/parser": ["@typescript-eslint/parser@8.57.2", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.57.2", "@typescript-eslint/types": "8.57.2", "@typescript-eslint/typescript-estree": "8.57.2", "@typescript-eslint/visitor-keys": "8.57.2", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA=="], + "@typescript-eslint/parser": ["@typescript-eslint/parser@8.60.1", "", { "dependencies": { "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/types": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1", "debug": "^4.4.3" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-A0M6ua6H252bVjPvvtSgl2QA4+ET9S5Mtkb2GDyTxIhH/C4qDItT7RQNO5PhMC6NXGYXOR9dIalcDDgBKT7oFA=="], - "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.57.2", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.57.2", "@typescript-eslint/types": "^8.57.2", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw=="], + "@typescript-eslint/project-service": ["@typescript-eslint/project-service@8.60.1", "", { "dependencies": { "@typescript-eslint/tsconfig-utils": "^8.60.1", "@typescript-eslint/types": "^8.60.1", "debug": "^4.4.3" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-eXkTH2bxmXlqD1RnOPmLZ9ZM9D3VwSx04JOwBnP9RQ+yUA5a2Mu7SfW8uaV2Aon53NJzZlZYuX7tn91Izf+xaw=="], - "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.57.2", "", { "dependencies": { "@typescript-eslint/types": "8.57.2", "@typescript-eslint/visitor-keys": "8.57.2" } }, "sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw=="], + "@typescript-eslint/scope-manager": ["@typescript-eslint/scope-manager@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1" } }, "sha512-gvI5OQoptnxQnchOirukCuQ55svJSTuD/4k5+pC267xyBtYry748R9/c3tYUzb/iE6RZfllRz2lVulLCHkTm4w=="], - "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.57.2", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw=="], + "@typescript-eslint/tsconfig-utils": ["@typescript-eslint/tsconfig-utils@8.60.1", "", { "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-nh8w4qAteiKuZu3pSSzG/yGKpw0OlkrKnzFmbVRenKaD4qc+7i1GrmZaLVkr8rk4uipiPGMOW4YsM6WmKZ5CvA=="], - "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.57.2", "", { "dependencies": { "@typescript-eslint/types": "8.57.2", "@typescript-eslint/typescript-estree": "8.57.2", "@typescript-eslint/utils": "8.57.2", "debug": "^4.4.3", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg=="], + "@typescript-eslint/type-utils": ["@typescript-eslint/type-utils@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1", "@typescript-eslint/utils": "8.60.1", "debug": "^4.4.3", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-sdwTrpjosW7ANQYJ39ZBF1ZyEMEGVB2UsikrserVM/30a/F1dTLnu9bGxEdosugyu5caigjLrR2qiD11asjI1A=="], - "@typescript-eslint/types": ["@typescript-eslint/types@8.57.2", "", {}, "sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA=="], + "@typescript-eslint/types": ["@typescript-eslint/types@8.60.1", "", {}, "sha512-4h0tY8ppCkdCzcrl2YM5M3my0xsE1Tf8om3owEu5oPWmXwkKRmk0j0LGDzYBGUcAlesEbxBhazqu/K4cu3Ug7w=="], - "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.57.2", "", { "dependencies": { "@typescript-eslint/project-service": "8.57.2", "@typescript-eslint/tsconfig-utils": "8.57.2", "@typescript-eslint/types": "8.57.2", "@typescript-eslint/visitor-keys": "8.57.2", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.4.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.0.0" } }, "sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA=="], + "@typescript-eslint/typescript-estree": ["@typescript-eslint/typescript-estree@8.60.1", "", { "dependencies": { "@typescript-eslint/project-service": "8.60.1", "@typescript-eslint/tsconfig-utils": "8.60.1", "@typescript-eslint/types": "8.60.1", "@typescript-eslint/visitor-keys": "8.60.1", "debug": "^4.4.3", "minimatch": "^10.2.2", "semver": "^7.7.3", "tinyglobby": "^0.2.15", "ts-api-utils": "^2.5.0" }, "peerDependencies": { "typescript": ">=4.8.4 <6.1.0" } }, "sha512-alpRkfG8hlVE5kdJW2GkfgDgXxold3e8e4l6EnmhRmRLbekgAPCCGDVD++sABy9FcgPFroq+uFcCSM1vR57Cew=="], - "@typescript-eslint/utils": ["@typescript-eslint/utils@8.57.2", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.57.2", "@typescript-eslint/types": "8.57.2", "@typescript-eslint/typescript-estree": "8.57.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg=="], + "@typescript-eslint/utils": ["@typescript-eslint/utils@8.60.1", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.9.1", "@typescript-eslint/scope-manager": "8.60.1", "@typescript-eslint/types": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-h2MPBLoNtjc3qZWfY3Tl51yPorQ2McHn8pJfcMNTcIvrrZrr90Ykffit0yjrPFWQcRcUxzH20+6OcVdW4yHtUg=="], - "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.57.2", "", { "dependencies": { "@typescript-eslint/types": "8.57.2", "eslint-visitor-keys": "^5.0.0" } }, "sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw=="], + "@typescript-eslint/visitor-keys": ["@typescript-eslint/visitor-keys@8.60.1", "", { "dependencies": { "@typescript-eslint/types": "8.60.1", "eslint-visitor-keys": "^5.0.0" } }, "sha512-EbGRQg4FhrmwLodl+t3JNAnXHWVr9Vp+Zl1QBZVPY4ByfkzIT8cX3K6QWODHtkIZqqJVEWvhHSx3v5PDHsaQag=="], "@ungap/structured-clone": ["@ungap/structured-clone@1.3.0", "", {}, "sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g=="], - "@vercel/oidc": ["@vercel/oidc@3.1.0", "", {}, "sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w=="], + "@vercel/oidc": ["@vercel/oidc@3.2.0", "", {}, "sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug=="], - "@vitest/expect": ["@vitest/expect@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "tinyrainbow": "^2.0.0" } }, "sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig=="], + "@vitest/expect": ["@vitest/expect@4.1.8", "", { "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", "@vitest/spy": "4.1.8", "@vitest/utils": "4.1.8", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" } }, "sha512-h3nDO677RDLEGlBxyQ5CW8RlMThSKSRLUePLOx09gNIWRL40edgA1GCZSZgf1W55MFAG6/Sw14KeaAnqv0NKdQ=="], - "@vitest/mocker": ["@vitest/mocker@3.2.4", "", { "dependencies": { "@vitest/spy": "3.2.4", "estree-walker": "^3.0.3", "magic-string": "^0.30.17" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "optionalPeers": ["msw", "vite"] }, "sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ=="], + "@vitest/mocker": ["@vitest/mocker@4.1.8", "", { "dependencies": { "@vitest/spy": "4.1.8", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, "peerDependencies": { "msw": "^2.4.9", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" }, "optionalPeers": ["msw", "vite"] }, "sha512-LEiN/xe4OSIbKe9HQIp5OC24agGD9J5CnmMgsLohVVoOPWL9a2sBoR6VBx43jQZb7Kr1l4RCuyCJzcAa0+dojw=="], - "@vitest/pretty-format": ["@vitest/pretty-format@3.2.4", "", { "dependencies": { "tinyrainbow": "^2.0.0" } }, "sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA=="], + "@vitest/pretty-format": ["@vitest/pretty-format@4.1.8", "", { "dependencies": { "tinyrainbow": "^3.1.0" } }, "sha512-9GasEBxpZ1VYIpqHf/0+YGg121uSNwCKOJqIrTwWP/TB7DmFCiaBpNl3aPZzoLWfWkuqhbH8vJIVobZkvdo2cA=="], - "@vitest/runner": ["@vitest/runner@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "pathe": "^2.0.3", "strip-literal": "^3.0.0" } }, "sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ=="], + "@vitest/runner": ["@vitest/runner@4.1.8", "", { "dependencies": { "@vitest/utils": "4.1.8", "pathe": "^2.0.3" } }, "sha512-EmVxeBAfMJvycdjd6Hm+RbFBbA9fKvo0Kx37hNpBYoYeavH3RNsBXWDooR1mgD52dCrxIIuP7UotpfiwOikvcg=="], - "@vitest/snapshot": ["@vitest/snapshot@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "magic-string": "^0.30.17", "pathe": "^2.0.3" } }, "sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ=="], + "@vitest/snapshot": ["@vitest/snapshot@4.1.8", "", { "dependencies": { "@vitest/pretty-format": "4.1.8", "@vitest/utils": "4.1.8", "magic-string": "^0.30.21", "pathe": "^2.0.3" } }, "sha512-acfZboRmAIf05DEKcBQy33VXojFJjtUdLyo7oOmV9kebb2xdU01UknNiPuPZoJZQyO7DF0gZdTGTpeAzET9QPQ=="], - "@vitest/spy": ["@vitest/spy@3.2.4", "", { "dependencies": { "tinyspy": "^4.0.3" } }, "sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw=="], + "@vitest/spy": ["@vitest/spy@4.1.8", "", {}, "sha512-6EevtBp6OZOPF7bmz36HrGMeP3txgVSrgebWxHOafDXGkhIzfXK14f8KF6MuFfgXXUeHxmpD3BQxkV00/3s5mA=="], - "@vitest/ui": ["@vitest/ui@3.2.4", "", { "dependencies": { "@vitest/utils": "3.2.4", "fflate": "^0.8.2", "flatted": "^3.3.3", "pathe": "^2.0.3", "sirv": "^3.0.1", "tinyglobby": "^0.2.14", "tinyrainbow": "^2.0.0" }, "peerDependencies": { "vitest": "3.2.4" } }, "sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA=="], + "@vitest/ui": ["@vitest/ui@4.1.8", "", { "dependencies": { "@vitest/utils": "4.1.8", "fflate": "^0.8.2", "flatted": "^3.4.2", "pathe": "^2.0.3", "sirv": "^3.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0" }, "peerDependencies": { "vitest": "4.1.8" } }, "sha512-RUS2ZU2TsduVrI+9c12uTNaKrNUTsm6yFt3fueEUB9iKvyC2UP83F+sqIz00HQIah4UOL1TMoDAki8K0NjGvsA=="], - "@vitest/utils": ["@vitest/utils@3.2.4", "", { "dependencies": { "@vitest/pretty-format": "3.2.4", "loupe": "^3.1.4", "tinyrainbow": "^2.0.0" } }, "sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA=="], + "@vitest/utils": ["@vitest/utils@4.1.8", "", { "dependencies": { "@vitest/pretty-format": "4.1.8", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" } }, "sha512-uOJamYALNhfJ6iolExyQM40yIQwDqYnkKtQ5VCiSe17E33H0aQ/u+1GlRuz4LZBk6Mm3sg90G9hEbmEt37C1Zg=="], "@webgpu/types": ["@webgpu/types@0.1.69", "", {}, "sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ=="], @@ -600,7 +608,7 @@ "agent-base": ["agent-base@7.1.4", "", {}, "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ=="], - "ai": ["ai@6.0.138", "", { "dependencies": { "@ai-sdk/gateway": "3.0.80", "@ai-sdk/provider": "3.0.8", "@ai-sdk/provider-utils": "4.0.21", "@opentelemetry/api": "1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-49OfPe0f5uxJ6jUdA5BBXjIinP6+ZdYfAtpF2aEH64GA5wPcxH2rf/TBUQQ0bbamBz/D+TLMV18xilZqOC+zaA=="], + "ai": ["ai@6.0.194", "", { "dependencies": { "@ai-sdk/gateway": "3.0.122", "@ai-sdk/provider": "3.0.10", "@ai-sdk/provider-utils": "4.0.27", "@opentelemetry/api": "^1.9.0" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-0MkYqrSZZuC1zTECppcaUT0i54aocXpYaUMVue3V8z/weBHCytfO5/CcwZCU80msZpfkbBUKYSSrkZFotEO5wQ=="], "ajv": ["ajv@6.14.0", "", { "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" } }, "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw=="], @@ -642,14 +650,12 @@ "binary-extensions": ["binary-extensions@2.3.0", "", {}, "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw=="], - "brace-expansion": ["brace-expansion@5.0.5", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ=="], + "brace-expansion": ["brace-expansion@5.0.9", "", { "dependencies": { "balanced-match": "^4.0.2" } }, "sha512-ScQ4IuvIEF1TMlP7Zt+vjJ//9zlPb2SDcxWxM3bk8s6t6GGdJ7KO1dCcTidOPJKePW30LE/2cT7wCyPho9/Wxg=="], "braces": ["braces@3.0.3", "", { "dependencies": { "fill-range": "^7.1.1" } }, "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA=="], "browserslist": ["browserslist@4.28.1", "", { "dependencies": { "baseline-browser-mapping": "^2.9.0", "caniuse-lite": "^1.0.30001759", "electron-to-chromium": "^1.5.263", "node-releases": "^2.0.27", "update-browserslist-db": "^1.2.0" }, "bin": { "browserslist": "cli.js" } }, "sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA=="], - "cac": ["cac@6.7.14", "", {}, "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ=="], - "call-bind": ["call-bind@1.0.8", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.0", "es-define-property": "^1.0.0", "get-intrinsic": "^1.2.4", "set-function-length": "^1.2.2" } }, "sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww=="], "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], @@ -664,7 +670,7 @@ "ccount": ["ccount@2.0.1", "", {}, "sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg=="], - "chai": ["chai@5.3.3", "", { "dependencies": { "assertion-error": "^2.0.1", "check-error": "^2.1.1", "deep-eql": "^5.0.1", "loupe": "^3.1.0", "pathval": "^2.0.0" } }, "sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw=="], + "chai": ["chai@6.2.2", "", {}, "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg=="], "chalk": ["chalk@4.1.2", "", { "dependencies": { "ansi-styles": "^4.1.0", "supports-color": "^7.1.0" } }, "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA=="], @@ -672,9 +678,7 @@ "character-entities-legacy": ["character-entities-legacy@3.0.0", "", {}, "sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ=="], - "check-error": ["check-error@2.1.3", "", {}, "sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA=="], - - "chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + "chokidar": ["chokidar@5.0.0", "", { "dependencies": { "readdirp": "^5.0.0" } }, "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw=="], "cjs-module-lexer": ["cjs-module-lexer@1.4.3", "", {}, "sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q=="], @@ -776,14 +780,12 @@ "data-urls": ["data-urls@5.0.0", "", { "dependencies": { "whatwg-mimetype": "^4.0.0", "whatwg-url": "^14.0.0" } }, "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg=="], - "dayjs": ["dayjs@1.11.20", "", {}, "sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ=="], + "dayjs": ["dayjs@1.11.21", "", {}, "sha512-98IT+HOahAisibz/yjKbzuOBwYcjJ7BCLPzARyHiyEBmRz4fatF+KPJszEHXsGYjUG234aH/cOjW1wwTbKUZlA=="], "debug": ["debug@4.4.3", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA=="], "decimal.js": ["decimal.js@10.6.0", "", {}, "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg=="], - "deep-eql": ["deep-eql@5.0.2", "", {}, "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q=="], - "deep-equal": ["deep-equal@2.2.3", "", { "dependencies": { "array-buffer-byte-length": "^1.0.0", "call-bind": "^1.0.5", "es-get-iterator": "^1.1.3", "get-intrinsic": "^1.2.2", "is-arguments": "^1.1.1", "is-array-buffer": "^3.0.2", "is-date-object": "^1.0.5", "is-regex": "^1.1.4", "is-shared-array-buffer": "^1.0.2", "isarray": "^2.0.5", "object-is": "^1.1.5", "object-keys": "^1.1.1", "object.assign": "^4.1.4", "regexp.prototype.flags": "^1.5.1", "side-channel": "^1.0.4", "which-boxed-primitive": "^1.0.2", "which-collection": "^1.0.1", "which-typed-array": "^1.1.13" } }, "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA=="], "deep-is": ["deep-is@0.1.4", "", {}, "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ=="], @@ -800,7 +802,7 @@ "detect-libc": ["detect-libc@2.1.2", "", {}, "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ=="], - "devalue": ["devalue@5.6.4", "", {}, "sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA=="], + "devalue": ["devalue@5.8.1", "", {}, "sha512-4CXDYRBGqN+57wVJkuXBYmpAVUSg3L6JAQa/DFqm238G73E1wuyc/JhGQJzN7vUf/CMphYau2zXbfWzDR5aTEw=="], "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], @@ -810,6 +812,8 @@ "dom-accessibility-api": ["dom-accessibility-api@0.5.16", "", {}, "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg=="], + "dompurify": ["dompurify@3.4.12", "", { "optionalDependencies": { "@types/trusted-types": "^2.0.7" } }, "sha512-zQvGet8Z2sWbQhCmfFz/T5QWH2oBmjnqK3qvOjaqaNLrLEF912WamU+ohnTp0TCep/MFVHpdJuCZEdFOdTnEFg=="], + "dotenv": ["dotenv@16.6.1", "", {}, "sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow=="], "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], @@ -830,7 +834,7 @@ "es-get-iterator": ["es-get-iterator@1.1.3", "", { "dependencies": { "call-bind": "^1.0.2", "get-intrinsic": "^1.1.3", "has-symbols": "^1.0.3", "is-arguments": "^1.1.1", "is-map": "^2.0.2", "is-set": "^2.0.2", "is-string": "^1.0.7", "isarray": "^2.0.5", "stop-iteration-iterator": "^1.0.0" } }, "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw=="], - "es-module-lexer": ["es-module-lexer@1.7.0", "", {}, "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA=="], + "es-module-lexer": ["es-module-lexer@2.1.0", "", {}, "sha512-n27zTYMjYu1aj4MjCWzSP7G9r75utsaoc8m61weK+W8JMBGGQybd43GstCXZ3WNmSFtGT9wi59qQTW6mhTR5LQ=="], "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], @@ -842,7 +846,7 @@ "eslint-config-prettier": ["eslint-config-prettier@10.1.8", "", { "peerDependencies": { "eslint": ">=7.0.0" }, "bin": { "eslint-config-prettier": "bin/cli.js" } }, "sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w=="], - "eslint-plugin-svelte": ["eslint-plugin-svelte@3.16.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.6.1", "@jridgewell/sourcemap-codec": "^1.5.0", "esutils": "^2.0.3", "globals": "^16.0.0", "known-css-properties": "^0.37.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.4.0" }, "peerDependencies": { "eslint": "^8.57.1 || ^9.0.0 || ^10.0.0", "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-DJXxqpYZUxcE0SfYo8EJzV2ZC+zAD7fJp1n1HwcEMRR1cOEUYvjT9GuzJeNghMjgb7uxuK3IJAzI+x6zzUxO5A=="], + "eslint-plugin-svelte": ["eslint-plugin-svelte@3.19.0", "", { "dependencies": { "@eslint-community/eslint-utils": "^4.6.1", "@jridgewell/sourcemap-codec": "^1.5.0", "esutils": "^2.0.3", "globals": "^16.0.0", "known-css-properties": "^0.37.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.7.0" }, "peerDependencies": { "eslint": "^8.57.1 || ^9.0.0 || ^10.0.0", "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-t3rNaZeXz4d2gG4uJyMEYfJCFKf22+SWbSizIIXIWKu4wM+XPLiMWuSSr/C5821JmFeN9ogK+eExbG+z+twyxw=="], "eslint-scope": ["eslint-scope@8.4.0", "", { "dependencies": { "esrecurse": "^4.3.0", "estraverse": "^5.2.0" } }, "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg=="], @@ -856,7 +860,7 @@ "esquery": ["esquery@1.7.0", "", { "dependencies": { "estraverse": "^5.1.0" } }, "sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g=="], - "esrap": ["esrap@2.2.4", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "@typescript-eslint/types": "^8.2.0" } }, "sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg=="], + "esrap": ["esrap@2.2.9", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15" }, "peerDependencies": { "@typescript-eslint/types": "^8.2.0" }, "optionalPeers": ["@typescript-eslint/types"] }, "sha512-4KijP+NxCWthMCUC3qHbE6n4vCjqgJS1uAYKhuT/GWfFTf1Qyive2TgOjep+gzbSzRfnNyaN/UU9YmdOt8Eg0A=="], "esrecurse": ["esrecurse@4.3.0", "", { "dependencies": { "estraverse": "^5.2.0" } }, "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag=="], @@ -956,7 +960,7 @@ "ignore": ["ignore@6.0.2", "", {}, "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A=="], - "immutable": ["immutable@5.1.5", "", {}, "sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A=="], + "immutable": ["immutable@5.1.9", "", {}, "sha512-m8nVez3rwrgmWxtLMt1ZYXB2Lv7OKYn/disyxAlSDYAlKSlFoPPfIAmAM/M5xqL4m4C/wAPw7S2/CNaUii1Hxg=="], "import-fresh": ["import-fresh@3.3.1", "", { "dependencies": { "parent-module": "^1.0.0", "resolve-from": "^4.0.0" } }, "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ=="], @@ -1020,7 +1024,7 @@ "js-tokens": ["js-tokens@4.0.0", "", {}, "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="], - "js-yaml": ["js-yaml@4.1.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA=="], + "js-yaml": ["js-yaml@4.3.1", "", { "dependencies": { "argparse": "^2.0.1" }, "bin": { "js-yaml": "bin/js-yaml.js" } }, "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ=="], "jsdom": ["jsdom@26.1.0", "", { "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" }, "peerDependencies": { "canvas": "^3.0.0" }, "optionalPeers": ["canvas"] }, "sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg=="], @@ -1080,8 +1084,6 @@ "lodash.merge": ["lodash.merge@4.6.2", "", {}, "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ=="], - "loupe": ["loupe@3.2.1", "", {}, "sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ=="], - "lru-cache": ["lru-cache@10.4.3", "", {}, "sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ=="], "luxon": ["luxon@3.7.2", "", {}, "sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew=="], @@ -1118,8 +1120,6 @@ "minipass": ["minipass@4.2.8", "", {}, "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ=="], - "mitt": ["mitt@3.0.1", "", {}, "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="], - "module-details-from-path": ["module-details-from-path@1.0.4", "", {}, "sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w=="], "mri": ["mri@1.2.0", "", {}, "sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA=="], @@ -1128,7 +1128,7 @@ "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], - "nanoid": ["nanoid@5.1.7", "", { "bin": { "nanoid": "bin/nanoid.js" } }, "sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ=="], + "nanoid": ["nanoid@3.3.18", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w=="], "nanotar": ["nanotar@0.3.0", "", {}, "sha512-Kv2JYYiCzt16Kt5QwAc9BFG89xfPNBx+oQL4GQXD9nLqPkZBiNaqaCWtwnbk/q7UVsTYevvM1b0UF8zmEI4pCg=="], @@ -1152,6 +1152,8 @@ "object.assign": ["object.assign@4.1.7", "", { "dependencies": { "call-bind": "^1.0.8", "call-bound": "^1.0.3", "define-properties": "^1.2.1", "es-object-atoms": "^1.0.0", "has-symbols": "^1.1.0", "object-keys": "^1.1.1" } }, "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw=="], + "obug": ["obug@2.1.1", "", {}, "sha512-uTqF9MuPraAQ+IsnPf366RG4cP9RtUi7MLO1N3KEc+wb0a6yKpeL0lmk2IB1jY5KHPAlTc6T/JRdC/YqxHNwkQ=="], + "oniguruma-to-es": ["oniguruma-to-es@2.3.0", "", { "dependencies": { "emoji-regex-xs": "^1.0.0", "regex": "^5.1.1", "regex-recursion": "^5.1.1" } }, "sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g=="], "optionator": ["optionator@0.9.4", "", { "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" } }, "sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g=="], @@ -1174,8 +1176,6 @@ "pathe": ["pathe@2.0.3", "", {}, "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w=="], - "pathval": ["pathval@2.0.1", "", {}, "sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ=="], - "pg-int8": ["pg-int8@1.0.1", "", {}, "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw=="], "pg-protocol": ["pg-protocol@1.13.0", "", {}, "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w=="], @@ -1186,15 +1186,15 @@ "picomatch": ["picomatch@4.0.4", "", {}, "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A=="], - "playwright": ["playwright@1.58.2", "", { "dependencies": { "playwright-core": "1.58.2" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A=="], + "playwright": ["playwright@1.60.0", "", { "dependencies": { "playwright-core": "1.60.0" }, "optionalDependencies": { "fsevents": "2.3.2" }, "bin": { "playwright": "cli.js" } }, "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA=="], - "playwright-core": ["playwright-core@1.58.2", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg=="], + "playwright-core": ["playwright-core@1.60.0", "", { "bin": { "playwright-core": "cli.js" } }, "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA=="], "popmotion": ["popmotion@11.0.5", "", { "dependencies": { "framesync": "6.1.2", "hey-listen": "^1.0.8", "style-value-types": "5.1.2", "tslib": "2.4.0" } }, "sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA=="], "possible-typed-array-names": ["possible-typed-array-names@1.1.0", "", {}, "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg=="], - "postcss": ["postcss@8.5.8", "", { "dependencies": { "nanoid": "^3.3.11", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg=="], + "postcss": ["postcss@8.5.23", "", { "dependencies": { "nanoid": "^3.3.16", "picocolors": "^1.1.1", "source-map-js": "^1.2.1" } }, "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg=="], "postcss-load-config": ["postcss-load-config@3.1.4", "", { "dependencies": { "lilconfig": "^2.0.5", "yaml": "^1.10.2" }, "peerDependencies": { "postcss": ">=8.0.9", "ts-node": ">=9.0.0" }, "optionalPeers": ["postcss", "ts-node"] }, "sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg=="], @@ -1214,9 +1214,9 @@ "prelude-ls": ["prelude-ls@1.2.1", "", {}, "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g=="], - "prettier": ["prettier@3.8.1", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg=="], + "prettier": ["prettier@3.8.3", "", { "bin": { "prettier": "bin/prettier.cjs" } }, "sha512-7igPTM53cGHMW8xWuVTydi2KO233VFiTNyF5hLJqpilHfmn8C8gPf+PS7dUT64YcXFbiMGZxS9pCSxL/Dxm/Jw=="], - "prettier-plugin-svelte": ["prettier-plugin-svelte@3.5.1", "", { "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" } }, "sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg=="], + "prettier-plugin-svelte": ["prettier-plugin-svelte@3.5.2", "", { "peerDependencies": { "prettier": "^3.0.0", "svelte": "^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0" } }, "sha512-ItFouLvzSFE3ulNl4DKoWM3BGcbDCNVpIyy/Y3F2gC3aNiGLxtFUdffVqO5Z5hhYG+DFT5KULWaxmeFFpdbvaQ=="], "pretty-bytes": ["pretty-bytes@6.1.1", "", {}, "sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ=="], @@ -1232,7 +1232,7 @@ "react-is": ["react-is@17.0.2", "", {}, "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w=="], - "readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + "readdirp": ["readdirp@5.0.0", "", {}, "sha512-9u/XQ1pvrQtYyMpZe7DXKv2p5CNvyVwzUB6uhLAnQwHMSgKMBR62lc7AHljaeteeHXn11XTAaLLUVZYVZyuRBQ=="], "recast": ["recast@0.23.11", "", { "dependencies": { "ast-types": "^0.16.1", "esprima": "~4.0.0", "source-map": "~0.6.1", "tiny-invariant": "^1.3.3", "tslib": "^2.0.1" } }, "sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA=="], @@ -1270,7 +1270,7 @@ "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], - "sass": ["sass@1.98.0", "", { "dependencies": { "chokidar": "^4.0.0", "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A=="], + "sass": ["sass@1.100.0", "", { "dependencies": { "chokidar": "^5.0.0", "immutable": "^5.1.5", "source-map-js": ">=0.6.2 <2.0.0" }, "optionalDependencies": { "@parcel/watcher": "^2.4.1" }, "bin": { "sass": "sass.js" } }, "sha512-B5j0rYMlinhhOo9tjQebMVVn0TfyXAF+wB3b2ggZUuJ/is/Y+7+JGjirAMxHZ9Z3hIP98NPfamlAkBHa1lAaXQ=="], "saxes": ["saxes@6.0.0", "", { "dependencies": { "xmlchars": "^2.2.0" } }, "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA=="], @@ -1316,7 +1316,7 @@ "stackback": ["stackback@0.0.2", "", {}, "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw=="], - "std-env": ["std-env@3.10.0", "", {}, "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg=="], + "std-env": ["std-env@4.1.0", "", {}, "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ=="], "stop-iteration-iterator": ["stop-iteration-iterator@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "internal-slot": "^1.1.0" } }, "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ=="], @@ -1326,8 +1326,6 @@ "strip-json-comments": ["strip-json-comments@3.1.1", "", {}, "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig=="], - "strip-literal": ["strip-literal@3.1.0", "", { "dependencies": { "js-tokens": "^9.0.1" } }, "sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg=="], - "style-mod": ["style-mod@4.1.3", "", {}, "sha512-i/n8VsZydrugj3Iuzll8+x/00GH2vnYsk1eomD8QiRrSAeW6ItbCQDtfXCeJHd0iwiNagqjQkvpvREEPtW3IoQ=="], "style-value-types": ["style-value-types@5.1.2", "", { "dependencies": { "hey-listen": "^1.0.8", "tslib": "2.4.0" } }, "sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q=="], @@ -1336,17 +1334,15 @@ "supports-preserve-symlinks-flag": ["supports-preserve-symlinks-flag@1.0.0", "", {}, "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w=="], - "svelte": ["svelte@5.55.0", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.4", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-SThllKq6TRMBwPtat7ASnm/9CDXnIhBR0NPGw0ujn2DVYx9rVwsPZxDaDQcYGdUz/3BYVsCzdq7pZarRQoGvtw=="], - - "svelte-check": ["svelte-check@4.4.5", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-1bSwIRCvvmSHrlK52fOlZmVtUZgil43jNL/2H18pRpa+eQjzGt6e3zayxhp1S7GajPFKNM/2PMCG+DZFHlG9fw=="], + "svelte": ["svelte@5.56.1", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.10", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.8.1", "esm-env": "^1.2.1", "esrap": "^2.2.9", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-eArsJmvl3xZVuTYD852PzIEdg2wgDdIZ1NEsIPbzAukHwi284B18No4nK2rCO9AwsWUDza4Cjvmoa4HaojTl5g=="], - "svelte-confetti": ["svelte-confetti@1.4.0", "", { "peerDependencies": { "svelte": "^4.0.0" } }, "sha512-B0woNwpsFGwhkEoP48BIDQgvW0bMxPhavLVD+E+tsTWevlpr1aiz1S2wA8ArIXX957BiaZWHRHKmI5/pFRDbdg=="], + "svelte-check": ["svelte-check@4.5.0", "", { "dependencies": { "@jridgewell/trace-mapping": "^0.3.25", "chokidar": "^4.0.1", "fdir": "^6.2.0", "picocolors": "^1.0.0", "sade": "^1.7.4" }, "peerDependencies": { "svelte": "^4.0.0 || ^5.0.0-next.0", "typescript": ">=5.0.0" }, "bin": { "svelte-check": "bin/svelte-check" } }, "sha512-9lNwPxCLWniFvQIcEv1LFqjIxcFtO3smb5+5BKbRJ3ttL4o2lXCej5rLF4DAnfLPI66oaA81vAxw6ILdIWI7kA=="], - "svelte-eslint-parser": ["svelte-eslint-parser@1.6.0", "", { "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", "semver": "^7.7.2" }, "peerDependencies": { "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-qoB1ehychT6OxEtQAqc/guSqLS20SlA53Uijl7x375s8nlUT0lb9ol/gzraEEatQwsyPTJo87s2CmKL9Xab+Uw=="], + "svelte-eslint-parser": ["svelte-eslint-parser@1.7.1", "", { "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", "semver": "^7.7.2" }, "peerDependencies": { "svelte": "^3.37.0 || ^4.0.0 || ^5.0.0" }, "optionalPeers": ["svelte"] }, "sha512-mmwwKL9L/MB0QyBKdfyWxGjDuQfEyzxWy5S9Kkd0O/V5XD57MQ33KQtXrO6vKLuP6PIt8CRozvOX1mxpcRTqUg=="], "svelte-motion": ["svelte-motion@0.12.2", "", { "dependencies": { "@types/react": "^18.2.42", "framesync": "^6.1.2", "popmotion": "^11.0.5", "style-value-types": "5.1.2", "tslib": "^2.6.2" }, "peerDependencies": { "svelte": ">=3.35.0 || ^4.0.0 || ^5.0.0 || ^5.0.0-next.0" } }, "sha512-7RrdRz9iVP55B9HT/C0hYW3pyrKlF61kAby/AkDtOAP0uHFQDrfd0qQetDC81cEsK9b40jt+jfcqSAXcA7LPEw=="], - "svelte-preprocess": ["svelte-preprocess@6.0.3", "", { "peerDependencies": { "@babel/core": "^7.10.2", "coffeescript": "^2.5.1", "less": "^3.11.3 || ^4.0.0", "postcss": "^7 || ^8", "postcss-load-config": ">=3", "pug": "^3.0.0", "sass": "^1.26.8", "stylus": ">=0.55", "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", "svelte": "^4.0.0 || ^5.0.0-next.100 || ^5.0.0", "typescript": "^5.0.0" }, "optionalPeers": ["@babel/core", "coffeescript", "less", "postcss", "postcss-load-config", "pug", "sass", "stylus", "sugarss", "typescript"] }, "sha512-PLG2k05qHdhmRG7zR/dyo5qKvakhm8IJ+hD2eFRQmMLHp7X3eJnjeupUtvuRpbNiF31RjVw45W+abDwHEmP5OA=="], + "svelte-preprocess": ["svelte-preprocess@6.0.5", "", { "peerDependencies": { "@babel/core": "^7.10.2", "coffeescript": "^2.5.1", "less": "^3.11.3 || ^4.0.0", "postcss": "^7 || ^8", "postcss-load-config": ">=3", "pug": "^3.0.0", "sass": "^1.26.8", "stylus": ">=0.55", "sugarss": "^2.0.0 || ^3.0.0 || ^4.0.0", "svelte": "^4.0.0 || ^5.0.0-next.100 || ^5.0.0", "typescript": "^5.0.0 || ^6.0.0" }, "optionalPeers": ["@babel/core", "coffeescript", "less", "postcss", "postcss-load-config", "pug", "sass", "stylus", "sugarss", "typescript"] }, "sha512-sgwew5yV/2eMeQobIWgAxCNarKwiTUDIc3siAUbq3sp0G6ONtzk0W+wJihMdqjbYb3iGU3ubpGv0usnnuXT3qg=="], "svelte-sequential-preprocessor": ["svelte-sequential-preprocessor@2.0.3", "", { "dependencies": { "svelte": "^5.45.2", "tslib": "~2.8.1" } }, "sha512-AAtm4gwbB6Mj5SFZUDnmZQl2g1Qh7q1mU1MAqnGSRusRmDK20RiNdLkqfk/Mz5SbJS7zMj46JPFdkz+KTSkejw=="], @@ -1374,21 +1370,17 @@ "tinybench": ["tinybench@2.9.0", "", {}, "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg=="], - "tinyexec": ["tinyexec@0.3.2", "", {}, "sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA=="], + "tinyexec": ["tinyexec@1.2.4", "", {}, "sha512-SHf/r48b7vOrjve9PxJo3MN5v5yuyjHvdUcrQffT3WXMUfnGmHDVbC4k3sHJaJTgZCwpUplIaAo5ANtMyp3YHg=="], "tinyglobby": ["tinyglobby@0.2.15", "", { "dependencies": { "fdir": "^6.5.0", "picomatch": "^4.0.3" } }, "sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ=="], - "tinypool": ["tinypool@1.1.1", "", {}, "sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg=="], - - "tinyrainbow": ["tinyrainbow@2.0.0", "", {}, "sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw=="], - - "tinyspy": ["tinyspy@4.0.4", "", {}, "sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q=="], + "tinyrainbow": ["tinyrainbow@3.1.0", "", {}, "sha512-Bf+ILmBgretUrdJxzXM0SgXLZ3XfiaUuOj/IKQHuTXip+05Xn+uyEYdVg0kYDipTBcLrCVyUzAPz7QmArb0mmw=="], "tippy.js": ["tippy.js@6.3.7", "", { "dependencies": { "@popperjs/core": "^2.9.0" } }, "sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ=="], - "tldts": ["tldts@7.0.27", "", { "dependencies": { "tldts-core": "^7.0.27" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg=="], + "tldts": ["tldts@7.4.2", "", { "dependencies": { "tldts-core": "^7.4.2" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-kCwffuaH8ntKtygnWe1b4BJKWiCUH30n5KfoTr6IchcXOwR7chAOFJxFrH3vjANafUYrIA4a7SDL+nn7SiR4Sw=="], - "tldts-core": ["tldts-core@7.0.27", "", {}, "sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg=="], + "tldts-core": ["tldts-core@7.4.2", "", {}, "sha512-nwEyF4vl4RSJjwSjBUmOSxc3BFPoIFdlRthJ6e+5v9P3bHNsoD06UjuqMUspqp7vsEZ1beaHi1km+optiE17yA=="], "to-regex-range": ["to-regex-range@5.0.1", "", { "dependencies": { "is-number": "^7.0.0" } }, "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ=="], @@ -1406,7 +1398,7 @@ "troika-worker-utils": ["troika-worker-utils@0.52.0", "", {}, "sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw=="], - "ts-api-utils": ["ts-api-utils@2.4.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA=="], + "ts-api-utils": ["ts-api-utils@2.5.0", "", { "peerDependencies": { "typescript": ">=4.8.4" } }, "sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA=="], "tslib": ["tslib@2.8.1", "", {}, "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w=="], @@ -1416,7 +1408,7 @@ "typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="], - "typescript-eslint": ["typescript-eslint@8.57.2", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.57.2", "@typescript-eslint/parser": "8.57.2", "@typescript-eslint/typescript-estree": "8.57.2", "@typescript-eslint/utils": "8.57.2" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.0.0" } }, "sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A=="], + "typescript-eslint": ["typescript-eslint@8.60.1", "", { "dependencies": { "@typescript-eslint/eslint-plugin": "8.60.1", "@typescript-eslint/parser": "8.60.1", "@typescript-eslint/typescript-estree": "8.60.1", "@typescript-eslint/utils": "8.60.1" }, "peerDependencies": { "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", "typescript": ">=4.8.4 <6.1.0" } }, "sha512-6m5hkkRAp8lKvhVpcprAIn5KkehQEh+47oHH2VGnExEh7dhNxXlg6GPAOIu6TxbVQxhebrJDvjl3020ooiWCMA=="], "undici-types": ["undici-types@7.18.2", "", {}, "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w=="], @@ -1444,11 +1436,9 @@ "vite": ["rolldown-vite@7.3.1", "", { "dependencies": { "@oxc-project/runtime": "0.101.0", "fdir": "^6.5.0", "lightningcss": "^1.30.2", "picomatch": "^4.0.3", "postcss": "^8.5.6", "rolldown": "1.0.0-beta.53", "tinyglobby": "^0.2.15" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "peerDependencies": { "@types/node": "^20.19.0 || >=22.12.0", "esbuild": "^0.27.0", "jiti": ">=1.21.0", "less": "^4.0.0", "sass": "^1.70.0", "sass-embedded": "^1.70.0", "stylus": ">=0.54.8", "sugarss": "^5.0.0", "terser": "^5.16.0", "tsx": "^4.8.1", "yaml": "^2.4.2" }, "optionalPeers": ["@types/node", "esbuild", "jiti", "less", "sass", "sass-embedded", "stylus", "sugarss", "terser", "tsx", "yaml"], "bin": { "vite": "bin/vite.js" } }, "sha512-LYzdNAjRHhF2yA4JUQm/QyARyi216N2rpJ0lJZb8E9FU2y5v6Vk+xq/U4XBOxMefpWixT5H3TslmAHm1rqIq2w=="], - "vite-node": ["vite-node@3.2.4", "", { "dependencies": { "cac": "^6.7.14", "debug": "^4.4.1", "es-module-lexer": "^1.7.0", "pathe": "^2.0.3", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, "bin": { "vite-node": "vite-node.mjs" } }, "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg=="], - "vitefu": ["vitefu@1.1.2", "", { "peerDependencies": { "vite": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0" }, "optionalPeers": ["vite"] }, "sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw=="], - "vitest": ["vitest@3.2.4", "", { "dependencies": { "@types/chai": "^5.2.2", "@vitest/expect": "3.2.4", "@vitest/mocker": "3.2.4", "@vitest/pretty-format": "^3.2.4", "@vitest/runner": "3.2.4", "@vitest/snapshot": "3.2.4", "@vitest/spy": "3.2.4", "@vitest/utils": "3.2.4", "chai": "^5.2.0", "debug": "^4.4.1", "expect-type": "^1.2.1", "magic-string": "^0.30.17", "pathe": "^2.0.3", "picomatch": "^4.0.2", "std-env": "^3.9.0", "tinybench": "^2.9.0", "tinyexec": "^0.3.2", "tinyglobby": "^0.2.14", "tinypool": "^1.1.1", "tinyrainbow": "^2.0.0", "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0", "vite-node": "3.2.4", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@types/debug": "^4.1.12", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", "@vitest/browser": "3.2.4", "@vitest/ui": "3.2.4", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@types/debug", "@types/node", "@vitest/browser", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A=="], + "vitest": ["vitest@4.1.8", "", { "dependencies": { "@vitest/expect": "4.1.8", "@vitest/mocker": "4.1.8", "@vitest/pretty-format": "4.1.8", "@vitest/runner": "4.1.8", "@vitest/snapshot": "4.1.8", "@vitest/spy": "4.1.8", "@vitest/utils": "4.1.8", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", "obug": "^2.1.1", "pathe": "^2.0.3", "picomatch": "^4.0.3", "std-env": "^4.0.0-rc.1", "tinybench": "^2.9.0", "tinyexec": "^1.0.2", "tinyglobby": "^0.2.15", "tinyrainbow": "^3.1.0", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0", "why-is-node-running": "^2.3.0" }, "peerDependencies": { "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", "@vitest/browser-playwright": "4.1.8", "@vitest/browser-preview": "4.1.8", "@vitest/browser-webdriverio": "4.1.8", "@vitest/coverage-istanbul": "4.1.8", "@vitest/coverage-v8": "4.1.8", "@vitest/ui": "4.1.8", "happy-dom": "*", "jsdom": "*" }, "optionalPeers": ["@edge-runtime/vm", "@opentelemetry/api", "@types/node", "@vitest/browser-playwright", "@vitest/browser-preview", "@vitest/browser-webdriverio", "@vitest/coverage-istanbul", "@vitest/coverage-v8", "@vitest/ui", "happy-dom", "jsdom"], "bin": { "vitest": "vitest.mjs" } }, "sha512-flY6ScbCIt9HThs+C5HS7jvGOB560DJtk/Z15IQROTA6zEy49Nh8T/dofWTQL+n3vswqn87sbJNiuqw1SDp5Ig=="], "w3c-keyname": ["w3c-keyname@2.2.8", "", {}, "sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ=="], @@ -1480,7 +1470,7 @@ "word-wrap": ["word-wrap@1.2.5", "", {}, "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA=="], - "ws": ["ws@8.19.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-blAT2mjOEIi0ZzruJfIhb3nps74PRWTCz1IjglWEEpQl5XS/UNama6u2/rjFkDDouqr4L67ry+1aGIALViWjDg=="], + "ws": ["ws@8.21.0", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g=="], "xml-name-validator": ["xml-name-validator@5.0.0", "", {}, "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg=="], @@ -1504,12 +1494,10 @@ "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], - "@ai-sdk/gateway/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="], + "@ai-sdk/gateway/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="], "@ai-sdk/provider-utils/@ai-sdk/provider": ["@ai-sdk/provider@1.0.11", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-CPyImHGiT3svyfmvPvAFTianZzWFtm0qK82XjwlQIA1C3IQ2iku/PMQXi7aFyrX0TyMh3VTkJPB03tjU2VXVrw=="], - "@ai-sdk/provider-utils/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - "@ai-sdk/ui-utils/@ai-sdk/provider": ["@ai-sdk/provider@1.0.11", "", { "dependencies": { "json-schema": "^0.4.0" } }, "sha512-CPyImHGiT3svyfmvPvAFTianZzWFtm0qK82XjwlQIA1C3IQ2iku/PMQXi7aFyrX0TyMh3VTkJPB03tjU2VXVrw=="], "@appwrite.io/pink-legacy/@appwrite.io/pink-icons": ["@appwrite.io/pink-icons@1.0.0", "", {}, "sha512-+zpksP07MvOYwhx9AZDFW0pxXQNC2juKwyOQVRAwAOkN1ACSQKPlyytkI1u2ci6CQPWjJe20CzbvBBuRNXOKjA=="], @@ -1522,6 +1510,10 @@ "@babel/helper-compilation-targets/semver": ["semver@6.3.1", "", { "bin": { "semver": "bin/semver.js" } }, "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA=="], + "@codemirror/commands/@codemirror/view": ["@codemirror/view@6.41.1", "", { "dependencies": { "@codemirror/state": "^6.6.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-ToDnWKbBnke+ZLrP6vgTTDScGi5H37YYuZGniQaBzxMVdtCxMrslsmtnOvbPZk4RX9bvkQqnWR/WS/35tJA0qg=="], + + "@codemirror/language/@codemirror/view": ["@codemirror/view@6.41.1", "", { "dependencies": { "@codemirror/state": "^6.6.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-ToDnWKbBnke+ZLrP6vgTTDScGi5H37YYuZGniQaBzxMVdtCxMrslsmtnOvbPZk4RX9bvkQqnWR/WS/35tJA0qg=="], + "@eslint-community/eslint-utils/eslint-visitor-keys": ["eslint-visitor-keys@3.4.3", "", {}, "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag=="], "@eslint/eslintrc/globals": ["globals@14.0.0", "", {}, "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ=="], @@ -1554,16 +1546,16 @@ "@typescript-eslint/visitor-keys/eslint-visitor-keys": ["eslint-visitor-keys@5.0.1", "", {}, "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA=="], - "ai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.21", "", { "dependencies": { "@ai-sdk/provider": "3.0.8", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.6" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw=="], + "ai/@ai-sdk/provider-utils": ["@ai-sdk/provider-utils@4.0.27", "", { "dependencies": { "@ai-sdk/provider": "3.0.10", "@standard-schema/spec": "^1.1.0", "eventsource-parser": "^3.0.8" }, "peerDependencies": { "zod": "^3.25.76 || ^4.1.8" } }, "sha512-ubkAJ+xODouwtmN1tYlvTPphH1hPOBfZaEQe8U7skGvFAnIRs9PPpsq57bC2+Ky/MB4yzhd6YOsxTAx9sGpazw=="], "chalk/ansi-styles": ["ansi-styles@4.3.0", "", { "dependencies": { "color-convert": "^2.0.1" } }, "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg=="], + "codemirror-json5/@codemirror/view": ["@codemirror/view@6.41.1", "", { "dependencies": { "@codemirror/state": "^6.6.0", "crelt": "^1.0.6", "style-mod": "^4.1.0", "w3c-keyname": "^2.2.4" } }, "sha512-ToDnWKbBnke+ZLrP6vgTTDScGi5H37YYuZGniQaBzxMVdtCxMrslsmtnOvbPZk4RX9bvkQqnWR/WS/35tJA0qg=="], + "echarts/tslib": ["tslib@2.3.0", "", {}, "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="], "eslint/ignore": ["ignore@5.3.2", "", {}, "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g=="], - "esrap/@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="], - "framesync/tslib": ["tslib@2.4.0", "", {}, "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="], "js-yaml/argparse": ["argparse@2.0.1", "", {}, "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q=="], @@ -1576,14 +1568,12 @@ "popmotion/tslib": ["tslib@2.4.0", "", {}, "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="], - "postcss/nanoid": ["nanoid@3.3.11", "", { "bin": { "nanoid": "bin/nanoid.cjs" } }, "sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w=="], - - "strip-literal/js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], - "style-value-types/tslib": ["tslib@2.4.0", "", {}, "sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ=="], "svelte/aria-query": ["aria-query@5.3.1", "", {}, "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g=="], + "svelte-check/chokidar": ["chokidar@4.0.3", "", { "dependencies": { "readdirp": "^4.0.1" } }, "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA=="], + "svelte-sequential-preprocessor/svelte": ["svelte@5.53.12", "", { "dependencies": { "@jridgewell/remapping": "^2.3.4", "@jridgewell/sourcemap-codec": "^1.5.0", "@sveltejs/acorn-typescript": "^1.0.5", "@types/estree": "^1.0.5", "@types/trusted-types": "^2.0.7", "acorn": "^8.12.1", "aria-query": "5.3.1", "axobject-query": "^4.1.0", "clsx": "^2.1.1", "devalue": "^5.6.4", "esm-env": "^1.2.1", "esrap": "^2.2.2", "is-reference": "^3.0.3", "locate-character": "^3.0.0", "magic-string": "^0.30.11", "zimmerframe": "^1.1.2" } }, "sha512-4x/uk4rQe/d7RhfvS8wemTfNjQ0bJbKvamIzRBfTe2eHHjzBZ7PZicUQrC2ryj83xxEacfA1zHKd1ephD1tAxA=="], "tough-cookie/tldts": ["tldts@6.1.86", "", { "dependencies": { "tldts-core": "^6.1.86" }, "bin": { "tldts": "bin/cli.js" } }, "sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ=="], @@ -1592,20 +1582,30 @@ "zrender/tslib": ["tslib@2.3.0", "", {}, "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg=="], + "@ai-sdk/gateway/@ai-sdk/provider-utils/eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="], + "@opentelemetry/instrumentation-http/@opentelemetry/instrumentation/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.57.1", "", { "dependencies": { "@opentelemetry/api": "^1.3.0" } }, "sha512-I4PHczeujhQAQv6ZBzqHYEUiggZL4IdSMixtVD3EYqbdrjujE7kRfI5QohjlPoJm8BvenoW5YaTMWRrbpot6tg=="], "@prisma/instrumentation/@opentelemetry/instrumentation/@opentelemetry/api-logs": ["@opentelemetry/api-logs@0.53.0", "", { "dependencies": { "@opentelemetry/api": "^1.0.0" } }, "sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw=="], "@sentry/cli/https-proxy-agent/agent-base": ["agent-base@6.0.2", "", { "dependencies": { "debug": "4" } }, "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ=="], + "ai/@ai-sdk/provider-utils/eventsource-parser": ["eventsource-parser@3.0.8", "", {}, "sha512-70QWGkr4snxr0OXLRWsFLeRBIRPuQOvt4s8QYjmUlmlkyTZkRqS7EDVRZtzU3TiyDbXSzaOeF0XUKy8PchzukQ=="], + "chalk/ansi-styles/color-convert": ["color-convert@2.0.1", "", { "dependencies": { "color-name": "~1.1.4" } }, "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ=="], "node-fetch/whatwg-url/tr46": ["tr46@0.0.3", "", {}, "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="], "node-fetch/whatwg-url/webidl-conversions": ["webidl-conversions@3.0.1", "", {}, "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="], + "svelte-check/chokidar/readdirp": ["readdirp@4.1.2", "", {}, "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg=="], + + "svelte-sequential-preprocessor/svelte/@sveltejs/acorn-typescript": ["@sveltejs/acorn-typescript@1.0.9", "", { "peerDependencies": { "acorn": "^8.9.0" } }, "sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA=="], + "svelte-sequential-preprocessor/svelte/aria-query": ["aria-query@5.3.1", "", {}, "sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g=="], + "svelte-sequential-preprocessor/svelte/esrap": ["esrap@2.2.4", "", { "dependencies": { "@jridgewell/sourcemap-codec": "^1.4.15", "@typescript-eslint/types": "^8.2.0" } }, "sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg=="], + "tough-cookie/tldts/tldts-core": ["tldts-core@6.1.86", "", {}, "sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA=="], "unplugin/chokidar/fsevents": ["fsevents@2.3.2", "", { "os": "darwin" }, "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA=="], @@ -1615,5 +1615,7 @@ "unplugin/chokidar/readdirp": ["readdirp@3.6.0", "", { "dependencies": { "picomatch": "^2.2.1" } }, "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA=="], "chalk/ansi-styles/color-convert/color-name": ["color-name@1.1.4", "", {}, "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="], + + "svelte-sequential-preprocessor/svelte/esrap/@typescript-eslint/types": ["@typescript-eslint/types@8.57.0", "", {}, "sha512-dTLI8PEXhjUC7B9Kre+u0XznO696BhXcTlOn0/6kf1fHaQW8+VjJAVHJ3eTI14ZapTxdkOmc80HblPQLaEeJdg=="], } } diff --git a/package.json b/package.json index 71e5403165..fd0ebc590d 100644 --- a/package.json +++ b/package.json @@ -20,93 +20,99 @@ }, "dependencies": { "@ai-sdk/svelte": "^1.1.24", - "@appwrite.io/console": "^12.2.0", + "@appwrite.io/console": "https://pkg.vc/-/@appwrite/@appwrite.io/console@ed09983", "@appwrite.io/pink-icons": "0.25.0", "@appwrite.io/pink-icons-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3", "@appwrite.io/pink-legacy": "^1.0.3", "@appwrite.io/pink-svelte": "https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@8dcaa17", - "@codemirror/autocomplete": "^6.19.0", - "@codemirror/commands": "^6.9.0", - "@codemirror/language": "^6.11.3", - "@codemirror/lint": "^6.9.0", - "@codemirror/search": "^6.5.11", - "@codemirror/state": "^6.5.2", - "@codemirror/view": "^6.38.6", + "@codemirror/autocomplete": "^6.20.2", + "@codemirror/commands": "^6.10.3", + "@codemirror/language": "^6.12.3", + "@codemirror/lint": "^6.9.6", + "@codemirror/search": "^6.7.0", + "@codemirror/state": "^6.6.0", + "@codemirror/view": "^6.43.0", "@faker-js/faker": "^9.9.0", - "@lezer/highlight": "^1.2.1", - "@plausible-analytics/tracker": "^0.4.4", + "@lezer/highlight": "^1.2.3", + "@plausible-analytics/tracker": "^0.4.5", "@popperjs/core": "^2.11.8", - "@sentry/sveltekit": "^8.55.1", + "@sentry/sveltekit": "^8.55.2", "@stripe/stripe-js": "^3.5.0", - "@threlte/core": "^8.5.2", - "@threlte/extras": "^9.13.0", - "ai": "^6.0.138", + "@threlte/core": "^8.5.16", + "@threlte/extras": "^9.20.1", + "ai": "^6.0.194", "analytics": "^0.8.19", "codemirror-json5": "^1.0.3", "cron-parser": "^4.9.0", - "dayjs": "^1.11.20", + "dayjs": "^1.11.21", "deep-equal": "^2.2.3", + "dompurify": "^3.4.12", "echarts": "^5.6.0", "flatted": "^3.4.2", "ignore": "^6.0.2", "json5": "^2.2.3", - "nanoid": "^5.1.7", + "nanoid": "^3.3.18", "nanotar": "^0.3.0", "pretty-bytes": "^6.1.1", "remarkable": "^2.0.1", - "svelte-confetti": "^1.4.0", "three": "^0.181.2", "tippy.js": "^6.3.7" }, "devDependencies": { "@eslint/compat": "^1.4.1", "@eslint/js": "^9.39.4", - "@lezer/common": "^1.5.0", + "@lezer/common": "^1.5.2", "@melt-ui/pp": "^0.3.2", "@melt-ui/svelte": "^0.86.6", - "@playwright/test": "^1.58.2", + "@playwright/test": "^1.60.0", "@sveltejs/adapter-static": "^3.0.10", - "@sveltejs/kit": "^2.57.1", + "@sveltejs/kit": "^2.61.1", "@sveltejs/vite-plugin-svelte": "^5.1.1", "@testing-library/dom": "^10.4.1", "@testing-library/jest-dom": "^6.9.1", "@testing-library/svelte": "^5.3.1", "@testing-library/user-event": "^14.6.1", "@types/deep-equal": "^1.0.4", + "@types/dompurify": "^3.2.0", "@types/remarkable": "^2.0.8", "@types/three": "^0.182.0", - "@typescript-eslint/eslint-plugin": "^8.57.2", - "@typescript-eslint/parser": "^8.57.2", - "@vitest/ui": "^3.2.4", + "@typescript-eslint/eslint-plugin": "^8.60.1", + "@typescript-eslint/parser": "^8.60.1", + "@vitest/ui": "^4.1.8", "color": "^5.0.3", "eslint": "^9.39.4", "eslint-config-prettier": "^10.1.8", - "eslint-plugin-svelte": "^3.16.0", + "eslint-plugin-svelte": "^3.19.0", "globals": "^16.5.0", "jsdom": "^26.1.0", "kleur": "^4.1.5", - "prettier": "^3.8.1", - "prettier-plugin-svelte": "^3.5.1", - "sass": "^1.98.0", - "svelte": "^5.55.0", - "svelte-check": "^4.4.5", - "svelte-preprocess": "^6.0.3", + "prettier": "^3.8.3", + "prettier-plugin-svelte": "^3.5.2", + "sass": "^1.100.0", + "svelte": "^5.56.1", + "svelte-check": "^4.5.0", + "svelte-preprocess": "^6.0.5", "svelte-sequential-preprocessor": "^2.0.3", - "tldts": "^7.0.27", + "tldts": "^7.4.2", "tslib": "^2.8.1", "typescript": "^5.9.3", - "typescript-eslint": "^8.57.2", + "typescript-eslint": "^8.60.1", "vite": "^7.3.1", - "vitest": "^3.2.4" + "vitest": "^4.1.8" }, "overrides": { "vite": "npm:rolldown-vite@latest", "minimatch": "10.2.3", - "brace-expansion": ">=5.0.5", - "immutable": "^5.1.5", + "brace-expansion": ">=5.0.9", + "js-yaml": "^4.3.1", + "immutable": "^5.1.8", "flatted": "^3.4.2", + "devalue": "^5.8.1", "yaml": "^1.10.3", "picomatch": "^4.0.4", - "cookie": "^0.7.0" + "cookie": "^0.7.0", + "ws": "^8.21.0", + "postcss": "^8.5.18", + "nanoid": "^3.3.18" } } diff --git a/playwright.config.ts b/playwright.config.ts index c7fdc85350..03a4493b65 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -13,7 +13,7 @@ const config: PlaywrightTestConfig = { webServer: { timeout: 120000, env: { - PUBLIC_APPWRITE_ENDPOINT: 'https://stage.cloud.appwrite.io/v1', + PUBLIC_APPWRITE_ENDPOINT: 'https://cloud.staging.appwrite.io/v1', PUBLIC_CONSOLE_MODE: 'cloud', PUBLIC_APPWRITE_MULTI_REGION: 'true', PUBLIC_STRIPE_KEY: diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml deleted file mode 100644 index c2890878a0..0000000000 --- a/pnpm-lock.yaml +++ /dev/null @@ -1,7003 +0,0 @@ -lockfileVersion: '9.0' - -settings: - autoInstallPeers: true - excludeLinksFromLockfile: false - -importers: - - .: - dependencies: - '@ai-sdk/svelte': - specifier: ^1.1.24 - version: 1.1.24(svelte@5.55.0)(zod@3.25.76) - '@appwrite.io/console': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/console@67539a6 - version: https://pkg.vc/-/@appwrite/@appwrite.io/console@67539a6 - '@appwrite.io/pink-icons': - specifier: 0.25.0 - version: 0.25.0 - '@appwrite.io/pink-icons-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3 - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3(svelte@5.55.0) - '@appwrite.io/pink-legacy': - specifier: ^1.0.3 - version: 1.0.3 - '@appwrite.io/pink-svelte': - specifier: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bfe7ce3 - version: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bfe7ce3(svelte@5.55.0) - '@faker-js/faker': - specifier: ^9.9.0 - version: 9.9.0 - '@plausible-analytics/tracker': - specifier: ^0.4.4 - version: 0.4.4 - '@popperjs/core': - specifier: ^2.11.8 - version: 2.11.8 - '@sentry/sveltekit': - specifier: ^8.55.1 - version: 8.55.1(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)) - '@stripe/stripe-js': - specifier: ^3.5.0 - version: 3.5.0 - '@threlte/core': - specifier: ^8.5.2 - version: 8.5.4(svelte@5.55.0)(three@0.181.2) - '@threlte/extras': - specifier: ^9.13.0 - version: 9.13.3(@types/three@0.182.0)(svelte@5.55.0)(three@0.181.2) - ai: - specifier: ^6.0.138 - version: 6.0.141(zod@3.25.76) - analytics: - specifier: ^0.8.19 - version: 0.8.19(@types/dlv@1.1.5) - cron-parser: - specifier: ^4.9.0 - version: 4.9.0 - dayjs: - specifier: ^1.11.20 - version: 1.11.20 - deep-equal: - specifier: ^2.2.3 - version: 2.2.3 - echarts: - specifier: ^5.6.0 - version: 5.6.0 - flatted: - specifier: ^3.4.2 - version: 3.4.2 - ignore: - specifier: ^6.0.2 - version: 6.0.2 - nanoid: - specifier: ^5.1.7 - version: 5.1.7 - nanotar: - specifier: ^0.3.0 - version: 0.3.0 - pretty-bytes: - specifier: ^6.1.1 - version: 6.1.1 - remarkable: - specifier: ^2.0.1 - version: 2.0.1 - svelte-confetti: - specifier: ^1.4.0 - version: 1.4.0(svelte@5.55.0) - three: - specifier: ^0.181.2 - version: 0.181.2 - tippy.js: - specifier: ^6.3.7 - version: 6.3.7 - devDependencies: - '@eslint/compat': - specifier: ^1.4.1 - version: 1.4.1(eslint@9.39.4) - '@eslint/js': - specifier: ^9.39.4 - version: 9.39.4 - '@melt-ui/pp': - specifier: ^0.3.2 - version: 0.3.2(@melt-ui/svelte@0.86.6(svelte@5.55.0))(svelte@5.55.0) - '@melt-ui/svelte': - specifier: ^0.86.6 - version: 0.86.6(svelte@5.55.0) - '@playwright/test': - specifier: ^1.58.2 - version: 1.58.2 - '@sveltejs/adapter-static': - specifier: ^3.0.10 - version: 3.0.10(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0))) - '@sveltejs/kit': - specifier: ^2.55.0 - version: 2.55.0(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)) - '@sveltejs/vite-plugin-svelte': - specifier: ^5.1.1 - version: 5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)) - '@testing-library/dom': - specifier: ^10.4.1 - version: 10.4.1 - '@testing-library/jest-dom': - specifier: ^6.9.1 - version: 6.9.1 - '@testing-library/svelte': - specifier: ^5.3.1 - version: 5.3.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0))(vitest@3.2.4) - '@testing-library/user-event': - specifier: ^14.6.1 - version: 14.6.1(@testing-library/dom@10.4.1) - '@types/deep-equal': - specifier: ^1.0.4 - version: 1.0.4 - '@types/remarkable': - specifier: ^2.0.8 - version: 2.0.8 - '@types/three': - specifier: ^0.182.0 - version: 0.182.0 - '@typescript-eslint/eslint-plugin': - specifier: ^8.57.2 - version: 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/parser': - specifier: ^8.57.2 - version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) - '@vitest/ui': - specifier: ^3.2.4 - version: 3.2.4(vitest@3.2.4) - color: - specifier: ^5.0.3 - version: 5.0.3 - eslint: - specifier: ^9.39.4 - version: 9.39.4 - eslint-config-prettier: - specifier: ^10.1.8 - version: 10.1.8(eslint@9.39.4) - eslint-plugin-svelte: - specifier: ^3.16.0 - version: 3.16.0(eslint@9.39.4)(svelte@5.55.0) - globals: - specifier: ^16.5.0 - version: 16.5.0 - jsdom: - specifier: ^26.1.0 - version: 26.1.0 - kleur: - specifier: ^4.1.5 - version: 4.1.5 - prettier: - specifier: ^3.8.1 - version: 3.8.1 - prettier-plugin-svelte: - specifier: ^3.5.1 - version: 3.5.1(prettier@3.8.1)(svelte@5.55.0) - sass: - specifier: ^1.98.0 - version: 1.98.0 - svelte: - specifier: ^5.55.0 - version: 5.55.0 - svelte-check: - specifier: ^4.4.5 - version: 4.4.5(picomatch@4.0.4)(svelte@5.55.0)(typescript@5.9.3) - svelte-preprocess: - specifier: ^6.0.3 - version: 6.0.3(@babel/core@7.29.0)(postcss-load-config@3.1.4(postcss@8.5.8))(postcss@8.5.8)(sass@1.98.0)(svelte@5.55.0)(typescript@5.9.3) - svelte-sequential-preprocessor: - specifier: ^2.0.3 - version: 2.0.3 - tldts: - specifier: ^7.0.27 - version: 7.0.27 - tslib: - specifier: ^2.8.1 - version: 2.8.1 - typescript: - specifier: ^5.9.3 - version: 5.9.3 - typescript-eslint: - specifier: ^8.57.2 - version: 8.57.2(eslint@9.39.4)(typescript@5.9.3) - vite: - specifier: ^7.3.1 - version: 7.3.1(@types/node@25.5.0)(sass@1.98.0) - vitest: - specifier: ^3.2.4 - version: 3.2.4(@types/node@25.5.0)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.98.0) - -packages: - - '@adobe/css-tools@4.4.4': - resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} - - '@ai-sdk/gateway@3.0.83': - resolution: {integrity: sha512-LvlWujbSdEkTBXBLFtF7GS6riXdHhH0O+DpDrCaNQvXeHmSF2jKsOg7JWXiCgygAHM5cWFAO3JYmZp83DjiuBQ==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - '@ai-sdk/provider-utils@2.1.13': - resolution: {integrity: sha512-kLjqsfOdONr6DGcGEntFYM1niXz1H05vyZNf9OAzK+KKKc64izyP4/q/9HX7W4+6g8hm6BnmKxu8vkr6FSOqDg==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.0.0 - peerDependenciesMeta: - zod: - optional: true - - '@ai-sdk/provider-utils@4.0.21': - resolution: {integrity: sha512-MtFUYI1/8mgDvRmaBDjbLJPFFrMG777AvSgyIFQtZHIMzm88R/12vYBBpnk7pfiWLFE1DSZzY4WDYzGbKAcmiw==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - '@ai-sdk/provider@1.0.11': - resolution: {integrity: sha512-CPyImHGiT3svyfmvPvAFTianZzWFtm0qK82XjwlQIA1C3IQ2iku/PMQXi7aFyrX0TyMh3VTkJPB03tjU2VXVrw==} - engines: {node: '>=18'} - - '@ai-sdk/provider@3.0.8': - resolution: {integrity: sha512-oGMAgGoQdBXbZqNG0Ze56CHjDZ1IDYOwGYxYjO5KLSlz5HiNQ9udIXsPZ61VWaHGZ5XW/jyjmr6t2xz2jGVwbQ==} - engines: {node: '>=18'} - - '@ai-sdk/svelte@1.1.24': - resolution: {integrity: sha512-nlSSd4FirQyM10MQb9vCzF3e/R4id0od0/cKtB1JdtcIvT4ZaJzyltIK3Q72ceOjEbHXSGbucW6gVyExBzHCLQ==} - engines: {node: '>=18'} - peerDependencies: - svelte: ^3.0.0 || ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - svelte: - optional: true - - '@ai-sdk/ui-utils@1.1.19': - resolution: {integrity: sha512-rDHy2uxlPMt3jjS9L6mBrsfhEInZ5BVoWevmD13fsAt2s/XWy2OwwKmgmUQkdLlY4mn/eyeYAfDGK8+5CbOAgg==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.0.0 - peerDependenciesMeta: - zod: - optional: true - - '@analytics/cookie-utils@0.2.14': - resolution: {integrity: sha512-x51x2cLqvP5Fb1ydgNvTCX+SVv0ALK/yTNwp/53++yk4kLhxb850krWtQ4aASN0612oXrIGotwfmdJIttnLiPQ==} - - '@analytics/core@0.13.2': - resolution: {integrity: sha512-ejvfoPP8TEh2hA2szMEq9c4TdeX8FAeY1j/7MxJVZjzDaq8BDHOyaAAQzTFiLMHvV0WcU2YC0smJ5Ids5Ll5ng==} - - '@analytics/global-storage-utils@0.1.9': - resolution: {integrity: sha512-+xm6CDnWsVOQIKkqbPRPRdYDXKk3PNgr/bCZWSI+7tEDT5PCDgI0QSBZe+FqCVkCRtTkgOrjFOY7wOM8Gq+ndA==} - - '@analytics/localstorage-utils@0.1.12': - resolution: {integrity: sha512-BL3vuZUwWgMqdkQsE0GKsED5SPLC6daI4K4LE0a/BkKv+4Cae5JLLqpO5gju2HUGOjJxIvw8U/G5EcglNY5+1w==} - - '@analytics/session-storage-utils@0.0.9': - resolution: {integrity: sha512-fhP9QCpyq45rZKsXaAxyz+VTmOUWljIW08CWSkFzpwOHkDM4Xy5tymc1YcWqSBBaLjHldo3HlY4qfqEIS4Aj1A==} - - '@analytics/storage-utils@0.4.4': - resolution: {integrity: sha512-873P4wDIunbOnBqADc2AhTVsLbluUv1dP6k9UrK8FIeV8WXv5+fG12HdwwaniUIxq6QLgZJfKEaCwtWSKrrV0g==} - - '@analytics/type-utils@0.6.4': - resolution: {integrity: sha512-Ou1gQxFakOWLcPnbFVsrPb8g1wLLUZYYJXDPjHkG07+5mustGs5yqACx42UAu4A6NszNN6Z5gGxhyH45zPWRxw==} - - '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@67539a6': - resolution: {integrity: sha512-IV+eVqF6tzL/voA1vqNtn5hL9lgJL78MVZkP4ABYwyaDRaXFyLQbPiRlJJesN4m7PYlCztyfAqcOn3QdCCjwIQ==, tarball: https://pkg.vc/-/@appwrite/@appwrite.io/console@67539a6} - version: 8.2.0 - engines: {node: '>=18.0.0'} - - '@appwrite.io/pink-icons-svelte@2.0.0-RC.1': - resolution: {integrity: sha512-iLFlV55hj8mGuAbmxJGenxN5RaZMmVT4GJb9dv/MP1xBAtYibFq7JvBcxm18qV2KU8c31Rntf+Ub4GL7HwqTYg==} - peerDependencies: - svelte: ^4.0.0 - - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3': - resolution: {integrity: sha512-2HYl/CC2OlfZIR7LzbLXuSPBn0iNkjbnxpaeGCkZ7UNZ/hFeSeeWjDJqTBMdZ8+X95uuZqHx62XPTiE/svuSXQ==, tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3} - version: 2.0.0-RC.1 - peerDependencies: - svelte: ^4.0.0 - - '@appwrite.io/pink-icons@0.25.0': - resolution: {integrity: sha512-0O3i2oEuh5mWvjO80i+X6rbzrWLJ1m5wmv2/M3a1p2PyBJsFxN8xQMTEmTn3Wl/D26SsM7SpzbdW6gmfgoVU9Q==} - - '@appwrite.io/pink-icons@1.0.0': - resolution: {integrity: sha512-+zpksP07MvOYwhx9AZDFW0pxXQNC2juKwyOQVRAwAOkN1ACSQKPlyytkI1u2ci6CQPWjJe20CzbvBBuRNXOKjA==} - - '@appwrite.io/pink-legacy@1.0.3': - resolution: {integrity: sha512-GGde5fmPhs+s6/3aFeMPc/kKADG/gTFkYQSy6oBN8pK0y0XNCLrZZgBv+EBbdhwdtqVEWXa0X85Mv9w7jcIlwQ==} - - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bfe7ce3': - resolution: {integrity: sha512-kOC6T1uhmggl02Wmu++WUBpVh1SqzwlRDpR4xw79Sl8Cy1RJju55IkeVl6doKcNYQyPl6kJItgxFwF1MhkB1DQ==, tarball: https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bfe7ce3} - version: 2.0.0-RC.2 - peerDependencies: - svelte: ^4.0.0 - - '@asamuzakjp/css-color@3.2.0': - resolution: {integrity: sha512-K1A6z8tS3XsmCMM86xoWdn7Fkdn9m6RSVtocUrJYIwZnFVkng/PvkEoWtOWmP+Scc6saYWHWZYbndEEXxl24jw==} - - '@babel/code-frame@7.29.0': - resolution: {integrity: sha512-9NhCeYjq9+3uxgdtp20LSiJXJvN0FeCtNGpJxuMFZ1Kv3cWUNb6DOhJwUvcVCzKGR66cw4njwM6hrJLqgOwbcw==} - engines: {node: '>=6.9.0'} - - '@babel/compat-data@7.29.0': - resolution: {integrity: sha512-T1NCJqT/j9+cn8fvkt7jtwbLBfLC/1y1c7NtCeXFRgzGTsafi68MRv8yzkYSapBnFA6L3U2VSc02ciDzoAJhJg==} - engines: {node: '>=6.9.0'} - - '@babel/core@7.29.0': - resolution: {integrity: sha512-CGOfOJqWjg2qW/Mb6zNsDm+u5vFQ8DxXfbM09z69p5Z6+mE1ikP2jUXw+j42Pf1XTYED2Rni5f95npYeuwMDQA==} - engines: {node: '>=6.9.0'} - - '@babel/generator@7.29.1': - resolution: {integrity: sha512-qsaF+9Qcm2Qv8SRIMMscAvG4O3lJ0F1GuMo5HR/Bp02LopNgnZBC/EkbevHFeGs4ls/oPz9v+Bsmzbkbe+0dUw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-compilation-targets@7.28.6': - resolution: {integrity: sha512-JYtls3hqi15fcx5GaSNL7SCTJ2MNmjrkHXg4FSpOA/grxK8KwyZ5bubHsCq8FXCkua6xhuaaBit+3b7+VZRfcA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-imports@7.28.6': - resolution: {integrity: sha512-l5XkZK7r7wa9LucGw9LwZyyCUscb4x37JWTPz7swwFE/0FMQAGpiWUZn8u9DzkSBWEcK25jmvubfpw2dnAMdbw==} - engines: {node: '>=6.9.0'} - - '@babel/helper-module-transforms@7.28.6': - resolution: {integrity: sha512-67oXFAYr2cDLDVGLXTEABjdBJZ6drElUSI7WKp70NrpyISso3plG9SAGEF6y7zbha/wOzUByWWTJvEDVNIUGcA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0 - - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} - engines: {node: '>=6.9.0'} - - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} - engines: {node: '>=6.9.0'} - - '@babel/helpers@7.29.2': - resolution: {integrity: sha512-HoGuUs4sCZNezVEKdVcwqmZN8GoHirLUcLaYVNBK2J0DadGtdcqgr3BCbvH8+XUo4NGjNl3VOtSjEKNzqfFgKw==} - engines: {node: '>=6.9.0'} - - '@babel/parser@7.29.2': - resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} - engines: {node: '>=6.0.0'} - hasBin: true - - '@babel/runtime@7.29.2': - resolution: {integrity: sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==} - engines: {node: '>=6.9.0'} - - '@babel/template@7.28.6': - resolution: {integrity: sha512-YA6Ma2KsCdGb+WC6UpBVFJGXL58MDA6oyONbjyF/+5sBgxY/dwkhLogbMT2GXXyU84/IhRw/2D1Os1B/giz+BQ==} - engines: {node: '>=6.9.0'} - - '@babel/traverse@7.29.0': - resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} - engines: {node: '>=6.9.0'} - - '@babel/types@7.29.0': - resolution: {integrity: sha512-LwdZHpScM4Qz8Xw2iKSzS+cfglZzJGvofQICy7W7v4caru4EaAmyUuO6BGrbyQ2mYV11W0U8j5mBhd14dd3B0A==} - engines: {node: '>=6.9.0'} - - '@csstools/color-helpers@5.1.0': - resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} - engines: {node: '>=18'} - - '@csstools/css-calc@2.1.4': - resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-color-parser@3.1.0': - resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-parser-algorithms@3.0.5': - resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} - engines: {node: '>=18'} - peerDependencies: - '@csstools/css-tokenizer': ^3.0.4 - - '@csstools/css-tokenizer@3.0.4': - resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} - engines: {node: '>=18'} - - '@dimforge/rapier3d-compat@0.12.0': - resolution: {integrity: sha512-uekIGetywIgopfD97oDL5PfeezkFpNhwlzlaEYNOA0N6ghdsOvh/HYjSMek5Q2O1PYvRSDFcqFVJl4r4ZBwOow==} - - '@esbuild/aix-ppc64@0.27.4': - resolution: {integrity: sha512-cQPwL2mp2nSmHHJlCyoXgHGhbEPMrEEU5xhkcy3Hs/O7nGZqEpZ2sUtLaL9MORLtDfRvVl2/3PAuEkYZH0Ty8Q==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [aix] - - '@esbuild/android-arm64@0.27.4': - resolution: {integrity: sha512-gdLscB7v75wRfu7QSm/zg6Rx29VLdy9eTr2t44sfTW7CxwAtQghZ4ZnqHk3/ogz7xao0QAgrkradbBzcqFPasw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [android] - - '@esbuild/android-arm@0.27.4': - resolution: {integrity: sha512-X9bUgvxiC8CHAGKYufLIHGXPJWnr0OCdR0anD2e21vdvgCI8lIfqFbnoeOz7lBjdrAGUhqLZLcQo6MLhTO2DKQ==} - engines: {node: '>=18'} - cpu: [arm] - os: [android] - - '@esbuild/android-x64@0.27.4': - resolution: {integrity: sha512-PzPFnBNVF292sfpfhiyiXCGSn9HZg5BcAz+ivBuSsl6Rk4ga1oEXAamhOXRFyMcjwr2DVtm40G65N3GLeH1Lvw==} - engines: {node: '>=18'} - cpu: [x64] - os: [android] - - '@esbuild/darwin-arm64@0.27.4': - resolution: {integrity: sha512-b7xaGIwdJlht8ZFCvMkpDN6uiSmnxxK56N2GDTMYPr2/gzvfdQN8rTfBsvVKmIVY/X7EM+/hJKEIbbHs9oA4tQ==} - engines: {node: '>=18'} - cpu: [arm64] - os: [darwin] - - '@esbuild/darwin-x64@0.27.4': - resolution: {integrity: sha512-sR+OiKLwd15nmCdqpXMnuJ9W2kpy0KigzqScqHI3Hqwr7IXxBp3Yva+yJwoqh7rE8V77tdoheRYataNKL4QrPw==} - engines: {node: '>=18'} - cpu: [x64] - os: [darwin] - - '@esbuild/freebsd-arm64@0.27.4': - resolution: {integrity: sha512-jnfpKe+p79tCnm4GVav68A7tUFeKQwQyLgESwEAUzyxk/TJr4QdGog9sqWNcUbr/bZt/O/HXouspuQDd9JxFSw==} - engines: {node: '>=18'} - cpu: [arm64] - os: [freebsd] - - '@esbuild/freebsd-x64@0.27.4': - resolution: {integrity: sha512-2kb4ceA/CpfUrIcTUl1wrP/9ad9Atrp5J94Lq69w7UwOMolPIGrfLSvAKJp0RTvkPPyn6CIWrNy13kyLikZRZQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [freebsd] - - '@esbuild/linux-arm64@0.27.4': - resolution: {integrity: sha512-7nQOttdzVGth1iz57kxg9uCz57dxQLHWxopL6mYuYthohPKEK0vU0C3O21CcBK6KDlkYVcnDXY099HcCDXd9dA==} - engines: {node: '>=18'} - cpu: [arm64] - os: [linux] - - '@esbuild/linux-arm@0.27.4': - resolution: {integrity: sha512-aBYgcIxX/wd5n2ys0yESGeYMGF+pv6g0DhZr3G1ZG4jMfruU9Tl1i2Z+Wnj9/KjGz1lTLCcorqE2viePZqj4Eg==} - engines: {node: '>=18'} - cpu: [arm] - os: [linux] - - '@esbuild/linux-ia32@0.27.4': - resolution: {integrity: sha512-oPtixtAIzgvzYcKBQM/qZ3R+9TEUd1aNJQu0HhGyqtx6oS7qTpvjheIWBbes4+qu1bNlo2V4cbkISr8q6gRBFA==} - engines: {node: '>=18'} - cpu: [ia32] - os: [linux] - - '@esbuild/linux-loong64@0.27.4': - resolution: {integrity: sha512-8mL/vh8qeCoRcFH2nM8wm5uJP+ZcVYGGayMavi8GmRJjuI3g1v6Z7Ni0JJKAJW+m0EtUuARb6Lmp4hMjzCBWzA==} - engines: {node: '>=18'} - cpu: [loong64] - os: [linux] - - '@esbuild/linux-mips64el@0.27.4': - resolution: {integrity: sha512-1RdrWFFiiLIW7LQq9Q2NES+HiD4NyT8Itj9AUeCl0IVCA459WnPhREKgwrpaIfTOe+/2rdntisegiPWn/r/aAw==} - engines: {node: '>=18'} - cpu: [mips64el] - os: [linux] - - '@esbuild/linux-ppc64@0.27.4': - resolution: {integrity: sha512-tLCwNG47l3sd9lpfyx9LAGEGItCUeRCWeAx6x2Jmbav65nAwoPXfewtAdtbtit/pJFLUWOhpv0FpS6GQAmPrHA==} - engines: {node: '>=18'} - cpu: [ppc64] - os: [linux] - - '@esbuild/linux-riscv64@0.27.4': - resolution: {integrity: sha512-BnASypppbUWyqjd1KIpU4AUBiIhVr6YlHx/cnPgqEkNoVOhHg+YiSVxM1RLfiy4t9cAulbRGTNCKOcqHrEQLIw==} - engines: {node: '>=18'} - cpu: [riscv64] - os: [linux] - - '@esbuild/linux-s390x@0.27.4': - resolution: {integrity: sha512-+eUqgb/Z7vxVLezG8bVB9SfBie89gMueS+I0xYh2tJdw3vqA/0ImZJ2ROeWwVJN59ihBeZ7Tu92dF/5dy5FttA==} - engines: {node: '>=18'} - cpu: [s390x] - os: [linux] - - '@esbuild/linux-x64@0.27.4': - resolution: {integrity: sha512-S5qOXrKV8BQEzJPVxAwnryi2+Iq5pB40gTEIT69BQONqR7JH1EPIcQ/Uiv9mCnn05jff9umq/5nqzxlqTOg9NA==} - engines: {node: '>=18'} - cpu: [x64] - os: [linux] - - '@esbuild/netbsd-arm64@0.27.4': - resolution: {integrity: sha512-xHT8X4sb0GS8qTqiwzHqpY00C95DPAq7nAwX35Ie/s+LO9830hrMd3oX0ZMKLvy7vsonee73x0lmcdOVXFzd6Q==} - engines: {node: '>=18'} - cpu: [arm64] - os: [netbsd] - - '@esbuild/netbsd-x64@0.27.4': - resolution: {integrity: sha512-RugOvOdXfdyi5Tyv40kgQnI0byv66BFgAqjdgtAKqHoZTbTF2QqfQrFwa7cHEORJf6X2ht+l9ABLMP0dnKYsgg==} - engines: {node: '>=18'} - cpu: [x64] - os: [netbsd] - - '@esbuild/openbsd-arm64@0.27.4': - resolution: {integrity: sha512-2MyL3IAaTX+1/qP0O1SwskwcwCoOI4kV2IBX1xYnDDqthmq5ArrW94qSIKCAuRraMgPOmG0RDTA74mzYNQA9ow==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openbsd] - - '@esbuild/openbsd-x64@0.27.4': - resolution: {integrity: sha512-u8fg/jQ5aQDfsnIV6+KwLOf1CmJnfu1ShpwqdwC0uA7ZPwFws55Ngc12vBdeUdnuWoQYx/SOQLGDcdlfXhYmXQ==} - engines: {node: '>=18'} - cpu: [x64] - os: [openbsd] - - '@esbuild/openharmony-arm64@0.27.4': - resolution: {integrity: sha512-JkTZrl6VbyO8lDQO3yv26nNr2RM2yZzNrNHEsj9bm6dOwwu9OYN28CjzZkH57bh4w0I2F7IodpQvUAEd1mbWXg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [openharmony] - - '@esbuild/sunos-x64@0.27.4': - resolution: {integrity: sha512-/gOzgaewZJfeJTlsWhvUEmUG4tWEY2Spp5M20INYRg2ZKl9QPO3QEEgPeRtLjEWSW8FilRNacPOg8R1uaYkA6g==} - engines: {node: '>=18'} - cpu: [x64] - os: [sunos] - - '@esbuild/win32-arm64@0.27.4': - resolution: {integrity: sha512-Z9SExBg2y32smoDQdf1HRwHRt6vAHLXcxD2uGgO/v2jK7Y718Ix4ndsbNMU/+1Qiem9OiOdaqitioZwxivhXYg==} - engines: {node: '>=18'} - cpu: [arm64] - os: [win32] - - '@esbuild/win32-ia32@0.27.4': - resolution: {integrity: sha512-DAyGLS0Jz5G5iixEbMHi5KdiApqHBWMGzTtMiJ72ZOLhbu/bzxgAe8Ue8CTS3n3HbIUHQz/L51yMdGMeoxXNJw==} - engines: {node: '>=18'} - cpu: [ia32] - os: [win32] - - '@esbuild/win32-x64@0.27.4': - resolution: {integrity: sha512-+knoa0BDoeXgkNvvV1vvbZX4+hizelrkwmGJBdT17t8FNPwG2lKemmuMZlmaNQ3ws3DKKCxpb4zRZEIp3UxFCg==} - engines: {node: '>=18'} - cpu: [x64] - os: [win32] - - '@eslint-community/eslint-utils@4.9.1': - resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - - '@eslint-community/regexpp@4.12.2': - resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} - engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - - '@eslint/compat@1.4.1': - resolution: {integrity: sha512-cfO82V9zxxGBxcQDr1lfaYB7wykTa0b00mGa36FrJl7iTFd0Z2cHfEYuxcBRP/iNijCsWsEkA+jzT8hGYmv33w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.40 || 9 - peerDependenciesMeta: - eslint: - optional: true - - '@eslint/config-array@0.21.2': - resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/eslintrc@3.3.5': - resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/js@9.39.4': - resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/object-schema@2.1.7': - resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@faker-js/faker@9.9.0': - resolution: {integrity: sha512-OEl393iCOoo/z8bMezRlJu+GlRGlsKbUAN7jKB6LhnKoqKve5DXRpalbItIIcwnCjs1k/FOPjFzcA6Qn+H+YbA==} - engines: {node: '>=18.0.0', npm: '>=9.0.0'} - - '@floating-ui/core@1.7.5': - resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} - - '@floating-ui/dom@1.7.6': - resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} - - '@floating-ui/utils@0.2.11': - resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} - - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} - engines: {node: '>=18.18.0'} - - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} - engines: {node: '>=18.18.0'} - - '@humanwhocodes/module-importer@1.0.1': - resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} - engines: {node: '>=12.22'} - - '@humanwhocodes/retry@0.4.3': - resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} - engines: {node: '>=18.18'} - - '@internationalized/date@3.12.0': - resolution: {integrity: sha512-/PyIMzK29jtXaGU23qTvNZxvBXRtKbNnGDFD+PY6CZw/Y8Ex8pFUzkuCJCG9aOqmShjqhS9mPqP6Dk5onQY8rQ==} - - '@jridgewell/gen-mapping@0.3.13': - resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - - '@jridgewell/remapping@2.3.5': - resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - - '@jridgewell/resolve-uri@3.1.2': - resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} - engines: {node: '>=6.0.0'} - - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - - '@jridgewell/trace-mapping@0.3.31': - resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - - '@melt-ui/pp@0.3.2': - resolution: {integrity: sha512-xKkPvaIAFinklLXcQOpwZ8YSpqAFxykjWf8Y/fSJQwsixV/0rcFs07hJ49hJjPy5vItvw5Qa0uOjzFUbXzBypQ==} - peerDependencies: - '@melt-ui/svelte': '>= 0.29.0' - svelte: ^3.55.0 || ^4.0.0 || ^5.0.0-next.1 - - '@melt-ui/svelte@0.86.6': - resolution: {integrity: sha512-Jer+M7DgIwT5IHfTayb4Iw/fkkxWNmC/mqn/nMh9JrbPbkxmyabfLQnhJ+JDn5HK77f84j34lubO3iqFtYAfMg==} - peerDependencies: - svelte: ^3.0.0 || ^4.0.0 || ^5.0.0-next.118 - - '@opentelemetry/api-logs@0.53.0': - resolution: {integrity: sha512-8HArjKx+RaAI8uEIgcORbZIPklyh1YLjPSBus8hjRmvLi6DeFzgOcdZ7KwPabKj8mXF8dX0hyfAyGfycz0DbFw==} - engines: {node: '>=14'} - - '@opentelemetry/api-logs@0.57.1': - resolution: {integrity: sha512-I4PHczeujhQAQv6ZBzqHYEUiggZL4IdSMixtVD3EYqbdrjujE7kRfI5QohjlPoJm8BvenoW5YaTMWRrbpot6tg==} - engines: {node: '>=14'} - - '@opentelemetry/api-logs@0.57.2': - resolution: {integrity: sha512-uIX52NnTM0iBh84MShlpouI7UKqkZ7MrUszTmaypHBu4r7NofznSnQRfJ+uUeDtQDj6w8eFGg5KBLDAwAPz1+A==} - engines: {node: '>=14'} - - '@opentelemetry/api@1.9.0': - resolution: {integrity: sha512-3giAOQvZiH5F9bMlMiv8+GSPMeqg0dbaeo58/0SlA9sxSqZhnUtxzX9/2FzyhS9sWQf5S0GJE0AKBrFqjpeYcg==} - engines: {node: '>=8.0.0'} - - '@opentelemetry/api@1.9.1': - resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} - engines: {node: '>=8.0.0'} - - '@opentelemetry/context-async-hooks@1.30.1': - resolution: {integrity: sha512-s5vvxXPVdjqS3kTLKMeBMvop9hbWkwzBpu+mUO2M7sZtlkyDJGwFe33wRKnbaYDo8ExRVBIIdwIGrqpxHuKttA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - - '@opentelemetry/core@1.30.1': - resolution: {integrity: sha512-OOCM2C/QIURhJMuKaekP3TRBxBKxG/TWWA0TL2J6nXUtDnuCtccy49LUJF8xPFXMX+0LMcxFpCo8M9cGY1W6rQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - - '@opentelemetry/instrumentation-amqplib@0.46.1': - resolution: {integrity: sha512-AyXVnlCf/xV3K/rNumzKxZqsULyITJH6OVLiW6730JPRqWA7Zc9bvYoVNpN6iOpTU8CasH34SU/ksVJmObFibQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-connect@0.43.0': - resolution: {integrity: sha512-Q57JGpH6T4dkYHo9tKXONgLtxzsh1ZEW5M9A/OwKrZFyEpLqWgjhcZ3hIuVvDlhb426iDF1f9FPToV/mi5rpeA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-dataloader@0.16.0': - resolution: {integrity: sha512-88+qCHZC02up8PwKHk0UQKLLqGGURzS3hFQBZC7PnGwReuoKjHXS1o29H58S+QkXJpkTr2GACbx8j6mUoGjNPA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-express@0.47.0': - resolution: {integrity: sha512-XFWVx6k0XlU8lu6cBlCa29ONtVt6ADEjmxtyAyeF2+rifk8uBJbk1La0yIVfI0DoKURGbaEDTNelaXG9l/lNNQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-fastify@0.44.1': - resolution: {integrity: sha512-RoVeMGKcNttNfXMSl6W4fsYoCAYP1vi6ZAWIGhBY+o7R9Y0afA7f9JJL0j8LHbyb0P0QhSYk+6O56OwI2k4iRQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-fs@0.19.0': - resolution: {integrity: sha512-JGwmHhBkRT2G/BYNV1aGI+bBjJu4fJUD/5/Jat0EWZa2ftrLV3YE8z84Fiij/wK32oMZ88eS8DI4ecLGZhpqsQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-generic-pool@0.43.0': - resolution: {integrity: sha512-at8GceTtNxD1NfFKGAuwtqM41ot/TpcLh+YsGe4dhf7gvv1HW/ZWdq6nfRtS6UjIvZJOokViqLPJ3GVtZItAnQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-graphql@0.47.0': - resolution: {integrity: sha512-Cc8SMf+nLqp0fi8oAnooNEfwZWFnzMiBHCGmDFYqmgjPylyLmi83b+NiTns/rKGwlErpW0AGPt0sMpkbNlzn8w==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-hapi@0.45.1': - resolution: {integrity: sha512-VH6mU3YqAKTePPfUPwfq4/xr049774qWtfTuJqVHoVspCLiT3bW+fCQ1toZxt6cxRPYASoYaBsMA3CWo8B8rcw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-http@0.57.1': - resolution: {integrity: sha512-ThLmzAQDs7b/tdKI3BV2+yawuF09jF111OFsovqT1Qj3D8vjwKBwhi/rDE5xethwn4tSXtZcJ9hBsVAlWFQZ7g==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-ioredis@0.47.0': - resolution: {integrity: sha512-4HqP9IBC8e7pW9p90P3q4ox0XlbLGme65YTrA3UTLvqvo4Z6b0puqZQP203YFu8m9rE/luLfaG7/xrwwqMUpJw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-kafkajs@0.7.0': - resolution: {integrity: sha512-LB+3xiNzc034zHfCtgs4ITWhq6Xvdo8bsq7amR058jZlf2aXXDrN9SV4si4z2ya9QX4tz6r4eZJwDkXOp14/AQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-knex@0.44.0': - resolution: {integrity: sha512-SlT0+bLA0Lg3VthGje+bSZatlGHw/vwgQywx0R/5u9QC59FddTQSPJeWNw29M6f8ScORMeUOOTwihlQAn4GkJQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-koa@0.47.0': - resolution: {integrity: sha512-HFdvqf2+w8sWOuwtEXayGzdZ2vWpCKEQv5F7+2DSA74Te/Cv4rvb2E5So5/lh+ok4/RAIPuvCbCb/SHQFzMmbw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-lru-memoizer@0.44.0': - resolution: {integrity: sha512-Tn7emHAlvYDFik3vGU0mdwvWJDwtITtkJ+5eT2cUquct6nIs+H8M47sqMJkCpyPe5QIBJoTOHxmc6mj9lz6zDw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-mongodb@0.51.0': - resolution: {integrity: sha512-cMKASxCX4aFxesoj3WK8uoQ0YUrRvnfxaO72QWI2xLu5ZtgX/QvdGBlU3Ehdond5eb74c2s1cqRQUIptBnKz1g==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-mongoose@0.46.0': - resolution: {integrity: sha512-mtVv6UeaaSaWTeZtLo4cx4P5/ING2obSqfWGItIFSunQBrYROfhuVe7wdIrFUs2RH1tn2YYpAJyMaRe/bnTTIQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-mysql2@0.45.0': - resolution: {integrity: sha512-qLslv/EPuLj0IXFvcE3b0EqhWI8LKmrgRPIa4gUd8DllbBpqJAvLNJSv3cC6vWwovpbSI3bagNO/3Q2SuXv2xA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-mysql@0.45.0': - resolution: {integrity: sha512-tWWyymgwYcTwZ4t8/rLDfPYbOTF3oYB8SxnYMtIQ1zEf5uDm90Ku3i6U/vhaMyfHNlIHvDhvJh+qx5Nc4Z3Acg==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-nestjs-core@0.44.0': - resolution: {integrity: sha512-t16pQ7A4WYu1yyQJZhRKIfUNvl5PAaF2pEteLvgJb/BWdd1oNuU1rOYt4S825kMy+0q4ngiX281Ss9qiwHfxFQ==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-pg@0.50.0': - resolution: {integrity: sha512-TtLxDdYZmBhFswm8UIsrDjh/HFBeDXd4BLmE8h2MxirNHewLJ0VS9UUddKKEverb5Sm2qFVjqRjcU+8Iw4FJ3w==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-redis-4@0.46.0': - resolution: {integrity: sha512-aTUWbzbFMFeRODn3720TZO0tsh/49T8H3h8vVnVKJ+yE36AeW38Uj/8zykQ/9nO8Vrtjr5yKuX3uMiG/W8FKNw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-tedious@0.18.0': - resolution: {integrity: sha512-9zhjDpUDOtD+coeADnYEJQ0IeLVCj7w/hqzIutdp5NqS1VqTAanaEfsEcSypyvYv5DX3YOsTUoF+nr2wDXPETA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-undici@0.10.0': - resolution: {integrity: sha512-vm+V255NGw9gaSsPD6CP0oGo8L55BffBc8KnxqsMuc6XiAD1L8SFNzsW0RHhxJFqy9CJaJh+YiJ5EHXuZ5rZBw==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.7.0 - - '@opentelemetry/instrumentation@0.53.0': - resolution: {integrity: sha512-DMwg0hy4wzf7K73JJtl95m/e0boSoWhH07rfvHvYzQtBD3Bmv0Wc1x733vyZBqmFm8OjJD0/pfiUg1W3JjFX0A==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation@0.57.1': - resolution: {integrity: sha512-SgHEKXoVxOjc20ZYusPG3Fh+RLIZTSa4x8QtD3NfgAUDyqdFFS9W1F2ZVbZkqDCdyMcQG02Ok4duUGLHJXHgbA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation@0.57.2': - resolution: {integrity: sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/redis-common@0.36.2': - resolution: {integrity: sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==} - engines: {node: '>=14'} - - '@opentelemetry/resources@1.30.1': - resolution: {integrity: sha512-5UxZqiAgLYGFjS4s9qm5mBVo433u+dSPUFWVWXmLAD4wB65oMCoXaJP1KJa9DIYYMeHu3z4BZcStG3LC593cWA==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - - '@opentelemetry/sdk-trace-base@1.30.1': - resolution: {integrity: sha512-jVPgBbH1gCy2Lb7X0AVQ8XAfgg0pJ4nvl8/IiQA6nxOsPvS+0zMJaFSs2ltXe0J6C8dqjcnpyqINDJmU30+uOg==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - - '@opentelemetry/semantic-conventions@1.27.0': - resolution: {integrity: sha512-sAay1RrB+ONOem0OZanAR1ZI/k7yDpnOQSQmTMuGImUQb2y8EbSaCJ94FQluM74xoU03vlb2d2U90hZluL6nQg==} - engines: {node: '>=14'} - - '@opentelemetry/semantic-conventions@1.28.0': - resolution: {integrity: sha512-lp4qAiMTD4sNWW4DbKLBkfiMZ4jbAboJIGOQr5DvciMRI494OapieI9qiODpOt0XBr1LjIDy1xAGAnVs5supTA==} - engines: {node: '>=14'} - - '@opentelemetry/semantic-conventions@1.40.0': - resolution: {integrity: sha512-cifvXDhcqMwwTlTK04GBNeIe7yyo28Mfby85QXFe1Yk8nmi36Ab/5UQwptOx84SsoGNRg+EVSjwzfSZMy6pmlw==} - engines: {node: '>=14'} - - '@opentelemetry/sql-common@0.40.1': - resolution: {integrity: sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.1.0 - - '@parcel/watcher-android-arm64@2.5.6': - resolution: {integrity: sha512-YQxSS34tPF/6ZG7r/Ih9xy+kP/WwediEUsqmtf0cuCV5TPPKw/PQHRhueUo6JdeFJaqV3pyjm0GdYjZotbRt/A==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [android] - - '@parcel/watcher-darwin-arm64@2.5.6': - resolution: {integrity: sha512-Z2ZdrnwyXvvvdtRHLmM4knydIdU9adO3D4n/0cVipF3rRiwP+3/sfzpAwA/qKFL6i1ModaabkU7IbpeMBgiVEA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [darwin] - - '@parcel/watcher-darwin-x64@2.5.6': - resolution: {integrity: sha512-HgvOf3W9dhithcwOWX9uDZyn1lW9R+7tPZ4sug+NGrGIo4Rk1hAXLEbcH1TQSqxts0NYXXlOWqVpvS1SFS4fRg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [darwin] - - '@parcel/watcher-freebsd-x64@2.5.6': - resolution: {integrity: sha512-vJVi8yd/qzJxEKHkeemh7w3YAn6RJCtYlE4HPMoVnCpIXEzSrxErBW5SJBgKLbXU3WdIpkjBTeUNtyBVn8TRng==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [freebsd] - - '@parcel/watcher-linux-arm-glibc@2.5.6': - resolution: {integrity: sha512-9JiYfB6h6BgV50CCfasfLf/uvOcJskMSwcdH1PHH9rvS1IrNy8zad6IUVPVUfmXr+u+Km9IxcfMLzgdOudz9EQ==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm-musl@2.5.6': - resolution: {integrity: sha512-Ve3gUCG57nuUUSyjBq/MAM0CzArtuIOxsBdQ+ftz6ho8n7s1i9E1Nmk/xmP323r2YL0SONs1EuwqBp2u1k5fxg==} - engines: {node: '>= 10.0.0'} - cpu: [arm] - os: [linux] - - '@parcel/watcher-linux-arm64-glibc@2.5.6': - resolution: {integrity: sha512-f2g/DT3NhGPdBmMWYoxixqYr3v/UXcmLOYy16Bx0TM20Tchduwr4EaCbmxh1321TABqPGDpS8D/ggOTaljijOA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-arm64-musl@2.5.6': - resolution: {integrity: sha512-qb6naMDGlbCwdhLj6hgoVKJl2odL34z2sqkC7Z6kzir8b5W65WYDpLB6R06KabvZdgoHI/zxke4b3zR0wAbDTA==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [linux] - - '@parcel/watcher-linux-x64-glibc@2.5.6': - resolution: {integrity: sha512-kbT5wvNQlx7NaGjzPFu8nVIW1rWqV780O7ZtkjuWaPUgpv2NMFpjYERVi0UYj1msZNyCzGlaCWEtzc+exjMGbQ==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-linux-x64-musl@2.5.6': - resolution: {integrity: sha512-1JRFeC+h7RdXwldHzTsmdtYR/Ku8SylLgTU/reMuqdVD7CtLwf0VR1FqeprZ0eHQkO0vqsbvFLXUmYm/uNKJBg==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [linux] - - '@parcel/watcher-win32-arm64@2.5.6': - resolution: {integrity: sha512-3ukyebjc6eGlw9yRt678DxVF7rjXatWiHvTXqphZLvo7aC5NdEgFufVwjFfY51ijYEWpXbqF5jtrK275z52D4Q==} - engines: {node: '>= 10.0.0'} - cpu: [arm64] - os: [win32] - - '@parcel/watcher-win32-ia32@2.5.6': - resolution: {integrity: sha512-k35yLp1ZMwwee3Ez/pxBi5cf4AoBKYXj00CZ80jUz5h8prpiaQsiRPKQMxoLstNuqe2vR4RNPEAEcjEFzhEz/g==} - engines: {node: '>= 10.0.0'} - cpu: [ia32] - os: [win32] - - '@parcel/watcher-win32-x64@2.5.6': - resolution: {integrity: sha512-hbQlYcCq5dlAX9Qx+kFb0FHue6vbjlf0FrNzSKdYK2APUf7tGfGxQCk2ihEREmbR6ZMc0MVAD5RIX/41gpUzTw==} - engines: {node: '>= 10.0.0'} - cpu: [x64] - os: [win32] - - '@parcel/watcher@2.5.6': - resolution: {integrity: sha512-tmmZ3lQxAe/k/+rNnXQRawJ4NjxO2hqiOLTHvWchtGZULp4RyFeh6aU4XdOYBFe2KE1oShQTv4AblOs2iOrNnQ==} - engines: {node: '>= 10.0.0'} - - '@plausible-analytics/tracker@0.4.4': - resolution: {integrity: sha512-fz0NOYUEYXtg1TBaPEEvtcBq3FfmLFuTe1VZw4M8sTWX129br5dguu3M15+plOQnc181ShYe67RfwhKgK89VnA==} - - '@playwright/test@1.58.2': - resolution: {integrity: sha512-akea+6bHYBBfA9uQqSYmlJXn61cTa+jbO87xVLCWbTqbWadRVmhxlXATaOjOgcBaWU4ePo0wB41KMFv3o35IXA==} - engines: {node: '>=18'} - hasBin: true - - '@polka/url@1.0.0-next.29': - resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - - '@popperjs/core@2.11.8': - resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} - - '@prisma/instrumentation@5.22.0': - resolution: {integrity: sha512-LxccF392NN37ISGxIurUljZSh1YWnphO34V5a0+T7FVQG2u9bhAXRTJpgmQ3483woVhkraQZFF7cbRrpbw/F4Q==} - - '@rollup/rollup-android-arm-eabi@4.60.0': - resolution: {integrity: sha512-WOhNW9K8bR3kf4zLxbfg6Pxu2ybOUbB2AjMDHSQx86LIF4rH4Ft7vmMwNt0loO0eonglSNy4cpD3MKXXKQu0/A==} - cpu: [arm] - os: [android] - - '@rollup/rollup-android-arm64@4.60.0': - resolution: {integrity: sha512-u6JHLll5QKRvjciE78bQXDmqRqNs5M/3GVqZeMwvmjaNODJih/WIrJlFVEihvV0MiYFmd+ZyPr9wxOVbPAG2Iw==} - cpu: [arm64] - os: [android] - - '@rollup/rollup-darwin-arm64@4.60.0': - resolution: {integrity: sha512-qEF7CsKKzSRc20Ciu2Zw1wRrBz4g56F7r/vRwY430UPp/nt1x21Q/fpJ9N5l47WWvJlkNCPJz3QRVw008fi7yA==} - cpu: [arm64] - os: [darwin] - - '@rollup/rollup-darwin-x64@4.60.0': - resolution: {integrity: sha512-WADYozJ4QCnXCH4wPB+3FuGmDPoFseVCUrANmA5LWwGmC6FL14BWC7pcq+FstOZv3baGX65tZ378uT6WG8ynTw==} - cpu: [x64] - os: [darwin] - - '@rollup/rollup-freebsd-arm64@4.60.0': - resolution: {integrity: sha512-6b8wGHJlDrGeSE3aH5mGNHBjA0TTkxdoNHik5EkvPHCt351XnigA4pS7Wsj/Eo9Y8RBU6f35cjN9SYmCFBtzxw==} - cpu: [arm64] - os: [freebsd] - - '@rollup/rollup-freebsd-x64@4.60.0': - resolution: {integrity: sha512-h25Ga0t4jaylMB8M/JKAyrvvfxGRjnPQIR8lnCayyzEjEOx2EJIlIiMbhpWxDRKGKF8jbNH01NnN663dH638mA==} - cpu: [x64] - os: [freebsd] - - '@rollup/rollup-linux-arm-gnueabihf@4.60.0': - resolution: {integrity: sha512-RzeBwv0B3qtVBWtcuABtSuCzToo2IEAIQrcyB/b2zMvBWVbjo8bZDjACUpnaafaxhTw2W+imQbP2BD1usasK4g==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm-musleabihf@4.60.0': - resolution: {integrity: sha512-Sf7zusNI2CIU1HLzuu9Tc5YGAHEZs5Lu7N1ssJG4Tkw6e0MEsN7NdjUDDfGNHy2IU+ENyWT+L2obgWiguWibWQ==} - cpu: [arm] - os: [linux] - - '@rollup/rollup-linux-arm64-gnu@4.60.0': - resolution: {integrity: sha512-DX2x7CMcrJzsE91q7/O02IJQ5/aLkVtYFryqCjduJhUfGKG6yJV8hxaw8pZa93lLEpPTP/ohdN4wFz7yp/ry9A==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-arm64-musl@4.60.0': - resolution: {integrity: sha512-09EL+yFVbJZlhcQfShpswwRZ0Rg+z/CsSELFCnPt3iK+iqwGsI4zht3secj5vLEs957QvFFXnzAT0FFPIxSrkQ==} - cpu: [arm64] - os: [linux] - - '@rollup/rollup-linux-loong64-gnu@4.60.0': - resolution: {integrity: sha512-i9IcCMPr3EXm8EQg5jnja0Zyc1iFxJjZWlb4wr7U2Wx/GrddOuEafxRdMPRYVaXjgbhvqalp6np07hN1w9kAKw==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-loong64-musl@4.60.0': - resolution: {integrity: sha512-DGzdJK9kyJ+B78MCkWeGnpXJ91tK/iKA6HwHxF4TAlPIY7GXEvMe8hBFRgdrR9Ly4qebR/7gfUs9y2IoaVEyog==} - cpu: [loong64] - os: [linux] - - '@rollup/rollup-linux-ppc64-gnu@4.60.0': - resolution: {integrity: sha512-RwpnLsqC8qbS8z1H1AxBA1H6qknR4YpPR9w2XX0vo2Sz10miu57PkNcnHVaZkbqyw/kUWfKMI73jhmfi9BRMUQ==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-ppc64-musl@4.60.0': - resolution: {integrity: sha512-Z8pPf54Ly3aqtdWC3G4rFigZgNvd+qJlOE52fmko3KST9SoGfAdSRCwyoyG05q1HrrAblLbk1/PSIV+80/pxLg==} - cpu: [ppc64] - os: [linux] - - '@rollup/rollup-linux-riscv64-gnu@4.60.0': - resolution: {integrity: sha512-3a3qQustp3COCGvnP4SvrMHnPQ9d1vzCakQVRTliaz8cIp/wULGjiGpbcqrkv0WrHTEp8bQD/B3HBjzujVWLOA==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-riscv64-musl@4.60.0': - resolution: {integrity: sha512-pjZDsVH/1VsghMJ2/kAaxt6dL0psT6ZexQVrijczOf+PeP2BUqTHYejk3l6TlPRydggINOeNRhvpLa0AYpCWSQ==} - cpu: [riscv64] - os: [linux] - - '@rollup/rollup-linux-s390x-gnu@4.60.0': - resolution: {integrity: sha512-3ObQs0BhvPgiUVZrN7gqCSvmFuMWvWvsjG5ayJ3Lraqv+2KhOsp+pUbigqbeWqueGIsnn+09HBw27rJ+gYK4VQ==} - cpu: [s390x] - os: [linux] - - '@rollup/rollup-linux-x64-gnu@4.60.0': - resolution: {integrity: sha512-EtylprDtQPdS5rXvAayrNDYoJhIz1/vzN2fEubo3yLE7tfAw+948dO0g4M0vkTVFhKojnF+n6C8bDNe+gDRdTg==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-linux-x64-musl@4.60.0': - resolution: {integrity: sha512-k09oiRCi/bHU9UVFqD17r3eJR9bn03TyKraCrlz5ULFJGdJGi7VOmm9jl44vOJvRJ6P7WuBi/s2A97LxxHGIdw==} - cpu: [x64] - os: [linux] - - '@rollup/rollup-openbsd-x64@4.60.0': - resolution: {integrity: sha512-1o/0/pIhozoSaDJoDcec+IVLbnRtQmHwPV730+AOD29lHEEo4F5BEUB24H0OBdhbBBDwIOSuf7vgg0Ywxdfiiw==} - cpu: [x64] - os: [openbsd] - - '@rollup/rollup-openharmony-arm64@4.60.0': - resolution: {integrity: sha512-pESDkos/PDzYwtyzB5p/UoNU/8fJo68vcXM9ZW2V0kjYayj1KaaUfi1NmTUTUpMn4UhU4gTuK8gIaFO4UGuMbA==} - cpu: [arm64] - os: [openharmony] - - '@rollup/rollup-win32-arm64-msvc@4.60.0': - resolution: {integrity: sha512-hj1wFStD7B1YBeYmvY+lWXZ7ey73YGPcViMShYikqKT1GtstIKQAtfUI6yrzPjAy/O7pO0VLXGmUVWXQMaYgTQ==} - cpu: [arm64] - os: [win32] - - '@rollup/rollup-win32-ia32-msvc@4.60.0': - resolution: {integrity: sha512-SyaIPFoxmUPlNDq5EHkTbiKzmSEmq/gOYFI/3HHJ8iS/v1mbugVa7dXUzcJGQfoytp9DJFLhHH4U3/eTy2Bq4w==} - cpu: [ia32] - os: [win32] - - '@rollup/rollup-win32-x64-gnu@4.60.0': - resolution: {integrity: sha512-RdcryEfzZr+lAr5kRm2ucN9aVlCCa2QNq4hXelZxb8GG0NJSazq44Z3PCCc8wISRuCVnGs0lQJVX5Vp6fKA+IA==} - cpu: [x64] - os: [win32] - - '@rollup/rollup-win32-x64-msvc@4.60.0': - resolution: {integrity: sha512-PrsWNQ8BuE00O3Xsx3ALh2Df8fAj9+cvvX9AIA6o4KpATR98c9mud4XtDWVvsEuyia5U4tVSTKygawyJkjm60w==} - cpu: [x64] - os: [win32] - - '@sentry-internal/browser-utils@8.55.1': - resolution: {integrity: sha512-SipXiwVhJrxzy3/4kf+YIFmpYlLKtGSRD+er7SBCcuSBtv31Fee8IXMDvk+bq24gRXxyjOLUmT//GGXjy2LL6w==} - engines: {node: '>=14.18'} - - '@sentry-internal/feedback@8.55.1': - resolution: {integrity: sha512-9iFHaT/ijtzB0ffZhXMnt2rPNIXO/dDiCL1G1Bc55rQMPXgawR9AIaAWciyqQjYcbL1DDOhWbzdVqB+kVs5gXw==} - engines: {node: '>=14.18'} - - '@sentry-internal/replay-canvas@8.55.1': - resolution: {integrity: sha512-2sKRu96Qe70y6TiYdYbwkhg4um2prgzH/ZJRItuoSEAjPjoFYYlP+1qjE2CcBw4RPS8/PimV7SFheSaeZs2GCw==} - engines: {node: '>=14.18'} - - '@sentry-internal/replay@8.55.1': - resolution: {integrity: sha512-XaX6r8pXeX47rfiQrSQUwkgxHsDkOKzIT++zfTwrmveVlYSqAhp3x+AKhxAXGmKG62wlmAKQz54GJKcG4cgyKQ==} - engines: {node: '>=14.18'} - - '@sentry/babel-plugin-component-annotate@2.22.6': - resolution: {integrity: sha512-V2g1Y1I5eSe7dtUVMBvAJr8BaLRr4CLrgNgtPaZyMT4Rnps82SrZ5zqmEkLXPumlXhLUWR6qzoMNN2u+RXVXfQ==} - engines: {node: '>= 14'} - - '@sentry/browser@8.55.1': - resolution: {integrity: sha512-OEn2eg8h3Mr7BmBGQ28BqbWehYA/NklZ0pAZB1FypPPl+kMd85AbaRdGTnaSjgmpc8bKbBO64edq4Y14sbCs5w==} - engines: {node: '>=14.18'} - - '@sentry/bundler-plugin-core@2.22.6': - resolution: {integrity: sha512-1esQdgSUCww9XAntO4pr7uAM5cfGhLsgTK9MEwAKNfvpMYJi9NUTYa3A7AZmdA8V6107Lo4OD7peIPrDRbaDCg==} - engines: {node: '>= 14'} - - '@sentry/cli-darwin@2.58.5': - resolution: {integrity: sha512-lYrNzenZFJftfwSya7gwrHGxtE+Kob/e1sr9lmHMFOd4utDlmq0XFDllmdZAMf21fxcPRI1GL28ejZ3bId01fQ==} - engines: {node: '>=10'} - os: [darwin] - - '@sentry/cli-linux-arm64@2.58.5': - resolution: {integrity: sha512-/4gywFeBqRB6tR/iGMRAJ3HRqY6Z7Yp4l8ZCbl0TDLAfHNxu7schEw4tSnm2/Hh9eNMiOVy4z58uzAWlZXAYBQ==} - engines: {node: '>=10'} - cpu: [arm64] - os: [linux, freebsd, android] - - '@sentry/cli-linux-arm@2.58.5': - resolution: {integrity: sha512-KtHweSIomYL4WVDrBrYSYJricKAAzxUgX86kc6OnlikbyOhoK6Fy8Vs6vwd52P6dvWPjgrMpUYjW2M5pYXQDUw==} - engines: {node: '>=10'} - cpu: [arm] - os: [linux, freebsd, android] - - '@sentry/cli-linux-i686@2.58.5': - resolution: {integrity: sha512-G7261dkmyxqlMdyvyP06b+RTIVzp1gZNgglj5UksxSouSUqRd/46W/2pQeOMPhloDYo9yLtCN2YFb3Mw4aUsWw==} - engines: {node: '>=10'} - cpu: [x86, ia32] - os: [linux, freebsd, android] - - '@sentry/cli-linux-x64@2.58.5': - resolution: {integrity: sha512-rP04494RSmt86xChkQ+ecBNRYSPbyXc4u0IA7R7N1pSLCyO74e5w5Al+LnAq35cMfVbZgz5Sm0iGLjyiUu4I1g==} - engines: {node: '>=10'} - cpu: [x64] - os: [linux, freebsd, android] - - '@sentry/cli-win32-arm64@2.58.5': - resolution: {integrity: sha512-AOJ2nCXlQL1KBaCzv38m3i2VmSHNurUpm7xVKd6yAHX+ZoVBI8VT0EgvwmtJR2TY2N2hNCC7UrgRmdUsQ152bA==} - engines: {node: '>=10'} - cpu: [arm64] - os: [win32] - - '@sentry/cli-win32-i686@2.58.5': - resolution: {integrity: sha512-EsuboLSOnlrN7MMPJ1eFvfMDm+BnzOaSWl8eYhNo8W/BIrmNgpRUdBwnWn9Q2UOjJj5ZopukmsiMYtU/D7ml9g==} - engines: {node: '>=10'} - cpu: [x86, ia32] - os: [win32] - - '@sentry/cli-win32-x64@2.58.5': - resolution: {integrity: sha512-IZf+XIMiQwj+5NzqbOQfywlOitmCV424Vtf9c+ep61AaVScUFD1TSrQbOcJJv5xGxhlxNOMNgMeZhdexdzrKZg==} - engines: {node: '>=10'} - cpu: [x64] - os: [win32] - - '@sentry/cli@2.58.5': - resolution: {integrity: sha512-tavJ7yGUZV+z3Ct2/ZB6mg339i08sAk6HDkgqmSRuQEu2iLS5sl9HIvuXfM6xjv8fwlgFOSy++WNABNAcGHUbg==} - engines: {node: '>= 10'} - hasBin: true - - '@sentry/core@8.55.1': - resolution: {integrity: sha512-0ea+yDOgaijR3ba2al1QZxY0bZ9MBZq2a0G+2A0uCBpBkiXnpLFGVAo9UAlEikN1C4M8ROZYiuFU7yZCqacgLQ==} - engines: {node: '>=14.18'} - - '@sentry/node@8.55.1': - resolution: {integrity: sha512-s8ydn/OxZFIxc9Fvt23gJkrXkCvPnUu2bDKwjQBCx0M1b4DdNdp4FaimT6B9reya7buj+tsNkZAoT11KqFhG/g==} - engines: {node: '>=14.18'} - - '@sentry/opentelemetry@8.55.1': - resolution: {integrity: sha512-ipiM/k3Hzt8visoBfkDb4AQBWHkJeou3SjoPec7NlDabH/Jj8x6VlK5Hex4z+WOv99rRy+5MUtga/CZnOjvh0A==} - engines: {node: '>=14.18'} - peerDependencies: - '@opentelemetry/api': ^1.9.0 - '@opentelemetry/context-async-hooks': ^1.30.1 - '@opentelemetry/core': ^1.30.1 - '@opentelemetry/instrumentation': ^0.57.1 - '@opentelemetry/sdk-trace-base': ^1.30.1 - '@opentelemetry/semantic-conventions': ^1.28.0 - - '@sentry/svelte@8.55.1': - resolution: {integrity: sha512-INuwEscDDkHY3rnZyYiRCBtI8vz9qkTprTpegMC01W7mWE2vh9bNft8V/c41una8m8m6JLREy+1eYRvd/uDr3A==} - engines: {node: '>=14.18'} - peerDependencies: - svelte: 3.x || 4.x || 5.x - - '@sentry/sveltekit@8.55.1': - resolution: {integrity: sha512-Kt05HMaWvbtvUYFF5gmZmNBY2Wn1kJnyTXDjYusTxsAtM9RfU05UbOSqedBcOqhSALohZUwHA4/QO3lqgXEsAg==} - engines: {node: '>=16'} - peerDependencies: - '@sveltejs/kit': 1.x || 2.x - vite: '*' - peerDependenciesMeta: - vite: - optional: true - - '@sentry/vite-plugin@2.22.6': - resolution: {integrity: sha512-zIieP1VLWQb3wUjFJlwOAoaaJygJhXeUoGd0e/Ha2RLb2eW2S+4gjf6y6NqyY71tZ74LYVZKg/4prB6FAZSMXQ==} - engines: {node: '>= 14'} - - '@shikijs/core@1.29.2': - resolution: {integrity: sha512-vju0lY9r27jJfOY4Z7+Rt/nIOjzJpZ3y+nYpqtUZInVoXQ/TJZcfGnNOGnKjFdVZb8qexiCuSlZRKcGfhhTTZQ==} - - '@shikijs/engine-javascript@1.29.2': - resolution: {integrity: sha512-iNEZv4IrLYPv64Q6k7EPpOCE/nuvGiKl7zxdq0WFuRPF5PAE9PRo2JGq/d8crLusM59BRemJ4eOqrFrC4wiQ+A==} - - '@shikijs/engine-oniguruma@1.29.2': - resolution: {integrity: sha512-7iiOx3SG8+g1MnlzZVDYiaeHe7Ez2Kf2HrJzdmGwkRisT7r4rak0e655AcM/tF9JG/kg5fMNYlLLKglbN7gBqA==} - - '@shikijs/langs@1.29.2': - resolution: {integrity: sha512-FIBA7N3LZ+223U7cJDUYd5shmciFQlYkFXlkKVaHsCPgfVLiO+e12FmQE6Tf9vuyEsFe3dIl8qGWKXgEHL9wmQ==} - - '@shikijs/themes@1.29.2': - resolution: {integrity: sha512-i9TNZlsq4uoyqSbluIcZkmPL9Bfi3djVxRnofUHwvx/h6SRW3cwgBC5SML7vsDcWyukY0eCzVN980rqP6qNl9g==} - - '@shikijs/types@1.29.2': - resolution: {integrity: sha512-VJjK0eIijTZf0QSTODEXCqinjBn0joAHQ+aPSBzrv4O2d/QSbsMw+ZeSRx03kV34Hy7NzUvV/7NqfYGRLrASmw==} - - '@shikijs/vscode-textmate@10.0.2': - resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} - - '@standard-schema/spec@1.1.0': - resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} - - '@stripe/stripe-js@3.5.0': - resolution: {integrity: sha512-pKS3wZnJoL1iTyGBXAvCwduNNeghJHY6QSRSNNvpYnrrQrLZ6Owsazjyynu0e0ObRgks0i7Rv+pe2M7/MBTZpQ==} - engines: {node: '>=12.16'} - - '@sveltejs/acorn-typescript@1.0.9': - resolution: {integrity: sha512-lVJX6qEgs/4DOcRTpo56tmKzVPtoWAaVbL4hfO7t7NVwl9AAXzQR6cihesW1BmNMPl+bK6dreu2sOKBP2Q9CIA==} - peerDependencies: - acorn: ^8.9.0 - - '@sveltejs/adapter-static@3.0.10': - resolution: {integrity: sha512-7D9lYFWJmB7zxZyTE/qxjksvMqzMuYrrsyh1f4AlZqeZeACPRySjbC3aFiY55wb1tWUaKOQG9PVbm74JcN2Iew==} - peerDependencies: - '@sveltejs/kit': ^2.0.0 - - '@sveltejs/kit@2.55.0': - resolution: {integrity: sha512-MdFRjevVxmAknf2NbaUkDF16jSIzXMWd4Nfah0Qp8TtQVoSp3bV4jKt8mX7z7qTUTWvgSaxtR0EG5WJf53gcuA==} - engines: {node: '>=18.13'} - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.0.0 - '@sveltejs/vite-plugin-svelte': ^3.0.0 || ^4.0.0-next.1 || ^5.0.0 || ^6.0.0-next.0 || ^7.0.0 - svelte: ^4.0.0 || ^5.0.0-next.0 - typescript: ^5.3.3 - vite: ^5.0.3 || ^6.0.0 || ^7.0.0-beta.0 || ^8.0.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - typescript: - optional: true - - '@sveltejs/vite-plugin-svelte-inspector@4.0.1': - resolution: {integrity: sha512-J/Nmb2Q2y7mck2hyCX4ckVHcR5tu2J+MtBEQqpDrrgELZ2uvraQcK/ioCV61AqkdXFgriksOKIceDcQmqnGhVw==} - 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 - - '@sveltejs/vite-plugin-svelte@5.1.1': - resolution: {integrity: sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22} - peerDependencies: - svelte: ^5.0.0 - vite: ^6.0.0 - - '@swc/helpers@0.5.20': - resolution: {integrity: sha512-2egEBHUMasdypIzrprsu8g+OEVd7Vp2MM3a2eVlM/cyFYto0nGz5BX5BTgh/ShZZI9ed+ozEq+Ngt+rgmUs8tw==} - - '@tanstack/svelte-virtual@3.13.23': - resolution: {integrity: sha512-kUFdKtevYPhuv9bN2/NhE8zCr6pO3lP2a4xYwyzwqvNZim0EMHdq9nKMFgS4rMHE9Iacdj4+PwMYDfRZ45a/+Q==} - peerDependencies: - svelte: ^3.48.0 || ^4.0.0 || ^5.0.0 - - '@tanstack/virtual-core@3.13.23': - resolution: {integrity: sha512-zSz2Z2HNyLjCplANTDyl3BcdQJc2k1+yyFoKhNRmCr7V7dY8o8q5m8uFTI1/Pg1kL+Hgrz6u3Xo6eFUB7l66cg==} - - '@testing-library/dom@10.4.1': - resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} - engines: {node: '>=18'} - - '@testing-library/jest-dom@6.9.1': - resolution: {integrity: sha512-zIcONa+hVtVSSep9UT3jZ5rizo2BsxgyDYU7WFD5eICBE7no3881HGeb/QkGfsJs6JTkY1aQhT7rIPC7e+0nnA==} - engines: {node: '>=14', npm: '>=6', yarn: '>=1'} - - '@testing-library/svelte-core@1.0.0': - resolution: {integrity: sha512-VkUePoLV6oOYwSUvX6ShA8KLnJqZiYMIbP2JW2t0GLWLkJxKGvuH5qrrZBV/X7cXFnLGuFQEC7RheYiZOW68KQ==} - engines: {node: '>=16'} - peerDependencies: - svelte: ^3 || ^4 || ^5 || ^5.0.0-next.0 - - '@testing-library/svelte@5.3.1': - resolution: {integrity: sha512-8Ez7ZOqW5geRf9PF5rkuopODe5RGy3I9XR+kc7zHh26gBiktLaxTfKmhlGaSHYUOTQE7wFsLMN9xCJVCszw47w==} - engines: {node: '>= 10'} - peerDependencies: - svelte: ^3 || ^4 || ^5 || ^5.0.0-next.0 - vite: '*' - vitest: '*' - peerDependenciesMeta: - vite: - optional: true - vitest: - optional: true - - '@testing-library/user-event@14.6.1': - resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} - engines: {node: '>=12', npm: '>=6'} - peerDependencies: - '@testing-library/dom': '>=7.21.4' - - '@threejs-kit/instanced-sprite-mesh@2.5.1': - resolution: {integrity: sha512-pmt1ALRhbHhCJQTj2FuthH6PeLIeaM4hOuS2JO3kWSwlnvx/9xuUkjFR3JOi/myMqsH7pSsLIROSaBxDfttjeA==} - peerDependencies: - three: '>=0.170.0' - - '@threlte/core@8.5.4': - resolution: {integrity: sha512-hqFkD0/CHVUFh/FavLKCI5snYqwGL4InO9hpYgbf+XirKyx/atqiDoiCv/gVhPjQAojojyur8Frj+lNu8u/J5Q==} - peerDependencies: - svelte: '>=5' - three: '>=0.160' - - '@threlte/extras@9.13.3': - resolution: {integrity: sha512-ElXna1kGuS9b9pCG5swChpwpbrDxoMVxchCG8mXjjcXk9HW8qZDicf2mq0SBll2fLP0Nb8iGlkskSJ04qqWCGg==} - peerDependencies: - svelte: '>=5' - three: '>=0.160' - - '@tweenjs/tween.js@23.1.3': - resolution: {integrity: sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==} - - '@types/aria-query@5.0.4': - resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - - '@types/chai@5.2.3': - resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - - '@types/connect@3.4.36': - resolution: {integrity: sha512-P63Zd/JUGq+PdrM1lv0Wv5SBYeA2+CORvbrXbngriYY0jzLUWfQMQQxOhjONEz/wlHOAxOdY7CY65rgQdTjq2w==} - - '@types/cookie@0.6.0': - resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} - - '@types/deep-eql@4.0.2': - resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - - '@types/deep-equal@1.0.4': - resolution: {integrity: sha512-tqdiS4otQP4KmY0PR3u6KbZ5EWvhNdUoS/jc93UuK23C220lOZ/9TvjfxdPcKvqwwDVtmtSCrnr0p/2dirAxkA==} - - '@types/dlv@1.1.5': - resolution: {integrity: sha512-JHOWNfiWepAhfwlSw17kiWrWrk6od2dEQgHltJw9AS0JPFoLZJBge5+Dnil2NfdjAvJ/+vGSX60/BRW20PpUXw==} - - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - - '@types/hast@3.0.4': - resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - - '@types/json-schema@7.0.15': - resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - - '@types/mdast@4.0.4': - resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - - '@types/mysql@2.15.26': - resolution: {integrity: sha512-DSLCOXhkvfS5WNNPbfn2KdICAmk8lLc+/PNvnPnF7gOdMZCxopXduqv0OQ13y/yA/zXTSikZZqVgybUxOEg6YQ==} - - '@types/node@25.5.0': - resolution: {integrity: sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==} - - '@types/pg-pool@2.0.6': - resolution: {integrity: sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==} - - '@types/pg@8.6.1': - resolution: {integrity: sha512-1Kc4oAGzAl7uqUStZCDvaLFqZrW9qWSjXOmBfdgyBP5La7Us6Mg4GBvRlSoaZMhQF/zSj1C8CtKMBkoiT8eL8w==} - - '@types/prop-types@15.7.15': - resolution: {integrity: sha512-F6bEyamV9jKGAFBEmlQnesRPGOQqS2+Uwi0Em15xenOxHaf2hv6L8YCVn3rPdPJOiJfPiCnLIRyvwVaqMY3MIw==} - - '@types/react@18.3.28': - resolution: {integrity: sha512-z9VXpC7MWrhfWipitjNdgCauoMLRdIILQsAEV+ZesIzBq/oUlxk0m3ApZuMFCXdnS4U7KrI+l3WRUEGQ8K1QKw==} - - '@types/remarkable@2.0.8': - resolution: {integrity: sha512-eKXqPZfpQl1kOADjdKchHrp2gwn9qMnGXhH/AtZe0UrklzhGJkawJo/Y/D0AlWcdWoWamFNIum8+/nkAISQVGg==} - - '@types/shimmer@1.2.0': - resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==} - - '@types/stats.js@0.17.4': - resolution: {integrity: sha512-jIBvWWShCvlBqBNIZt0KAshWpvSjhkwkEu4ZUcASoAvhmrgAUI2t1dXrjSL4xXVLB4FznPrIsX3nKXFl/Dt4vA==} - - '@types/tedious@4.0.14': - resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} - - '@types/three@0.182.0': - resolution: {integrity: sha512-WByN9V3Sbwbe2OkWuSGyoqQO8Du6yhYaXtXLoA5FkKTUJorZ+yOHBZ35zUUPQXlAKABZmbYp5oAqpA4RBjtJ/Q==} - - '@types/trusted-types@2.0.7': - resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - - '@types/unist@3.0.3': - resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - - '@types/webxr@0.5.24': - resolution: {integrity: sha512-h8fgEd/DpoS9CBrjEQXR+dIDraopAEfu4wYVNY2tEPwk60stPWhvZMf4Foo5FakuQ7HFZoa8WceaWFervK2Ovg==} - - '@typescript-eslint/eslint-plugin@8.57.2': - resolution: {integrity: sha512-NZZgp0Fm2IkD+La5PR81sd+g+8oS6JwJje+aRWsDocxHkjyRw0J5L5ZTlN3LI1LlOcGL7ph3eaIUmTXMIjLk0w==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - '@typescript-eslint/parser': ^8.57.2 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/parser@8.57.2': - resolution: {integrity: sha512-30ScMRHIAD33JJQkgfGW1t8CURZtjc2JpTrq5n2HFhOefbAhb7ucc7xJwdWcrEtqUIYJ73Nybpsggii6GtAHjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/project-service@8.57.2': - resolution: {integrity: sha512-FuH0wipFywXRTHf+bTTjNyuNQQsQC3qh/dYzaM4I4W0jrCqjCVuUh99+xd9KamUfmCGPvbO8NDngo/vsnNVqgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/scope-manager@8.57.2': - resolution: {integrity: sha512-snZKH+W4WbWkrBqj4gUNRIGb/jipDW3qMqVJ4C9rzdFc+wLwruxk+2a5D+uoFcKPAqyqEnSb4l2ULuZf95eSkw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/tsconfig-utils@8.57.2': - resolution: {integrity: sha512-3Lm5DSM+DCowsUOJC+YqHHnKEfFh5CoGkj5Z31NQSNF4l5wdOwqGn99wmwN/LImhfY3KJnmordBq/4+VDe2eKw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/type-utils@8.57.2': - resolution: {integrity: sha512-Co6ZCShm6kIbAM/s+oYVpKFfW7LBc6FXoPXjTRQ449PPNBY8U0KZXuevz5IFuuUj2H9ss40atTaf9dlGLzbWZg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/types@8.57.2': - resolution: {integrity: sha512-/iZM6FnM4tnx9csuTxspMW4BOSegshwX5oBDznJ7S4WggL7Vczz5d2W11ecc4vRrQMQHXRSxzrCsyG5EsPPTbA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@typescript-eslint/typescript-estree@8.57.2': - resolution: {integrity: sha512-2MKM+I6g8tJxfSmFKOnHv2t8Sk3T6rF20A1Puk0svLK+uVapDZB/4pfAeB7nE83uAZrU6OxW+HmOd5wHVdXwXA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/utils@8.57.2': - resolution: {integrity: sha512-krRIbvPK1ju1WBKIefiX+bngPs+odIQUtR7kymzPfo1POVw3jlF+nLkmexdSSd4UCbDcQn+wMBATOOmpBbqgKg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' - - '@typescript-eslint/visitor-keys@8.57.2': - resolution: {integrity: sha512-zhahknjobV2FiD6Ee9iLbS7OV9zi10rG26odsQdfBO/hjSzUQbkIYgda+iNKK1zNiW2ey+Lf8MU5btN17V3dUw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - '@ungap/structured-clone@1.3.0': - resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - - '@vercel/oidc@3.1.0': - resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} - engines: {node: '>= 20'} - - '@vitest/expect@3.2.4': - resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - - '@vitest/mocker@3.2.4': - resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} - peerDependencies: - msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 - peerDependenciesMeta: - msw: - optional: true - vite: - optional: true - - '@vitest/pretty-format@3.2.4': - resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - - '@vitest/runner@3.2.4': - resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - - '@vitest/snapshot@3.2.4': - resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} - - '@vitest/spy@3.2.4': - resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - - '@vitest/ui@3.2.4': - resolution: {integrity: sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==} - peerDependencies: - vitest: 3.2.4 - - '@vitest/utils@3.2.4': - resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - - '@webgpu/types@0.1.69': - resolution: {integrity: sha512-RPmm6kgRbI8e98zSD3RVACvnuktIja5+yLgDAkTmxLr90BEwdTXRQWNLF3ETTTyH/8mKhznZuN5AveXYFEsMGQ==} - - acorn-import-attributes@1.9.5: - resolution: {integrity: sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==} - peerDependencies: - acorn: ^8 - - acorn-jsx@5.3.2: - resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - - acorn@8.16.0: - resolution: {integrity: sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==} - engines: {node: '>=0.4.0'} - hasBin: true - - agent-base@6.0.2: - resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} - engines: {node: '>= 6.0.0'} - - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - - ai@6.0.141: - resolution: {integrity: sha512-+GomGQWaId3xN0wcugUW/H7xMMaFkID2PiS7K/Wugj45G3efv0BXhQ3psRZoQVoRbOpdNoUqcK/KTB+FR4h6qg==} - engines: {node: '>=18'} - peerDependencies: - zod: ^3.25.76 || ^4.1.8 - - ajv@6.14.0: - resolution: {integrity: sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==} - - analytics-utils@1.1.1: - resolution: {integrity: sha512-nRybjTpRAcHVhWb1cvYaOLJaI3R79r8XjMbu5c0wd2jKmANNqSrYwybiU0X3mp+CQQdm4YiAggTXb2cIA8XhUg==} - peerDependencies: - '@types/dlv': ^1.0.0 - - analytics@0.8.19: - resolution: {integrity: sha512-JFgasxpWFiAoqm5UHaGQv9j9OGz+f1KAeQkABYr3Z7YGhiqhQrBpPhIVAIEyttBRJZmew1QwMhN9/bOGGBnpJA==} - - ansi-regex@5.0.1: - resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} - engines: {node: '>=8'} - - ansi-styles@4.3.0: - resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} - engines: {node: '>=8'} - - ansi-styles@5.2.0: - resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} - engines: {node: '>=10'} - - ansicolor@2.0.3: - resolution: {integrity: sha512-pzusTqk9VHrjgMCcTPDTTvfJfx6Q3+L5tQ6yKC8Diexmoit4YROTFIkxFvRTNL9y5s0Q8HrSrgerCD5bIC+Kiw==} - - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} - - argparse@1.0.10: - resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} - - argparse@2.0.1: - resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - - aria-query@5.3.0: - resolution: {integrity: sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==} - - aria-query@5.3.1: - resolution: {integrity: sha512-Z/ZeOgVl7bcSYZ/u/rh0fOpvEpq//LZmdbkXyc7syVzjPAhfOa9ebsdTSjEBDU4vs5nC98Kfduj1uFo0qyET3g==} - engines: {node: '>= 0.4'} - - aria-query@5.3.2: - resolution: {integrity: sha512-COROpnaoap1E2F000S62r6A60uHZnmlvomhfyT2DlTcrY1OrBKn2UhH7qn5wTC9zMvD0AY7csdPSNwKP+7WiQw==} - engines: {node: '>= 0.4'} - - array-buffer-byte-length@1.0.2: - resolution: {integrity: sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==} - engines: {node: '>= 0.4'} - - assertion-error@2.0.1: - resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} - engines: {node: '>=12'} - - ast-types@0.16.1: - resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} - engines: {node: '>=4'} - - autolinker@3.16.2: - resolution: {integrity: sha512-JiYl7j2Z19F9NdTmirENSUUIIL/9MytEWtmzhfmsKPCp9E+G35Y0UNCMoM9tFigxT59qSc8Ml2dlZXOCVTYwuA==} - - available-typed-arrays@1.0.7: - resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} - engines: {node: '>= 0.4'} - - axobject-query@4.1.0: - resolution: {integrity: sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==} - engines: {node: '>= 0.4'} - - balanced-match@1.0.2: - resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - - balanced-match@4.0.4: - resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} - engines: {node: 18 || 20 || >=22} - - baseline-browser-mapping@2.10.12: - resolution: {integrity: sha512-qyq26DxfY4awP2gIRXhhLWfwzwI+N5Nxk6iQi8EFizIaWIjqicQTE4sLnZZVdeKPRcVNoJOkkpfzoIYuvCKaIQ==} - engines: {node: '>=6.0.0'} - hasBin: true - - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - - bignumber.js@9.3.1: - resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} - - brace-expansion@1.1.13: - resolution: {integrity: sha512-9ZLprWS6EENmhEOpjCYW2c8VkmOvckIJZfkr7rBW6dObmfgJ/L1GpSYW5Hpo9lDz4D1+n0Ckz8rU7FwHDQiG/w==} - - brace-expansion@2.0.3: - resolution: {integrity: sha512-MCV/fYJEbqx68aE58kv2cA/kiky1G8vux3OR6/jbS+jIMe/6fJWa0DTzJU7dqijOWYwHi1t29FlfYI9uytqlpA==} - - brace-expansion@5.0.5: - resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} - engines: {node: 18 || 20 || >=22} - - braces@3.0.3: - resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} - engines: {node: '>=8'} - - browserslist@4.28.1: - resolution: {integrity: sha512-ZC5Bd0LgJXgwGqUknZY/vkUQ04r8NXnJZ3yYi4vDmSiZmC/pdSN0NbNRPxZpbtO4uAfDUAFffO8IZoM3Gj8IkA==} - engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} - hasBin: true - - cac@6.7.14: - resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} - engines: {node: '>=8'} - - call-bind-apply-helpers@1.0.2: - resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} - engines: {node: '>= 0.4'} - - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} - engines: {node: '>= 0.4'} - - call-bound@1.0.4: - resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} - engines: {node: '>= 0.4'} - - callsites@3.1.0: - resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} - engines: {node: '>=6'} - - camera-controls@3.1.2: - resolution: {integrity: sha512-xkxfpG2ECZ6Ww5/9+kf4mfg1VEYAoe9aDSY+IwF0UEs7qEzwy0aVRfs2grImIECs/PoBtWFrh7RXsQkwG922JA==} - engines: {node: '>=22.0.0', npm: '>=10.5.1'} - peerDependencies: - three: '>=0.126.1' - - caniuse-lite@1.0.30001781: - resolution: {integrity: sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==} - - ccount@2.0.1: - resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - - chai@5.3.3: - resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} - engines: {node: '>=18'} - - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - - character-entities-html4@2.1.0: - resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - - character-entities-legacy@3.0.0: - resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - - check-error@2.1.3: - resolution: {integrity: sha512-PAJdDJusoxnwm1VwW07VWwUN1sl7smmC3OKggvndJFadxxDRyFJBX/ggnu/KE4kQAB7a3Dp8f/YXC1FlUprWmA==} - engines: {node: '>= 16'} - - chokidar@3.6.0: - resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} - engines: {node: '>= 8.10.0'} - - chokidar@4.0.3: - resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} - engines: {node: '>= 14.16.0'} - - cjs-module-lexer@1.4.3: - resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} - - clsx@2.1.1: - resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} - engines: {node: '>=6'} - - color-convert@2.0.1: - resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} - engines: {node: '>=7.0.0'} - - color-convert@3.1.3: - resolution: {integrity: sha512-fasDH2ont2GqF5HpyO4w0+BcewlhHEZOFn9c1ckZdHpJ56Qb7MHhH/IcJZbBGgvdtwdwNbLvxiBEdg336iA9Sg==} - engines: {node: '>=14.6'} - - color-name@1.1.4: - resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - - color-name@2.1.0: - resolution: {integrity: sha512-1bPaDNFm0axzE4MEAzKPuqKWeRaT43U/hyxKPBdqTfmPF+d6n7FSoTFxLVULUJOmiLp01KjhIPPH+HrXZJN4Rg==} - engines: {node: '>=12.20'} - - color-string@2.1.4: - resolution: {integrity: sha512-Bb6Cq8oq0IjDOe8wJmi4JeNn763Xs9cfrBcaylK1tPypWzyoy2G3l90v9k64kjphl/ZJjPIShFztenRomi8WTg==} - engines: {node: '>=18'} - - color@5.0.3: - resolution: {integrity: sha512-ezmVcLR3xAVp8kYOm4GS45ZLLgIE6SPAFoduLr6hTDajwb3KZ2F46gulK3XpcwRFb5KKGCSezCBAY4Dw4HsyXA==} - engines: {node: '>=18'} - - comma-separated-tokens@2.0.3: - resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - - commander@7.2.0: - resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==} - engines: {node: '>= 10'} - - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - convert-source-map@2.0.0: - resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - - cookie@0.6.0: - resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} - engines: {node: '>= 0.6'} - - cron-parser@4.9.0: - resolution: {integrity: sha512-p0SaNjrHOnQeR8/VnfGbmg9te2kfyYSQ7Sc/j/6DtPL3JQvKxmjO9TSjNFpujqV3vEYYBvNNvXSxzyksBWAx1Q==} - engines: {node: '>=12.0.0'} - - cross-spawn@7.0.6: - resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} - engines: {node: '>= 8'} - - css.escape@1.5.1: - resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==} - - cssesc@3.0.0: - resolution: {integrity: sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==} - engines: {node: '>=4'} - hasBin: true - - cssstyle@4.6.0: - resolution: {integrity: sha512-2z+rWdzbbSZv6/rhtvzvqeZQHrBaqgogqt85sqFNbabZOuFbCVFb8kPeEtZjiKkbrm395irpNKiYeFeLiQnFPg==} - engines: {node: '>=18'} - - csstype@3.2.3: - resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - - d3-array@3.2.4: - resolution: {integrity: sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==} - engines: {node: '>=12'} - - d3-axis@3.0.0: - resolution: {integrity: sha512-IH5tgjV4jE/GhHkRV0HiVYPDtvfjHQlQfJHs0usq7M30XcSBvOotpmH1IgkcXsO/5gEQZD43B//fc7SRT5S+xw==} - engines: {node: '>=12'} - - d3-brush@3.0.0: - resolution: {integrity: sha512-ALnjWlVYkXsVIGlOsuWH1+3udkYFI48Ljihfnh8FZPF2QS9o+PzGLBslO0PjzVoHLZ2KCVgAM8NVkXPJB2aNnQ==} - engines: {node: '>=12'} - - d3-chord@3.0.1: - resolution: {integrity: sha512-VE5S6TNa+j8msksl7HwjxMHDM2yNK3XCkusIlpX5kwauBfXuyLAtNg9jCp/iHH61tgI4sb6R/EIMWCqEIdjT/g==} - engines: {node: '>=12'} - - d3-color@3.1.0: - resolution: {integrity: sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==} - engines: {node: '>=12'} - - d3-contour@4.0.2: - resolution: {integrity: sha512-4EzFTRIikzs47RGmdxbeUvLWtGedDUNkTcmzoeyg4sP/dvCexO47AaQL7VKy/gul85TOxw+IBgA8US2xwbToNA==} - engines: {node: '>=12'} - - d3-delaunay@6.0.4: - resolution: {integrity: sha512-mdjtIZ1XLAM8bm/hx3WwjfHt6Sggek7qH043O8KEjDXN40xi3vx/6pYSVTwLjEgiXQTbvaouWKynLBiUZ6SK6A==} - engines: {node: '>=12'} - - d3-dispatch@3.0.1: - resolution: {integrity: sha512-rzUyPU/S7rwUflMyLc1ETDeBj0NRuHKKAcvukozwhshr6g6c5d8zh4c2gQjY2bZ0dXeGLWc1PF174P2tVvKhfg==} - engines: {node: '>=12'} - - d3-drag@3.0.0: - resolution: {integrity: sha512-pWbUJLdETVA8lQNJecMxoXfH6x+mO2UQo8rSmZ+QqxcbyA3hfeprFgIT//HW2nlHChWeIIMwS2Fq+gEARkhTkg==} - engines: {node: '>=12'} - - d3-dsv@3.0.1: - resolution: {integrity: sha512-UG6OvdI5afDIFP9w4G0mNq50dSOsXHJaRE8arAS5o9ApWnIElp8GZw1Dun8vP8OyHOZ/QJUKUJwxiiCCnUwm+Q==} - engines: {node: '>=12'} - hasBin: true - - d3-ease@3.0.1: - resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} - engines: {node: '>=12'} - - d3-fetch@3.0.1: - resolution: {integrity: sha512-kpkQIM20n3oLVBKGg6oHrUchHM3xODkTzjMoj7aWQFq5QEM+R6E4WkzT5+tojDY7yjez8KgCBRoj4aEr99Fdqw==} - engines: {node: '>=12'} - - d3-force@3.0.0: - resolution: {integrity: sha512-zxV/SsA+U4yte8051P4ECydjD/S+qeYtnaIyAs9tgHCqfguma/aAQDjo85A9Z6EKhBirHRJHXIgJUlffT4wdLg==} - engines: {node: '>=12'} - - d3-format@3.1.2: - resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} - engines: {node: '>=12'} - - d3-geo@3.1.1: - resolution: {integrity: sha512-637ln3gXKXOwhalDzinUgY83KzNWZRKbYubaG+fGVuc/dxO64RRljtCTnf5ecMyE1RIdtqpkVcq0IbtU2S8j2Q==} - engines: {node: '>=12'} - - d3-hierarchy@3.1.2: - resolution: {integrity: sha512-FX/9frcub54beBdugHjDCdikxThEqjnR93Qt7PvQTOHxyiNCAlvMrHhclk3cD5VeAaq9fxmfRp+CnWw9rEMBuA==} - engines: {node: '>=12'} - - d3-interpolate@3.0.1: - resolution: {integrity: sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==} - engines: {node: '>=12'} - - d3-path@3.1.0: - resolution: {integrity: sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==} - engines: {node: '>=12'} - - d3-polygon@3.0.1: - resolution: {integrity: sha512-3vbA7vXYwfe1SYhED++fPUQlWSYTTGmFmQiany/gdbiWgU/iEyQzyymwL9SkJjFFuCS4902BSzewVGsHHmHtXg==} - engines: {node: '>=12'} - - d3-quadtree@3.0.1: - resolution: {integrity: sha512-04xDrxQTDTCFwP5H6hRhsRcb9xxv2RzkcsygFzmkSIOJy3PeRJP7sNk3VRIbKXcog561P9oU0/rVH6vDROAgUw==} - engines: {node: '>=12'} - - d3-random@3.0.1: - resolution: {integrity: sha512-FXMe9GfxTxqd5D6jFsQ+DJ8BJS4E/fT5mqqdjovykEB2oFbTMDVdg1MGFxfQW+FBOGoB++k8swBrgwSHT1cUXQ==} - engines: {node: '>=12'} - - d3-scale-chromatic@3.1.0: - resolution: {integrity: sha512-A3s5PWiZ9YCXFye1o246KoscMWqf8BsD9eRiJ3He7C9OBaxKhAd5TFCdEx/7VbKtxxTsu//1mMJFrEt572cEyQ==} - engines: {node: '>=12'} - - d3-scale@4.0.2: - resolution: {integrity: sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==} - engines: {node: '>=12'} - - d3-selection@3.0.0: - resolution: {integrity: sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==} - engines: {node: '>=12'} - - d3-shape@3.2.0: - resolution: {integrity: sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==} - engines: {node: '>=12'} - - d3-time-format@4.1.0: - resolution: {integrity: sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==} - engines: {node: '>=12'} - - d3-time@3.1.0: - resolution: {integrity: sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==} - engines: {node: '>=12'} - - d3-timer@3.0.1: - resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} - engines: {node: '>=12'} - - d3-transition@3.0.1: - resolution: {integrity: sha512-ApKvfjsSR6tg06xrL434C0WydLr7JewBB3V+/39RMHsaXTOG0zmt/OAXeng5M5LBm0ojmxJrpomQVZ1aPvBL4w==} - engines: {node: '>=12'} - peerDependencies: - d3-selection: 2 - 3 - - d3-zoom@3.0.0: - resolution: {integrity: sha512-b8AmV3kfQaqWAuacbPuNbL6vahnOJflOhexLzMMNLga62+/nh0JzvJ0aO/5a5MVgUFGS7Hu1P9P03o3fJkDCyw==} - engines: {node: '>=12'} - - d3@7.9.0: - resolution: {integrity: sha512-e1U46jVP+w7Iut8Jt8ri1YsPOvFpg46k+K8TpCb0P+zjCkjkPnV7WzfDJzMHy1LnA+wj5pLT1wjO901gLXeEhA==} - engines: {node: '>=12'} - - data-urls@5.0.0: - resolution: {integrity: sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==} - engines: {node: '>=18'} - - dayjs@1.11.20: - resolution: {integrity: sha512-YbwwqR/uYpeoP4pu043q+LTDLFBLApUP6VxRihdfNTqu4ubqMlGDLd6ErXhEgsyvY0K6nCs7nggYumAN+9uEuQ==} - - debug@4.4.3: - resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - - decimal.js@10.6.0: - resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - - deep-eql@5.0.2: - resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} - engines: {node: '>=6'} - - deep-equal@2.2.3: - resolution: {integrity: sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==} - engines: {node: '>= 0.4'} - - deep-is@0.1.4: - resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - - deepmerge@4.3.1: - resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} - engines: {node: '>=0.10.0'} - - define-data-property@1.1.4: - resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} - engines: {node: '>= 0.4'} - - define-properties@1.2.1: - resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} - engines: {node: '>= 0.4'} - - delaunator@5.1.0: - resolution: {integrity: sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==} - - dequal@2.0.3: - resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} - engines: {node: '>=6'} - - detect-libc@2.1.2: - resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} - engines: {node: '>=8'} - - devalue@5.6.4: - resolution: {integrity: sha512-Gp6rDldRsFh/7XuouDbxMH3Mx8GMCcgzIb1pDTvNyn8pZGQ22u+Wa+lGV9dQCltFQ7uVw0MhRyb8XDskNFOReA==} - - devlop@1.1.0: - resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - - diet-sprite@0.0.1: - resolution: {integrity: sha512-zSHI2WDAn1wJqJYxcmjWfJv3Iw8oL9reQIbEyx2x2/EZ4/qmUTIo8/5qOCurnAcq61EwtJJaZ0XTy2NRYqpB5A==} - - dlv@1.1.3: - resolution: {integrity: sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==} - - dom-accessibility-api@0.5.16: - resolution: {integrity: sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==} - - dom-accessibility-api@0.6.3: - resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==} - - dotenv@16.6.1: - resolution: {integrity: sha512-uBq4egWHTcTt33a72vpSG0z3HnPuIl6NqYcTrKEg2azoEyl2hpW0zqlxysq2pK9HlDIHyHyakeYaYnSAwd8bow==} - engines: {node: '>=12'} - - dunder-proto@1.0.1: - resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} - engines: {node: '>= 0.4'} - - earcut@2.2.4: - resolution: {integrity: sha512-/pjZsA1b4RPHbeWZQn66SWS8nZZWLQQ23oE3Eam7aroEFGEvwKAsJfZ9ytiEMycfzXWpca4FA9QIOehf7PocBQ==} - - echarts@5.6.0: - resolution: {integrity: sha512-oTbVTsXfKuEhxftHqL5xprgLoc0k7uScAwtryCgWF6hPYFLRwOUHiFmHGCBKP5NPFNkDVopOieyUqYGH8Fa3kA==} - - electron-to-chromium@1.5.328: - resolution: {integrity: sha512-QNQ5l45DzYytThO21403XN3FvK0hOkWDG8viNf6jqS42msJ8I4tGDSpBCgvDRRPnkffafiwAym2X2eHeGD2V0w==} - - emoji-regex-xs@1.0.0: - resolution: {integrity: sha512-LRlerrMYoIDrT6jgpeZ2YYl/L8EulRTt5hQcYjy5AInh7HWXKimpqx68aknBFpGL2+/IcogTcaydJEgaTmOpDg==} - - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} - engines: {node: '>=0.12'} - - es-define-property@1.0.1: - resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} - engines: {node: '>= 0.4'} - - es-errors@1.3.0: - resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} - engines: {node: '>= 0.4'} - - es-get-iterator@1.1.3: - resolution: {integrity: sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==} - - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} - engines: {node: '>= 0.4'} - - esbuild@0.27.4: - resolution: {integrity: sha512-Rq4vbHnYkK5fws5NF7MYTU68FPRE1ajX7heQ/8QXXWqNgqqJ/GkmmyxIzUnf2Sr/bakf8l54716CcMGHYhMrrQ==} - engines: {node: '>=18'} - hasBin: true - - escalade@3.2.0: - resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} - engines: {node: '>=6'} - - escape-string-regexp@4.0.0: - resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} - engines: {node: '>=10'} - - eslint-config-prettier@10.1.8: - resolution: {integrity: sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w==} - hasBin: true - peerDependencies: - eslint: '>=7.0.0' - - eslint-plugin-svelte@3.16.0: - resolution: {integrity: sha512-DJXxqpYZUxcE0SfYo8EJzV2ZC+zAD7fJp1n1HwcEMRR1cOEUYvjT9GuzJeNghMjgb7uxuK3IJAzI+x6zzUxO5A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.1 || ^9.0.0 || ^10.0.0 - svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - svelte: - optional: true - - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@3.4.3: - resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} - engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - - eslint-visitor-keys@4.2.1: - resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - eslint-visitor-keys@5.0.1: - resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24} - - eslint@9.39.4: - resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - hasBin: true - peerDependencies: - jiti: '*' - peerDependenciesMeta: - jiti: - optional: true - - esm-env@1.2.2: - resolution: {integrity: sha512-Epxrv+Nr/CaL4ZcFGPJIYLWFom+YeV1DqMLHJoEd9SYRxNbaFruBwfEX/kkHUJf55j2+TUbmDcmuilbP1TmXHA==} - - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - - esprima@4.0.1: - resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} - engines: {node: '>=4'} - hasBin: true - - esquery@1.7.0: - resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} - engines: {node: '>=0.10'} - - esrap@2.2.4: - resolution: {integrity: sha512-suICpxAmZ9A8bzJjEl/+rLJiDKC0X4gYWUxT6URAWBLvlXmtbZd5ySMu/N2ZGEtMCAmflUDPSehrP9BQcsGcSg==} - - esrecurse@4.3.0: - resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} - engines: {node: '>=4.0'} - - estraverse@5.3.0: - resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} - engines: {node: '>=4.0'} - - estree-walker@3.0.3: - resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - - esutils@2.0.3: - resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} - engines: {node: '>=0.10.0'} - - eventsource-parser@3.0.6: - resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} - engines: {node: '>=18.0.0'} - - expect-type@1.3.0: - resolution: {integrity: sha512-knvyeauYhqjOYvQ66MznSMs83wmHrCycNEN6Ao+2AeYEfxUIkuiVxdEa1qlGEPK+We3n0THiDciYSsCcgW/DoA==} - engines: {node: '>=12.0.0'} - - fast-deep-equal@3.1.3: - resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - - fast-json-stable-stringify@2.1.0: - resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - - fast-levenshtein@2.0.6: - resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - - fdir@6.5.0: - resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} - engines: {node: '>=12.0.0'} - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - - fflate@0.8.2: - resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} - - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - fill-range@7.1.1: - resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} - engines: {node: '>=8'} - - find-up@5.0.0: - resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} - engines: {node: '>=10'} - - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} - - flatted@3.4.2: - resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} - - focus-trap@7.8.0: - resolution: {integrity: sha512-/yNdlIkpWbM0ptxno3ONTuf+2g318kh2ez3KSeZN5dZ8YC6AAmgeWz+GasYYiBJPFaYcSAPeu4GfhUaChzIJXA==} - - for-each@0.3.5: - resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} - engines: {node: '>= 0.4'} - - forwarded-parse@2.1.2: - resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} - - framesync@6.1.2: - resolution: {integrity: sha512-jBTqhX6KaQVDyus8muwZbBeGGP0XgujBRbQ7gM7BRdS3CadCZIHiawyzYLnafYcvZIh5j8WE7cxZKFn7dXhu9g==} - - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - - fsevents@2.3.2: - resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - fsevents@2.3.3: - resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} - engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} - os: [darwin] - - function-bind@1.1.2: - resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - - functions-have-names@1.2.3: - resolution: {integrity: sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==} - - fuse.js@7.1.0: - resolution: {integrity: sha512-trLf4SzuuUxfusZADLINj+dE8clK1frKdmqiJNb1Es75fmI5oY6X2mxLVUciLLjxqw/xr72Dhy+lER6dGd02FQ==} - engines: {node: '>=10'} - - gensync@1.0.0-beta.2: - resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} - engines: {node: '>=6.9.0'} - - get-intrinsic@1.3.0: - resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} - engines: {node: '>= 0.4'} - - get-proto@1.0.1: - resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} - engines: {node: '>= 0.4'} - - glob-parent@5.1.2: - resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} - engines: {node: '>= 6'} - - glob-parent@6.0.2: - resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} - engines: {node: '>=10.13.0'} - - glob@9.3.5: - resolution: {integrity: sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==} - engines: {node: '>=16 || 14 >=14.17'} - deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me - - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} - - globals@16.5.0: - resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} - engines: {node: '>=18'} - - globalyzer@0.1.0: - resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} - - globrex@0.1.2: - resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} - - gopd@1.2.0: - resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} - engines: {node: '>= 0.4'} - - has-bigints@1.1.0: - resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} - engines: {node: '>= 0.4'} - - has-flag@4.0.0: - resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} - engines: {node: '>=8'} - - has-property-descriptors@1.0.2: - resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} - - has-symbols@1.1.0: - resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} - engines: {node: '>= 0.4'} - - has-tostringtag@1.0.2: - resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} - engines: {node: '>= 0.4'} - - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} - - hast-util-to-html@9.0.5: - resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} - - hast-util-whitespace@3.0.0: - resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - - hey-listen@1.0.8: - resolution: {integrity: sha512-COpmrF2NOg4TBWUJ5UVyaCU2A88wEMkUPK4hNqyCkqHbxT92BbvfjoSozkAIIm6XhicGlJHhFdullInrdhwU8Q==} - - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} - - html-void-elements@3.0.0: - resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - - https-proxy-agent@5.0.1: - resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} - engines: {node: '>= 6'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - ignore@5.3.2: - resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} - engines: {node: '>= 4'} - - ignore@6.0.2: - resolution: {integrity: sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==} - engines: {node: '>= 4'} - - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} - engines: {node: '>= 4'} - - immutable@5.1.5: - resolution: {integrity: sha512-t7xcm2siw+hlUM68I+UEOK+z84RzmN59as9DZ7P1l0994DKUWV7UXBMQZVxaoMSRQ+PBZbHCOoBt7a2wxOMt+A==} - - import-fresh@3.3.1: - resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} - engines: {node: '>=6'} - - import-in-the-middle@1.15.0: - resolution: {integrity: sha512-bpQy+CrsRmYmoPMAE/0G33iwRqwW4ouqdRg8jgbH3aKuCtOc8lxgmYXg2dMM92CRiGP660EtBcymH/eVUpCSaA==} - - imurmurhash@0.1.4: - resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} - engines: {node: '>=0.8.19'} - - indent-string@4.0.0: - resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} - engines: {node: '>=8'} - - internal-slot@1.1.0: - resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} - engines: {node: '>= 0.4'} - - internmap@2.0.3: - resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} - engines: {node: '>=12'} - - is-arguments@1.2.0: - resolution: {integrity: sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==} - engines: {node: '>= 0.4'} - - is-array-buffer@3.0.5: - resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} - engines: {node: '>= 0.4'} - - is-bigint@1.1.0: - resolution: {integrity: sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==} - engines: {node: '>= 0.4'} - - is-binary-path@2.1.0: - resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} - engines: {node: '>=8'} - - is-boolean-object@1.2.2: - resolution: {integrity: sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==} - engines: {node: '>= 0.4'} - - is-callable@1.2.7: - resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} - engines: {node: '>= 0.4'} - - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} - engines: {node: '>= 0.4'} - - is-date-object@1.1.0: - resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} - engines: {node: '>= 0.4'} - - is-extglob@2.1.1: - resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} - engines: {node: '>=0.10.0'} - - is-glob@4.0.3: - resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} - engines: {node: '>=0.10.0'} - - is-map@2.0.3: - resolution: {integrity: sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==} - engines: {node: '>= 0.4'} - - is-number-object@1.1.1: - resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} - engines: {node: '>= 0.4'} - - is-number@7.0.0: - resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} - engines: {node: '>=0.12.0'} - - is-potential-custom-element-name@1.0.1: - resolution: {integrity: sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==} - - is-reference@3.0.3: - resolution: {integrity: sha512-ixkJoqQvAP88E6wLydLGGqCJsrFUnqoH6HnaczB8XmDH1oaWU+xxdptvikTgaEhtZ53Ky6YXiBuUI2WXLMCwjw==} - - is-regex@1.2.1: - resolution: {integrity: sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==} - engines: {node: '>= 0.4'} - - is-set@2.0.3: - resolution: {integrity: sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==} - engines: {node: '>= 0.4'} - - is-shared-array-buffer@1.0.4: - resolution: {integrity: sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==} - engines: {node: '>= 0.4'} - - is-string@1.1.1: - resolution: {integrity: sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==} - engines: {node: '>= 0.4'} - - is-symbol@1.1.1: - resolution: {integrity: sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==} - engines: {node: '>= 0.4'} - - is-weakmap@2.0.2: - resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} - engines: {node: '>= 0.4'} - - is-weakset@2.0.4: - resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} - engines: {node: '>= 0.4'} - - isarray@2.0.5: - resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - - isexe@2.0.0: - resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - - js-tokens@4.0.0: - resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} - hasBin: true - - jsdom@26.1.0: - resolution: {integrity: sha512-Cvc9WUhxSMEo4McES3P7oK3QaXldCfNWp7pl2NNeiIFlCoLr3kfq9kb1fxftiwk1FLV7CvpvDfonxtzUDeSOPg==} - engines: {node: '>=18'} - peerDependencies: - canvas: ^3.0.0 - peerDependenciesMeta: - canvas: - optional: true - - jsesc@3.1.0: - resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} - engines: {node: '>=6'} - hasBin: true - - json-bigint@1.0.0: - resolution: {integrity: sha512-SiPv/8VpZuWbvLSMtTDU8hEfrZWg/mH/nV/b4o0CYbSxu1UIQPLdwKOCIyLQX+VIPO5vrLX3i8qtqFyhdPSUSQ==} - - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - - json-schema-traverse@0.4.1: - resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - - json-schema@0.4.0: - resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} - - json-stable-stringify-without-jsonify@1.0.1: - resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - - json5@2.2.3: - resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} - engines: {node: '>=6'} - hasBin: true - - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - - kleur@4.1.5: - resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} - engines: {node: '>=6'} - - known-css-properties@0.37.0: - resolution: {integrity: sha512-JCDrsP4Z1Sb9JwG0aJ8Eo2r7k4Ou5MwmThS/6lcIe1ICyb7UBJKGRIUUdqc2ASdE/42lgz6zFUnzAIhtXnBVrQ==} - - levn@0.4.1: - resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} - engines: {node: '>= 0.8.0'} - - lilconfig@2.1.0: - resolution: {integrity: sha512-utWOt/GHzuUxnLKxB6dk81RoOeoNeHgbrXiuGk4yyF5qlRz+iIVWu56E2fqGHFrXz0QNUhLB/8nKqvRH66JKGQ==} - engines: {node: '>=10'} - - locate-character@3.0.0: - resolution: {integrity: sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==} - - locate-path@6.0.0: - resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} - engines: {node: '>=10'} - - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - loupe@3.2.1: - resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - - lru-cache@10.4.3: - resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} - - lru-cache@5.1.1: - resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - - luxon@3.7.2: - resolution: {integrity: sha512-vtEhXh/gNjI9Yg1u4jX/0YVPMvxzHuGgCm6tC5kZyb08yjGWGnqAjGJvcXbqQR2P3MyMEFnRbpcdFS6PBcLqew==} - engines: {node: '>=12'} - - lz-string@1.5.0: - resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} - hasBin: true - - maath@0.10.8: - resolution: {integrity: sha512-tRvbDF0Pgqz+9XUa4jjfgAQ8/aPKmQdWXilFu2tMy4GWj4NOsx99HlULO4IeREfbO3a0sA145DZYyvXPkybm0g==} - peerDependencies: - '@types/three': '>=0.134.0' - three: '>=0.134.0' - - magic-string@0.30.21: - resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - - magic-string@0.30.7: - resolution: {integrity: sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==} - engines: {node: '>=12'} - - magic-string@0.30.8: - resolution: {integrity: sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==} - engines: {node: '>=12'} - - magicast@0.2.8: - resolution: {integrity: sha512-zEnqeb3E6TfMKYXGyHv3utbuHNixr04o3/gVGviSzVQkbFiU46VZUd+Ea/1npKfvEsEWxBYuIksKzoztTDPg0A==} - - math-intrinsics@1.1.0: - resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} - engines: {node: '>= 0.4'} - - mdast-util-to-hast@13.2.1: - resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} - - meshoptimizer@0.22.0: - resolution: {integrity: sha512-IebiK79sqIy+E4EgOr+CAw+Ke8hAspXKzBd0JdgEmPHiAwmvEj2S4h1rfvo+o/BnfEYd/jAOg5IeeIjzlzSnDg==} - - micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} - - micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - - micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} - - micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - - micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - - min-indent@1.0.1: - resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} - engines: {node: '>=4'} - - minimatch@10.2.4: - resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} - engines: {node: 18 || 20 || >=22} - - minimatch@3.1.5: - resolution: {integrity: sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==} - - minimatch@8.0.7: - resolution: {integrity: sha512-V+1uQNdzybxa14e/p00HZnQNNcTjnRJjDxg2V8wtkjFctq4M7hXFws4oekyTP0Jebeq7QYtpFyOeBAjc88zvYg==} - engines: {node: '>=16 || 14 >=14.17'} - - minimist@1.2.8: - resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - - minipass@4.2.8: - resolution: {integrity: sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==} - engines: {node: '>=8'} - - minipass@7.1.3: - resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} - engines: {node: '>=16 || 14 >=14.17'} - - mitt@3.0.1: - resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} - - module-details-from-path@1.0.4: - resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} - - mri@1.2.0: - resolution: {integrity: sha512-tzzskb3bG8LvYGFF/mDTpq3jpI6Q9wc3LEmBaghu+DdCssd1FakN7Bc0hVNmEyGq1bq3RgfkCb3cmQLpNPOroA==} - engines: {node: '>=4'} - - mrmime@2.0.1: - resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} - engines: {node: '>=10'} - - ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true - - nanoid@5.1.7: - resolution: {integrity: sha512-ua3NDgISf6jdwezAheMOk4mbE1LXjm1DfMUDMuJf4AqxLFK3ccGpgWizwa5YV7Yz9EpXwEaWoRXSb/BnV0t5dQ==} - engines: {node: ^18 || >=20} - hasBin: true - - nanotar@0.3.0: - resolution: {integrity: sha512-Kv2JYYiCzt16Kt5QwAc9BFG89xfPNBx+oQL4GQXD9nLqPkZBiNaqaCWtwnbk/q7UVsTYevvM1b0UF8zmEI4pCg==} - - natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - - node-addon-api@7.1.1: - resolution: {integrity: sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==} - - node-fetch@2.7.0: - resolution: {integrity: sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==} - engines: {node: 4.x || >=6.0.0} - peerDependencies: - encoding: ^0.1.0 - peerDependenciesMeta: - encoding: - optional: true - - node-releases@2.0.36: - resolution: {integrity: sha512-TdC8FSgHz8Mwtw9g5L4gR/Sh9XhSP/0DEkQxfEFXOpiul5IiHgHan2VhYYb6agDSfp4KuvltmGApc8HMgUrIkA==} - - normalize-path@3.0.0: - resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} - engines: {node: '>=0.10.0'} - - nwsapi@2.2.23: - resolution: {integrity: sha512-7wfH4sLbt4M0gCDzGE6vzQBo0bfTKjU7Sfpqy/7gs1qBfYz2vEJH6vXcBKpO3+6Yu1telwd0t9HpyOoLEQQbIQ==} - - object-inspect@1.13.4: - resolution: {integrity: sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==} - engines: {node: '>= 0.4'} - - object-is@1.1.6: - resolution: {integrity: sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==} - engines: {node: '>= 0.4'} - - object-keys@1.1.1: - resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} - engines: {node: '>= 0.4'} - - object.assign@4.1.7: - resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} - engines: {node: '>= 0.4'} - - oniguruma-to-es@2.3.0: - resolution: {integrity: sha512-bwALDxriqfKGfUufKGGepCzu9x7nJQuoRoAFp4AnwehhC2crqrDIAP/uN2qdlsAvSMpeRC3+Yzhqc7hLmle5+g==} - - optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} - - p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} - - p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} - - parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} - - parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} - - path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - - path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - - path-parse@1.0.7: - resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - - path-scurry@1.11.1: - resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} - engines: {node: '>=16 || 14 >=14.18'} - - pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - - pathval@2.0.1: - resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} - engines: {node: '>= 14.16'} - - pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - pg-protocol@1.13.0: - resolution: {integrity: sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==} - - pg-types@2.2.0: - resolution: {integrity: sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==} - engines: {node: '>=4'} - - picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} - - picomatch@2.3.2: - resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} - engines: {node: '>=8.6'} - - picomatch@4.0.4: - resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} - engines: {node: '>=12'} - - playwright-core@1.58.2: - resolution: {integrity: sha512-yZkEtftgwS8CsfYo7nm0KE8jsvm6i/PTgVtB8DL726wNf6H2IMsDuxCpJj59KDaxCtSnrWan2AeDqM7JBaultg==} - engines: {node: '>=18'} - hasBin: true - - playwright@1.58.2: - resolution: {integrity: sha512-vA30H8Nvkq/cPBnNw4Q8TWz1EJyqgpuinBcHET0YVJVFldr8JDNiU9LaWAE1KqSkRYazuaBhTpB5ZzShOezQ6A==} - engines: {node: '>=18'} - hasBin: true - - popmotion@11.0.5: - resolution: {integrity: sha512-la8gPM1WYeFznb/JqF4GiTkRRPZsfaj2+kCxqQgr2MJylMmIKUwBfWW8Wa5fml/8gmtlD5yI01MP1QCZPWmppA==} - - possible-typed-array-names@1.1.0: - resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} - engines: {node: '>= 0.4'} - - postcss-load-config@3.1.4: - resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} - engines: {node: '>= 10'} - peerDependencies: - postcss: '>=8.0.9' - ts-node: '>=9.0.0' - peerDependenciesMeta: - postcss: - optional: true - ts-node: - optional: true - - postcss-safe-parser@7.0.1: - resolution: {integrity: sha512-0AioNCJZ2DPYz5ABT6bddIqlhgwhpHZ/l65YAYo0BCIn0xiDpsnTHz0gnoTGk0OXZW0JRs+cDwL8u/teRdz+8A==} - engines: {node: '>=18.0'} - peerDependencies: - postcss: ^8.4.31 - - postcss-scss@4.0.9: - resolution: {integrity: sha512-AjKOeiwAitL/MXxQW2DliT28EKukvvbEWx3LBmJIRN8KfBGZbRTxNYW0kSqi1COiTZ57nZ9NW06S6ux//N1c9A==} - engines: {node: '>=12.0'} - peerDependencies: - postcss: ^8.4.29 - - postcss-selector-parser@7.1.1: - resolution: {integrity: sha512-orRsuYpJVw8LdAwqqLykBj9ecS5/cRHlI5+nvTo8LcCKmzDmqVORXtOIYEEQuL9D4BxtA1lm5isAqzQZCoQ6Eg==} - engines: {node: '>=4'} - - postcss@8.5.8: - resolution: {integrity: sha512-OW/rX8O/jXnm82Ey1k44pObPtdblfiuWnrd8X7GJ7emImCOstunGbXUpp7HdBrFQX6rJzn3sPT397Wp5aCwCHg==} - engines: {node: ^10 || ^12 || >=14} - - postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - - postgres-bytea@1.0.1: - resolution: {integrity: sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==} - engines: {node: '>=0.10.0'} - - postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} - - postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} - - prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - - prettier-plugin-svelte@3.5.1: - resolution: {integrity: sha512-65+fr5+cgIKWKiqM1Doum4uX6bY8iFCdztvvp2RcF+AJoieaw9kJOFMNcJo/bkmKYsxFaM9OsVZK/gWauG/5mg==} - peerDependencies: - prettier: ^3.0.0 - svelte: ^3.2.0 || ^4.0.0-next.0 || ^5.0.0-next.0 - - prettier@3.8.1: - resolution: {integrity: sha512-UOnG6LftzbdaHZcKoPFtOcCKztrQ57WkHDeRD9t/PTQtmT0NHSeWWepj6pS0z/N7+08BHFDQVUrfmfMRcZwbMg==} - engines: {node: '>=14'} - hasBin: true - - pretty-bytes@6.1.1: - resolution: {integrity: sha512-mQUvGU6aUFQ+rNvTIAcZuWGRT9a6f6Yrg9bHs4ImKF+HZCEK+plBvnAZYSIQztknZF2qnzNtr6F8s0+IuptdlQ==} - engines: {node: ^14.13.1 || >=16.0.0} - - pretty-format@27.5.1: - resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} - engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - - progress@2.0.3: - resolution: {integrity: sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==} - engines: {node: '>=0.4.0'} - - property-information@7.1.0: - resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} - - proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - - punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - - react-is@17.0.2: - resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - - readdirp@3.6.0: - resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} - engines: {node: '>=8.10.0'} - - readdirp@4.1.2: - resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} - engines: {node: '>= 14.18.0'} - - recast@0.23.11: - resolution: {integrity: sha512-YTUo+Flmw4ZXiWfQKGcwwc11KnoRAYgzAE2E7mXKCjSviTKShtxBsN6YUUBB2gtaBzKzeKunxhUwNHQuRryhWA==} - engines: {node: '>= 4'} - - redent@3.0.0: - resolution: {integrity: sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==} - engines: {node: '>=8'} - - regex-recursion@5.1.1: - resolution: {integrity: sha512-ae7SBCbzVNrIjgSbh7wMznPcQel1DNlDtzensnFxpiNpXt1U2ju/bHugH422r+4LAVS1FpW1YCwilmnNsjum9w==} - - regex-utilities@2.3.0: - resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} - - regex@5.1.1: - resolution: {integrity: sha512-dN5I359AVGPnwzJm2jN1k0W9LPZ+ePvoOeVMMfqIMFz53sSwXkxaJoxr50ptnsC771lK95BnTrVSZxq0b9yCGw==} - - regexp.prototype.flags@1.5.4: - resolution: {integrity: sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==} - engines: {node: '>= 0.4'} - - remarkable@2.0.1: - resolution: {integrity: sha512-YJyMcOH5lrR+kZdmB0aJJ4+93bEojRZ1HGDn9Eagu6ibg7aVZhc3OWbbShRid+Q5eAfsEqWxpe+g5W5nYNfNiA==} - engines: {node: '>= 6.0.0'} - hasBin: true - - require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - - require-in-the-middle@7.5.2: - resolution: {integrity: sha512-gAZ+kLqBdHarXB64XpAe2VCjB7rIRv+mU8tfRWziHRJ5umKsIHN2tLLv6EtMw7WCdP19S0ERVMldNvxYCHnhSQ==} - engines: {node: '>=8.6.0'} - - resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} - engines: {node: '>= 0.4'} - hasBin: true - - robust-predicates@3.0.3: - resolution: {integrity: sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==} - - rollup@4.60.0: - resolution: {integrity: sha512-yqjxruMGBQJ2gG4HtjZtAfXArHomazDHoFwFFmZZl0r7Pdo7qCIXKqKHZc8yeoMgzJJ+pO6pEEHa+V7uzWlrAQ==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true - - rrweb-cssom@0.8.0: - resolution: {integrity: sha512-guoltQEx+9aMf2gDZ0s62EcV8lsXR+0w8915TC3ITdn2YueuNjdAYh/levpU9nFaoChh9RUS5ZdQMrKfVEN9tw==} - - rw@1.3.3: - resolution: {integrity: sha512-PdhdWy89SiZogBLaw42zdeqtRJ//zFd2PgQavcICDUgJT5oW10QCRKbJ6bg4r0/UY2M6BWd5tkxuGFRvCkgfHQ==} - - sade@1.8.1: - resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} - engines: {node: '>=6'} - - safe-regex-test@1.1.0: - resolution: {integrity: sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==} - engines: {node: '>= 0.4'} - - safer-buffer@2.1.2: - resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - - sass@1.98.0: - resolution: {integrity: sha512-+4N/u9dZ4PrgzGgPlKnaaRQx64RO0JBKs9sDhQ2pLgN6JQZ25uPQZKQYaBJU48Kd5BxgXoJ4e09Dq7nMcOUW3A==} - engines: {node: '>=14.0.0'} - hasBin: true - - saxes@6.0.0: - resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} - engines: {node: '>=v12.22.7'} - - secure-json-parse@2.7.0: - resolution: {integrity: sha512-6aU+Rwsezw7VR8/nyvKTx8QpWH9FrcYiXXlqC4z5d5XQBDRqtbfsRjnwGyqbi3gddNtWHuEk9OANUotL26qKUw==} - - semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - - semver@7.7.4: - resolution: {integrity: sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==} - engines: {node: '>=10'} - hasBin: true - - set-cookie-parser@3.1.0: - resolution: {integrity: sha512-kjnC1DXBHcxaOaOXBHBeRtltsDG2nUiUni+jP92M9gYdW12rsmx92UsfpH7o5tDRs7I1ZZPSQJQGv3UaRfCiuw==} - - set-function-length@1.2.2: - resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} - engines: {node: '>= 0.4'} - - set-function-name@2.0.2: - resolution: {integrity: sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==} - engines: {node: '>= 0.4'} - - shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} - - shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - - shiki@1.29.2: - resolution: {integrity: sha512-njXuliz/cP+67jU2hukkxCNuH1yUi4QfdZZY+sMr5PPrIyXSu5iTb/qYC4BiWWB0vZ+7TbdvYUCeL23zpwCfbg==} - - shimmer@1.2.1: - resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} - engines: {node: '>= 0.4'} - - side-channel-map@1.0.1: - resolution: {integrity: sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==} - engines: {node: '>= 0.4'} - - side-channel-weakmap@1.0.2: - resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} - engines: {node: '>= 0.4'} - - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} - engines: {node: '>= 0.4'} - - siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - - sirv@3.0.2: - resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} - engines: {node: '>=18'} - - sorcery@1.0.0: - resolution: {integrity: sha512-5ay9oJE+7sNmhzl3YNG18jEEEf4AOQCM/FAqR5wMmzqd1FtRorFbJXn3w3SKOhbiQaVgHM+Q1lszZspjri7bpA==} - hasBin: true - - source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} - - source-map@0.6.1: - resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} - engines: {node: '>=0.10.0'} - - space-separated-tokens@2.0.2: - resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - - sprintf-js@1.0.3: - resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} - - stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - - stop-iteration-iterator@1.1.0: - resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} - engines: {node: '>= 0.4'} - - stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} - - strip-indent@3.0.0: - resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} - engines: {node: '>=8'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - - strip-literal@3.1.0: - resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} - - style-value-types@5.1.2: - resolution: {integrity: sha512-Vs9fNreYF9j6W2VvuDTP7kepALi7sk0xtk2Tu8Yxi9UoajJdEVpNpCov0HsLTqXvNGKX+Uv09pkozVITi1jf3Q==} - - supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} - - supports-preserve-symlinks-flag@1.0.0: - resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} - engines: {node: '>= 0.4'} - - svelte-check@4.4.5: - resolution: {integrity: sha512-1bSwIRCvvmSHrlK52fOlZmVtUZgil43jNL/2H18pRpa+eQjzGt6e3zayxhp1S7GajPFKNM/2PMCG+DZFHlG9fw==} - engines: {node: '>= 18.0.0'} - hasBin: true - peerDependencies: - svelte: ^4.0.0 || ^5.0.0-next.0 - typescript: '>=5.0.0' - - svelte-confetti@1.4.0: - resolution: {integrity: sha512-B0woNwpsFGwhkEoP48BIDQgvW0bMxPhavLVD+E+tsTWevlpr1aiz1S2wA8ArIXX957BiaZWHRHKmI5/pFRDbdg==} - peerDependencies: - svelte: ^4.0.0 - - svelte-eslint-parser@1.6.0: - resolution: {integrity: sha512-qoB1ehychT6OxEtQAqc/guSqLS20SlA53Uijl7x375s8nlUT0lb9ol/gzraEEatQwsyPTJo87s2CmKL9Xab+Uw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0, pnpm: 10.30.3} - peerDependencies: - svelte: ^3.37.0 || ^4.0.0 || ^5.0.0 - peerDependenciesMeta: - svelte: - optional: true - - svelte-motion@0.12.2: - resolution: {integrity: sha512-7RrdRz9iVP55B9HT/C0hYW3pyrKlF61kAby/AkDtOAP0uHFQDrfd0qQetDC81cEsK9b40jt+jfcqSAXcA7LPEw==} - peerDependencies: - svelte: '>=3.35.0 || ^4.0.0 || ^5.0.0 || ^5.0.0-next.0' - - svelte-preprocess@6.0.3: - resolution: {integrity: sha512-PLG2k05qHdhmRG7zR/dyo5qKvakhm8IJ+hD2eFRQmMLHp7X3eJnjeupUtvuRpbNiF31RjVw45W+abDwHEmP5OA==} - engines: {node: '>= 18.0.0'} - peerDependencies: - '@babel/core': ^7.10.2 - coffeescript: ^2.5.1 - less: ^3.11.3 || ^4.0.0 - postcss: ^7 || ^8 - postcss-load-config: '>=3' - pug: ^3.0.0 - sass: ^1.26.8 - stylus: '>=0.55' - sugarss: ^2.0.0 || ^3.0.0 || ^4.0.0 - svelte: ^4.0.0 || ^5.0.0-next.100 || ^5.0.0 - typescript: ^5.0.0 - peerDependenciesMeta: - '@babel/core': - optional: true - coffeescript: - optional: true - less: - optional: true - postcss: - optional: true - postcss-load-config: - optional: true - pug: - optional: true - sass: - optional: true - stylus: - optional: true - sugarss: - optional: true - typescript: - optional: true - - svelte-sequential-preprocessor@2.0.3: - resolution: {integrity: sha512-AAtm4gwbB6Mj5SFZUDnmZQl2g1Qh7q1mU1MAqnGSRusRmDK20RiNdLkqfk/Mz5SbJS7zMj46JPFdkz+KTSkejw==} - engines: {node: '>=18'} - - svelte-sonner@0.3.28: - resolution: {integrity: sha512-K3AmlySeFifF/cKgsYNv5uXqMVNln0NBAacOYgmkQStLa/UoU0LhfAACU6Gr+YYC8bOCHdVmFNoKuDbMEsppJg==} - peerDependencies: - svelte: ^3.0.0 || ^4.0.0 || ^5.0.0-next.1 - - svelte@5.55.0: - resolution: {integrity: sha512-SThllKq6TRMBwPtat7ASnm/9CDXnIhBR0NPGw0ujn2DVYx9rVwsPZxDaDQcYGdUz/3BYVsCzdq7pZarRQoGvtw==} - engines: {node: '>=18'} - - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - - tabbable@6.4.0: - resolution: {integrity: sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==} - - the-new-css-reset@1.11.3: - resolution: {integrity: sha512-61SB81vu9foUyEIqoU1CeqxrdlsVjJojj/CBXoG8BdvlKFsllB0Rza63DblnRqH+3uttPj3FGWo7+c9nu7MT+A==} - - three-instanced-uniforms-mesh@0.52.4: - resolution: {integrity: sha512-YwDBy05hfKZQtU+Rp0KyDf9yH4GxfhxMbVt9OYruxdgLfPwmDG5oAbGoW0DrKtKZSM3BfFcCiejiOHCjFBTeng==} - peerDependencies: - three: '>=0.125.0' - - three-mesh-bvh@0.9.9: - resolution: {integrity: sha512-FJKitcjvbALmeQRK+Sc+nLGorCpkrZBrbgJZFzhdyWboak37DZikn46hvQkNqSbJPm227ahYmS6k3N/GXaAyXw==} - peerDependencies: - three: '>= 0.159.0' - - three-perf@1.0.11: - resolution: {integrity: sha512-OgBpZjwL+csQKGKZjpkH/QHdbGFMxqngMbSEJeSnVNfXDYd6On7WHNv/GhUZH4YxIpNMwMahBWrNnsJvnbSJHQ==} - peerDependencies: - three: '>=0.170' - - three-viewport-gizmo@2.2.0: - resolution: {integrity: sha512-Jo9Liur1rUmdKk75FZumLU/+hbF+RtJHi1qsKZpntjKlCYScK6tjbYoqvJ9M+IJphrlQJF5oReFW7Sambh0N4Q==} - peerDependencies: - three: '>=0.162.0 <1.0.0' - - three@0.181.2: - resolution: {integrity: sha512-k/CjiZ80bYss6Qs7/ex1TBlPD11whT9oKfT8oTGiHa34W4JRd1NiH/Tr1DbHWQ2/vMUypxksLnF2CfmlmM5XFQ==} - - tiny-glob@0.2.9: - resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} - - tiny-invariant@1.3.3: - resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - - tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} - - tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} - - tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} - - tinyspy@4.0.4: - resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} - engines: {node: '>=14.0.0'} - - tippy.js@6.3.7: - resolution: {integrity: sha512-E1d3oP2emgJ9dRQZdf3Kkn0qJgI6ZLpyS5z6ZkY1DF3kaQaBsGZsndEpHwx+eC+tYM41HaSNvNtLx8tU57FzTQ==} - - tldts-core@6.1.86: - resolution: {integrity: sha512-Je6p7pkk+KMzMv2XXKmAE3McmolOQFdxkKw0R8EYNr7sELW46JqnNeTX8ybPiQgvg1ymCoF8LXs5fzFaZvJPTA==} - - tldts-core@7.0.27: - resolution: {integrity: sha512-YQ7uPjgWUibIK6DW5lrKujGwUKhLevU4hcGbP5O6TcIUb+oTjJYJVWPS4nZsIHrEEEG6myk/oqAJUEQmpZrHsg==} - - tldts@6.1.86: - resolution: {integrity: sha512-WMi/OQ2axVTf/ykqCQgXiIct+mSQDFdH2fkwhPwgEwvJ1kSzZRiinb0zF2Xb8u4+OqPChmyI6MEu4EezNJz+FQ==} - hasBin: true - - tldts@7.0.27: - resolution: {integrity: sha512-I4FZcVFcqCRuT0ph6dCDpPuO4Xgzvh+spkcTr1gK7peIvxWauoloVO0vuy1FQnijT63ss6AsHB6+OIM4aXHbPg==} - hasBin: true - - to-regex-range@5.0.1: - resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} - engines: {node: '>=8.0'} - - totalist@3.0.1: - resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} - engines: {node: '>=6'} - - tough-cookie@5.1.2: - resolution: {integrity: sha512-FVDYdxtnj0G6Qm/DhNPSb8Ju59ULcup3tuJxkFb5K8Bv2pUXILbf0xZWU8PX8Ov19OXljbUyveOFwRMwkXzO+A==} - engines: {node: '>=16'} - - tr46@0.0.3: - resolution: {integrity: sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==} - - tr46@5.1.1: - resolution: {integrity: sha512-hdF5ZgjTqgAntKkklYw0R03MG2x/bSzTtkxmIRw/sTNV8YXsCJ1tfLAX23lhxhHJlEf3CRCOCGGWw3vI3GaSPw==} - engines: {node: '>=18'} - - trim-lines@3.0.1: - resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - - troika-three-text@0.52.4: - resolution: {integrity: sha512-V50EwcYGruV5rUZ9F4aNsrytGdKcXKALjEtQXIOBfhVoZU9VAqZNIoGQ3TMiooVqFAbR1w15T+f+8gkzoFzawg==} - peerDependencies: - three: '>=0.125.0' - - troika-three-utils@0.52.4: - resolution: {integrity: sha512-NORAStSVa/BDiG52Mfudk4j1FG4jC4ILutB3foPnfGbOeIs9+G5vZLa0pnmnaftZUGm4UwSoqEpWdqvC7zms3A==} - peerDependencies: - three: '>=0.125.0' - - troika-worker-utils@0.52.0: - resolution: {integrity: sha512-W1CpvTHykaPH5brv5VHLfQo9D1OYuo0cSBEUQFFT/nBUzM8iD6Lq2/tgG/f1OelbAS1WtaTPQzE5uM49egnngw==} - - ts-api-utils@2.5.0: - resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' - - tslib@2.3.0: - resolution: {integrity: sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==} - - tslib@2.4.0: - resolution: {integrity: sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ==} - - tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} - - tweakpane@3.1.10: - resolution: {integrity: sha512-rqwnl/pUa7+inhI2E9ayGTqqP0EPOOn/wVvSWjZsRbZUItzNShny7pzwL3hVlaN4m9t/aZhsP0aFQ9U5VVR2VQ==} - - type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} - - typescript-eslint@8.57.2: - resolution: {integrity: sha512-VEPQ0iPgWO/sBaZOU1xo4nuNdODVOajPnTIbog2GKYr31nIlZ0fWPoCQgGfF3ETyBl1vn63F/p50Um9Z4J8O8A==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: '>=4.8.4 <6.0.0' - - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true - - undici-types@7.18.2: - resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - - unist-util-is@6.0.1: - resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} - - unist-util-position@5.0.0: - resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} - - unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} - - unist-util-visit-parents@6.0.2: - resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} - - unist-util-visit@5.1.0: - resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} - - unplugin@1.0.1: - resolution: {integrity: sha512-aqrHaVBWW1JVKBHmGo33T5TxeL0qWzfvjWokObHA9bYmN7eNDkwOxmLjhioHl9878qDFMAaT51XNroRyuz7WxA==} - - update-browserslist-db@1.2.3: - resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' - - uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - - util-deprecate@1.0.2: - resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - - vfile-message@4.0.3: - resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} - - vfile@6.0.3: - resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} - - vite-node@3.2.4: - resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - - vite@7.3.1: - resolution: {integrity: sha512-w+N7Hifpc3gRjZ63vYBXA56dvvRlNWRczTdmCBBa+CotUzAPf5b7YMdMR/8CQoeYE5LX3W4wj6RYTgonm1b9DA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - 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 - - vitefu@1.1.2: - resolution: {integrity: sha512-zpKATdUbzbsycPFBN71nS2uzBUQiVnFoOrr2rvqv34S1lcAgMKKkjWleLGeiJlZ8lwCXvtWaRn7R3ZC16SYRuw==} - peerDependencies: - vite: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-beta.0 - peerDependenciesMeta: - vite: - optional: true - - vitest@3.2.4: - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 - 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 - - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} - - webgl-sdf-generator@1.1.1: - resolution: {integrity: sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA==} - - webidl-conversions@3.0.1: - resolution: {integrity: sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==} - - webidl-conversions@7.0.0: - resolution: {integrity: sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==} - engines: {node: '>=12'} - - webpack-sources@3.3.4: - resolution: {integrity: sha512-7tP1PdV4vF+lYPnkMR0jMY5/la2ub5Fc/8VQrrU+lXkiM6C4TjVfGw7iKfyhnTQOsD+6Q/iKw0eFciziRgD58Q==} - engines: {node: '>=10.13.0'} - - webpack-virtual-modules@0.5.0: - resolution: {integrity: sha512-kyDivFZ7ZM0BVOUteVbDFhlRt7Ah/CSPwJdi8hBpkK7QLumUqdLtVfm/PX/hkcnrvr0i77fO5+TjZ94Pe+C9iw==} - - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - deprecated: Use @exodus/bytes instead for a more spec-conformant and faster implementation - - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-url@14.2.0: - resolution: {integrity: sha512-De72GdQZzNTUBBChsXueQUnPKDkg/5A5zp7pFDuQAj5UFoENpiACU0wlCvzpAGnTkj++ihpKwKyYewn/XNUbKw==} - engines: {node: '>=18'} - - whatwg-url@5.0.0: - resolution: {integrity: sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==} - - which-boxed-primitive@1.1.1: - resolution: {integrity: sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==} - engines: {node: '>= 0.4'} - - which-collection@1.0.2: - resolution: {integrity: sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==} - engines: {node: '>= 0.4'} - - which-typed-array@1.1.20: - resolution: {integrity: sha512-LYfpUkmqwl0h9A2HL09Mms427Q1RZWuOHsukfVcKRq9q95iQxdw0ix1JQrqbcDR9PH1QDwf5Qo8OZb5lksZ8Xg==} - engines: {node: '>= 0.4'} - - which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true - - why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true - - word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - - ws@8.20.0: - resolution: {integrity: sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==} - 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 - - xml-name-validator@5.0.0: - resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} - engines: {node: '>=18'} - - xmlchars@2.2.0: - resolution: {integrity: sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==} - - xtend@4.0.2: - resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} - engines: {node: '>=0.4'} - - yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - - yaml@1.10.3: - resolution: {integrity: sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==} - engines: {node: '>= 6'} - - yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - - zimmerframe@1.1.4: - resolution: {integrity: sha512-B58NGBEoc8Y9MWWCQGl/gq9xBCe4IiKM0a2x7GZdQKOW5Exr8S1W24J6OgM1njK8xCRGvAJIL/MxXHf6SkmQKQ==} - - zod-to-json-schema@3.25.2: - resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} - peerDependencies: - zod: ^3.25.28 || ^4 - - zod@3.25.76: - resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - - zrender@5.6.1: - resolution: {integrity: sha512-OFXkDJKcrlx5su2XbzJvj/34Q3m6PvyCZkVPHGYpcCJ52ek4U/ymZyfuV1nKE23AyBJ51E/6Yr0mhZ7xGTO4ag==} - - zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - -snapshots: - - '@adobe/css-tools@4.4.4': {} - - '@ai-sdk/gateway@3.0.83(zod@3.25.76)': - dependencies: - '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.21(zod@3.25.76) - '@vercel/oidc': 3.1.0 - zod: 3.25.76 - - '@ai-sdk/provider-utils@2.1.13(zod@3.25.76)': - dependencies: - '@ai-sdk/provider': 1.0.11 - eventsource-parser: 3.0.6 - nanoid: 3.3.11 - secure-json-parse: 2.7.0 - optionalDependencies: - zod: 3.25.76 - - '@ai-sdk/provider-utils@4.0.21(zod@3.25.76)': - dependencies: - '@ai-sdk/provider': 3.0.8 - '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.0.6 - zod: 3.25.76 - - '@ai-sdk/provider@1.0.11': - dependencies: - json-schema: 0.4.0 - - '@ai-sdk/provider@3.0.8': - dependencies: - json-schema: 0.4.0 - - '@ai-sdk/svelte@1.1.24(svelte@5.55.0)(zod@3.25.76)': - dependencies: - '@ai-sdk/provider-utils': 2.1.13(zod@3.25.76) - '@ai-sdk/ui-utils': 1.1.19(zod@3.25.76) - optionalDependencies: - svelte: 5.55.0 - transitivePeerDependencies: - - zod - - '@ai-sdk/ui-utils@1.1.19(zod@3.25.76)': - dependencies: - '@ai-sdk/provider': 1.0.11 - '@ai-sdk/provider-utils': 2.1.13(zod@3.25.76) - zod-to-json-schema: 3.25.2(zod@3.25.76) - optionalDependencies: - zod: 3.25.76 - - '@analytics/cookie-utils@0.2.14': - dependencies: - '@analytics/global-storage-utils': 0.1.9 - - '@analytics/core@0.13.2(@types/dlv@1.1.5)': - dependencies: - '@analytics/global-storage-utils': 0.1.9 - '@analytics/type-utils': 0.6.4 - analytics-utils: 1.1.1(@types/dlv@1.1.5) - transitivePeerDependencies: - - '@types/dlv' - - '@analytics/global-storage-utils@0.1.9': - dependencies: - '@analytics/type-utils': 0.6.4 - - '@analytics/localstorage-utils@0.1.12': - dependencies: - '@analytics/global-storage-utils': 0.1.9 - - '@analytics/session-storage-utils@0.0.9': - dependencies: - '@analytics/global-storage-utils': 0.1.9 - - '@analytics/storage-utils@0.4.4': - dependencies: - '@analytics/cookie-utils': 0.2.14 - '@analytics/global-storage-utils': 0.1.9 - '@analytics/localstorage-utils': 0.1.12 - '@analytics/session-storage-utils': 0.0.9 - '@analytics/type-utils': 0.6.4 - - '@analytics/type-utils@0.6.4': {} - - '@appwrite.io/console@https://pkg.vc/-/@appwrite/@appwrite.io/console@67539a6': - dependencies: - json-bigint: 1.0.0 - - '@appwrite.io/pink-icons-svelte@2.0.0-RC.1(svelte@5.55.0)': - dependencies: - svelte: 5.55.0 - - '@appwrite.io/pink-icons-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-icons-svelte@bfe7ce3(svelte@5.55.0)': - dependencies: - svelte: 5.55.0 - - '@appwrite.io/pink-icons@0.25.0': {} - - '@appwrite.io/pink-icons@1.0.0': {} - - '@appwrite.io/pink-legacy@1.0.3': - dependencies: - '@appwrite.io/pink-icons': 1.0.0 - the-new-css-reset: 1.11.3 - - '@appwrite.io/pink-svelte@https://pkg.vc/-/@appwrite/@appwrite.io/pink-svelte@bfe7ce3(svelte@5.55.0)': - dependencies: - '@appwrite.io/pink-icons-svelte': 2.0.0-RC.1(svelte@5.55.0) - '@floating-ui/dom': 1.7.6 - '@melt-ui/pp': 0.3.2(@melt-ui/svelte@0.86.6(svelte@5.55.0))(svelte@5.55.0) - '@melt-ui/svelte': 0.86.6(svelte@5.55.0) - '@tanstack/svelte-virtual': 3.13.23(svelte@5.55.0) - ansicolor: 2.0.3 - d3: 7.9.0 - fuse.js: 7.1.0 - pretty-bytes: 6.1.1 - shiki: 1.29.2 - svelte: 5.55.0 - svelte-motion: 0.12.2(svelte@5.55.0) - svelte-sonner: 0.3.28(svelte@5.55.0) - - '@asamuzakjp/css-color@3.2.0': - dependencies: - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-color-parser': 3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - lru-cache: 10.4.3 - - '@babel/code-frame@7.29.0': - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - - '@babel/compat-data@7.29.0': {} - - '@babel/core@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-compilation-targets': 7.28.6 - '@babel/helper-module-transforms': 7.28.6(@babel/core@7.29.0) - '@babel/helpers': 7.29.2 - '@babel/parser': 7.29.2 - '@babel/template': 7.28.6 - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3 - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - - '@babel/generator@7.29.1': - dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - - '@babel/helper-compilation-targets@7.28.6': - dependencies: - '@babel/compat-data': 7.29.0 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 - lru-cache: 5.1.1 - semver: 6.3.1 - - '@babel/helper-globals@7.28.0': {} - - '@babel/helper-module-imports@7.28.6': - dependencies: - '@babel/traverse': 7.29.0 - '@babel/types': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-module-transforms@7.28.6(@babel/core@7.29.0)': - dependencies: - '@babel/core': 7.29.0 - '@babel/helper-module-imports': 7.28.6 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.29.0 - transitivePeerDependencies: - - supports-color - - '@babel/helper-string-parser@7.27.1': {} - - '@babel/helper-validator-identifier@7.28.5': {} - - '@babel/helper-validator-option@7.27.1': {} - - '@babel/helpers@7.29.2': - dependencies: - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - - '@babel/parser@7.29.2': - dependencies: - '@babel/types': 7.29.0 - - '@babel/runtime@7.29.2': {} - - '@babel/template@7.28.6': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - - '@babel/traverse@7.29.0': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/generator': 7.29.1 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.29.2 - '@babel/template': 7.28.6 - '@babel/types': 7.29.0 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - '@babel/types@7.29.0': - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - - '@csstools/color-helpers@5.1.0': {} - - '@csstools/css-calc@2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - - '@csstools/css-color-parser@3.1.0(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/color-helpers': 5.1.0 - '@csstools/css-calc': 2.1.4(@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4))(@csstools/css-tokenizer@3.0.4) - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 - - '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': - dependencies: - '@csstools/css-tokenizer': 3.0.4 - - '@csstools/css-tokenizer@3.0.4': {} - - '@dimforge/rapier3d-compat@0.12.0': {} - - '@esbuild/aix-ppc64@0.27.4': - optional: true - - '@esbuild/android-arm64@0.27.4': - optional: true - - '@esbuild/android-arm@0.27.4': - optional: true - - '@esbuild/android-x64@0.27.4': - optional: true - - '@esbuild/darwin-arm64@0.27.4': - optional: true - - '@esbuild/darwin-x64@0.27.4': - optional: true - - '@esbuild/freebsd-arm64@0.27.4': - optional: true - - '@esbuild/freebsd-x64@0.27.4': - optional: true - - '@esbuild/linux-arm64@0.27.4': - optional: true - - '@esbuild/linux-arm@0.27.4': - optional: true - - '@esbuild/linux-ia32@0.27.4': - optional: true - - '@esbuild/linux-loong64@0.27.4': - optional: true - - '@esbuild/linux-mips64el@0.27.4': - optional: true - - '@esbuild/linux-ppc64@0.27.4': - optional: true - - '@esbuild/linux-riscv64@0.27.4': - optional: true - - '@esbuild/linux-s390x@0.27.4': - optional: true - - '@esbuild/linux-x64@0.27.4': - optional: true - - '@esbuild/netbsd-arm64@0.27.4': - optional: true - - '@esbuild/netbsd-x64@0.27.4': - optional: true - - '@esbuild/openbsd-arm64@0.27.4': - optional: true - - '@esbuild/openbsd-x64@0.27.4': - optional: true - - '@esbuild/openharmony-arm64@0.27.4': - optional: true - - '@esbuild/sunos-x64@0.27.4': - optional: true - - '@esbuild/win32-arm64@0.27.4': - optional: true - - '@esbuild/win32-ia32@0.27.4': - optional: true - - '@esbuild/win32-x64@0.27.4': - optional: true - - '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4)': - dependencies: - eslint: 9.39.4 - eslint-visitor-keys: 3.4.3 - - '@eslint-community/regexpp@4.12.2': {} - - '@eslint/compat@1.4.1(eslint@9.39.4)': - dependencies: - '@eslint/core': 0.17.0 - optionalDependencies: - eslint: 9.39.4 - - '@eslint/config-array@0.21.2': - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.5 - transitivePeerDependencies: - - supports-color - - '@eslint/config-helpers@0.4.2': - dependencies: - '@eslint/core': 0.17.0 - - '@eslint/core@0.17.0': - dependencies: - '@types/json-schema': 7.0.15 - - '@eslint/eslintrc@3.3.5': - dependencies: - ajv: 6.14.0 - debug: 4.4.3 - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.5 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.4': {} - - '@eslint/object-schema@2.1.7': {} - - '@eslint/plugin-kit@0.4.1': - dependencies: - '@eslint/core': 0.17.0 - levn: 0.4.1 - - '@faker-js/faker@9.9.0': {} - - '@floating-ui/core@1.7.5': - dependencies: - '@floating-ui/utils': 0.2.11 - - '@floating-ui/dom@1.7.6': - dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/utils': 0.2.11 - - '@floating-ui/utils@0.2.11': {} - - '@humanfs/core@0.19.1': {} - - '@humanfs/node@0.16.7': - dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.4.3 - - '@humanwhocodes/module-importer@1.0.1': {} - - '@humanwhocodes/retry@0.4.3': {} - - '@internationalized/date@3.12.0': - dependencies: - '@swc/helpers': 0.5.20 - - '@jridgewell/gen-mapping@0.3.13': - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/remapping@2.3.5': - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - - '@jridgewell/resolve-uri@3.1.2': {} - - '@jridgewell/sourcemap-codec@1.5.5': {} - - '@jridgewell/trace-mapping@0.3.31': - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - - '@melt-ui/pp@0.3.2(@melt-ui/svelte@0.86.6(svelte@5.55.0))(svelte@5.55.0)': - dependencies: - '@melt-ui/svelte': 0.86.6(svelte@5.55.0) - estree-walker: 3.0.3 - magic-string: 0.30.21 - svelte: 5.55.0 - - '@melt-ui/svelte@0.86.6(svelte@5.55.0)': - dependencies: - '@floating-ui/core': 1.7.5 - '@floating-ui/dom': 1.7.6 - '@internationalized/date': 3.12.0 - dequal: 2.0.3 - focus-trap: 7.8.0 - nanoid: 5.1.7 - svelte: 5.55.0 - - '@opentelemetry/api-logs@0.53.0': - dependencies: - '@opentelemetry/api': 1.9.1 - - '@opentelemetry/api-logs@0.57.1': - dependencies: - '@opentelemetry/api': 1.9.1 - - '@opentelemetry/api-logs@0.57.2': - dependencies: - '@opentelemetry/api': 1.9.1 - - '@opentelemetry/api@1.9.0': {} - - '@opentelemetry/api@1.9.1': {} - - '@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - - '@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/semantic-conventions': 1.28.0 - - '@opentelemetry/instrumentation-amqplib@0.46.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-connect@0.43.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@types/connect': 3.4.36 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-dataloader@0.16.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-express@0.47.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-fastify@0.44.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-fs@0.19.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-generic-pool@0.43.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-graphql@0.47.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-hapi@0.45.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-http@0.57.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.28.0 - forwarded-parse: 2.1.2 - semver: 7.7.4 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-ioredis@0.47.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/redis-common': 0.36.2 - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-kafkajs@0.7.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-knex@0.44.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-koa@0.47.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-lru-memoizer@0.44.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-mongodb@0.51.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-mongoose@0.46.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-mysql2@0.45.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.1) - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-mysql@0.45.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@types/mysql': 2.15.26 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-nestjs-core@0.44.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-pg@0.50.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.27.0 - '@opentelemetry/sql-common': 0.40.1(@opentelemetry/api@1.9.1) - '@types/pg': 8.6.1 - '@types/pg-pool': 2.0.6 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-redis-4@0.46.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/redis-common': 0.36.2 - '@opentelemetry/semantic-conventions': 1.40.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-tedious@0.18.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@types/tedious': 4.0.14 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-undici@0.10.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation@0.53.0(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.53.0 - '@types/shimmer': 1.2.0 - import-in-the-middle: 1.15.0 - require-in-the-middle: 7.5.2 - semver: 7.7.4 - shimmer: 1.2.1 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation@0.57.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.57.1 - '@types/shimmer': 1.2.0 - import-in-the-middle: 1.15.0 - require-in-the-middle: 7.5.2 - semver: 7.7.4 - shimmer: 1.2.1 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/api-logs': 0.57.2 - '@types/shimmer': 1.2.0 - import-in-the-middle: 1.15.0 - require-in-the-middle: 7.5.2 - semver: 7.7.4 - shimmer: 1.2.1 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/redis-common@0.36.2': {} - - '@opentelemetry/resources@1.30.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.28.0 - - '@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.28.0 - - '@opentelemetry/semantic-conventions@1.27.0': {} - - '@opentelemetry/semantic-conventions@1.28.0': {} - - '@opentelemetry/semantic-conventions@1.40.0': {} - - '@opentelemetry/sql-common@0.40.1(@opentelemetry/api@1.9.1)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - - '@parcel/watcher-android-arm64@2.5.6': - optional: true - - '@parcel/watcher-darwin-arm64@2.5.6': - optional: true - - '@parcel/watcher-darwin-x64@2.5.6': - optional: true - - '@parcel/watcher-freebsd-x64@2.5.6': - optional: true - - '@parcel/watcher-linux-arm-glibc@2.5.6': - optional: true - - '@parcel/watcher-linux-arm-musl@2.5.6': - optional: true - - '@parcel/watcher-linux-arm64-glibc@2.5.6': - optional: true - - '@parcel/watcher-linux-arm64-musl@2.5.6': - optional: true - - '@parcel/watcher-linux-x64-glibc@2.5.6': - optional: true - - '@parcel/watcher-linux-x64-musl@2.5.6': - optional: true - - '@parcel/watcher-win32-arm64@2.5.6': - optional: true - - '@parcel/watcher-win32-ia32@2.5.6': - optional: true - - '@parcel/watcher-win32-x64@2.5.6': - optional: true - - '@parcel/watcher@2.5.6': - dependencies: - detect-libc: 2.1.2 - is-glob: 4.0.3 - node-addon-api: 7.1.1 - picomatch: 4.0.4 - optionalDependencies: - '@parcel/watcher-android-arm64': 2.5.6 - '@parcel/watcher-darwin-arm64': 2.5.6 - '@parcel/watcher-darwin-x64': 2.5.6 - '@parcel/watcher-freebsd-x64': 2.5.6 - '@parcel/watcher-linux-arm-glibc': 2.5.6 - '@parcel/watcher-linux-arm-musl': 2.5.6 - '@parcel/watcher-linux-arm64-glibc': 2.5.6 - '@parcel/watcher-linux-arm64-musl': 2.5.6 - '@parcel/watcher-linux-x64-glibc': 2.5.6 - '@parcel/watcher-linux-x64-musl': 2.5.6 - '@parcel/watcher-win32-arm64': 2.5.6 - '@parcel/watcher-win32-ia32': 2.5.6 - '@parcel/watcher-win32-x64': 2.5.6 - optional: true - - '@plausible-analytics/tracker@0.4.4': {} - - '@playwright/test@1.58.2': - dependencies: - playwright: 1.58.2 - - '@polka/url@1.0.0-next.29': {} - - '@popperjs/core@2.11.8': {} - - '@prisma/instrumentation@5.22.0': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation': 0.53.0(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) - transitivePeerDependencies: - - supports-color - - '@rollup/rollup-android-arm-eabi@4.60.0': - optional: true - - '@rollup/rollup-android-arm64@4.60.0': - optional: true - - '@rollup/rollup-darwin-arm64@4.60.0': - optional: true - - '@rollup/rollup-darwin-x64@4.60.0': - optional: true - - '@rollup/rollup-freebsd-arm64@4.60.0': - optional: true - - '@rollup/rollup-freebsd-x64@4.60.0': - optional: true - - '@rollup/rollup-linux-arm-gnueabihf@4.60.0': - optional: true - - '@rollup/rollup-linux-arm-musleabihf@4.60.0': - optional: true - - '@rollup/rollup-linux-arm64-gnu@4.60.0': - optional: true - - '@rollup/rollup-linux-arm64-musl@4.60.0': - optional: true - - '@rollup/rollup-linux-loong64-gnu@4.60.0': - optional: true - - '@rollup/rollup-linux-loong64-musl@4.60.0': - optional: true - - '@rollup/rollup-linux-ppc64-gnu@4.60.0': - optional: true - - '@rollup/rollup-linux-ppc64-musl@4.60.0': - optional: true - - '@rollup/rollup-linux-riscv64-gnu@4.60.0': - optional: true - - '@rollup/rollup-linux-riscv64-musl@4.60.0': - optional: true - - '@rollup/rollup-linux-s390x-gnu@4.60.0': - optional: true - - '@rollup/rollup-linux-x64-gnu@4.60.0': - optional: true - - '@rollup/rollup-linux-x64-musl@4.60.0': - optional: true - - '@rollup/rollup-openbsd-x64@4.60.0': - optional: true - - '@rollup/rollup-openharmony-arm64@4.60.0': - optional: true - - '@rollup/rollup-win32-arm64-msvc@4.60.0': - optional: true - - '@rollup/rollup-win32-ia32-msvc@4.60.0': - optional: true - - '@rollup/rollup-win32-x64-gnu@4.60.0': - optional: true - - '@rollup/rollup-win32-x64-msvc@4.60.0': - optional: true - - '@sentry-internal/browser-utils@8.55.1': - dependencies: - '@sentry/core': 8.55.1 - - '@sentry-internal/feedback@8.55.1': - dependencies: - '@sentry/core': 8.55.1 - - '@sentry-internal/replay-canvas@8.55.1': - dependencies: - '@sentry-internal/replay': 8.55.1 - '@sentry/core': 8.55.1 - - '@sentry-internal/replay@8.55.1': - dependencies: - '@sentry-internal/browser-utils': 8.55.1 - '@sentry/core': 8.55.1 - - '@sentry/babel-plugin-component-annotate@2.22.6': {} - - '@sentry/browser@8.55.1': - dependencies: - '@sentry-internal/browser-utils': 8.55.1 - '@sentry-internal/feedback': 8.55.1 - '@sentry-internal/replay': 8.55.1 - '@sentry-internal/replay-canvas': 8.55.1 - '@sentry/core': 8.55.1 - - '@sentry/bundler-plugin-core@2.22.6': - dependencies: - '@babel/core': 7.29.0 - '@sentry/babel-plugin-component-annotate': 2.22.6 - '@sentry/cli': 2.58.5 - dotenv: 16.6.1 - find-up: 5.0.0 - glob: 9.3.5 - magic-string: 0.30.8 - unplugin: 1.0.1 - transitivePeerDependencies: - - encoding - - supports-color - - '@sentry/cli-darwin@2.58.5': - optional: true - - '@sentry/cli-linux-arm64@2.58.5': - optional: true - - '@sentry/cli-linux-arm@2.58.5': - optional: true - - '@sentry/cli-linux-i686@2.58.5': - optional: true - - '@sentry/cli-linux-x64@2.58.5': - optional: true - - '@sentry/cli-win32-arm64@2.58.5': - optional: true - - '@sentry/cli-win32-i686@2.58.5': - optional: true - - '@sentry/cli-win32-x64@2.58.5': - optional: true - - '@sentry/cli@2.58.5': - dependencies: - https-proxy-agent: 5.0.1 - node-fetch: 2.7.0 - progress: 2.0.3 - proxy-from-env: 1.1.0 - which: 2.0.2 - optionalDependencies: - '@sentry/cli-darwin': 2.58.5 - '@sentry/cli-linux-arm': 2.58.5 - '@sentry/cli-linux-arm64': 2.58.5 - '@sentry/cli-linux-i686': 2.58.5 - '@sentry/cli-linux-x64': 2.58.5 - '@sentry/cli-win32-arm64': 2.58.5 - '@sentry/cli-win32-i686': 2.58.5 - '@sentry/cli-win32-x64': 2.58.5 - transitivePeerDependencies: - - encoding - - supports-color - - '@sentry/core@8.55.1': {} - - '@sentry/node@8.55.1': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-amqplib': 0.46.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-connect': 0.43.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-dataloader': 0.16.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-express': 0.47.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-fastify': 0.44.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-fs': 0.19.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-generic-pool': 0.43.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-graphql': 0.47.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-hapi': 0.45.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-http': 0.57.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-ioredis': 0.47.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-kafkajs': 0.7.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-knex': 0.44.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-koa': 0.47.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-lru-memoizer': 0.44.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mongodb': 0.51.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mongoose': 0.46.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mysql': 0.45.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-mysql2': 0.45.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-nestjs-core': 0.44.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-pg': 0.50.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-redis-4': 0.46.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-tedious': 0.18.0(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation-undici': 0.10.0(@opentelemetry/api@1.9.1) - '@opentelemetry/resources': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@prisma/instrumentation': 5.22.0 - '@sentry/core': 8.55.1 - '@sentry/opentelemetry': 8.55.1(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - import-in-the-middle: 1.15.0 - transitivePeerDependencies: - - supports-color - - '@sentry/opentelemetry@8.55.1(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)': - dependencies: - '@opentelemetry/api': 1.9.1 - '@opentelemetry/context-async-hooks': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/core': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.1) - '@opentelemetry/sdk-trace-base': 1.30.1(@opentelemetry/api@1.9.1) - '@opentelemetry/semantic-conventions': 1.40.0 - '@sentry/core': 8.55.1 - - '@sentry/svelte@8.55.1(svelte@5.55.0)': - dependencies: - '@sentry/browser': 8.55.1 - '@sentry/core': 8.55.1 - magic-string: 0.30.7 - svelte: 5.55.0 - - '@sentry/sveltekit@8.55.1(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0)(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0))': - dependencies: - '@sentry/core': 8.55.1 - '@sentry/node': 8.55.1 - '@sentry/opentelemetry': 8.55.1(@opentelemetry/api@1.9.1)(@opentelemetry/context-async-hooks@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/core@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@1.30.1(@opentelemetry/api@1.9.1))(@opentelemetry/semantic-conventions@1.40.0) - '@sentry/svelte': 8.55.1(svelte@5.55.0) - '@sentry/vite-plugin': 2.22.6 - '@sveltejs/kit': 2.55.0(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)) - magic-string: 0.30.7 - magicast: 0.2.8 - sorcery: 1.0.0 - optionalDependencies: - vite: 7.3.1(@types/node@25.5.0)(sass@1.98.0) - transitivePeerDependencies: - - '@opentelemetry/api' - - '@opentelemetry/context-async-hooks' - - '@opentelemetry/core' - - '@opentelemetry/instrumentation' - - '@opentelemetry/sdk-trace-base' - - '@opentelemetry/semantic-conventions' - - encoding - - supports-color - - svelte - - '@sentry/vite-plugin@2.22.6': - dependencies: - '@sentry/bundler-plugin-core': 2.22.6 - unplugin: 1.0.1 - transitivePeerDependencies: - - encoding - - supports-color - - '@shikijs/core@1.29.2': - dependencies: - '@shikijs/engine-javascript': 1.29.2 - '@shikijs/engine-oniguruma': 1.29.2 - '@shikijs/types': 1.29.2 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - hast-util-to-html: 9.0.5 - - '@shikijs/engine-javascript@1.29.2': - dependencies: - '@shikijs/types': 1.29.2 - '@shikijs/vscode-textmate': 10.0.2 - oniguruma-to-es: 2.3.0 - - '@shikijs/engine-oniguruma@1.29.2': - dependencies: - '@shikijs/types': 1.29.2 - '@shikijs/vscode-textmate': 10.0.2 - - '@shikijs/langs@1.29.2': - dependencies: - '@shikijs/types': 1.29.2 - - '@shikijs/themes@1.29.2': - dependencies: - '@shikijs/types': 1.29.2 - - '@shikijs/types@1.29.2': - dependencies: - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - '@shikijs/vscode-textmate@10.0.2': {} - - '@standard-schema/spec@1.1.0': {} - - '@stripe/stripe-js@3.5.0': {} - - '@sveltejs/acorn-typescript@1.0.9(acorn@8.16.0)': - dependencies: - acorn: 8.16.0 - - '@sveltejs/adapter-static@3.0.10(@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))': - dependencies: - '@sveltejs/kit': 2.55.0(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)) - - '@sveltejs/kit@2.55.0(@opentelemetry/api@1.9.1)(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(typescript@5.9.3)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0))': - dependencies: - '@standard-schema/spec': 1.1.0 - '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)) - '@types/cookie': 0.6.0 - acorn: 8.16.0 - cookie: 0.6.0 - devalue: 5.6.4 - esm-env: 1.2.2 - kleur: 4.1.5 - magic-string: 0.30.21 - mrmime: 2.0.1 - set-cookie-parser: 3.1.0 - sirv: 3.0.2 - svelte: 5.55.0 - vite: 7.3.1(@types/node@25.5.0)(sass@1.98.0) - optionalDependencies: - '@opentelemetry/api': 1.9.1 - typescript: 5.9.3 - - '@sveltejs/vite-plugin-svelte-inspector@4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0))': - dependencies: - '@sveltejs/vite-plugin-svelte': 5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)) - debug: 4.4.3 - svelte: 5.55.0 - vite: 7.3.1(@types/node@25.5.0)(sass@1.98.0) - transitivePeerDependencies: - - supports-color - - '@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0))': - dependencies: - '@sveltejs/vite-plugin-svelte-inspector': 4.0.1(@sveltejs/vite-plugin-svelte@5.1.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)))(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)) - debug: 4.4.3 - deepmerge: 4.3.1 - kleur: 4.1.5 - magic-string: 0.30.21 - svelte: 5.55.0 - vite: 7.3.1(@types/node@25.5.0)(sass@1.98.0) - vitefu: 1.1.2(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)) - transitivePeerDependencies: - - supports-color - - '@swc/helpers@0.5.20': - dependencies: - tslib: 2.8.1 - - '@tanstack/svelte-virtual@3.13.23(svelte@5.55.0)': - dependencies: - '@tanstack/virtual-core': 3.13.23 - svelte: 5.55.0 - - '@tanstack/virtual-core@3.13.23': {} - - '@testing-library/dom@10.4.1': - dependencies: - '@babel/code-frame': 7.29.0 - '@babel/runtime': 7.29.2 - '@types/aria-query': 5.0.4 - aria-query: 5.3.0 - dom-accessibility-api: 0.5.16 - lz-string: 1.5.0 - picocolors: 1.1.1 - pretty-format: 27.5.1 - - '@testing-library/jest-dom@6.9.1': - dependencies: - '@adobe/css-tools': 4.4.4 - aria-query: 5.3.2 - css.escape: 1.5.1 - dom-accessibility-api: 0.6.3 - picocolors: 1.1.1 - redent: 3.0.0 - - '@testing-library/svelte-core@1.0.0(svelte@5.55.0)': - dependencies: - svelte: 5.55.0 - - '@testing-library/svelte@5.3.1(svelte@5.55.0)(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0))(vitest@3.2.4)': - dependencies: - '@testing-library/dom': 10.4.1 - '@testing-library/svelte-core': 1.0.0(svelte@5.55.0) - svelte: 5.55.0 - optionalDependencies: - vite: 7.3.1(@types/node@25.5.0)(sass@1.98.0) - vitest: 3.2.4(@types/node@25.5.0)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.98.0) - - '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': - dependencies: - '@testing-library/dom': 10.4.1 - - '@threejs-kit/instanced-sprite-mesh@2.5.1(@types/three@0.182.0)(three@0.181.2)': - dependencies: - diet-sprite: 0.0.1 - earcut: 2.2.4 - maath: 0.10.8(@types/three@0.182.0)(three@0.181.2) - three: 0.181.2 - three-instanced-uniforms-mesh: 0.52.4(three@0.181.2) - troika-three-utils: 0.52.4(three@0.181.2) - transitivePeerDependencies: - - '@types/three' - - '@threlte/core@8.5.4(svelte@5.55.0)(three@0.181.2)': - dependencies: - mitt: 3.0.1 - svelte: 5.55.0 - three: 0.181.2 - - '@threlte/extras@9.13.3(@types/three@0.182.0)(svelte@5.55.0)(three@0.181.2)': - dependencies: - '@threejs-kit/instanced-sprite-mesh': 2.5.1(@types/three@0.182.0)(three@0.181.2) - camera-controls: 3.1.2(three@0.181.2) - svelte: 5.55.0 - three: 0.181.2 - three-mesh-bvh: 0.9.9(three@0.181.2) - three-perf: 1.0.11(three@0.181.2) - three-viewport-gizmo: 2.2.0(three@0.181.2) - troika-three-text: 0.52.4(three@0.181.2) - transitivePeerDependencies: - - '@types/three' - - '@tweenjs/tween.js@23.1.3': {} - - '@types/aria-query@5.0.4': {} - - '@types/chai@5.2.3': - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - - '@types/connect@3.4.36': - dependencies: - '@types/node': 25.5.0 - - '@types/cookie@0.6.0': {} - - '@types/deep-eql@4.0.2': {} - - '@types/deep-equal@1.0.4': {} - - '@types/dlv@1.1.5': {} - - '@types/estree@1.0.8': {} - - '@types/hast@3.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/json-schema@7.0.15': {} - - '@types/mdast@4.0.4': - dependencies: - '@types/unist': 3.0.3 - - '@types/mysql@2.15.26': - dependencies: - '@types/node': 25.5.0 - - '@types/node@25.5.0': - dependencies: - undici-types: 7.18.2 - - '@types/pg-pool@2.0.6': - dependencies: - '@types/pg': 8.6.1 - - '@types/pg@8.6.1': - dependencies: - '@types/node': 25.5.0 - pg-protocol: 1.13.0 - pg-types: 2.2.0 - - '@types/prop-types@15.7.15': {} - - '@types/react@18.3.28': - dependencies: - '@types/prop-types': 15.7.15 - csstype: 3.2.3 - - '@types/remarkable@2.0.8': {} - - '@types/shimmer@1.2.0': {} - - '@types/stats.js@0.17.4': {} - - '@types/tedious@4.0.14': - dependencies: - '@types/node': 25.5.0 - - '@types/three@0.182.0': - dependencies: - '@dimforge/rapier3d-compat': 0.12.0 - '@tweenjs/tween.js': 23.1.3 - '@types/stats.js': 0.17.4 - '@types/webxr': 0.5.24 - '@webgpu/types': 0.1.69 - fflate: 0.8.2 - meshoptimizer: 0.22.0 - - '@types/trusted-types@2.0.7': {} - - '@types/unist@3.0.3': {} - - '@types/webxr@0.5.24': {} - - '@typescript-eslint/eslint-plugin@8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3)': - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.57.2(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.57.2 - '@typescript-eslint/type-utils': 8.57.2(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.2(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.2 - eslint: 9.39.4 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/scope-manager': 8.57.2 - '@typescript-eslint/types': 8.57.2 - '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.57.2 - debug: 4.4.3 - eslint: 9.39.4 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/project-service@8.57.2(typescript@5.9.3)': - dependencies: - '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) - '@typescript-eslint/types': 8.57.2 - debug: 4.4.3 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/scope-manager@8.57.2': - dependencies: - '@typescript-eslint/types': 8.57.2 - '@typescript-eslint/visitor-keys': 8.57.2 - - '@typescript-eslint/tsconfig-utils@8.57.2(typescript@5.9.3)': - dependencies: - typescript: 5.9.3 - - '@typescript-eslint/type-utils@8.57.2(eslint@9.39.4)(typescript@5.9.3)': - dependencies: - '@typescript-eslint/types': 8.57.2 - '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.2(eslint@9.39.4)(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.39.4 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/types@8.57.2': {} - - '@typescript-eslint/typescript-estree@8.57.2(typescript@5.9.3)': - dependencies: - '@typescript-eslint/project-service': 8.57.2(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.57.2(typescript@5.9.3) - '@typescript-eslint/types': 8.57.2 - '@typescript-eslint/visitor-keys': 8.57.2 - debug: 4.4.3 - minimatch: 10.2.4 - semver: 7.7.4 - tinyglobby: 0.2.15 - ts-api-utils: 2.5.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/utils@8.57.2(eslint@9.39.4)(typescript@5.9.3)': - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@typescript-eslint/scope-manager': 8.57.2 - '@typescript-eslint/types': 8.57.2 - '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) - eslint: 9.39.4 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - '@typescript-eslint/visitor-keys@8.57.2': - dependencies: - '@typescript-eslint/types': 8.57.2 - eslint-visitor-keys: 5.0.1 - - '@ungap/structured-clone@1.3.0': {} - - '@vercel/oidc@3.1.0': {} - - '@vitest/expect@3.2.4': - dependencies: - '@types/chai': 5.2.3 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - tinyrainbow: 2.0.0 - - '@vitest/mocker@3.2.4(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0))': - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.21 - optionalDependencies: - vite: 7.3.1(@types/node@25.5.0)(sass@1.98.0) - - '@vitest/pretty-format@3.2.4': - dependencies: - tinyrainbow: 2.0.0 - - '@vitest/runner@3.2.4': - dependencies: - '@vitest/utils': 3.2.4 - pathe: 2.0.3 - strip-literal: 3.1.0 - - '@vitest/snapshot@3.2.4': - dependencies: - '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.21 - pathe: 2.0.3 - - '@vitest/spy@3.2.4': - dependencies: - tinyspy: 4.0.4 - - '@vitest/ui@3.2.4(vitest@3.2.4)': - dependencies: - '@vitest/utils': 3.2.4 - fflate: 0.8.2 - flatted: 3.4.2 - pathe: 2.0.3 - sirv: 3.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 2.0.0 - vitest: 3.2.4(@types/node@25.5.0)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.98.0) - - '@vitest/utils@3.2.4': - dependencies: - '@vitest/pretty-format': 3.2.4 - loupe: 3.2.1 - tinyrainbow: 2.0.0 - - '@webgpu/types@0.1.69': {} - - acorn-import-attributes@1.9.5(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn-jsx@5.3.2(acorn@8.16.0): - dependencies: - acorn: 8.16.0 - - acorn@8.16.0: {} - - agent-base@6.0.2: - dependencies: - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - agent-base@7.1.4: {} - - ai@6.0.141(zod@3.25.76): - dependencies: - '@ai-sdk/gateway': 3.0.83(zod@3.25.76) - '@ai-sdk/provider': 3.0.8 - '@ai-sdk/provider-utils': 4.0.21(zod@3.25.76) - '@opentelemetry/api': 1.9.0 - zod: 3.25.76 - - ajv@6.14.0: - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - - analytics-utils@1.1.1(@types/dlv@1.1.5): - dependencies: - '@analytics/type-utils': 0.6.4 - '@types/dlv': 1.1.5 - dlv: 1.1.3 - - analytics@0.8.19(@types/dlv@1.1.5): - dependencies: - '@analytics/core': 0.13.2(@types/dlv@1.1.5) - '@analytics/storage-utils': 0.4.4 - transitivePeerDependencies: - - '@types/dlv' - - ansi-regex@5.0.1: {} - - ansi-styles@4.3.0: - dependencies: - color-convert: 2.0.1 - - ansi-styles@5.2.0: {} - - ansicolor@2.0.3: {} - - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.2 - - argparse@1.0.10: - dependencies: - sprintf-js: 1.0.3 - - argparse@2.0.1: {} - - aria-query@5.3.0: - dependencies: - dequal: 2.0.3 - - aria-query@5.3.1: {} - - aria-query@5.3.2: {} - - array-buffer-byte-length@1.0.2: - dependencies: - call-bound: 1.0.4 - is-array-buffer: 3.0.5 - - assertion-error@2.0.1: {} - - ast-types@0.16.1: - dependencies: - tslib: 2.8.1 - - autolinker@3.16.2: - dependencies: - tslib: 2.8.1 - - available-typed-arrays@1.0.7: - dependencies: - possible-typed-array-names: 1.1.0 - - axobject-query@4.1.0: {} - - balanced-match@1.0.2: {} - - balanced-match@4.0.4: {} - - baseline-browser-mapping@2.10.12: {} - - bidi-js@1.0.3: - dependencies: - require-from-string: 2.0.2 - - bignumber.js@9.3.1: {} - - binary-extensions@2.3.0: {} - - brace-expansion@1.1.13: - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - - brace-expansion@2.0.3: - dependencies: - balanced-match: 1.0.2 - - brace-expansion@5.0.5: - dependencies: - balanced-match: 4.0.4 - - braces@3.0.3: - dependencies: - fill-range: 7.1.1 - - browserslist@4.28.1: - dependencies: - baseline-browser-mapping: 2.10.12 - caniuse-lite: 1.0.30001781 - electron-to-chromium: 1.5.328 - node-releases: 2.0.36 - update-browserslist-db: 1.2.3(browserslist@4.28.1) - - cac@6.7.14: {} - - call-bind-apply-helpers@1.0.2: - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - - call-bind@1.0.8: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - get-intrinsic: 1.3.0 - set-function-length: 1.2.2 - - call-bound@1.0.4: - dependencies: - call-bind-apply-helpers: 1.0.2 - get-intrinsic: 1.3.0 - - callsites@3.1.0: {} - - camera-controls@3.1.2(three@0.181.2): - dependencies: - three: 0.181.2 - - caniuse-lite@1.0.30001781: {} - - ccount@2.0.1: {} - - chai@5.3.3: - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.3 - deep-eql: 5.0.2 - loupe: 3.2.1 - pathval: 2.0.1 - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - - character-entities-html4@2.1.0: {} - - character-entities-legacy@3.0.0: {} - - check-error@2.1.3: {} - - chokidar@3.6.0: - dependencies: - anymatch: 3.1.3 - braces: 3.0.3 - glob-parent: 5.1.2 - is-binary-path: 2.1.0 - is-glob: 4.0.3 - normalize-path: 3.0.0 - readdirp: 3.6.0 - optionalDependencies: - fsevents: 2.3.3 - - chokidar@4.0.3: - dependencies: - readdirp: 4.1.2 - - cjs-module-lexer@1.4.3: {} - - clsx@2.1.1: {} - - color-convert@2.0.1: - dependencies: - color-name: 1.1.4 - - color-convert@3.1.3: - dependencies: - color-name: 2.1.0 - - color-name@1.1.4: {} - - color-name@2.1.0: {} - - color-string@2.1.4: - dependencies: - color-name: 2.1.0 - - color@5.0.3: - dependencies: - color-convert: 3.1.3 - color-string: 2.1.4 - - comma-separated-tokens@2.0.3: {} - - commander@7.2.0: {} - - concat-map@0.0.1: {} - - convert-source-map@2.0.0: {} - - cookie@0.6.0: {} - - cron-parser@4.9.0: - dependencies: - luxon: 3.7.2 - - cross-spawn@7.0.6: - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - - css.escape@1.5.1: {} - - cssesc@3.0.0: {} - - cssstyle@4.6.0: - dependencies: - '@asamuzakjp/css-color': 3.2.0 - rrweb-cssom: 0.8.0 - - csstype@3.2.3: {} - - d3-array@3.2.4: - dependencies: - internmap: 2.0.3 - - d3-axis@3.0.0: {} - - d3-brush@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - - d3-chord@3.0.1: - dependencies: - d3-path: 3.1.0 - - d3-color@3.1.0: {} - - d3-contour@4.0.2: - dependencies: - d3-array: 3.2.4 - - d3-delaunay@6.0.4: - dependencies: - delaunator: 5.1.0 - - d3-dispatch@3.0.1: {} - - d3-drag@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-selection: 3.0.0 - - d3-dsv@3.0.1: - dependencies: - commander: 7.2.0 - iconv-lite: 0.6.3 - rw: 1.3.3 - - d3-ease@3.0.1: {} - - d3-fetch@3.0.1: - dependencies: - d3-dsv: 3.0.1 - - d3-force@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-quadtree: 3.0.1 - d3-timer: 3.0.1 - - d3-format@3.1.2: {} - - d3-geo@3.1.1: - dependencies: - d3-array: 3.2.4 - - d3-hierarchy@3.1.2: {} - - d3-interpolate@3.0.1: - dependencies: - d3-color: 3.1.0 - - d3-path@3.1.0: {} - - d3-polygon@3.0.1: {} - - d3-quadtree@3.0.1: {} - - d3-random@3.0.1: {} - - d3-scale-chromatic@3.1.0: - dependencies: - d3-color: 3.1.0 - d3-interpolate: 3.0.1 - - d3-scale@4.0.2: - dependencies: - d3-array: 3.2.4 - d3-format: 3.1.2 - d3-interpolate: 3.0.1 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - - d3-selection@3.0.0: {} - - d3-shape@3.2.0: - dependencies: - d3-path: 3.1.0 - - d3-time-format@4.1.0: - dependencies: - d3-time: 3.1.0 - - d3-time@3.1.0: - dependencies: - d3-array: 3.2.4 - - d3-timer@3.0.1: {} - - d3-transition@3.0.1(d3-selection@3.0.0): - dependencies: - d3-color: 3.1.0 - d3-dispatch: 3.0.1 - d3-ease: 3.0.1 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-timer: 3.0.1 - - d3-zoom@3.0.0: - dependencies: - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-interpolate: 3.0.1 - d3-selection: 3.0.0 - d3-transition: 3.0.1(d3-selection@3.0.0) - - d3@7.9.0: - dependencies: - d3-array: 3.2.4 - d3-axis: 3.0.0 - d3-brush: 3.0.0 - d3-chord: 3.0.1 - d3-color: 3.1.0 - d3-contour: 4.0.2 - d3-delaunay: 6.0.4 - d3-dispatch: 3.0.1 - d3-drag: 3.0.0 - d3-dsv: 3.0.1 - d3-ease: 3.0.1 - d3-fetch: 3.0.1 - d3-force: 3.0.0 - d3-format: 3.1.2 - d3-geo: 3.1.1 - d3-hierarchy: 3.1.2 - d3-interpolate: 3.0.1 - d3-path: 3.1.0 - d3-polygon: 3.0.1 - d3-quadtree: 3.0.1 - d3-random: 3.0.1 - d3-scale: 4.0.2 - d3-scale-chromatic: 3.1.0 - d3-selection: 3.0.0 - d3-shape: 3.2.0 - d3-time: 3.1.0 - d3-time-format: 4.1.0 - d3-timer: 3.0.1 - d3-transition: 3.0.1(d3-selection@3.0.0) - d3-zoom: 3.0.0 - - data-urls@5.0.0: - dependencies: - whatwg-mimetype: 4.0.0 - whatwg-url: 14.2.0 - - dayjs@1.11.20: {} - - debug@4.4.3: - dependencies: - ms: 2.1.3 - - decimal.js@10.6.0: {} - - deep-eql@5.0.2: {} - - deep-equal@2.2.3: - dependencies: - array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 - es-get-iterator: 1.1.3 - get-intrinsic: 1.3.0 - is-arguments: 1.2.0 - is-array-buffer: 3.0.5 - is-date-object: 1.1.0 - is-regex: 1.2.1 - is-shared-array-buffer: 1.0.4 - isarray: 2.0.5 - object-is: 1.1.6 - object-keys: 1.1.1 - object.assign: 4.1.7 - regexp.prototype.flags: 1.5.4 - side-channel: 1.1.0 - which-boxed-primitive: 1.1.1 - which-collection: 1.0.2 - which-typed-array: 1.1.20 - - deep-is@0.1.4: {} - - deepmerge@4.3.1: {} - - define-data-property@1.1.4: - dependencies: - es-define-property: 1.0.1 - es-errors: 1.3.0 - gopd: 1.2.0 - - define-properties@1.2.1: - dependencies: - define-data-property: 1.1.4 - has-property-descriptors: 1.0.2 - object-keys: 1.1.1 - - delaunator@5.1.0: - dependencies: - robust-predicates: 3.0.3 - - dequal@2.0.3: {} - - detect-libc@2.1.2: - optional: true - - devalue@5.6.4: {} - - devlop@1.1.0: - dependencies: - dequal: 2.0.3 - - diet-sprite@0.0.1: {} - - dlv@1.1.3: {} - - dom-accessibility-api@0.5.16: {} - - dom-accessibility-api@0.6.3: {} - - dotenv@16.6.1: {} - - dunder-proto@1.0.1: - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - - earcut@2.2.4: {} - - echarts@5.6.0: - dependencies: - tslib: 2.3.0 - zrender: 5.6.1 - - electron-to-chromium@1.5.328: {} - - emoji-regex-xs@1.0.0: {} - - entities@6.0.1: {} - - es-define-property@1.0.1: {} - - es-errors@1.3.0: {} - - es-get-iterator@1.1.3: - dependencies: - call-bind: 1.0.8 - get-intrinsic: 1.3.0 - has-symbols: 1.1.0 - is-arguments: 1.2.0 - is-map: 2.0.3 - is-set: 2.0.3 - is-string: 1.1.1 - isarray: 2.0.5 - stop-iteration-iterator: 1.1.0 - - es-module-lexer@1.7.0: {} - - es-object-atoms@1.1.1: - dependencies: - es-errors: 1.3.0 - - esbuild@0.27.4: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.4 - '@esbuild/android-arm': 0.27.4 - '@esbuild/android-arm64': 0.27.4 - '@esbuild/android-x64': 0.27.4 - '@esbuild/darwin-arm64': 0.27.4 - '@esbuild/darwin-x64': 0.27.4 - '@esbuild/freebsd-arm64': 0.27.4 - '@esbuild/freebsd-x64': 0.27.4 - '@esbuild/linux-arm': 0.27.4 - '@esbuild/linux-arm64': 0.27.4 - '@esbuild/linux-ia32': 0.27.4 - '@esbuild/linux-loong64': 0.27.4 - '@esbuild/linux-mips64el': 0.27.4 - '@esbuild/linux-ppc64': 0.27.4 - '@esbuild/linux-riscv64': 0.27.4 - '@esbuild/linux-s390x': 0.27.4 - '@esbuild/linux-x64': 0.27.4 - '@esbuild/netbsd-arm64': 0.27.4 - '@esbuild/netbsd-x64': 0.27.4 - '@esbuild/openbsd-arm64': 0.27.4 - '@esbuild/openbsd-x64': 0.27.4 - '@esbuild/openharmony-arm64': 0.27.4 - '@esbuild/sunos-x64': 0.27.4 - '@esbuild/win32-arm64': 0.27.4 - '@esbuild/win32-ia32': 0.27.4 - '@esbuild/win32-x64': 0.27.4 - - escalade@3.2.0: {} - - escape-string-regexp@4.0.0: {} - - eslint-config-prettier@10.1.8(eslint@9.39.4): - dependencies: - eslint: 9.39.4 - - eslint-plugin-svelte@3.16.0(eslint@9.39.4)(svelte@5.55.0): - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@jridgewell/sourcemap-codec': 1.5.5 - eslint: 9.39.4 - esutils: 2.0.3 - globals: 16.5.0 - known-css-properties: 0.37.0 - postcss: 8.5.8 - postcss-load-config: 3.1.4(postcss@8.5.8) - postcss-safe-parser: 7.0.1(postcss@8.5.8) - semver: 7.7.4 - svelte-eslint-parser: 1.6.0(svelte@5.55.0) - optionalDependencies: - svelte: 5.55.0 - transitivePeerDependencies: - - ts-node - - eslint-scope@8.4.0: - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - - eslint-visitor-keys@3.4.3: {} - - eslint-visitor-keys@4.2.1: {} - - eslint-visitor-keys@5.0.1: {} - - eslint@9.39.4: - dependencies: - '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.2 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.5 - '@eslint/js': 9.39.4 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.14.0 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3 - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.7.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.5 - natural-compare: 1.4.0 - optionator: 0.9.4 - transitivePeerDependencies: - - supports-color - - esm-env@1.2.2: {} - - espree@10.4.0: - dependencies: - acorn: 8.16.0 - acorn-jsx: 5.3.2(acorn@8.16.0) - eslint-visitor-keys: 4.2.1 - - esprima@4.0.1: {} - - esquery@1.7.0: - dependencies: - estraverse: 5.3.0 - - esrap@2.2.4: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@typescript-eslint/types': 8.57.2 - - esrecurse@4.3.0: - dependencies: - estraverse: 5.3.0 - - estraverse@5.3.0: {} - - estree-walker@3.0.3: - dependencies: - '@types/estree': 1.0.8 - - esutils@2.0.3: {} - - eventsource-parser@3.0.6: {} - - expect-type@1.3.0: {} - - fast-deep-equal@3.1.3: {} - - fast-json-stable-stringify@2.1.0: {} - - fast-levenshtein@2.0.6: {} - - fdir@6.5.0(picomatch@4.0.4): - optionalDependencies: - picomatch: 4.0.4 - - fflate@0.8.2: {} - - file-entry-cache@8.0.0: - dependencies: - flat-cache: 4.0.1 - - fill-range@7.1.1: - dependencies: - to-regex-range: 5.0.1 - - find-up@5.0.0: - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - - flat-cache@4.0.1: - dependencies: - flatted: 3.4.2 - keyv: 4.5.4 - - flatted@3.4.2: {} - - focus-trap@7.8.0: - dependencies: - tabbable: 6.4.0 - - for-each@0.3.5: - dependencies: - is-callable: 1.2.7 - - forwarded-parse@2.1.2: {} - - framesync@6.1.2: - dependencies: - tslib: 2.4.0 - - fs.realpath@1.0.0: {} - - fsevents@2.3.2: - optional: true - - fsevents@2.3.3: - optional: true - - function-bind@1.1.2: {} - - functions-have-names@1.2.3: {} - - fuse.js@7.1.0: {} - - gensync@1.0.0-beta.2: {} - - get-intrinsic@1.3.0: - 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 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - - get-proto@1.0.1: - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - - glob-parent@5.1.2: - dependencies: - is-glob: 4.0.3 - - glob-parent@6.0.2: - dependencies: - is-glob: 4.0.3 - - glob@9.3.5: - dependencies: - fs.realpath: 1.0.0 - minimatch: 8.0.7 - minipass: 4.2.8 - path-scurry: 1.11.1 - - globals@14.0.0: {} - - globals@16.5.0: {} - - globalyzer@0.1.0: {} - - globrex@0.1.2: {} - - gopd@1.2.0: {} - - has-bigints@1.1.0: {} - - has-flag@4.0.0: {} - - has-property-descriptors@1.0.2: - dependencies: - es-define-property: 1.0.1 - - has-symbols@1.1.0: {} - - has-tostringtag@1.0.2: - dependencies: - has-symbols: 1.1.0 - - hasown@2.0.2: - dependencies: - function-bind: 1.1.2 - - hast-util-to-html@9.0.5: - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - ccount: 2.0.1 - comma-separated-tokens: 2.0.3 - hast-util-whitespace: 3.0.0 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - stringify-entities: 4.0.4 - zwitch: 2.0.4 - - hast-util-whitespace@3.0.0: - dependencies: - '@types/hast': 3.0.4 - - hey-listen@1.0.8: {} - - html-encoding-sniffer@4.0.0: - dependencies: - whatwg-encoding: 3.1.1 - - html-void-elements@3.0.0: {} - - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - https-proxy-agent@5.0.1: - dependencies: - agent-base: 6.0.2 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - https-proxy-agent@7.0.6: - dependencies: - agent-base: 7.1.4 - debug: 4.4.3 - transitivePeerDependencies: - - supports-color - - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - ignore@5.3.2: {} - - ignore@6.0.2: {} - - ignore@7.0.5: {} - - immutable@5.1.5: {} - - import-fresh@3.3.1: - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - - import-in-the-middle@1.15.0: - dependencies: - acorn: 8.16.0 - acorn-import-attributes: 1.9.5(acorn@8.16.0) - cjs-module-lexer: 1.4.3 - module-details-from-path: 1.0.4 - - imurmurhash@0.1.4: {} - - indent-string@4.0.0: {} - - internal-slot@1.1.0: - dependencies: - es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.1.0 - - internmap@2.0.3: {} - - is-arguments@1.2.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-array-buffer@3.0.5: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - is-bigint@1.1.0: - dependencies: - has-bigints: 1.1.0 - - is-binary-path@2.1.0: - dependencies: - binary-extensions: 2.3.0 - - is-boolean-object@1.2.2: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-callable@1.2.7: {} - - is-core-module@2.16.1: - dependencies: - hasown: 2.0.2 - - is-date-object@1.1.0: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-extglob@2.1.1: {} - - is-glob@4.0.3: - dependencies: - is-extglob: 2.1.1 - - is-map@2.0.3: {} - - is-number-object@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-number@7.0.0: {} - - is-potential-custom-element-name@1.0.1: {} - - is-reference@3.0.3: - dependencies: - '@types/estree': 1.0.8 - - is-regex@1.2.1: - dependencies: - call-bound: 1.0.4 - gopd: 1.2.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - - is-set@2.0.3: {} - - is-shared-array-buffer@1.0.4: - dependencies: - call-bound: 1.0.4 - - is-string@1.1.1: - dependencies: - call-bound: 1.0.4 - has-tostringtag: 1.0.2 - - is-symbol@1.1.1: - dependencies: - call-bound: 1.0.4 - has-symbols: 1.1.0 - safe-regex-test: 1.1.0 - - is-weakmap@2.0.2: {} - - is-weakset@2.0.4: - dependencies: - call-bound: 1.0.4 - get-intrinsic: 1.3.0 - - isarray@2.0.5: {} - - isexe@2.0.0: {} - - js-tokens@4.0.0: {} - - js-tokens@9.0.1: {} - - js-yaml@4.1.1: - dependencies: - argparse: 2.0.1 - - jsdom@26.1.0: - dependencies: - cssstyle: 4.6.0 - data-urls: 5.0.0 - decimal.js: 10.6.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.23 - parse5: 7.3.0 - rrweb-cssom: 0.8.0 - saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 5.1.2 - w3c-xmlserializer: 5.0.0 - webidl-conversions: 7.0.0 - whatwg-encoding: 3.1.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 14.2.0 - ws: 8.20.0 - xml-name-validator: 5.0.0 - transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate - - jsesc@3.1.0: {} - - json-bigint@1.0.0: - dependencies: - bignumber.js: 9.3.1 - - json-buffer@3.0.1: {} - - json-schema-traverse@0.4.1: {} - - json-schema@0.4.0: {} - - json-stable-stringify-without-jsonify@1.0.1: {} - - json5@2.2.3: {} - - keyv@4.5.4: - dependencies: - json-buffer: 3.0.1 - - kleur@4.1.5: {} - - known-css-properties@0.37.0: {} - - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - - lilconfig@2.1.0: {} - - locate-character@3.0.0: {} - - locate-path@6.0.0: - dependencies: - p-locate: 5.0.0 - - lodash.merge@4.6.2: {} - - loupe@3.2.1: {} - - lru-cache@10.4.3: {} - - lru-cache@5.1.1: - dependencies: - yallist: 3.1.1 - - luxon@3.7.2: {} - - lz-string@1.5.0: {} - - maath@0.10.8(@types/three@0.182.0)(three@0.181.2): - dependencies: - '@types/three': 0.182.0 - three: 0.181.2 - - magic-string@0.30.21: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - magic-string@0.30.7: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - magic-string@0.30.8: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - - magicast@0.2.8: - dependencies: - '@babel/parser': 7.29.2 - '@babel/types': 7.29.0 - recast: 0.23.11 - - math-intrinsics@1.1.0: {} - - mdast-util-to-hast@13.2.1: - dependencies: - '@types/hast': 3.0.4 - '@types/mdast': 4.0.4 - '@ungap/structured-clone': 1.3.0 - devlop: 1.1.0 - micromark-util-sanitize-uri: 2.0.1 - trim-lines: 3.0.1 - unist-util-position: 5.0.0 - unist-util-visit: 5.1.0 - vfile: 6.0.3 - - meshoptimizer@0.22.0: {} - - micromark-util-character@2.1.1: - dependencies: - micromark-util-symbol: 2.0.1 - micromark-util-types: 2.0.2 - - micromark-util-encode@2.0.1: {} - - micromark-util-sanitize-uri@2.0.1: - dependencies: - micromark-util-character: 2.1.1 - micromark-util-encode: 2.0.1 - micromark-util-symbol: 2.0.1 - - micromark-util-symbol@2.0.1: {} - - micromark-util-types@2.0.2: {} - - min-indent@1.0.1: {} - - minimatch@10.2.4: - dependencies: - brace-expansion: 5.0.5 - - minimatch@3.1.5: - dependencies: - brace-expansion: 1.1.13 - - minimatch@8.0.7: - dependencies: - brace-expansion: 2.0.3 - - minimist@1.2.8: {} - - minipass@4.2.8: {} - - minipass@7.1.3: {} - - mitt@3.0.1: {} - - module-details-from-path@1.0.4: {} - - mri@1.2.0: {} - - mrmime@2.0.1: {} - - ms@2.1.3: {} - - nanoid@3.3.11: {} - - nanoid@5.1.7: {} - - nanotar@0.3.0: {} - - natural-compare@1.4.0: {} - - node-addon-api@7.1.1: - optional: true - - node-fetch@2.7.0: - dependencies: - whatwg-url: 5.0.0 - - node-releases@2.0.36: {} - - normalize-path@3.0.0: {} - - nwsapi@2.2.23: {} - - object-inspect@1.13.4: {} - - object-is@1.1.6: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - - object-keys@1.1.1: {} - - object.assign@4.1.7: - dependencies: - call-bind: 1.0.8 - call-bound: 1.0.4 - define-properties: 1.2.1 - es-object-atoms: 1.1.1 - has-symbols: 1.1.0 - object-keys: 1.1.1 - - oniguruma-to-es@2.3.0: - dependencies: - emoji-regex-xs: 1.0.0 - regex: 5.1.1 - regex-recursion: 5.1.1 - - optionator@0.9.4: - dependencies: - deep-is: 0.1.4 - fast-levenshtein: 2.0.6 - levn: 0.4.1 - prelude-ls: 1.2.1 - type-check: 0.4.0 - word-wrap: 1.2.5 - - p-limit@3.1.0: - dependencies: - yocto-queue: 0.1.0 - - p-locate@5.0.0: - dependencies: - p-limit: 3.1.0 - - parent-module@1.0.1: - dependencies: - callsites: 3.1.0 - - parse5@7.3.0: - dependencies: - entities: 6.0.1 - - path-exists@4.0.0: {} - - path-key@3.1.1: {} - - path-parse@1.0.7: {} - - path-scurry@1.11.1: - dependencies: - lru-cache: 10.4.3 - minipass: 7.1.3 - - pathe@2.0.3: {} - - pathval@2.0.1: {} - - pg-int8@1.0.1: {} - - pg-protocol@1.13.0: {} - - pg-types@2.2.0: - dependencies: - pg-int8: 1.0.1 - postgres-array: 2.0.0 - postgres-bytea: 1.0.1 - postgres-date: 1.0.7 - postgres-interval: 1.2.0 - - picocolors@1.1.1: {} - - picomatch@2.3.2: {} - - picomatch@4.0.4: {} - - playwright-core@1.58.2: {} - - playwright@1.58.2: - dependencies: - playwright-core: 1.58.2 - optionalDependencies: - fsevents: 2.3.2 - - popmotion@11.0.5: - dependencies: - framesync: 6.1.2 - hey-listen: 1.0.8 - style-value-types: 5.1.2 - tslib: 2.4.0 - - possible-typed-array-names@1.1.0: {} - - postcss-load-config@3.1.4(postcss@8.5.8): - dependencies: - lilconfig: 2.1.0 - yaml: 1.10.3 - optionalDependencies: - postcss: 8.5.8 - - postcss-safe-parser@7.0.1(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - - postcss-scss@4.0.9(postcss@8.5.8): - dependencies: - postcss: 8.5.8 - - postcss-selector-parser@7.1.1: - dependencies: - cssesc: 3.0.0 - util-deprecate: 1.0.2 - - postcss@8.5.8: - dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 - - postgres-array@2.0.0: {} - - postgres-bytea@1.0.1: {} - - postgres-date@1.0.7: {} - - postgres-interval@1.2.0: - dependencies: - xtend: 4.0.2 - - prelude-ls@1.2.1: {} - - prettier-plugin-svelte@3.5.1(prettier@3.8.1)(svelte@5.55.0): - dependencies: - prettier: 3.8.1 - svelte: 5.55.0 - - prettier@3.8.1: {} - - pretty-bytes@6.1.1: {} - - pretty-format@27.5.1: - dependencies: - ansi-regex: 5.0.1 - ansi-styles: 5.2.0 - react-is: 17.0.2 - - progress@2.0.3: {} - - property-information@7.1.0: {} - - proxy-from-env@1.1.0: {} - - punycode@2.3.1: {} - - react-is@17.0.2: {} - - readdirp@3.6.0: - dependencies: - picomatch: 2.3.2 - - readdirp@4.1.2: {} - - recast@0.23.11: - dependencies: - ast-types: 0.16.1 - esprima: 4.0.1 - source-map: 0.6.1 - tiny-invariant: 1.3.3 - tslib: 2.8.1 - - redent@3.0.0: - dependencies: - indent-string: 4.0.0 - strip-indent: 3.0.0 - - regex-recursion@5.1.1: - dependencies: - regex: 5.1.1 - regex-utilities: 2.3.0 - - regex-utilities@2.3.0: {} - - regex@5.1.1: - dependencies: - regex-utilities: 2.3.0 - - regexp.prototype.flags@1.5.4: - dependencies: - call-bind: 1.0.8 - define-properties: 1.2.1 - es-errors: 1.3.0 - get-proto: 1.0.1 - gopd: 1.2.0 - set-function-name: 2.0.2 - - remarkable@2.0.1: - dependencies: - argparse: 1.0.10 - autolinker: 3.16.2 - - require-from-string@2.0.2: {} - - require-in-the-middle@7.5.2: - dependencies: - debug: 4.4.3 - module-details-from-path: 1.0.4 - resolve: 1.22.11 - transitivePeerDependencies: - - supports-color - - resolve-from@4.0.0: {} - - resolve@1.22.11: - dependencies: - is-core-module: 2.16.1 - path-parse: 1.0.7 - supports-preserve-symlinks-flag: 1.0.0 - - robust-predicates@3.0.3: {} - - rollup@4.60.0: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.60.0 - '@rollup/rollup-android-arm64': 4.60.0 - '@rollup/rollup-darwin-arm64': 4.60.0 - '@rollup/rollup-darwin-x64': 4.60.0 - '@rollup/rollup-freebsd-arm64': 4.60.0 - '@rollup/rollup-freebsd-x64': 4.60.0 - '@rollup/rollup-linux-arm-gnueabihf': 4.60.0 - '@rollup/rollup-linux-arm-musleabihf': 4.60.0 - '@rollup/rollup-linux-arm64-gnu': 4.60.0 - '@rollup/rollup-linux-arm64-musl': 4.60.0 - '@rollup/rollup-linux-loong64-gnu': 4.60.0 - '@rollup/rollup-linux-loong64-musl': 4.60.0 - '@rollup/rollup-linux-ppc64-gnu': 4.60.0 - '@rollup/rollup-linux-ppc64-musl': 4.60.0 - '@rollup/rollup-linux-riscv64-gnu': 4.60.0 - '@rollup/rollup-linux-riscv64-musl': 4.60.0 - '@rollup/rollup-linux-s390x-gnu': 4.60.0 - '@rollup/rollup-linux-x64-gnu': 4.60.0 - '@rollup/rollup-linux-x64-musl': 4.60.0 - '@rollup/rollup-openbsd-x64': 4.60.0 - '@rollup/rollup-openharmony-arm64': 4.60.0 - '@rollup/rollup-win32-arm64-msvc': 4.60.0 - '@rollup/rollup-win32-ia32-msvc': 4.60.0 - '@rollup/rollup-win32-x64-gnu': 4.60.0 - '@rollup/rollup-win32-x64-msvc': 4.60.0 - fsevents: 2.3.3 - - rrweb-cssom@0.8.0: {} - - rw@1.3.3: {} - - sade@1.8.1: - dependencies: - mri: 1.2.0 - - safe-regex-test@1.1.0: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - is-regex: 1.2.1 - - safer-buffer@2.1.2: {} - - sass@1.98.0: - dependencies: - chokidar: 4.0.3 - immutable: 5.1.5 - source-map-js: 1.2.1 - optionalDependencies: - '@parcel/watcher': 2.5.6 - - saxes@6.0.0: - dependencies: - xmlchars: 2.2.0 - - secure-json-parse@2.7.0: {} - - semver@6.3.1: {} - - semver@7.7.4: {} - - set-cookie-parser@3.1.0: {} - - set-function-length@1.2.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - function-bind: 1.1.2 - get-intrinsic: 1.3.0 - gopd: 1.2.0 - has-property-descriptors: 1.0.2 - - set-function-name@2.0.2: - dependencies: - define-data-property: 1.1.4 - es-errors: 1.3.0 - functions-have-names: 1.2.3 - has-property-descriptors: 1.0.2 - - shebang-command@2.0.0: - dependencies: - shebang-regex: 3.0.0 - - shebang-regex@3.0.0: {} - - shiki@1.29.2: - dependencies: - '@shikijs/core': 1.29.2 - '@shikijs/engine-javascript': 1.29.2 - '@shikijs/engine-oniguruma': 1.29.2 - '@shikijs/langs': 1.29.2 - '@shikijs/themes': 1.29.2 - '@shikijs/types': 1.29.2 - '@shikijs/vscode-textmate': 10.0.2 - '@types/hast': 3.0.4 - - shimmer@1.2.1: {} - - side-channel-list@1.0.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - - side-channel-map@1.0.1: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - - side-channel-weakmap@1.0.2: - dependencies: - call-bound: 1.0.4 - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - object-inspect: 1.13.4 - side-channel-map: 1.0.1 - - side-channel@1.1.0: - dependencies: - es-errors: 1.3.0 - object-inspect: 1.13.4 - side-channel-list: 1.0.0 - side-channel-map: 1.0.1 - side-channel-weakmap: 1.0.2 - - siginfo@2.0.0: {} - - sirv@3.0.2: - dependencies: - '@polka/url': 1.0.0-next.29 - mrmime: 2.0.1 - totalist: 3.0.1 - - sorcery@1.0.0: - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - minimist: 1.2.8 - tiny-glob: 0.2.9 - - source-map-js@1.2.1: {} - - source-map@0.6.1: {} - - space-separated-tokens@2.0.2: {} - - sprintf-js@1.0.3: {} - - stackback@0.0.2: {} - - std-env@3.10.0: {} - - stop-iteration-iterator@1.1.0: - dependencies: - es-errors: 1.3.0 - internal-slot: 1.1.0 - - stringify-entities@4.0.4: - dependencies: - character-entities-html4: 2.1.0 - character-entities-legacy: 3.0.0 - - strip-indent@3.0.0: - dependencies: - min-indent: 1.0.1 - - strip-json-comments@3.1.1: {} - - strip-literal@3.1.0: - dependencies: - js-tokens: 9.0.1 - - style-value-types@5.1.2: - dependencies: - hey-listen: 1.0.8 - tslib: 2.4.0 - - supports-color@7.2.0: - dependencies: - has-flag: 4.0.0 - - supports-preserve-symlinks-flag@1.0.0: {} - - svelte-check@4.4.5(picomatch@4.0.4)(svelte@5.55.0)(typescript@5.9.3): - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - chokidar: 4.0.3 - fdir: 6.5.0(picomatch@4.0.4) - picocolors: 1.1.1 - sade: 1.8.1 - svelte: 5.55.0 - typescript: 5.9.3 - transitivePeerDependencies: - - picomatch - - svelte-confetti@1.4.0(svelte@5.55.0): - dependencies: - svelte: 5.55.0 - - svelte-eslint-parser@1.6.0(svelte@5.55.0): - dependencies: - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - postcss: 8.5.8 - postcss-scss: 4.0.9(postcss@8.5.8) - postcss-selector-parser: 7.1.1 - semver: 7.7.4 - optionalDependencies: - svelte: 5.55.0 - - svelte-motion@0.12.2(svelte@5.55.0): - dependencies: - '@types/react': 18.3.28 - framesync: 6.1.2 - popmotion: 11.0.5 - style-value-types: 5.1.2 - svelte: 5.55.0 - tslib: 2.8.1 - - svelte-preprocess@6.0.3(@babel/core@7.29.0)(postcss-load-config@3.1.4(postcss@8.5.8))(postcss@8.5.8)(sass@1.98.0)(svelte@5.55.0)(typescript@5.9.3): - dependencies: - svelte: 5.55.0 - optionalDependencies: - '@babel/core': 7.29.0 - postcss: 8.5.8 - postcss-load-config: 3.1.4(postcss@8.5.8) - sass: 1.98.0 - typescript: 5.9.3 - - svelte-sequential-preprocessor@2.0.3: - dependencies: - svelte: 5.55.0 - tslib: 2.8.1 - - svelte-sonner@0.3.28(svelte@5.55.0): - dependencies: - svelte: 5.55.0 - - svelte@5.55.0: - dependencies: - '@jridgewell/remapping': 2.3.5 - '@jridgewell/sourcemap-codec': 1.5.5 - '@sveltejs/acorn-typescript': 1.0.9(acorn@8.16.0) - '@types/estree': 1.0.8 - '@types/trusted-types': 2.0.7 - acorn: 8.16.0 - aria-query: 5.3.1 - axobject-query: 4.1.0 - clsx: 2.1.1 - devalue: 5.6.4 - esm-env: 1.2.2 - esrap: 2.2.4 - is-reference: 3.0.3 - locate-character: 3.0.0 - magic-string: 0.30.21 - zimmerframe: 1.1.4 - - symbol-tree@3.2.4: {} - - tabbable@6.4.0: {} - - the-new-css-reset@1.11.3: {} - - three-instanced-uniforms-mesh@0.52.4(three@0.181.2): - dependencies: - three: 0.181.2 - troika-three-utils: 0.52.4(three@0.181.2) - - three-mesh-bvh@0.9.9(three@0.181.2): - dependencies: - three: 0.181.2 - - three-perf@1.0.11(three@0.181.2): - dependencies: - three: 0.181.2 - troika-three-text: 0.52.4(three@0.181.2) - tweakpane: 3.1.10 - - three-viewport-gizmo@2.2.0(three@0.181.2): - dependencies: - three: 0.181.2 - - three@0.181.2: {} - - tiny-glob@0.2.9: - dependencies: - globalyzer: 0.1.0 - globrex: 0.1.2 - - tiny-invariant@1.3.3: {} - - tinybench@2.9.0: {} - - tinyexec@0.3.2: {} - - tinyglobby@0.2.15: - dependencies: - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - - tinypool@1.1.1: {} - - tinyrainbow@2.0.0: {} - - tinyspy@4.0.4: {} - - tippy.js@6.3.7: - dependencies: - '@popperjs/core': 2.11.8 - - tldts-core@6.1.86: {} - - tldts-core@7.0.27: {} - - tldts@6.1.86: - dependencies: - tldts-core: 6.1.86 - - tldts@7.0.27: - dependencies: - tldts-core: 7.0.27 - - to-regex-range@5.0.1: - dependencies: - is-number: 7.0.0 - - totalist@3.0.1: {} - - tough-cookie@5.1.2: - dependencies: - tldts: 6.1.86 - - tr46@0.0.3: {} - - tr46@5.1.1: - dependencies: - punycode: 2.3.1 - - trim-lines@3.0.1: {} - - troika-three-text@0.52.4(three@0.181.2): - dependencies: - bidi-js: 1.0.3 - three: 0.181.2 - troika-three-utils: 0.52.4(three@0.181.2) - troika-worker-utils: 0.52.0 - webgl-sdf-generator: 1.1.1 - - troika-three-utils@0.52.4(three@0.181.2): - dependencies: - three: 0.181.2 - - troika-worker-utils@0.52.0: {} - - ts-api-utils@2.5.0(typescript@5.9.3): - dependencies: - typescript: 5.9.3 - - tslib@2.3.0: {} - - tslib@2.4.0: {} - - tslib@2.8.1: {} - - tweakpane@3.1.10: {} - - type-check@0.4.0: - dependencies: - prelude-ls: 1.2.1 - - typescript-eslint@8.57.2(eslint@9.39.4)(typescript@5.9.3): - dependencies: - '@typescript-eslint/eslint-plugin': 8.57.2(@typescript-eslint/parser@8.57.2(eslint@9.39.4)(typescript@5.9.3))(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/parser': 8.57.2(eslint@9.39.4)(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.57.2(typescript@5.9.3) - '@typescript-eslint/utils': 8.57.2(eslint@9.39.4)(typescript@5.9.3) - eslint: 9.39.4 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - - typescript@5.9.3: {} - - undici-types@7.18.2: {} - - unist-util-is@6.0.1: - dependencies: - '@types/unist': 3.0.3 - - unist-util-position@5.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-stringify-position@4.0.0: - dependencies: - '@types/unist': 3.0.3 - - unist-util-visit-parents@6.0.2: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - - unist-util-visit@5.1.0: - dependencies: - '@types/unist': 3.0.3 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - - unplugin@1.0.1: - dependencies: - acorn: 8.16.0 - chokidar: 3.6.0 - webpack-sources: 3.3.4 - webpack-virtual-modules: 0.5.0 - - update-browserslist-db@1.2.3(browserslist@4.28.1): - dependencies: - browserslist: 4.28.1 - escalade: 3.2.0 - picocolors: 1.1.1 - - uri-js@4.4.1: - dependencies: - punycode: 2.3.1 - - util-deprecate@1.0.2: {} - - vfile-message@4.0.3: - dependencies: - '@types/unist': 3.0.3 - unist-util-stringify-position: 4.0.0 - - vfile@6.0.3: - dependencies: - '@types/unist': 3.0.3 - vfile-message: 4.0.3 - - vite-node@3.2.4(@types/node@25.5.0)(sass@1.98.0): - dependencies: - cac: 6.7.14 - debug: 4.4.3 - es-module-lexer: 1.7.0 - pathe: 2.0.3 - vite: 7.3.1(@types/node@25.5.0)(sass@1.98.0) - transitivePeerDependencies: - - '@types/node' - - jiti - - less - - lightningcss - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - vite@7.3.1(@types/node@25.5.0)(sass@1.98.0): - dependencies: - esbuild: 0.27.4 - fdir: 6.5.0(picomatch@4.0.4) - picomatch: 4.0.4 - postcss: 8.5.8 - rollup: 4.60.0 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 25.5.0 - fsevents: 2.3.3 - sass: 1.98.0 - - vitefu@1.1.2(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)): - optionalDependencies: - vite: 7.3.1(@types/node@25.5.0)(sass@1.98.0) - - vitest@3.2.4(@types/node@25.5.0)(@vitest/ui@3.2.4)(jsdom@26.1.0)(sass@1.98.0): - dependencies: - '@types/chai': 5.2.3 - '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.3.1(@types/node@25.5.0)(sass@1.98.0)) - '@vitest/pretty-format': 3.2.4 - '@vitest/runner': 3.2.4 - '@vitest/snapshot': 3.2.4 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - debug: 4.4.3 - expect-type: 1.3.0 - magic-string: 0.30.21 - pathe: 2.0.3 - picomatch: 4.0.4 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tinypool: 1.1.1 - tinyrainbow: 2.0.0 - vite: 7.3.1(@types/node@25.5.0)(sass@1.98.0) - vite-node: 3.2.4(@types/node@25.5.0)(sass@1.98.0) - why-is-node-running: 2.3.0 - optionalDependencies: - '@types/node': 25.5.0 - '@vitest/ui': 3.2.4(vitest@3.2.4) - jsdom: 26.1.0 - transitivePeerDependencies: - - jiti - - less - - lightningcss - - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml - - w3c-xmlserializer@5.0.0: - dependencies: - xml-name-validator: 5.0.0 - - webgl-sdf-generator@1.1.1: {} - - webidl-conversions@3.0.1: {} - - webidl-conversions@7.0.0: {} - - webpack-sources@3.3.4: {} - - webpack-virtual-modules@0.5.0: {} - - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 - - whatwg-mimetype@4.0.0: {} - - whatwg-url@14.2.0: - dependencies: - tr46: 5.1.1 - webidl-conversions: 7.0.0 - - whatwg-url@5.0.0: - dependencies: - tr46: 0.0.3 - webidl-conversions: 3.0.1 - - which-boxed-primitive@1.1.1: - dependencies: - is-bigint: 1.1.0 - is-boolean-object: 1.2.2 - is-number-object: 1.1.1 - is-string: 1.1.1 - is-symbol: 1.1.1 - - which-collection@1.0.2: - dependencies: - is-map: 2.0.3 - is-set: 2.0.3 - is-weakmap: 2.0.2 - is-weakset: 2.0.4 - - which-typed-array@1.1.20: - dependencies: - available-typed-arrays: 1.0.7 - 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 - - which@2.0.2: - dependencies: - isexe: 2.0.0 - - why-is-node-running@2.3.0: - dependencies: - siginfo: 2.0.0 - stackback: 0.0.2 - - word-wrap@1.2.5: {} - - ws@8.20.0: {} - - xml-name-validator@5.0.0: {} - - xmlchars@2.2.0: {} - - xtend@4.0.2: {} - - yallist@3.1.1: {} - - yaml@1.10.3: {} - - yocto-queue@0.1.0: {} - - zimmerframe@1.1.4: {} - - zod-to-json-schema@3.25.2(zod@3.25.76): - dependencies: - zod: 3.25.76 - - zod@3.25.76: {} - - zrender@5.6.1: - dependencies: - tslib: 2.3.0 - - zwitch@2.0.4: {} diff --git a/src/lib/actions/analytics.ts b/src/lib/actions/analytics.ts index c806945d0f..ebd6e8abf0 100644 --- a/src/lib/actions/analytics.ts +++ b/src/lib/actions/analytics.ts @@ -225,6 +225,9 @@ export enum Submit { AccountRecoveryCodesCreate = 'submit_account_recovery_codes_create', AccountRecoveryCodesUpdate = 'submit_account_recovery_codes_update', AccountDeleteIdentity = 'submit_account_delete_identity', + AccountOAuth2ConsentApprove = 'submit_account_oauth2_consent_approve', + AccountOAuth2ConsentDeny = 'submit_account_oauth2_consent_deny', + AccountOAuth2DeviceVerify = 'submit_account_oauth2_device_verify', FeedbackSubmit = 'submit_leave_feedback', FilterClear = 'submit_clear_filter', FilterApply = 'submit_filter_apply', @@ -255,6 +258,8 @@ export enum Submit { ProjectUpdateLabels = 'submit_project_update_labels', ProjectService = 'submit_project_service', ProjectUpdateSMTP = 'submit_project_update_smtp', + ProjectUpdateOAuth2Server = 'submit_project_update_oauth2_server', + ProjectUsageExecutionsBreakdown = 'submit_project_usage_executions_breakdown', ProjectResume = 'submit_project_resume', MemberCreate = 'submit_member_create', MemberDelete = 'submit_member_delete', @@ -271,9 +276,15 @@ export enum Submit { AuthStatusUpdate = 'submit_auth_status_update', AuthPasswordHistoryUpdate = 'submit_auth_password_history_limit_update', AuthPasswordDictionaryUpdate = 'submit_auth_password_dictionary_update', + AuthPasswordStrengthUpdate = 'submit_auth_password_strength_update', AuthPersonalDataCheckUpdate = 'submit_auth_personal_data_check_update', + AuthAliasedEmailsUpdate = 'submit_auth_aliased_emails_update', + AuthDisposableEmailsUpdate = 'submit_auth_disposable_emails_update', + AuthFreeEmailsUpdate = 'submit_auth_free_emails_update', + AuthCorporateEmailsUpdate = 'submit_auth_corporate_emails_update', AuthSessionAlertsUpdate = 'submit_auth_session_alerts_update', AuthMembershipPrivacyUpdate = 'submit_auth_membership_privacy_update', + AuthMfaFactorsUpdate = 'submit_auth_mfa_factors_update', AuthMockNumbersUpdate = 'submit_auth_mock_numbers_update', AuthInvalidateSession = 'submit_auth_invalidate_session', SessionsLengthUpdate = 'submit_sessions_length_update', diff --git a/src/lib/appwrite/impersonation.ts b/src/lib/appwrite/impersonation.ts index 9339a99249..5db970dbc6 100644 --- a/src/lib/appwrite/impersonation.ts +++ b/src/lib/appwrite/impersonation.ts @@ -1,5 +1,5 @@ -import { writable } from 'svelte/store'; -import { building } from '$app/environment'; +import { derived, writable } from 'svelte/store'; +import { browser, building } from '$app/environment'; const KEY_TARGET_USER_ID = 'console.impersonation.targetUserId'; const KEY_OPERATOR = 'console.impersonation.operator'; @@ -17,6 +17,9 @@ export type TargetSnapshot = { email: string; }; +type ResourceUrl = string | URL; +type ResourceQueryParams = Record; + /** * Incrementing revision triggers reactive re-fetches after impersonation changes. * Consumers can depend() on this or subscribe to it. @@ -67,7 +70,7 @@ export function clearPersistedImpersonation(): void { } export function readTargetSnapshot(): TargetSnapshot | null { - if (building) return null; + if (building || !browser) return null; const raw = sessionStorage.getItem(KEY_TARGET); if (!raw) return null; try { @@ -78,12 +81,46 @@ export function readTargetSnapshot(): TargetSnapshot | null { } export function readImpersonationTargetUserId(): string | null { - if (building) return null; + if (building || !browser) return null; return sessionStorage.getItem(KEY_TARGET_USER_ID); } +export function createImpersonatedResourceUrl( + url: ResourceUrl, + queryParams: ResourceQueryParams = {} +): string { + const urlString = url.toString(); + const baseUrl = browser ? window.location.origin : 'http://localhost'; + const parsedUrl = new URL(urlString, baseUrl); + const targetUserId = readImpersonationTargetUserId(); + + for (const [key, value] of Object.entries(queryParams)) { + if (value !== undefined) { + parsedUrl.searchParams.set(key, value.toString()); + } + } + + const isAbsoluteUrl = /^[a-zA-Z][a-zA-Z\d+\-.]*:/.test(urlString); + const serializedUrl = + !browser && !isAbsoluteUrl + ? `${parsedUrl.pathname}${parsedUrl.search}${parsedUrl.hash}` + : parsedUrl.toString(); + + if (!targetUserId) return serializedUrl; + + parsedUrl.searchParams.set('impersonateUserId', targetUserId); + + return parsedUrl.toString(); +} + +export const impersonatedResourceUrl = derived( + impersonationRevision, + () => (url: ResourceUrl, queryParams?: ResourceQueryParams) => + createImpersonatedResourceUrl(url, queryParams) +); + export function readOperatorSnapshot(): OperatorSnapshot | null { - if (building) return null; + if (building || !browser) return null; const raw = sessionStorage.getItem(KEY_OPERATOR); if (!raw) return null; try { diff --git a/src/lib/commandCenter/searchers/functions.ts b/src/lib/commandCenter/searchers/functions.ts index d28992964e..0e708d5a96 100644 --- a/src/lib/commandCenter/searchers/functions.ts +++ b/src/lib/commandCenter/searchers/functions.ts @@ -56,16 +56,6 @@ export const functionsSearcher = (async (query: string) => { }, group: 'functions' }, - { - label: 'Go to usage', - nested: true, - callback() { - goto( - `${base}/project-${page.params.region}-${projectId}/functions/function-${func.$id}/usage` - ); - }, - group: 'functions' - }, { label: 'Go to executions', nested: true, diff --git a/src/lib/commandCenter/searchers/projects.ts b/src/lib/commandCenter/searchers/projects.ts index 6ecfe955db..7a3412ac1d 100644 --- a/src/lib/commandCenter/searchers/projects.ts +++ b/src/lib/commandCenter/searchers/projects.ts @@ -37,7 +37,7 @@ export const projectsSearcher = (async (query: string) => { return []; } - const { projects } = await sdk.forConsole.projects.list({ + const { projects } = await sdk.forConsole.organization(get(organization).$id).listProjects({ queries: [ Query.equal('teamId', get(organization).$id), Query.orderDesc(''), diff --git a/src/lib/commandCenter/searchers/teams.ts b/src/lib/commandCenter/searchers/teams.ts index 7e9f4dc609..15fff34334 100644 --- a/src/lib/commandCenter/searchers/teams.ts +++ b/src/lib/commandCenter/searchers/teams.ts @@ -33,17 +33,6 @@ export const teamSearcher = (async (query: string) => { }, group: 'teams', nested: true - }, - - { - label: 'Go to activity', - callback: () => { - goto( - `${base}/project-${page.params.region}-${page.params.project}/auth/teams/team-${teams[0].$id}/activity` - ); - }, - group: 'teams', - nested: true } ]; } diff --git a/src/lib/commandCenter/searchers/users.ts b/src/lib/commandCenter/searchers/users.ts index c4e08409a2..9e340694f3 100644 --- a/src/lib/commandCenter/searchers/users.ts +++ b/src/lib/commandCenter/searchers/users.ts @@ -34,16 +34,6 @@ export const userSearcher = (async (query: string) => { nested: true, icon: IconTrash }, - { - label: 'Go to activity', - callback: () => { - goto( - `${base}/project-${page.params.region}-${page.params.project}/auth/user-${users[0].$id}/activity` - ); - }, - group: 'users', - nested: true - }, { label: 'Go to sessions', callback: () => { diff --git a/src/lib/components/billing/alerts/newDevUpgradePro.svelte b/src/lib/components/billing/alerts/newDevUpgradePro.svelte index 7d38ec049c..b4b0254b3a 100644 --- a/src/lib/components/billing/alerts/newDevUpgradePro.svelte +++ b/src/lib/components/billing/alerts/newDevUpgradePro.svelte @@ -23,7 +23,7 @@ } -{#if show && $organization?.$id && !$organization?.billingPlanDetails.supportsCredits && !page.url.pathname.includes(base + '/account')} +{#if show && $organization?.$id && !$organization?.billingPlanDetails?.supportsCredits && !page.url.pathname.includes(base + '/account')} {#if $actionRequiredInvoices && $actionRequiredInvoices?.invoices?.length && !hideBillingHeaderRoutes.includes(page.url.pathname)} @@ -14,9 +21,7 @@ Please authorize your upcoming payment for {$organization.name}. Your bank requires this security measure to proceed with payment. - + + {#if open} + + {/if} + + + diff --git a/src/lib/components/git/connectGit.svelte b/src/lib/components/git/connectGit.svelte index a44fe5dab2..6473f5f6d1 100644 --- a/src/lib/components/git/connectGit.svelte +++ b/src/lib/components/git/connectGit.svelte @@ -1,14 +1,20 @@ @@ -23,7 +29,7 @@ @@ -35,13 +41,24 @@ title="No installation was added to the project yet" description="Add an installation to connect repositories"> - + + + {#if isGiteaEnabled} + + {/if} + diff --git a/src/lib/components/git/index.ts b/src/lib/components/git/index.ts index a5cab5eed2..ddec8646be 100644 --- a/src/lib/components/git/index.ts +++ b/src/lib/components/git/index.ts @@ -7,5 +7,6 @@ export { default as DeploymentSource } from './deploymentSource.svelte'; export { default as DeploymentDomains } from './deploymentDomains.svelte'; export { default as ConnectBehaviour } from './connectBehaviour.svelte'; export { default as ProductionBranchFieldset } from './productionBranchFieldset.svelte'; +export { default as BranchSelector } from './branchSelector.svelte'; export { default as RepositoryCard } from './repositoryCard.svelte'; export { default as ConnectRepoModal } from './connectRepoModal.svelte'; diff --git a/src/lib/components/git/productionBranchFieldset.svelte b/src/lib/components/git/productionBranchFieldset.svelte index addd405576..fbd98f81e4 100644 --- a/src/lib/components/git/productionBranchFieldset.svelte +++ b/src/lib/components/git/productionBranchFieldset.svelte @@ -1,9 +1,9 @@
- {#await loadBranches()} + {#await loadDefaultBranch()} - - - - - - - - - - - - - + - {:then branches} - {@const options = - branches - ?.map((branch) => { - return { - value: branch.name, - label: branch.name - }; - }) - ?.sort((a, b) => { - return a.label > b.label ? 1 : -1; - }) ?? []} + {:then} - { - branch = event.detail.value; - }} - {options} /> + {installationId} + {repositoryId} + on:select={(e) => (branch = e.detail)} /> - import { Form } from '$lib/elements/forms'; - import { disableCommands } from '$lib/commandCenter'; import { beforeNavigate } from '$app/navigation'; + import { disableCommands } from '$lib/commandCenter'; + import { Form } from '$lib/elements/forms'; import { Alert, Layout, Modal } from '@appwrite.io/pink-svelte'; + import DOMPurify from 'dompurify'; export let show = false; export let autoClose = true; @@ -27,6 +28,16 @@ $: if (error) { alert?.scrollIntoView({ behavior: 'smooth', block: 'start', inline: 'nearest' }); } + + // Melt UI's ComboBox (and other listbox-based components) call removeScroll() + // when they open, which adds overflow:hidden + compensatory padding-right + $: if (typeof document !== 'undefined') { + if (show) { + document.body.setAttribute('data-melt-scroll-lock', ''); + } else { + document.body.removeAttribute('data-melt-scroll-lock'); + } + }
@@ -34,14 +45,17 @@ {#if error} -
+
{ error = null; }}> - {error} + {@html DOMPurify.sanitize(error, { + ALLOWED_TAGS: ['a'], + ALLOWED_ATTR: ['href', 'target'] + }).replace(/
{/if} @@ -66,4 +80,9 @@ opacity: 0; animation: none; } + + .alert-error :global(a) { + color: inherit; + text-decoration: underline; + } diff --git a/src/lib/components/roles/roles.svelte b/src/lib/components/roles/roles.svelte index 79d1b1d838..4d58acf770 100644 --- a/src/lib/components/roles/roles.svelte +++ b/src/lib/components/roles/roles.svelte @@ -1,11 +1,16 @@

Roles

-

Owner, Developer, Editor, Analyst and Billing.

+

+ {isProjectSpecific + ? 'Owner, Developer, Editor and Analyst.' + : 'Owner, Developer, Editor, Analyst and Billing.'} +

({ ...variable, secret: true })); } - newVariables.forEach((variable) => { - if (('' + variable.value).length > 8192) { - throw new Error( - `Variable ${variable.key} is longer than 8192 allowed characters` - ); - } - }); + const validationError = validateVariables( + newVariables.filter((variable) => variable.key || variable.value) + ); + if (validationError) { + throw new Error(validationError); + } + const updatedVariables = [...variables]; newVariables.forEach((newVar) => { if (!newVar.key) { diff --git a/src/lib/components/variables/environmentVariables.svelte b/src/lib/components/variables/environmentVariables.svelte index 98290c0412..88dddf3019 100644 --- a/src/lib/components/variables/environmentVariables.svelte +++ b/src/lib/components/variables/environmentVariables.svelte @@ -2,27 +2,17 @@ import { Empty, Paginator } from '$lib/components'; import { Button } from '$lib/elements/forms'; import { - ActionMenu, Accordion, Badge, InteractiveText, Icon, Layout, - Popover, Skeleton, Table, - Tooltip, - Button as PinkButton + Tooltip } from '@appwrite.io/pink-svelte'; - import { - IconDotsHorizontal, - IconCode, - IconUpload, - IconPlus, - IconTrash, - IconEyeOff, - IconPencil - } from '@appwrite.io/pink-icons-svelte'; + import { IconCode, IconUpload, IconPlus } from '@appwrite.io/pink-icons-svelte'; + import VariableActionMenu from './variableActionMenu.svelte'; import type { Models } from '@appwrite.io/console'; import VariableEditorModal from './variableEditorModal.svelte'; import SecretVariableModal from './secretVariableModal.svelte'; @@ -32,6 +22,7 @@ import UpdateVariableModal from './updateVariableModal.svelte'; import { Click, trackEvent } from '$lib/actions/analytics'; import { isSmallViewport } from '$lib/stores/viewport'; + import { isValidVariableKey } from '$lib/helpers/variables'; const DOCS_LINKS: Record = { site: 'https://appwrite.io/docs/products/sites/develop#accessing-environment-variables', @@ -66,14 +57,14 @@ const tableColumns = $derived( $isSmallViewport ? [ - { id: 'key', width: { min: 420 } }, - { id: 'value', width: { min: 240 } }, + { id: 'key', width: { min: 120, max: 300 } }, + { id: 'value', width: { min: 100, max: 200 } }, { id: 'actions', width: 40 } ] : [ - { id: 'key', width: { min: 300 } }, - { id: 'value', width: { min: 280 } }, - { id: 'actions', width: 40 } + { id: 'key', width: { min: 280, max: 420 } }, + { id: 'value', width: { min: 200, max: 400 } }, + { id: 'actions', width: 50 } ] ); @@ -111,13 +102,15 @@ {/if} @@ -154,7 +147,28 @@ {#each paginatedItems as variable} - {variable.key} + + + {#if !isValidVariableKey(variable.key)} + + + + This key can't be used as an environment + variable name. Rename it using only letters, + digits and underscores, without starting + with a digit. + + + {/if} + {variable.key} + +

@@ -179,59 +193,20 @@
- - { - e.preventDefault(); - toggle(e); - }}> - - - - - - {#if !variable?.secret} - { - toggle(e); - currentVariable = variable; - showUpdate = true; - }}> - Update - - {/if} - {#if !variable?.secret} - { - toggle(e); - currentVariable = variable; - showSecretModal = true; - }}> - Secret - - {/if} - { - toggle(e); - currentVariable = variable; - showDelete = true; - }}> - Delete - - - - + { + currentVariable = variable; + showUpdate = true; + }} + onSecret={() => { + currentVariable = variable; + showSecretModal = true; + }} + onDelete={() => { + currentVariable = variable; + showDelete = true; + }} />
diff --git a/src/lib/components/variables/importVariablesModal.svelte b/src/lib/components/variables/importVariablesModal.svelte index 9f0b782d1e..9eed108b23 100644 --- a/src/lib/components/variables/importVariablesModal.svelte +++ b/src/lib/components/variables/importVariablesModal.svelte @@ -7,6 +7,7 @@ import { Icon, Layout, Selector, Tooltip, Typography, Upload } from '@appwrite.io/pink-svelte'; import { parse } from '$lib/helpers/envfile'; import { removeFile } from '$lib/helpers/files'; + import { validateVariables } from '$lib/helpers/variables'; export let show = false; export let variables: Partial[]; @@ -35,19 +36,20 @@ if (!Object.keys(uploaded).length) { throw new Error('No variables found'); } - const entries = Object.entries(uploaded); + // Drop the valueless entries first. They are never written, so an + // invalid key on one of them must not reject the whole file. + const entries = Object.entries(uploaded).filter(([, value]) => !!value); - for (const [key, value] of entries) { - if (value.length > 8192) { - throw new Error(`Variable ${key} is longer than 8192 allowed characters`); - } + const validationError = validateVariables( + entries.map(([key, value]) => ({ key, value })) + ); + if (validationError) { + throw new Error(validationError); } - entries - .filter(([, value]) => !!value) - .forEach(([key, value]) => { - variables.push({ key, value, secret }); - }); + entries.forEach(([key, value]) => { + variables.push({ key, value, secret }); + }); show = false; } catch (e) { diff --git a/src/lib/components/variables/updateVariableModal.svelte b/src/lib/components/variables/updateVariableModal.svelte index bf48d8b62f..005ec89ba0 100644 --- a/src/lib/components/variables/updateVariableModal.svelte +++ b/src/lib/components/variables/updateVariableModal.svelte @@ -7,6 +7,7 @@ import { Layout, Selector } from '@appwrite.io/pink-svelte'; import { Link } from '$lib/elements'; import { page } from '$app/state'; + import { validateVariables } from '$lib/helpers/variables'; export let show = false; export let selectedVar: Partial; @@ -20,13 +21,21 @@ secret: selectedVar?.secret }; + let error = ''; + function handleVariable() { + const validationError = validateVariables([pair]); + if (validationError) { + error = validationError; + return; + } + if (selectedVar) { variables = variables.map((variable) => { - if (variable.$id === selectedVar.$id) { - return pair; - } - return variable; + const match = selectedVar.$id + ? variable.$id === selectedVar.$id + : variable.key === selectedVar.key; + return match ? pair : variable; }); } else { variables = [...variables, pair]; @@ -39,7 +48,7 @@ } - + Update the environment variable for your {productLabel}. Global variables can be set in + import { computePosition, flip, offset, shift, autoUpdate } from '@floating-ui/dom'; + import { Icon, ActionMenu } from '@appwrite.io/pink-svelte'; + import { + IconDotsHorizontal, + IconPencil, + IconEyeOff, + IconTrash + } from '@appwrite.io/pink-icons-svelte'; + import { Button as PinkButton } from '@appwrite.io/pink-svelte'; + import type { Models } from '@appwrite.io/console'; + + let { + variable, + onUpdate, + onSecret, + onDelete + }: { + variable: Partial; + onUpdate: () => void; + onSecret: () => void; + onDelete: () => void; + } = $props(); + + let open = $state(false); + let triggerEl = $state(null); + let menuEl = $state(null); + let cleanup: (() => void) | null = null; + + function hide() { + open = false; + } + + function toggle() { + open = !open; + } + + function portalToBody(node: HTMLElement) { + document.body.appendChild(node); + return { + destroy() { + node.parentNode?.removeChild(node); + } + }; + } + + $effect(() => { + if (open && triggerEl && menuEl) { + cleanup = autoUpdate(triggerEl, menuEl, () => { + computePosition(triggerEl, menuEl, { + placement: 'bottom-end', + middleware: [offset(2), flip(), shift()] + }).then(({ x, y }) => { + if (menuEl) { + Object.assign(menuEl.style, { left: `${x}px`, top: `${y}px` }); + } + }); + }); + } else { + cleanup?.(); + cleanup = null; + } + }); + + function handleWindowClick(e: MouseEvent) { + if (!open) return; + const target = e.target as Node; + if (triggerEl?.contains(target) || menuEl?.contains(target)) return; + hide(); + } + + function handleKeydown(e: KeyboardEvent) { + if (e.key === 'Escape') hide(); + } + + + + + + { + e.preventDefault(); + toggle(); + }}> + + + + +{#if open} +
+ + {#if !variable?.secret} + { + hide(); + onUpdate(); + }}> + Update + + {/if} + {#if !variable?.secret} + { + hide(); + onSecret(); + }}> + Secret + + {/if} + { + hide(); + onDelete(); + }}> + Delete + + +
+{/if} diff --git a/src/lib/components/variables/variableEditorModal.svelte b/src/lib/components/variables/variableEditorModal.svelte index ad5405601c..82f87b625e 100644 --- a/src/lib/components/variables/variableEditorModal.svelte +++ b/src/lib/components/variables/variableEditorModal.svelte @@ -5,6 +5,7 @@ import Button from '$lib/elements/forms/button.svelte'; import { addNotification } from '$lib/stores/notifications'; import { parse } from '$lib/helpers/envfile'; + import { validateVariables } from '$lib/helpers/variables'; import { Alert, Icon, Layout, Tabs } from '@appwrite.io/pink-svelte'; import { IconDownload, IconDuplicate } from '@appwrite.io/pink-icons-svelte'; import { InputTextarea } from '$lib/elements/forms'; @@ -47,10 +48,11 @@ const vars = tab === 'env' ? parse(envCode) : JSON.parse(jsonCode ? jsonCode : '{}'); const entries = Object.entries(vars); - for (const [key, value] of entries) { - if (('' + value).length > 8192) { - throw new Error(`Variable ${key} is longer than 8192 allowed characters`); - } + const validationError = validateVariables( + entries.map(([key, value]) => ({ key, value })) + ); + if (validationError) { + throw new Error(validationError); } // Update or remove editable variables diff --git a/src/lib/elements/forms/inputPassword.svelte b/src/lib/elements/forms/inputPassword.svelte index 6e2d0c7b84..0b5153e396 100644 --- a/src/lib/elements/forms/inputPassword.svelte +++ b/src/lib/elements/forms/inputPassword.svelte @@ -10,7 +10,7 @@ export let required = false; export let disabled = false; export let autofocus = false; - export let autocomplete = false; + export let autocomplete: boolean | string = false; export let minlength = 8; export let maxlength: number = null; export let leadingIcon: ComponentType | undefined = undefined; @@ -47,7 +47,11 @@ {leadingIcon} state={error ? 'error' : 'default'} autofocus={autofocus || undefined} - autocomplete={autocomplete ? 'on' : 'off'} + autocomplete={typeof autocomplete === 'string' + ? (autocomplete as unknown as 'on') + : autocomplete + ? 'on' + : 'off'} helper={helper || error} on:invalid={handleInvalid} bind:value> diff --git a/src/lib/flags.ts b/src/lib/flags.ts index b7f92c9483..023f948748 100644 --- a/src/lib/flags.ts +++ b/src/lib/flags.ts @@ -19,5 +19,6 @@ function isFlagEnabled(name: string) { } export const flags = { - multiDb: isFlagEnabled('multi-db') + multiDb: isFlagEnabled('multi-db'), + oauth2Server: isFlagEnabled('oauth2-server') }; diff --git a/src/lib/helpers/campaign.ts b/src/lib/helpers/campaign.ts new file mode 100644 index 0000000000..1018d668f9 --- /dev/null +++ b/src/lib/helpers/campaign.ts @@ -0,0 +1,7 @@ +import { getApiEndpoint } from '$lib/stores/sdk'; + +export function getCampaignImageUrl(image: string) { + const endpoint = getApiEndpoint(); + const url = new URL(image, endpoint); + return url.toString(); +} diff --git a/src/lib/helpers/oauth2-app-logo.test.ts b/src/lib/helpers/oauth2-app-logo.test.ts new file mode 100644 index 0000000000..1ab56b2c05 --- /dev/null +++ b/src/lib/helpers/oauth2-app-logo.test.ts @@ -0,0 +1,27 @@ +import { describe, expect, it } from 'vitest'; +import { resolveOAuth2AppLogoUrl } from './oauth2-app-logo'; + +describe('resolveOAuth2AppLogoUrl', () => { + it('uses the square Appwrite icon for the first-party CLI client', () => { + expect( + resolveOAuth2AppLogoUrl({ + $id: 'appwrite-cli', + logoUri: 'https://example.com/wordmark.svg' + }) + ).toBe('/console/logos/appwrite-icon.svg'); + }); + + it('keeps third-party logoUri values', () => { + expect( + resolveOAuth2AppLogoUrl({ + $id: 'other-app', + logoUri: 'https://example.com/logo.png' + }) + ).toBe('https://example.com/logo.png'); + }); + + it('returns an empty string when no logo is available', () => { + expect(resolveOAuth2AppLogoUrl({ $id: 'other-app', logoUri: ' ' })).toBe(''); + expect(resolveOAuth2AppLogoUrl(null)).toBe(''); + }); +}); diff --git a/src/lib/helpers/oauth2-app-logo.ts b/src/lib/helpers/oauth2-app-logo.ts new file mode 100644 index 0000000000..3235ec749f --- /dev/null +++ b/src/lib/helpers/oauth2-app-logo.ts @@ -0,0 +1,18 @@ +import { base } from '$app/paths'; + +/** + * First-party clients may register a wide wordmark as `logoUri`. Consent and + * outcome avatars are square, so `object-fit: cover` crops those marks into + * unreadable fragments (see #3159 for Appwrite CLI). Prefer the square icon. + */ +const FIRST_PARTY_ICON_CLIENTS = new Set(['appwrite-cli']); + +export function resolveOAuth2AppLogoUrl( + app: { $id?: string; logoUri?: string } | null | undefined +): string { + if (app?.$id && FIRST_PARTY_ICON_CLIENTS.has(app.$id)) { + return `${base}/logos/appwrite-icon.svg`; + } + + return app?.logoUri?.trim() ?? ''; +} diff --git a/src/lib/helpers/oauth2-authorization-details.ts b/src/lib/helpers/oauth2-authorization-details.ts new file mode 100644 index 0000000000..3d6caf7440 --- /dev/null +++ b/src/lib/helpers/oauth2-authorization-details.ts @@ -0,0 +1,306 @@ +import { Query } from '@appwrite.io/console'; +import { sdk } from '$lib/stores/sdk'; +import { getTeamOrOrganizationList } from '$lib/stores/organization'; + +/** + * RFC 9396 Rich Authorization Requests (RAR) helpers for the console OAuth2 + * consent screen (contract v2). + * + * In v2 the `scope` parameter carries every privilege the client requests (see + * `oauth2-scopes.ts`). `authorization_details` only binds those privileges to + * concrete resources, as entries of two types: + * + * { "type": "project", "identifiers": ["", …] | ["*"] } + * { "type": "organization", "identifiers": ["", …] | ["*"] } + * + * `identifiers` is the only field besides `type`; `*` is a wildcard that binds + * the tier's scopes to every project / organization the user owns (present and + * future). The consent screen lets the user narrow the requested identifiers to + * a subset and sends the result back to the approve endpoint, which replaces the + * client's requested details. + */ + +export const PROJECT_RAR_TYPE = 'project'; +export const ORGANIZATION_RAR_TYPE = 'organization'; + +/** Wildcard identifier — binds a tier's scopes to every owned resource. */ +export const WILDCARD_IDENTIFIER = '*'; + +/** The reserved internal project id; never a valid RAR target. */ +const RESERVED_CONSOLE_PROJECT = 'console'; + +export interface AuthorizationDetail { + type: string; + identifiers?: string[]; + [key: string]: unknown; +} + +/** Parse the grant's `authorizationDetails` JSON string into entries. */ +export function parseAuthorizationDetails(raw: string | null | undefined): AuthorizationDetail[] { + if (!raw) return []; + try { + const parsed = JSON.parse(raw); + return Array.isArray(parsed) ? (parsed as AuthorizationDetail[]) : []; + } catch { + return []; + } +} + +/** Distinct, non-empty identifiers for a single entry. */ +export function identifiersOf(detail: AuthorizationDetail): string[] { + if (!Array.isArray(detail.identifiers)) return []; + const seen = new Set(); + const out: string[] = []; + for (const identifier of detail.identifiers) { + if (typeof identifier === 'string' && identifier !== '' && !seen.has(identifier)) { + seen.add(identifier); + out.push(identifier); + } + } + return out; +} + +/** + * Union of identifiers across every entry of the given type, request order + * preserved. Keeps the `*` wildcard; drops the reserved `console` project id + * from `project` entries (the server rejects it anyway). + */ +export function mergeIdentifiers(details: AuthorizationDetail[], type: string): string[] { + const seen = new Set(); + const out: string[] = []; + for (const detail of details) { + if (detail.type !== type) continue; + for (const identifier of identifiersOf(detail)) { + if (type === PROJECT_RAR_TYPE && identifier === RESERVED_CONSOLE_PROJECT) continue; + if (seen.has(identifier)) continue; + seen.add(identifier); + out.push(identifier); + } + } + return out; +} + +export function hasWildcard(identifiers: string[]): boolean { + return identifiers.includes(WILDCARD_IDENTIFIER); +} + +/** Concrete (non-wildcard) ids among a set of identifiers. */ +export function concreteIdentifiers(identifiers: string[]): string[] { + return identifiers.filter((identifier) => identifier !== WILDCARD_IDENTIFIER); +} + +/** + * Rebuild the `authorization_details` array from the user's granted selection. + * Emits a `project` / `organization` entry only when that tier ends up bound to + * at least one identifier. Returns a JSON string ready for the approve endpoint, + * or `'[]'` when nothing remains (an empty string would tell the server to keep + * the originally requested details, which is never what the consent screen + * wants). + */ +export function serializeGrantedDetails(granted: { + project?: string[]; + organization?: string[]; +}): string { + const out: AuthorizationDetail[] = []; + if (granted.project && granted.project.length > 0) { + out.push({ type: PROJECT_RAR_TYPE, identifiers: granted.project }); + } + if (granted.organization && granted.organization.length > 0) { + out.push({ type: ORGANIZATION_RAR_TYPE, identifiers: granted.organization }); + } + return JSON.stringify(out); +} + +/* -------------------------------------------------------------------------- */ +/* Resource name resolution — turn identifiers into display names */ +/* -------------------------------------------------------------------------- */ + +export interface ResolvedResource { + id: string; + /** Display name, or the raw id when it couldn't be resolved. */ + name: string; + region?: string; + /** True when a real name was found; false means we fell back to the id. */ + resolved: boolean; +} + +export type ResourceNameMap = Map; + +export interface ResourcePage { + resources: ResolvedResource[]; + hasMore: boolean; +} + +function idOnlyMap(ids: string[]): ResourceNameMap { + const map: ResourceNameMap = new Map(); + for (const id of ids) { + map.set(id, { id, name: id, resolved: false }); + } + return map; +} + +/** + * Best-effort resolution of project ids to their display names. A bare project + * id can't be fetched directly — projects are reachable only through their + * owning organization — so we list the user's organizations and ask each for + * the requested ids. Anything we can't find (not owned, or in a non-primary + * region the console endpoint doesn't see) falls back to showing the raw id. + * Never throws: on any failure the caller still gets an id-only map. + */ +export async function resolveProjectNames(ids: string[]): Promise { + const map = idOnlyMap(ids); + if (ids.length === 0) return map; + + try { + const orgs = await getTeamOrOrganizationList([Query.limit(100)]); + const results = await Promise.allSettled( + orgs.teams.map((org) => + sdk.forConsole.organization(org.$id).listProjects({ + queries: [ + Query.equal('$id', ids), + Query.select(['$id', 'name', 'region', 'teamId']), + Query.limit(ids.length) + ] + }) + ) + ); + + for (const result of results) { + if (result.status !== 'fulfilled') continue; + for (const project of result.value.projects) { + map.set(project.$id, { + id: project.$id, + name: project.name, + region: project.region, + resolved: true + }); + } + } + } catch { + // Keep the id-only fallback map. + } + + return map; +} + +/** + * Best-effort resolution of organization ids to their names. The user's + * organization list already carries names, so a single list call covers it. + * Never throws: on any failure the caller still gets an id-only map. + */ +export async function resolveOrganizationNames(ids: string[]): Promise { + const map = idOnlyMap(ids); + if (ids.length === 0) return map; + + try { + const orgs = await getTeamOrOrganizationList([Query.limit(100)]); + for (const org of orgs.teams) { + if (map.has(org.$id)) { + map.set(org.$id, { id: org.$id, name: org.name, resolved: true }); + } + } + } catch { + // Keep the id-only fallback map. + } + + return map; +} + +/* -------------------------------------------------------------------------- */ +/* Type-to-search — narrowing a wildcard grant to specific resources */ +/* -------------------------------------------------------------------------- */ + +/** Cap on organizations swept per project search, to bound the request fan-out. */ +const SEARCH_ORG_SCAN = 20; + +/** + * Search the user's projects by name for the resource picker. Projects are only + * reachable through their owning organization, so we sweep the user's orgs and + * ask each for name matches. Results are exposed as a global paginated list + * across those organizations so the picker can load more as the user scrolls. + * Never throws: returns an empty page on failure. + */ +export async function searchProjects( + term: string, + offset: number, + limit: number +): Promise { + try { + const orgs = await getTeamOrOrganizationList([Query.limit(SEARCH_ORG_SCAN)]); + const trimmed = term.trim(); + const resources: ResolvedResource[] = []; + let skip = offset; + + for (const org of orgs.teams) { + const pageLimit = limit + 1 - resources.length; + const queries = [ + Query.notEqual('$id', RESERVED_CONSOLE_PROJECT), + Query.offset(skip), + Query.limit(pageLimit), + Query.select(['$id', 'name', 'region', 'teamId']) + ]; + if (trimmed !== '') { + queries.unshift(Query.startsWith('name', trimmed)); + } + + const result = await sdk.forConsole + .organization(org.$id) + .listProjects({ queries }) + .catch(() => null); + if (!result) continue; + + if (skip >= result.total) { + skip -= result.total; + continue; + } + skip = 0; + + for (const project of result.projects) { + resources.push({ + id: project.$id, + name: project.name, + region: project.region, + resolved: true + }); + } + if (resources.length > limit) break; + } + + return { + resources: resources.slice(0, limit), + hasMore: resources.length > limit + }; + } catch { + return { resources: [], hasMore: false }; + } +} + +/** + * Search the user's organizations by name using offset pagination. Never + * throws: returns an empty page on failure. + */ +export async function searchOrganizations( + term: string, + offset: number, + limit: number +): Promise { + try { + const queries = [Query.offset(offset), Query.limit(limit)]; + const trimmed = term.trim(); + // startsWith over search: search is full-text (word-boundary) matching, + // which drops partial-fragment matches; this mirrors the project search. + if (trimmed !== '') queries.push(Query.startsWith('name', trimmed)); + + const orgs = await getTeamOrOrganizationList(queries); + return { + resources: orgs.teams.map((org) => ({ + id: org.$id, + name: org.name, + resolved: true + })), + hasMore: offset + orgs.teams.length < orgs.total + }; + } catch { + return { resources: [], hasMore: false }; + } +} diff --git a/src/lib/helpers/oauth2-cimd.test.ts b/src/lib/helpers/oauth2-cimd.test.ts new file mode 100644 index 0000000000..fce9d1b2a2 --- /dev/null +++ b/src/lib/helpers/oauth2-cimd.test.ts @@ -0,0 +1,76 @@ +import { cimdDocumentToApp, isCimdClientId } from '$lib/helpers/oauth2-cimd'; +import { describe, expect, it } from 'vitest'; + +describe('isCimdClientId', () => { + it('accepts https URLs', () => { + expect(isCimdClientId('https://example.com/oauth/client-metadata.json')).toBe(true); + }); + + it('accepts http only for loopback', () => { + expect(isCimdClientId('http://localhost:3000/client.json')).toBe(true); + expect(isCimdClientId('http://127.0.0.1/client.json')).toBe(true); + expect(isCimdClientId('http://example.com/client.json')).toBe(false); + }); + + it('rejects plain app IDs and non-http schemes', () => { + expect(isCimdClientId('my-app_1.0')).toBe(false); + expect(isCimdClientId('64f1e2a9b3c4d5e6f7a8')).toBe(false); + expect(isCimdClientId('javascript:alert(1)')).toBe(false); + }); +}); + +describe('cimdDocumentToApp', () => { + const clientId = 'https://example.com/oauth/client-metadata.json'; + + it('maps RFC 7591 metadata onto the App model', () => { + const app = cimdDocumentToApp(clientId, { + client_id: clientId, + client_name: 'Example App', + client_uri: 'https://example.com', + logo_uri: 'https://example.com/logo.png', + policy_uri: 'https://example.com/privacy', + tos_uri: 'https://example.com/terms', + contacts: ['support@example.com'], + redirect_uris: ['https://example.com/callback'], + token_endpoint_auth_method: 'none', + grant_types: ['authorization_code', 'urn:ietf:params:oauth:grant-type:device_code'] + }); + + expect(app.$id).toBe(clientId); + expect(app.name).toBe('Example App'); + expect(app.clientUri).toBe('https://example.com'); + expect(app.logoUri).toBe('https://example.com/logo.png'); + expect(app.privacyPolicyUrl).toBe('https://example.com/privacy'); + expect(app.termsUrl).toBe('https://example.com/terms'); + expect(app.contacts).toEqual(['support@example.com']); + expect(app.redirectUris).toEqual(['https://example.com/callback']); + expect(app.type).toBe('public'); + expect(app.deviceFlow).toBe(true); + expect(app.enabled).toBe(true); + }); + + it('falls back to the hostname when client_name is missing', () => { + const app = cimdDocumentToApp(clientId, { client_id: clientId }); + expect(app.name).toBe('example.com'); + expect(app.deviceFlow).toBe(false); + }); + + it('rejects a document whose client_id does not match its URL', () => { + expect(() => + cimdDocumentToApp(clientId, { client_id: 'https://evil.example/other.json' }) + ).toThrow(); + expect(() => cimdDocumentToApp(clientId, 'not an object')).toThrow(); + }); + + it('drops unrenderable URI values', () => { + const app = cimdDocumentToApp(clientId, { + client_id: clientId, + logo_uri: 'javascript:alert(1)', + client_uri: 'not a url', + contacts: ['ok', 42] + }); + expect(app.logoUri).toBe(''); + expect(app.clientUri).toBe(''); + expect(app.contacts).toEqual(['ok']); + }); +}); diff --git a/src/lib/helpers/oauth2-cimd.ts b/src/lib/helpers/oauth2-cimd.ts new file mode 100644 index 0000000000..e9ec0c288a --- /dev/null +++ b/src/lib/helpers/oauth2-cimd.ts @@ -0,0 +1,111 @@ +import { sdk } from '$lib/stores/sdk'; +import type { Models } from '@appwrite.io/console'; + +// CIMD (Client ID Metadata Document): a client_id may be an HTTPS URL pointing +// to a JSON document of RFC 7591 client metadata. The Appwrite API no longer +// resolves these, so the console fetches the document itself for branding. + +const FETCH_TIMEOUT = 10_000; +const DEVICE_GRANT_TYPE = 'urn:ietf:params:oauth:grant-type:device_code'; +const HTTP_URL = /^https?:\/\//i; + +type CimdDocument = { + client_id?: unknown; + client_name?: unknown; + client_uri?: unknown; + logo_uri?: unknown; + policy_uri?: unknown; + tos_uri?: unknown; + contacts?: unknown; + redirect_uris?: unknown; + post_logout_redirect_uris?: unknown; + token_endpoint_auth_method?: unknown; + grant_types?: unknown; +}; + +// Plain app IDs never parse as URLs; http is allowed for local development only. +export function isCimdClientId(clientId: string): boolean { + try { + const url = new URL(clientId); + return ( + url.protocol === 'https:' || + (url.protocol === 'http:' && ['localhost', '127.0.0.1', '[::1]'].includes(url.hostname)) + ); + } catch { + return false; + } +} + +export function cimdDocumentToApp(clientId: string, document: unknown): Models.App { + if (typeof document !== 'object' || document === null) { + throw new Error('CIMD document is not a JSON object'); + } + const doc = document as CimdDocument; + // The document's client_id must equal the URL it was fetched from. + if (doc.client_id !== clientId) { + throw new Error('CIMD document client_id does not match its URL'); + } + const name = typeof doc.client_name === 'string' ? doc.client_name.trim() : ''; + return { + $id: clientId, + $createdAt: '', + $updatedAt: '', + name: name || new URL(clientId).hostname, + description: '', + // Untrusted values rendered in href/src must be http(s) URLs. + clientUri: + typeof doc.client_uri === 'string' && HTTP_URL.test(doc.client_uri) + ? doc.client_uri + : '', + logoUri: + typeof doc.logo_uri === 'string' && HTTP_URL.test(doc.logo_uri) ? doc.logo_uri : '', + privacyPolicyUrl: + typeof doc.policy_uri === 'string' && HTTP_URL.test(doc.policy_uri) + ? doc.policy_uri + : '', + termsUrl: typeof doc.tos_uri === 'string' && HTTP_URL.test(doc.tos_uri) ? doc.tos_uri : '', + contacts: Array.isArray(doc.contacts) + ? doc.contacts.filter((contact) => typeof contact === 'string') + : [], + tagline: '', + tags: [], + labels: [], + images: [], + supportUrl: '', + dataDeletionUrl: '', + redirectUris: Array.isArray(doc.redirect_uris) + ? doc.redirect_uris.filter((uri) => typeof uri === 'string') + : [], + postLogoutRedirectUris: Array.isArray(doc.post_logout_redirect_uris) + ? doc.post_logout_redirect_uris.filter((uri) => typeof uri === 'string') + : [], + enabled: true, + type: doc.token_endpoint_auth_method === 'none' ? 'public' : 'confidential', + deviceFlow: Array.isArray(doc.grant_types) && doc.grant_types.includes(DEVICE_GRANT_TYPE), + teamId: '', + userId: '', + installationScopes: [], + installationRedirectUrl: '', + secrets: [] + }; +} + +// Plain IDs resolve via the API; CIMD URLs are fetched directly. Fetch or +// validation failures fall back to hostname-only branding rather than blocking +// the flow — the server still validates the client during authorization. +export async function getOAuth2App(appId: string): Promise { + if (!isCimdClientId(appId)) { + return sdk.forConsole.apps.get({ appId }); + } + try { + const response = await fetch(appId, { + headers: { accept: 'application/json' }, + credentials: 'omit', + signal: AbortSignal.timeout(FETCH_TIMEOUT) + }); + if (!response.ok) throw new Error(`CIMD document request failed: ${response.status}`); + return cimdDocumentToApp(appId, await response.json()); + } catch { + return cimdDocumentToApp(appId, { client_id: appId }); + } +} diff --git a/src/lib/helpers/oauth2-mcp.ts b/src/lib/helpers/oauth2-mcp.ts new file mode 100644 index 0000000000..a45d6e2046 --- /dev/null +++ b/src/lib/helpers/oauth2-mcp.ts @@ -0,0 +1,209 @@ +import { env } from '$env/dynamic/public'; +import type { Models } from '@appwrite.io/console'; +import { + ALL_SCOPE, + PROJECT_ALL_SCOPE, + ORGANIZATION_ALL_SCOPE, + PROJECT_SCOPE_PREFIX, + ORGANIZATION_SCOPE_PREFIX, + scopeAction, + scopeResource, + type ConsentScopeModel, + type TierScopes +} from '$lib/helpers/oauth2-scopes'; + +/** + * MCP-grant detection and consent-time scope narrowing for the hosted Appwrite + * MCP server (granular MCP scopes design). + * + * The MCP server advertises the authorization server's full scope catalog, so + * MCP clients mechanically request *everything*. The consent screen detects + * those grants — the grant's RFC 8707 `resources` contains the MCP server's + * canonical resource URI — and only then offers a narrowing editor. Because + * every granular scope was literally requested, whatever the user narrows to is + * a plain subset that the approve endpoint's literal check already accepts. + * + * The detection signal is self-fulfilling: the resource value becomes the + * token's `aud`, and the MCP server hard-rejects foreign audiences, so a lying + * client gains nothing by claiming the MCP resource URI. + */ + +/** Resource URIs advertised by the hosted Appwrite MCP server. */ +export const DEFAULT_MCP_RESOURCE_URLS = ['https://mcp.appwrite.io', 'https://mcp.appwrite.io/mcp']; + +/** Mirror of the authorization server's `scope` parameter length cap. */ +export const MAX_SCOPE_PARAM_LENGTH = 8192; + +/** Normalize an RFC 8707 resource URI for comparison: trailing slashes only — + * resource indicators are canonical URIs, so anything else compares exactly. */ +export function normalizeResourceUrl(url: string): string { + return url.trim().replace(/\/+$/, ''); +} + +/** + * The MCP resource URIs this console recognizes. Defaults to the hosted MCP; + * extendable via the comma-separated `PUBLIC_MCP_RESOURCE_URLS` env var (e.g. + * `http://localhost:8000/mcp` for local development). + */ +export function mcpResourceUrls(raw?: string | null): string[] { + const configured = (raw ?? env.PUBLIC_MCP_RESOURCE_URLS ?? '') + .split(',') + .map(normalizeResourceUrl) + .filter((url) => url !== ''); + return configured.length > 0 ? configured : DEFAULT_MCP_RESOURCE_URLS; +} + +/** Whether any of the grant's requested resources is a known MCP resource URI. */ +export function isMcpResource(resources: string[], urls: string[] = mcpResourceUrls()): boolean { + const known = new Set(urls.map(normalizeResourceUrl)); + return resources.some( + (resource) => typeof resource === 'string' && known.has(normalizeResourceUrl(resource)) + ); +} + +/** MCP grants (and only MCP grants) get the consent-time narrowing editor. */ +export function isMcpGrant(grant: Models.Oauth2Grant, urls?: string[]): boolean { + return isMcpResource(grant.resources ?? [], urls ?? mcpResourceUrls()); +} + +/* -------------------------------------------------------------------------- */ +/* Grant composition — turn the editor's selection into the approve payload */ +/* -------------------------------------------------------------------------- */ + +/** Per-resource editor selection within one tier. Rows absent from the record + * default to selected with full requested access. */ +export interface ResourceSelection { + selected: boolean; + /** `full` grants every requested action; `read` keeps only `.read`. */ + level: 'full' | 'read'; +} + +export type TierSelection = Record; + +export interface ComposeInput { + model: ConsentScopeModel; + project: TierSelection; + organization: TierSelection; + /** Master read-only toggle — treats every selected resource as `read`. */ + readOnly: boolean; + /** True when the user narrowed the org/project resource pickers. */ + resourcesNarrowed: boolean; +} + +export interface ComposedGrant { + /** + * The `scope` value for the approve endpoint, or `undefined` to omit it. + * Omission means "grant the full literal requested list" — required so the + * consent-skip diff stays empty on the next re-authorization. + */ + scope: string | undefined; + /** The user's selection is the full request — nothing was narrowed. */ + untouched: boolean; + /** No non-identity scope remains; Authorize must be disabled. */ + blocked: boolean; + /** A tier was collapsed to its umbrella to fit the scope length cap. */ + lengthCollapsed: boolean; +} + +/** The bare scope tokens (`tables.read`, …) one tier's selection emits. Every + * emitted token is one of the tier's requested tokens — never synthesized — + * so the result is a literal subset of the request by construction. */ +function tierEmission( + tier: TierScopes, + selection: TierSelection, + readOnly: boolean +): { tokens: string[]; full: boolean } { + const tokens: string[] = []; + for (const token of tier.scopes) { + const resource = scopeResource(token); + const action = scopeAction(token); + const row = selection[resource] ?? { selected: true, level: 'full' }; + if (!row.selected) continue; + const level = readOnly ? 'read' : row.level; + if (level === 'read' && action !== 'read') continue; + tokens.push(token); + } + return { tokens, full: tokens.length === tier.scopes.length }; +} + +/** + * Compose the scope narrowing to send to the approve endpoint. + * + * - Untouched selection → omit `scope` entirely: the server keeps the full + * literal requested list, so re-authorizations skip consent (the diff against + * the previously approved scopes stays empty). + * - Any narrowing → identity scopes plus the selected granular tokens; a tier + * whose requested tokens all survive collapses to its requested umbrella + * (`project:all` / `organization:all`). The console-wide `all` is never part + * of a narrowed grant — it bypasses RFC 9396 resource restrictions. + * - `.write` never implies `.read`: a "Read + Write" row emits both tokens. + */ +export function composeGrantedScopes(input: ComposeInput): ComposedGrant { + const { model, readOnly, resourcesNarrowed } = input; + + const project = tierEmission(model.project, input.project, readOnly); + const organization = tierEmission(model.organization, input.organization, readOnly); + + const capabilitiesFull = project.full && organization.full && !readOnly; + if (capabilitiesFull && !resourcesNarrowed) { + return { scope: undefined, untouched: true, blocked: false, lengthCollapsed: false }; + } + + // A fully-kept tier collapses to its umbrella (when the umbrella was + // requested) — keeps the granted string short and re-consent diffs sane. + // Covers the degenerate umbrella-only request (`project:all` with no + // granular tokens) too: a full selection keeps the umbrella. + const tierScopes = ( + tier: TierScopes, + emission: { tokens: string[]; full: boolean }, + prefix: string, + umbrella: string + ): string[] => { + const requested = tier.all || tier.scopes.length > 0; + // Never collapse under read-only: the umbrella grants write, so a tier + // whose requested tokens are all `.read` (emission.full despite the + // toggle) must still emit the explicit token list. + if (requested && emission.full && tier.all && !readOnly) return [umbrella]; + return emission.tokens.map((token) => prefix + token); + }; + + let projectScopes = tierScopes(model.project, project, PROJECT_SCOPE_PREFIX, PROJECT_ALL_SCOPE); + let organizationScopes = tierScopes( + model.organization, + organization, + ORGANIZATION_SCOPE_PREFIX, + ORGANIZATION_ALL_SCOPE + ); + + const blocked = projectScopes.length === 0 && organizationScopes.length === 0; + + const identity = model.identity.map((scope) => scope.id); + const join = () => [...identity, ...projectScopes, ...organizationScopes].join(' '); + + // Client-side mirror of the server's scope length cap. Unreachable in + // practice (the full catalog is ~2.6 KB), but if a selection ever exceeds + // it, collapse the larger tier to its requested umbrella and surface that. + // Umbrella collapse grants write, so it is off the table under read-only — + // the toggle already halves the token list, keeping it well under the cap. + let lengthCollapsed = false; + if (!readOnly && join().length > MAX_SCOPE_PARAM_LENGTH) { + const projectLength = projectScopes.join(' ').length; + const organizationLength = organizationScopes.join(' ').length; + if (projectLength >= organizationLength && model.project.all) { + projectScopes = [PROJECT_ALL_SCOPE]; + lengthCollapsed = true; + } else if (model.organization.all) { + organizationScopes = [ORGANIZATION_ALL_SCOPE]; + lengthCollapsed = true; + } + if (join().length > MAX_SCOPE_PARAM_LENGTH && model.project.all) { + projectScopes = [PROJECT_ALL_SCOPE]; + lengthCollapsed = true; + } + } + + return { scope: join(), untouched: false, blocked, lengthCollapsed }; +} + +/** Never granted by a narrowed MCP consent — documented here for tests. */ +export const NARROWED_GRANT_NEVER_INCLUDES = [ALL_SCOPE]; diff --git a/src/lib/helpers/oauth2-redirect.ts b/src/lib/helpers/oauth2-redirect.ts new file mode 100644 index 0000000000..061d9046dc --- /dev/null +++ b/src/lib/helpers/oauth2-redirect.ts @@ -0,0 +1,14 @@ +/** + * Whether an OAuth2 redirect URI points back to the web (http/https) rather + * than a native application deep link (e.g. cursor://). Native redirects hand + * off to the OS and leave the tab open, so the console shows an outcome + * screen instead of relying on the navigation. + */ +export function isWebRedirect(uri: string): boolean { + try { + const { protocol } = new URL(uri); + return protocol === 'http:' || protocol === 'https:'; + } catch { + return false; + } +} diff --git a/src/lib/helpers/oauth2-scopes.ts b/src/lib/helpers/oauth2-scopes.ts new file mode 100644 index 0000000000..9cc3554bb5 --- /dev/null +++ b/src/lib/helpers/oauth2-scopes.ts @@ -0,0 +1,692 @@ +import type { ComponentType } from 'svelte'; +import { + IconIdentification, + IconUser, + IconMail, + IconDeviceMobile, + IconShieldCheck, + IconKey +} from '@appwrite.io/pink-icons-svelte'; + +/** + * Scope helpers for the console OAuth2 consent screen (RAR contract v2). + * + * The `scope` parameter now carries *every* privilege the client is asking for. + * `authorization_details` only binds those privileges to concrete resources + * (see `oauth2-authorization-details.ts`). A requested scope reads as one of: + * + * - an OIDC identity scope: `openid`, `profile`, `email`, `phone` + * - `all` — console-wide full access (replaces the old `account.admin`) + * - `project:all` / `project:` — project-tier permissions + * - `organization:all` / `organization:` — organization-tier permissions + * + * The consent screen only ever downscopes: it offers the requested scopes and + * sends back the subset the user consented to. + */ + +/** Console-wide full-access scope; grants everything when present. */ +export const ALL_SCOPE = 'all'; +/** Grants every project-tier scope for the bound projects. */ +export const PROJECT_ALL_SCOPE = 'project:all'; +/** Grants every organization-tier scope for the bound organizations. */ +export const ORGANIZATION_ALL_SCOPE = 'organization:all'; +export const PROJECT_SCOPE_PREFIX = 'project:'; +export const ORGANIZATION_SCOPE_PREFIX = 'organization:'; + +/** OIDC identity scopes — always granted, never toggleable, order preserved. */ +const IDENTITY_SCOPES = ['openid', 'profile', 'email', 'phone'] as const; + +export interface ScopeDescriptor { + id: string; + title: string; + description: string; + icon: ComponentType; +} + +/** + * Identity + full-access scopes are described locally: they're stable and are + * not returned by the project/organization scope endpoints. Everything else is + * a project/organization scope, described from the authored resource catalog below. + */ +const BUILTIN_SCOPES: Record> = { + openid: { + title: 'Verify your identity', + description: 'Confirm who you are using your Appwrite account.', + icon: IconIdentification + }, + profile: { + title: 'View your profile', + description: 'Read your name and profile details.', + icon: IconUser + }, + email: { + title: 'View your email address', + description: "Read your account's email address.", + icon: IconMail + }, + phone: { + title: 'View your phone number', + description: "Read your account's phone number.", + icon: IconDeviceMobile + }, + [ALL_SCOPE]: { + title: 'Full access to your account', + description: 'Manage all your organizations, projects, and their resources on your behalf.', + icon: IconShieldCheck + } +}; + +function titleizeScope(scope: string): string { + const cleaned = scope.replace(/[._:-]+/g, ' ').trim(); + if (!cleaned) return scope; + return cleaned.charAt(0).toUpperCase() + cleaned.slice(1); +} + +export function describeScope(scope: string): ScopeDescriptor { + const builtin = BUILTIN_SCOPES[scope]; + if (builtin) { + return { id: scope, ...builtin }; + } + return { + id: scope, + title: titleizeScope(scope), + description: `Access to ${scope}.`, + icon: IconKey + }; +} + +/** Per-tier (project / organization) requested scopes, prefix already stripped. */ +export interface TierScopes { + /** `:all` was requested — the tier's full-access toggle. */ + all: boolean; + /** Bare scope ids (prefix stripped, `all` excluded), request order preserved. */ + scopes: string[]; +} + +export interface ConsentScopeModel { + /** OIDC identity scopes, read-only, always granted. */ + identity: ScopeDescriptor[]; + /** Console-wide `all` full access, read-only, subsumes everything else. */ + all: ScopeDescriptor | null; + project: TierScopes; + organization: TierScopes; +} + +function collectTier(scopes: string[], prefix: string, allScope: string): TierScopes { + const seen = new Set(); + const out: string[] = []; + let all = false; + for (const scope of scopes) { + if (scope === allScope) { + all = true; + continue; + } + if (!scope.startsWith(prefix)) continue; + const bare = scope.slice(prefix.length); + if (bare === '' || seen.has(bare)) continue; + seen.add(bare); + out.push(bare); + } + return { all, scopes: out }; +} + +/** + * Split the requested `scope` values into the shape the consent screen renders: + * identity (read-only), console-wide `all` (read-only), and the project / + * organization tiers with their `all` flag and individual scopes. + */ +export function splitConsentScopes(scopes: string[]): ConsentScopeModel { + const requested = new Set(scopes); + return { + identity: IDENTITY_SCOPES.filter((scope) => requested.has(scope)).map(describeScope), + all: requested.has(ALL_SCOPE) ? describeScope(ALL_SCOPE) : null, + project: collectTier(scopes, PROJECT_SCOPE_PREFIX, PROJECT_ALL_SCOPE), + organization: collectTier(scopes, ORGANIZATION_SCOPE_PREFIX, ORGANIZATION_ALL_SCOPE) + }; +} + +/* -------------------------------------------------------------------------- */ +/* Resource catalog — console-authored copy for every scope Cloud exposes */ +/* -------------------------------------------------------------------------- */ + +/** + * Console-authored copy per resource (the part of a scope before the last dot, + * e.g. `tables` in `tables.read`). The server's own scope descriptions are terse + * ("Access to read database tables") and read/write pairs arrive as two lines; + * this catalog gives each resource a clean title plus a description. + * + * The read/write signal lives in the row *title* ("Read Tables" / "Write Tables" + * / "Read and write Tables"), generated from the requested actions. The + * description just says what the resource is — `noun` supplies it as a sentence + * ("database tables and their structure" → "Database tables and their structure."). + * Provide an explicit `read` / `write` / `both` description only when a noun + * phrase misses nuance (read-only services, the organization tier's project + * metadata, execute-style scopes). Resources not listed fall back to a titleized + * name with no description, so future scopes still render a sensible title. + */ +interface ResourceCopy { + /** Row title — just the resource name, e.g. "Tables". */ + name: string; + /** One full-line description of what the resource covers. */ + desc?: string; +} + +const PROJECT_RESOURCE_COPY: Record = { + project: { + name: 'Project settings', + desc: "This project's general settings, name, and configuration." + }, + keys: { + name: 'API keys', + desc: "API keys that grant server-side access to this project's resources." + }, + platforms: { + name: 'Platforms', + desc: 'The web, mobile, and native app platforms registered with this project.' + }, + mocks: { + name: 'Mock numbers', + desc: 'Mock phone numbers used to test phone authentication flows.' + }, + 'project.policies': { + name: 'Project policies', + desc: "This project's security and access policies." + }, + policies: { + name: 'Policies', + desc: "Legacy access to this project's security and backup policies." + }, + 'project.oauth2': { + name: 'OAuth2 configuration', + desc: "This project's OAuth2 authorization server configuration." + }, + templates: { + name: 'Templates', + desc: "The project's customizable email and SMS message templates." + }, + stages: { + name: 'Stages', + desc: 'Deployment stages used to promote changes across environments.' + }, + oauth2: { + name: 'OAuth2', + desc: "This project's OAuth2 provider configuration and token introspection." + }, + users: { + name: 'Users', + desc: 'End-user accounts, including their profiles, preferences, and identifiers.' + }, + sessions: { + name: 'Sessions', + desc: "Active login sessions belonging to this project's users." + }, + teams: { + name: 'Teams', + desc: 'Teams and their memberships, used to group and organize users.' + }, + databases: { + name: 'Databases', + desc: 'Databases and their overall configuration within this project.' + }, + tables: { + name: 'Tables', + desc: 'Database tables along with their columns, indexes, and structure.' + }, + columns: { + name: 'Columns', + desc: 'The columns that define the structure of your database tables.' + }, + indexes: { + name: 'Indexes', + desc: 'The indexes that speed up queries against your database tables.' + }, + rows: { + name: 'Rows', + desc: 'The individual rows of data stored inside your database tables.' + }, + collections: { + name: 'Collections', + desc: 'Legacy database collections and their structure, replaced by tables.' + }, + attributes: { + name: 'Attributes', + desc: 'Legacy collection attributes that define document structure, replaced by columns.' + }, + documents: { + name: 'Documents', + desc: 'Legacy documents stored inside your collections, replaced by rows.' + }, + buckets: { + name: 'Storage buckets', + desc: 'Storage buckets and their file-level permission and security settings.' + }, + files: { + name: 'Files', + desc: 'Files stored in your buckets, including uploads, downloads, and previews.' + }, + tokens: { + name: 'File tokens', + desc: 'Access tokens that grant shareable links to individual storage files.' + }, + functions: { + name: 'Functions', + desc: 'Serverless functions along with their code deployments and configuration.' + }, + executions: { + name: 'Executions', + desc: 'The execution history and logs of your serverless functions.' + }, + execution: { + name: 'Executions (legacy)', + desc: 'Legacy access to function executions, replaced by Executions.' + }, + sites: { + name: 'Sites', + desc: 'Hosted sites and their deployments, builds, and configuration.' + }, + log: { name: 'Site logs', desc: 'Runtime and build logs produced by your sites.' }, + providers: { + name: 'Messaging providers', + desc: 'Messaging providers used to send email, SMS, and push notifications.' + }, + topics: { + name: 'Topics', + desc: 'Messaging topics that group subscribers for targeted broadcasts.' + }, + subscribers: { + name: 'Subscribers', + desc: 'Subscribers enrolled in your messaging topics.' + }, + targets: { + name: 'Targets', + desc: 'The delivery targets (email, phone, or device) attached to your users.' + }, + messages: { + name: 'Messages', + desc: 'Email, SMS, and push messages, including drafts and delivery status.' + }, + rules: { + name: 'Proxy rules', + desc: "Proxy rules that route custom domains to this project's resources." + }, + webhooks: { + name: 'Webhooks', + desc: 'Webhooks that notify external services when project events occur.' + }, + locale: { + name: 'Locale', + desc: 'The Locale service for reading locale, language, and geo information.' + }, + avatars: { + name: 'Avatars', + desc: 'The Avatars service for generating avatars, icons, flags, and QR codes.' + }, + health: { + name: 'Health', + desc: "The health and operational status of this project's services." + }, + assistant: { + name: 'AI Assistant', + desc: 'The AI Assistant that suggests answers and configuration.' + }, + migrations: { + name: 'Migrations', + desc: 'Data migrations that import from or export to other projects.' + }, + schedules: { + name: 'Schedules', + desc: 'Scheduled tasks that run functions or messages at set times.' + }, + vcs: { + name: 'Git', + desc: 'Connected Git repositories used to deploy functions and sites.' + }, + insights: { + name: 'Advisor insights', + desc: 'Advisor insights that surface recommendations for your project.' + }, + reports: { + name: 'Advisor reports', + desc: "Advisor reports generated from your project's activity." + }, + presences: { + name: 'Presence', + desc: 'Realtime presence data showing which users are currently online.' + }, + 'backups.policies': { + name: 'Backup policies', + desc: 'Policies that define when and how your data is backed up.' + }, + archives: { + name: 'Backup archives', + desc: "Backup archives captured from this project's data." + }, + restorations: { + name: 'Restorations', + desc: 'Restore operations that recover data from backup archives.' + }, + dedicatedDatabases: { + name: 'Dedicated SQL', + desc: 'Direct SQL access to run statements against dedicated databases.' + }, + domains: { name: 'Domains', desc: 'Custom domains connected to this project.' }, + events: { + name: 'Events', + desc: 'The realtime and system events emitted by this project.' + }, + apps: { + name: 'OAuth2 apps', + desc: 'OAuth2 applications registered to authorize against this project.' + }, + usage: { + name: 'Usage', + desc: "Usage statistics and metrics for this project's resources." + } +}; + +const ORGANIZATION_RESOURCE_COPY: Record = { + projects: { + name: 'Projects', + // The organization tier grants org-level management of project metadata, + // never the data inside any project — spell that out so it can't be misread. + desc: "The names, IDs, and settings of this organization's projects, but not the data inside them." + }, + 'organization.keys': { + name: 'Organization keys', + desc: 'Organization-level API keys that authorize access across projects.' + }, + keys: { + name: 'Organization keys (legacy)', + desc: 'Legacy access to organization API keys, replaced by Organization keys.' + }, + devKeys: { + name: 'Development keys', + desc: 'Development keys used to bypass rate limits while building locally.' + }, + 'organization.memberships': { + name: 'Organization memberships', + desc: 'Memberships that control who belongs to this organization and their roles.' + }, + organization: { + name: 'Organization', + desc: "This organization's name, settings, and other general configuration." + }, + domains: { + name: 'Organization domains', + desc: 'Custom domains owned and managed at the organization level.' + } +}; + +/** + * Resolve the row for one resource, given which actions (`read` / `write` / + * `execute` / …) of it were requested. Following Supabase's consent screen, the + * title is just the resource name and the read/write signal lives in a chip + * ("READ" / "WRITE" / "READ + WRITE"); the description says what the resource is. + */ +function describeResource( + resource: string, + actions: string[], + copyMap: Record +): { title: string; description?: string; access: string; accessStrong: boolean } { + const copy = copyMap[resource]; + const title = copy?.name ?? titleizeScope(resource); + const hasRead = actions.includes('read'); + const hasWrite = actions.includes('write'); + + let access: string; + let accessStrong: boolean; + if (hasRead && hasWrite) { + access = 'Read + Write'; + accessStrong = true; + } else if (hasWrite) { + access = 'Write'; + accessStrong = true; + } else if (hasRead) { + access = 'Read'; + accessStrong = false; + } else { + // Non-CRUD actions (e.g. `execute`) — label with the action itself. + access = actions[0] ? titleizeScope(actions[0]) : 'Access'; + accessStrong = true; + } + + return { title, description: copy?.desc, access, accessStrong }; +} + +/* -------------------------------------------------------------------------- */ +/* Read-only permission summary (Railway-style consent list) */ +/* -------------------------------------------------------------------------- */ + +export interface PermissionLine { + /** Row title — the resource name ("Tables"), or a descriptive title for account lines. */ + title: string; + /** One-line description of what the resource covers. */ + description?: string; + /** Raw scope token(s), space-joined, exactly as issued (incl. tier prefix). Never rendered + * inline — surfaced only via the hover copy affordance. */ + token: string; + /** Access-level chip label, e.g. "Read" / "Write" / "Read + Write". Absent on account lines. */ + access?: string; + /** Whether the chip should read as elevated (write access) rather than neutral (read-only). */ + accessStrong?: boolean; +} + +export interface PermissionGroup { + /** Section heading, e.g. `Account`, `Projects`, `Organizations`. */ + heading: string; + /** Contextual note under the heading, e.g. which resources it applies to. */ + note?: string; + /** Whether the consent screen lets the user collapse this group. */ + collapsible?: boolean; + lines: PermissionLine[]; +} + +/** Rank actions so `read` sorts before `write`, everything else after. */ +function actionRank(action: string): number { + if (action === 'read') return 0; + if (action === 'write') return 1; + return 2; +} + +/** The action of a bare scope token — `read` in `tables.read`. */ +export function scopeAction(scope: string): string { + const dot = scope.lastIndexOf('.'); + return dot === -1 ? scope : scope.slice(dot + 1); +} + +/** The resource of a bare scope token — `tables` in `tables.read`. */ +export function scopeResource(scope: string): string { + const dot = scope.lastIndexOf('.'); + return dot === -1 ? scope : scope.slice(0, dot); +} + +const actionOf = scopeAction; +const resourceOf = scopeResource; + +function tierLines( + tier: TierScopes, + prefix: string, + allScope: string, + copyMap: Record +): PermissionLine[] { + const lines: PermissionLine[] = []; + if (tier.all) { + lines.push({ + title: + prefix === PROJECT_SCOPE_PREFIX + ? 'Full project access' + : 'Full organization access', + description: `Grant every available permission on the selected ${ + prefix === PROJECT_SCOPE_PREFIX ? 'projects' : 'organizations' + }.`, + token: allScope + }); + } + + // Group scopes by resource (everything before the last dot) so that, e.g., + // `tables.read` and `tables.write` collapse into a single "Tables" row with + // one combined description. + const groups = new Map(); + for (const scope of tier.scopes) { + const resource = resourceOf(scope); + const bucket = groups.get(resource); + if (bucket) bucket.push(scope); + else groups.set(resource, [scope]); + } + + // Order rows by how much access they grant — Read + Write first, then Write, + // then any other action, and read-only last — so the strongest grants lead. + const accessRank = (actions: string[]): number => { + const hasRead = actions.includes('read'); + const hasWrite = actions.includes('write'); + if (hasRead && hasWrite) return 0; + if (hasWrite) return 1; + if (hasRead) return 3; + return 2; + }; + + const groupLines = [...groups.entries()] + .map(([resource, scopes]) => { + scopes.sort((a, b) => actionRank(actionOf(a)) - actionRank(actionOf(b))); + const actions = scopes.map(actionOf); + const { title, description, access, accessStrong } = describeResource( + resource, + actions, + copyMap + ); + return { + line: { + title, + description, + token: scopes.map((scope) => prefix + scope).join(' '), + access, + accessStrong + }, + rank: accessRank(actions) + }; + }) + // Stable sort: equal ranks keep their requested order. + .sort((a, b) => a.rank - b.rank); + + for (const { line } of groupLines) lines.push(line); + + return lines; +} + +/* -------------------------------------------------------------------------- */ +/* Editor rows — per-resource rows for the MCP consent narrowing editor */ +/* -------------------------------------------------------------------------- */ + +export interface EditorRow { + /** Resource key (everything before the last dot), stable editor identity. */ + resource: string; + /** Display title from the resource catalog, e.g. "Tables". */ + title: string; + /** One-line description of what the resource covers. */ + description?: string; + /** Requested actions for this resource, `read` before `write` before others. */ + actions: string[]; + hasRead: boolean; + hasWrite: boolean; + /** Access chip label for the full requested access, e.g. "Read + Write". */ + access: string; + /** Whether the chip should read as elevated (write access). */ + accessStrong: boolean; +} + +/** + * Group one tier's requested scopes into per-resource editor rows for the MCP + * consent narrowing editor. Same grouping and copy as the read-only summary, + * but keyed by resource so each row can be toggled and its access level set. + */ +export function buildTierEditorRows(tier: TierScopes, prefix: string): EditorRow[] { + const copyMap = + prefix === PROJECT_SCOPE_PREFIX ? PROJECT_RESOURCE_COPY : ORGANIZATION_RESOURCE_COPY; + const groups = new Map(); + for (const scope of tier.scopes) { + const resource = resourceOf(scope); + const bucket = groups.get(resource); + if (bucket) bucket.push(scope); + else groups.set(resource, [scope]); + } + return [...groups.entries()].map(([resource, scopes]) => { + scopes.sort((a, b) => actionRank(actionOf(a)) - actionRank(actionOf(b))); + const actions = scopes.map(actionOf); + const { title, description, access, accessStrong } = describeResource( + resource, + actions, + copyMap + ); + return { + resource, + title, + description, + actions, + hasRead: actions.includes('read'), + hasWrite: actions.includes('write'), + access, + accessStrong + }; + }); +} + +/** + * Build the read-only permission summary the consent screen displays. Scopes are + * not individually selectable — the client decides what it requests — so this is + * purely descriptive: each requested scope becomes a titled line grouped under + * Account / Projects / Organizations, with the raw token shown for transparency. + */ +export function buildConsentPermissions(model: ConsentScopeModel): PermissionGroup[] { + const groups: PermissionGroup[] = []; + + const account: PermissionLine[] = []; + if (model.identity.length > 0) { + account.push({ + title: 'View your identity', + description: 'Confirm who you are and read your basic profile details.', + token: model.identity.map((scope) => scope.id).join(' ') + }); + } + if (model.all) { + account.push({ + title: model.all.title, + description: model.all.description, + token: model.all.id + }); + } + if (account.length > 0) { + groups.push({ heading: 'Account', lines: account }); + } + + const projectLines = tierLines( + model.project, + PROJECT_SCOPE_PREFIX, + PROJECT_ALL_SCOPE, + PROJECT_RESOURCE_COPY + ); + if (projectLines.length > 0) { + groups.push({ + heading: 'Projects', + note: 'Applies only to the projects you select below.', + collapsible: true, + lines: projectLines + }); + } + + const organizationLines = tierLines( + model.organization, + ORGANIZATION_SCOPE_PREFIX, + ORGANIZATION_ALL_SCOPE, + ORGANIZATION_RESOURCE_COPY + ); + if (organizationLines.length > 0) { + groups.push({ + heading: 'Organizations', + note: 'Applies only to the organizations you select below.', + collapsible: true, + lines: organizationLines + }); + } + + return groups; +} diff --git a/src/lib/helpers/specifications.test.ts b/src/lib/helpers/specifications.test.ts new file mode 100644 index 0000000000..4fb7ba0a07 --- /dev/null +++ b/src/lib/helpers/specifications.test.ts @@ -0,0 +1,61 @@ +import { trimLeadingDisabledSpecifications } from '$lib/helpers/specifications'; +import type { Models } from '@appwrite.io/console'; +import { describe, expect, it } from 'vitest'; + +const specification = (slug: string, enabled: boolean): Models.Specification => ({ + slug, + enabled, + cpus: 1, + memory: 512 +}); + +describe('trimLeadingDisabledSpecifications', () => { + it('hides disabled specifications before the first enabled specification', () => { + const list = { + total: 4, + specifications: [ + specification('disabled-small', false), + specification('enabled-small', true), + specification('enabled-large', true), + specification('disabled-large', false) + ] + }; + + expect(trimLeadingDisabledSpecifications(list)).toEqual({ + total: 3, + specifications: list.specifications.slice(1) + }); + expect(list.specifications).toHaveLength(4); + }); + + it('keeps the list unchanged when the first specification is enabled', () => { + const list = { + total: 2, + specifications: [specification('enabled', true), specification('disabled', false)] + }; + + expect(trimLeadingDisabledSpecifications(list)).toEqual(list); + }); + + it('returns an empty list when no specification is enabled', () => { + const list = { + total: 2, + specifications: [ + specification('disabled-small', false), + specification('disabled-large', false) + ] + }; + + expect(trimLeadingDisabledSpecifications(list)).toEqual({ + total: 0, + specifications: [] + }); + }); + + it('keeps an empty list empty', () => { + expect(trimLeadingDisabledSpecifications({ total: 0, specifications: [] })).toEqual({ + total: 0, + specifications: [] + }); + }); +}); diff --git a/src/lib/helpers/specifications.ts b/src/lib/helpers/specifications.ts new file mode 100644 index 0000000000..f33914c91f --- /dev/null +++ b/src/lib/helpers/specifications.ts @@ -0,0 +1,15 @@ +import type { Models } from '@appwrite.io/console'; + +export function trimLeadingDisabledSpecifications( + list: Models.SpecificationList +): Models.SpecificationList { + const firstEnabledIndex = list.specifications.findIndex(({ enabled }) => enabled); + const specifications = + firstEnabledIndex === -1 ? [] : list.specifications.slice(firstEnabledIndex); + + return { + ...list, + total: specifications.length, + specifications + }; +} diff --git a/src/lib/helpers/string.test.ts b/src/lib/helpers/string.test.ts index d4c907b1ed..7380e2de9a 100644 --- a/src/lib/helpers/string.test.ts +++ b/src/lib/helpers/string.test.ts @@ -1,4 +1,10 @@ -import { singular, camelize, capitalize } from '$lib/helpers/string'; +import { + singular, + camelize, + capitalize, + normalizeSmartQuotes, + repairSmartQuotedJson +} from '$lib/helpers/string'; import { expect, test } from 'vitest'; /* @@ -97,3 +103,40 @@ test('capitalize should handle strings with no lowercase letters', () => { test('capitalize should handle strings with only one character', () => { expect(capitalize('a')).toBe('A'); }); + +/* +NORMALIZE SMART QUOTES +*/ + +test('normalizeSmartQuotes replaces curly double quotes only', () => { + const curly = '{ \u201Ctest\u201D: \u2018value\u2019 }'; + expect(normalizeSmartQuotes(curly)).toBe('{ "test": \u2018value\u2019 }'); +}); + +test('normalizeSmartQuotes leaves ASCII quotes unchanged', () => { + expect(normalizeSmartQuotes('{ "test": \'value\' }')).toBe('{ "test": \'value\' }'); +}); + +test('normalizeSmartQuotes handles empty input', () => { + expect(normalizeSmartQuotes('')).toBe(''); +}); + +test('repairSmartQuotedJson fixes curly structural quotes', () => { + const curly = '{ \u201Ctest\u201D: \u201Cvalue\u201D }'; + expect(repairSmartQuotedJson(curly)).toBe('{ "test": "value" }'); +}); + +test('repairSmartQuotedJson leaves valid JSON with curly quotes in values', () => { + const valid = '{ "quote": "He said \u201Chello\u201D" }'; + expect(repairSmartQuotedJson(valid)).toBe(valid); +}); + +test('repairSmartQuotedJson preserves apostrophes when repairing delimiters', () => { + const curly = '{ \u201Cname\u201D: \u201CO\u2019Brien\u201D }'; + expect(repairSmartQuotedJson(curly)).toBe('{ "name": "O\u2019Brien" }'); +}); + +test('repairSmartQuotedJson leaves non-JSON bodies unchanged', () => { + const plain = 'Hello \u201Cworld\u201D'; + expect(repairSmartQuotedJson(plain)).toBe(plain); +}); diff --git a/src/lib/helpers/string.ts b/src/lib/helpers/string.ts index b013f2b152..5513a69cb8 100644 --- a/src/lib/helpers/string.ts +++ b/src/lib/helpers/string.ts @@ -127,3 +127,36 @@ export function hash(input: string | string[], delimiter: string = ','): string } return Math.abs(hash).toString(36); } + +/** + * Replace typographic / “smart” double quotes with ASCII `"`. + * Safari (and some other editors) substitute curly quotes while typing, which + * breaks JSON request bodies. Single quotes / apostrophes are left alone — + * JSON string delimiters are always double quotes. + */ +export function normalizeSmartQuotes(str: string): string { + if (!str) return str; + return str.replace(/[\u201C\u201D\u201E\u201F\u2033\u2036]/g, '"'); +} + +/** + * Fix Safari-style smart double quotes when they make an otherwise-JSON body + * invalid. Leaves already-valid JSON and non-JSON bodies unchanged so + * intentional typographic characters in string values or plain text are + * preserved. Only double quotes are rewritten (JSON delimiters). + */ +export function repairSmartQuotedJson(str: string): string { + if (!str) return str; + try { + JSON.parse(str); + return str; + } catch { + const normalized = normalizeSmartQuotes(str); + try { + JSON.parse(normalized); + return normalized; + } catch { + return str; + } + } +} diff --git a/src/lib/helpers/variables.test.ts b/src/lib/helpers/variables.test.ts new file mode 100644 index 0000000000..75f431a88b --- /dev/null +++ b/src/lib/helpers/variables.test.ts @@ -0,0 +1,49 @@ +import { expect, test } from 'vitest'; +import { + getVariableKeyError, + isValidVariableKey, + validateVariables, + VARIABLE_KEY_MAX_LENGTH, + VARIABLE_VALUE_MAX_LENGTH +} from '$lib/helpers/variables'; + +test('accept keys that are valid environment variable names', () => { + expect(isValidVariableKey('APP_TEST')).toBe(true); + expect(isValidVariableKey('_PRIVATE')).toBe(true); + expect(isValidVariableKey('key1')).toBe(true); + expect(isValidVariableKey('a'.repeat(VARIABLE_KEY_MAX_LENGTH))).toBe(true); +}); + +test('reject keys that cannot be used as environment variable names', () => { + expect(isValidVariableKey('MY-KEY')).toBe(false); + expect(isValidVariableKey('MY.KEY')).toBe(false); + expect(isValidVariableKey('MY KEY')).toBe(false); + expect(isValidVariableKey('9KEY')).toBe(false); + expect(isValidVariableKey('KÉY')).toBe(false); + expect(isValidVariableKey('KEY\t')).toBe(false); + expect(isValidVariableKey('')).toBe(false); + expect(isValidVariableKey('a'.repeat(VARIABLE_KEY_MAX_LENGTH + 1))).toBe(false); +}); + +test('report a missing key separately from an invalid one', () => { + expect(getVariableKeyError('')).toEqual('Variable key is required'); + expect(getVariableKeyError('MY-KEY')).toContain('is invalid'); + expect(getVariableKeyError('a'.repeat(VARIABLE_KEY_MAX_LENGTH + 1))).toContain('longer than'); + expect(getVariableKeyError('APP_TEST')).toBeNull(); +}); + +test('validate a list of variables and name the offending key', () => { + expect(validateVariables([{ key: 'APP_TEST', value: 'value' }])).toBeNull(); + expect(validateVariables([{ key: 'APP_TEST', value: '' }])).toBeNull(); + + expect( + validateVariables([ + { key: 'APP_TEST', value: 'value' }, + { key: 'MY-KEY', value: 'value' } + ]) + ).toContain('MY-KEY'); + + expect( + validateVariables([{ key: 'APP_TEST', value: 'v'.repeat(VARIABLE_VALUE_MAX_LENGTH + 1) }]) + ).toContain('APP_TEST'); +}); diff --git a/src/lib/helpers/variables.ts b/src/lib/helpers/variables.ts index 90219499ed..e93e25620f 100644 --- a/src/lib/helpers/variables.ts +++ b/src/lib/helpers/variables.ts @@ -1,5 +1,71 @@ import type { Models } from '@appwrite.io/console'; +export const VARIABLE_KEY_MAX_LENGTH = 255; +export const VARIABLE_VALUE_MAX_LENGTH = 8192; + +/** + * Variable keys become environment variable names at build and runtime, so the + * API only accepts C-style identifiers. Keys stored before that rule existed + * can still fail this check, which is why `isValidVariableKey` is also used to + * flag them in the variables table. + */ +const VARIABLE_KEY_PATTERN = /^[A-Za-z_][A-Za-z0-9_]*$/; + +export function isValidVariableKey(key: string): boolean { + return ( + typeof key === 'string' && + key.length <= VARIABLE_KEY_MAX_LENGTH && + VARIABLE_KEY_PATTERN.test(key) + ); +} + +export function getVariableKeyError(key: string): string | null { + if (!key) { + return 'Variable key is required'; + } + + if (key.length > VARIABLE_KEY_MAX_LENGTH) { + return `Variable key "${key}" is longer than ${VARIABLE_KEY_MAX_LENGTH} allowed characters`; + } + + if (!VARIABLE_KEY_PATTERN.test(key)) { + return `Variable key "${key}" is invalid. Keys can only contain letters, digits and underscores, and cannot start with a digit`; + } + + return null; +} + +export function getVariableValueError(key: string, value: unknown): string | null { + if (('' + (value ?? '')).length > VARIABLE_VALUE_MAX_LENGTH) { + return `Variable ${key} is longer than ${VARIABLE_VALUE_MAX_LENGTH} allowed characters`; + } + + return null; +} + +/** + * Returns the first problem found, or null when every variable is accepted by + * the API. Call before submitting so a rejected key is reported against the + * file or row it came from instead of as a bare server error. + */ +export function validateVariables( + variables: Array<{ key?: string; value?: unknown }> +): string | null { + for (const { key, value } of variables) { + const keyError = getVariableKeyError(key); + if (keyError) { + return keyError; + } + + const valueError = getVariableValueError(key, value); + if (valueError) { + return valueError; + } + } + + return null; +} + export function normalizeDetectedVariables( detected: Models.DetectionVariable[] = [] ): Partial[] { diff --git a/src/lib/images/promos/state-of-appwrite-survey.png b/src/lib/images/promos/state-of-appwrite-survey.png new file mode 100644 index 0000000000..7626c5d256 Binary files /dev/null and b/src/lib/images/promos/state-of-appwrite-survey.png differ diff --git a/src/lib/images/promos/terraform-provider.png b/src/lib/images/promos/terraform-provider.png deleted file mode 100644 index 4b5af07797..0000000000 Binary files a/src/lib/images/promos/terraform-provider.png and /dev/null differ diff --git a/src/lib/layout/activity.svelte b/src/lib/layout/activity.svelte deleted file mode 100644 index 04fef37d71..0000000000 --- a/src/lib/layout/activity.svelte +++ /dev/null @@ -1,128 +0,0 @@ - - - - {#if logs.total} - - - User - Event - Location - IP - Date - - {#each logs.logs as log} - - - - {#if log.userEmail} - {#if log.userName} - - {log.userName} - {:else} - - {log.userEmail} - {/if} - {:else} -
- -
- {log.userName ?? 'Anonymous'} - {/if} -
-
- - - {log.event} - - - - {#if log.countryCode !== '--'} - {log.countryName} - {:else} - Unknown - {/if} - - - - - - - - - -
- {/each} -
- - - {:else} - - - - - - - - {/if} -
diff --git a/src/lib/layout/containerButton.svelte b/src/lib/layout/containerButton.svelte index 370abfe349..df3aca4b50 100644 --- a/src/lib/layout/containerButton.svelte +++ b/src/lib/layout/containerButton.svelte @@ -10,10 +10,10 @@ export let title: string; export let tooltipContent = - $organization?.billingPlanDetails.group === BillingPlanGroup.Starter + $organization?.billingPlanDetails?.group === BillingPlanGroup.Starter ? `Upgrade to add more ${title.toLocaleLowerCase()}` : `You've reached the ${title.toLocaleLowerCase()} limit for the ${ - $organization?.billingPlanDetails.name + $organization?.billingPlanDetails?.name } plan`; export let disabled: boolean; diff --git a/src/lib/layout/containerHeader.svelte b/src/lib/layout/containerHeader.svelte index b162be4044..5cd2ef66df 100644 --- a/src/lib/layout/containerHeader.svelte +++ b/src/lib/layout/containerHeader.svelte @@ -96,7 +96,7 @@ .join(', ')} {#if services.length} - {@const supportsUsage = Object.keys($currentPlan.usage).length > 0} + {@const supportsUsage = Object.keys($currentPlan?.usage ?? {}).length > 0} 0 && pingCount === 0) { + if ((platforms?.total ?? 0) > 0 && pingCount === 0) { percentage = 66; } else if (pingCount > 0) { percentage = 100; diff --git a/src/lib/layout/unauthenticated.svelte b/src/lib/layout/unauthenticated.svelte index 27b44f624e..d68dcfa86a 100644 --- a/src/lib/layout/unauthenticated.svelte +++ b/src/lib/layout/unauthenticated.svelte @@ -7,7 +7,7 @@ import LoginLight from '$lib/images/login/login-light-mode.png'; import { app } from '$lib/stores/app'; import { Typography, Layout, Avatar } from '@appwrite.io/pink-svelte'; - import { getCampaignImageUrl } from '$routes/(public)/card/helpers'; + import { getCampaignImageUrl } from '$lib/helpers/campaign'; import { isSmallViewport } from '$lib/stores/viewport'; import type { Models } from '@appwrite.io/console'; diff --git a/src/lib/layout/usage.svelte b/src/lib/layout/usage.svelte deleted file mode 100644 index 9f5889b046..0000000000 --- a/src/lib/layout/usage.svelte +++ /dev/null @@ -1,145 +0,0 @@ - - - - - - {#if !hidePeriodSelect} -
- goto(`${path}/${e.detail}`)} - id="period" - options={[ - { - label: '24 hours', - value: '24h' - }, - { - label: '30 days', - value: '30d' - }, - { - label: '90 days', - value: '90d' - } - ]} - value={page.params.period ?? '30d'} /> -
- {/if} - - {#if count} - - {formatNumberWithCommas(total)} - {countMetadata.title} - -
- [m.date, m.value]) - : accumulateFromEndingTotal(count, total) - } - ]} /> -
- {/if} -
-
- - diff --git a/src/lib/layout/usageHelpers.ts b/src/lib/layout/usageHelpers.ts new file mode 100644 index 0000000000..61c457ef39 --- /dev/null +++ b/src/lib/layout/usageHelpers.ts @@ -0,0 +1,68 @@ +import { ProjectUsageRange, type Models } from '@appwrite.io/console'; + +export type UsagePeriods = '24h' | '30d' | '90d'; + +export function periodToDates(period: UsagePeriods): { + start: string; + end: string; + period: ProjectUsageRange; +} { + const start = new Date(); + switch (period) { + case '24h': + start.setUTCHours(start.getHours() - 24); + break; + case '30d': + start.setUTCHours(0, 0, 0, 0); + start.setUTCDate(start.getDate() - 30); + break; + case '90d': + start.setUTCHours(0, 0, 0, 0); + start.setUTCDate(start.getDate() - 90); + break; + } + const end = new Date(); + end.setUTCDate(end.getUTCDate() + 1); + end.setUTCHours(0, 0, 0, 0); + return { + start: start.toISOString(), + end: end.toISOString(), + period: period === '24h' ? ProjectUsageRange.OneHour : ProjectUsageRange.OneDay + }; +} + +export function last(set: Models.Metric[]): Models.Metric | null { + if (!set) return null; + return set.slice(-1)[0] ?? null; +} + +export function total(set: Models.Metric[]): number { + return set?.reduce((prev, curr) => prev + curr.value, 0) ?? 0; +} + +export function accumulateFromEndingTotal( + metrics: Models.Metric[], + endingTotal: number, + startingDayToFillZero: Date = null +): Array<[string, number]> { + return (metrics ?? []).reduceRight( + (acc, curr) => { + if (startingDayToFillZero !== null && startingDayToFillZero instanceof Date) { + const date = new Date(curr.date); + if (date > startingDayToFillZero) { + acc.data.unshift([date.toISOString(), 0]); + acc.total -= 0; + + return acc; + } + } + acc.data.unshift([curr.date, acc.total]); + acc.total -= curr.value; + return acc; + }, + { + total: endingTotal, + data: [] + } + ).data; +} diff --git a/src/lib/layout/usageMultiple.svelte b/src/lib/layout/usageMultiple.svelte deleted file mode 100644 index ff1789c49a..0000000000 --- a/src/lib/layout/usageMultiple.svelte +++ /dev/null @@ -1,99 +0,0 @@ - - -
- {#if showHeader} -
- {title} - - {#if path} - - - 24h - - - 30d - - - 90d - - - {/if} -
- {/if} - - - {#if count} - - {formatNumberWithCommas(totalCount)} - Total {title.toLocaleLowerCase()} - -
- - - {#if legendData} - - {/if} -
- {/if} -
-
- - diff --git a/src/lib/profiles/css/base.css b/src/lib/profiles/css/base.css index ae0218c273..b88c0e1c15 100644 --- a/src/lib/profiles/css/base.css +++ b/src/lib/profiles/css/base.css @@ -4,3 +4,15 @@ scrollbar-width: thin; position: relative; } + +/* + * Melt UI applies `position: absolute` to the combobox menu via floating-ui, + * but only after `tick()` — a one-frame delay. During that initial frame the + * menu is in the normal document flow, momentarily expanding any ancestor with + * `overflow: visible` (e.g. the element) and causing a visible layout + * shift. Pre-setting `position: absolute` here removes the element from flow + * immediately at mount, so there is no reflow before floating-ui takes over. + */ +[data-melt-combobox-menu] { + position: absolute; +} diff --git a/src/lib/sdk/usage.ts b/src/lib/sdk/usage.ts index b446bfa50f..d84a0cc26f 100644 --- a/src/lib/sdk/usage.ts +++ b/src/lib/sdk/usage.ts @@ -1,4 +1,12 @@ -import type { Models } from '@appwrite.io/console'; +import { + Query, + UsageEventDimension, + UsageEventMetric, + UsageOrderBy, + UsageOrderDirection, + type Models +} from '@appwrite.io/console'; +import { sdk } from '$lib/stores/sdk'; export function accumulateUsage(usage: Models.Metric[], base: number): Models.Metric[] { const accumulation = usage.reduce( @@ -18,6 +26,64 @@ export function accumulateUsage(usage: Models.Metric[], base: number): Models.Me return accumulation.metrics; } +export type ExecutionsBreakdown = { + resourceId: string; + name?: string; + value: number; +}; + +const executionsBreakdownLimit = 25; + +/** + * `UsageProject.executionsBreakdown` was dropped in SDK 16; the per-resource split now comes from + * the dimensional usage API, which returns bare resource IDs, so names are resolved separately. + * + * Scoped to `functions.executions` rather than the umbrella `executions` metric, which also counts + * site executions — those resolve to no name here and their rows link to a function that does not exist. + * Omitting `interval` makes each point a whole-window aggregate per resource, so the limit is a + * top-N-by-total rather than a truncation of the underlying data. + */ +export async function listExecutionsBreakdown( + region: string, + projectId: string, + startAt: string, + endAt: string +): Promise { + const project = sdk.forProject(region, projectId); + + const events = await project.usage.listEvents({ + metrics: [UsageEventMetric.FunctionsExecutions], + dimensions: [UsageEventDimension.ResourceId], + startAt, + endAt, + orderBy: UsageOrderBy.Value, + orderDir: UsageOrderDirection.Desc, + limit: executionsBreakdownLimit + }); + + const totals = new Map(); + for (const metric of events.metrics) { + for (const point of metric.points) { + if (!point.resourceId) continue; + totals.set(point.resourceId, (totals.get(point.resourceId) ?? 0) + point.value); + } + } + + if (totals.size === 0) return []; + + const resourceIds = [...totals.keys()]; + const functions = await project.functions.list({ + queries: [Query.equal('$id', resourceIds), Query.limit(resourceIds.length)] + }); + const names = new Map(functions.functions.map((func) => [func.$id, func.name])); + + return resourceIds.map((resourceId) => ({ + resourceId, + name: names.get(resourceId), + value: totals.get(resourceId) + })); +} + export type Metric = { /** * The value of this metric at the timestamp. diff --git a/src/lib/stores/auth-methods.ts b/src/lib/stores/auth-methods.ts index 4be9911c49..190a7a2106 100644 --- a/src/lib/stores/auth-methods.ts +++ b/src/lib/stores/auth-methods.ts @@ -1,48 +1,52 @@ import { writable } from 'svelte/store'; -import { type Models, AuthMethod as MethodId } from '@appwrite.io/console'; +import { type Models, ProjectAuthMethodId } from '@appwrite.io/console'; export type AuthMethod = { label: string; - method: MethodId; + method: ProjectAuthMethodId; value: boolean | null; }; const setAuthMethod = (project: Models.Project): AuthMethod[] => { + const authMethods = new Map( + project?.authMethods?.map((method) => [method.$id, method.enabled]) + ); + return [ { label: 'Email/Password', - method: MethodId.Emailpassword, - value: project?.authEmailPassword + method: ProjectAuthMethodId.Emailpassword, + value: authMethods.get(ProjectAuthMethodId.Emailpassword) ?? null }, { label: 'Phone', - method: MethodId.Phone, - value: project?.authPhone + method: ProjectAuthMethodId.Phone, + value: authMethods.get(ProjectAuthMethodId.Phone) ?? null }, { label: 'Magic URL', - method: MethodId.Magicurl, - value: project?.authUsersAuthMagicURL + method: ProjectAuthMethodId.Magicurl, + value: authMethods.get(ProjectAuthMethodId.Magicurl) ?? null }, { label: 'Email OTP', - method: MethodId.Emailotp, - value: project?.authEmailOtp + method: ProjectAuthMethodId.Emailotp, + value: authMethods.get(ProjectAuthMethodId.Emailotp) ?? null }, { label: 'Anonymous', - method: MethodId.Anonymous, - value: project?.authAnonymous + method: ProjectAuthMethodId.Anonymous, + value: authMethods.get(ProjectAuthMethodId.Anonymous) ?? null }, { label: 'Team Invites', - method: MethodId.Invites, - value: project?.authInvites + method: ProjectAuthMethodId.Invites, + value: authMethods.get(ProjectAuthMethodId.Invites) ?? null }, { label: 'JWT', - method: MethodId.Jwt, - value: project?.authJWT + method: ProjectAuthMethodId.Jwt, + value: authMethods.get(ProjectAuthMethodId.Jwt) ?? null } ]; }; diff --git a/src/lib/stores/billing.ts b/src/lib/stores/billing.ts index 289605db84..d2b42db269 100644 --- a/src/lib/stores/billing.ts +++ b/src/lib/stores/billing.ts @@ -93,7 +93,37 @@ function makeBillingPlan( return typeof billingPlanOrId === 'string' ? billingIdToPlan(billingPlanOrId) : billingPlanOrId; } +export const projectRoles = roles.filter((r) => r.value !== 'billing'); + +const projectRoleNames = new Set(projectRoles.map((r) => r.value)); + +export function isProjectSpecificRole(role: string): boolean { + if (!role.startsWith('project-')) return false; + const lastDash = role.lastIndexOf('-'); + if (lastDash <= 'project-'.length) return false; + return projectRoleNames.has(role.slice(lastDash + 1)); +} + +export function parseProjectRole(role: string): { projectId: string; roleName: string } | null { + if (!isProjectSpecificRole(role)) return null; + const withoutPrefix = role.slice('project-'.length); + const lastDashIdx = withoutPrefix.lastIndexOf('-'); + if (lastDashIdx === -1) return null; + return { + projectId: withoutPrefix.slice(0, lastDashIdx), + roleName: withoutPrefix.slice(lastDashIdx + 1) + }; +} + +export function buildProjectRole(projectId: string, roleName: string): string { + return `project-${projectId}-${roleName}`; +} + export function getRoleLabel(role: string) { + if (isProjectSpecificRole(role)) { + const parsed = parseProjectRole(role); + return projectRoles.find((r) => r.value === parsed?.roleName)?.label ?? role; + } return roles.find((r) => r.value === role)?.label ?? role; } @@ -151,7 +181,11 @@ export function getBasePlanFromGroup(billingPlanGroup: BillingPlanGroup): Models return proPlans.sort((a, b) => a.order - b.order)[0]; } -export function billingIdToPlan(billingId: string): Models.BillingPlan | null { +export function billingIdToPlan(billingId: string | null | undefined): Models.BillingPlan | null { + if (!billingId) { + return null; + } + const plansInfoStore = getPlansInfoStore(); if (plansInfoStore.has(billingId)) { return plansInfoStore.get(billingId); @@ -243,7 +277,8 @@ export function getServiceLimit( if (serviceId === 'members') { if (!plan?.addons?.seats) return Infinity; - return plan.addons.seats?.limit ?? 1; + // plans that don't cap seats omit `limit`, which the API serializes as `0` + return plan.addons.seats?.limit || Infinity; } if (serviceId === 'projects') { @@ -287,9 +322,9 @@ export const actionRequiredInvoices = writable(null); export const showUsageRatesModal = writable(false); export const useNewPricingModal = derived(currentPlan, ($plan) => $plan?.usagePerProject === true); -export function checkForUsageFees(plan: string, id: PlanServices) { +export function checkForUsageFees(plan: string | null | undefined, id: PlanServices) { const billingPlan = billingIdToPlan(plan); - const supportsUsage = Object.keys(billingPlan.usage).length > 0; + const supportsUsage = Object.keys(billingPlan?.usage ?? {}).length > 0; if (supportsUsage) { switch (id) { @@ -307,10 +342,10 @@ export function checkForUsageFees(plan: string, id: PlanServices) { } else return false; } -export function checkForProjectLimitation(plan: string, id: PlanServices) { +export function checkForProjectLimitation(plan: string | null | undefined, id: PlanServices) { if (id === 'members') { const billingPlan = billingIdToPlan(plan); - const hasUnlimitedProjects = billingPlan.projects === 0; + const hasUnlimitedProjects = billingPlan?.projects === 0; if (hasUnlimitedProjects) { return false; // No project limitation for members on Pro/Scale plans @@ -440,7 +475,8 @@ export async function checkForUsageLimit(organization: Models.Organization) { const members = organization.total; const memberLimit = getServiceLimit('members'); - const membersOverflow = memberLimit === Infinity ? 0 : Math.max(0, members - memberLimit); + const membersOverflow = + Number.isFinite(memberLimit) && memberLimit > 0 ? Math.max(0, members - memberLimit) : 0; if (resources.some((r) => r.value >= 100) || membersOverflow > 0) { readOnly.set(true); @@ -629,7 +665,7 @@ export async function checkForMissingPaymentMethod() { // Display upgrade banner for new users after 1 week for 30 days export async function checkForNewDevUpgradePro(org: Models.Organization) { // browser or plan check. - if (!browser || !org.billingPlanDetails.supportsCredits) return; + if (!browser || !org?.billingPlanDetails?.supportsCredits) return; // already dismissed by user! if (localStorage.getItem('newDevUpgradePro')) return; @@ -640,6 +676,8 @@ export async function checkForNewDevUpgradePro(org: Models.Organization) { const now = new Date().getTime(); const account = get(user); + if (!account?.$createdAt) return; + const accountCreated = new Date(account.$createdAt).getTime(); if (now - accountCreated < 1000 * 60 * 60 * 24 * 7) return; diff --git a/src/lib/stores/domains.ts b/src/lib/stores/domains.ts index 348e10c9b7..36c763dee3 100644 --- a/src/lib/stores/domains.ts +++ b/src/lib/stores/domains.ts @@ -3,19 +3,19 @@ import { StatusCode } from '@appwrite.io/console'; export const statusCodeOptions = [ { label: '301 Moved permanently', - value: StatusCode.MovedPermanently301 + value: StatusCode.MovedPermanently }, { label: '302 Found', - value: StatusCode.Found302 + value: StatusCode.Found }, { label: '307 Temporary redirect', - value: StatusCode.TemporaryRedirect307 + value: StatusCode.TemporaryRedirect }, { label: '308 Permanent redirect', - value: StatusCode.PermanentRedirect308 + value: StatusCode.PermanentRedirect } ]; diff --git a/src/lib/stores/git.ts b/src/lib/stores/git.ts index 51f8df20f7..8181f20cce 100644 --- a/src/lib/stores/git.ts +++ b/src/lib/stores/git.ts @@ -1,14 +1,14 @@ import { page } from '$app/state'; import { getApiEndpoint } from './sdk'; -export function connectGitHub(callbackState: Record = null) { +function connectVcsProvider(provider: string, callbackState: Record = null) { const redirect = new URL(page.url); if (callbackState) { Object.keys(callbackState).forEach((key) => { redirect.searchParams.append(key, callbackState[key]); }); } - const target = new URL(`${getApiEndpoint(page.params.region)}/vcs/github/authorize`); + const target = new URL(`${getApiEndpoint(page.params.region)}/vcs/${provider}/authorize`); target.searchParams.set('project', page.params.project); target.searchParams.set('success', redirect.toString()); target.searchParams.set('failure', redirect.toString()); @@ -16,6 +16,14 @@ export function connectGitHub(callbackState: Record = null) { return target; } +export function connectGitHub(callbackState: Record = null) { + return connectVcsProvider('github', callbackState); +} + +export function connectGitea(callbackState: Record = null) { + return connectVcsProvider('gitea', callbackState); +} + export function deploymentStatusConverter(status: string) { // Status component possible values - status: 'waiting' | 'ready' | 'processing' | 'pending' | 'failed' | 'complete'; switch (status) { diff --git a/src/lib/stores/oauth-providers.ts b/src/lib/stores/oauth-providers.ts index 1a2143a178..553e3a7ab4 100644 --- a/src/lib/stores/oauth-providers.ts +++ b/src/lib/stores/oauth-providers.ts @@ -1,5 +1,6 @@ import type { Component } from 'svelte'; import Main from '$routes/(console)/project-[region]-[project]/auth/(providers)/mainOAuth.svelte'; +import Google from '$routes/(console)/project-[region]-[project]/auth/(providers)/googleOAuth.svelte'; export type Provider = { name: string; @@ -22,6 +23,12 @@ export const oAuthProviders: Record = { docs: 'https://developer.apple.com/sign-in-with-apple/', component: Main }, + appwrite: { + name: 'Appwrite', + icon: 'appwrite', + docs: 'https://appwrite.io/docs/products/auth/oauth2', + component: Main + }, auth0: { name: 'Auth0', icon: 'auth0', @@ -129,13 +136,13 @@ export const oAuthProviders: Record = { name: 'Google', icon: 'google', docs: 'https://support.google.com/googleapi/answer/6158849', - component: Main + component: Google }, googleImagine: { name: 'Google', icon: 'google', docs: 'https://support.google.com/googleapi/answer/6158849', - component: Main, + component: Google, internal: true }, keycloak: { diff --git a/src/lib/stores/project-protocols.ts b/src/lib/stores/project-protocols.ts index 072c3c5225..1bab3701ef 100644 --- a/src/lib/stores/project-protocols.ts +++ b/src/lib/stores/project-protocols.ts @@ -1,28 +1,32 @@ import { writable } from 'svelte/store'; -import { ProtocolId, type Models } from '@appwrite.io/console'; +import { ProjectProtocolId, type Models } from '@appwrite.io/console'; export type Protocol = { label: string; - method: ProtocolId; + method: ProjectProtocolId; value: boolean | null; }; function projectProtocolRows(project: Models.Project | null): Protocol[] { + const protocols = new Map( + project?.protocols?.map((protocol) => [protocol.$id, protocol.enabled]) + ); + return [ { label: 'REST', - method: ProtocolId.Rest, - value: project?.protocolStatusForRest ?? null + method: ProjectProtocolId.Rest, + value: protocols.get(ProjectProtocolId.Rest) ?? null }, { label: 'GraphQL', - method: ProtocolId.Graphql, - value: project?.protocolStatusForGraphql ?? null + method: ProjectProtocolId.Graphql, + value: protocols.get(ProjectProtocolId.Graphql) ?? null }, { label: 'WebSocket', - method: ProtocolId.Websocket, - value: project?.protocolStatusForWebsocket ?? null + method: ProjectProtocolId.Websocket, + value: protocols.get(ProjectProtocolId.Websocket) ?? null } ]; } diff --git a/src/lib/stores/project-services.ts b/src/lib/stores/project-services.ts index 1098c2f2dc..20d38f0781 100644 --- a/src/lib/stores/project-services.ts +++ b/src/lib/stores/project-services.ts @@ -1,89 +1,91 @@ import { writable } from 'svelte/store'; -import { ServiceId, type Models } from '@appwrite.io/console'; +import { ProjectServiceId, type Models } from '@appwrite.io/console'; export type Service = { label: string; - method: ServiceId; + method: ProjectServiceId; value: boolean | null; }; function projectServiceRows(project: Models.Project | null): Service[] { + const services = new Map(project?.services?.map((service) => [service.$id, service.enabled])); + const rows: Service[] = [ { label: 'Account', - method: ServiceId.Account, - value: project?.serviceStatusForAccount ?? null + method: ProjectServiceId.Account, + value: services.get(ProjectServiceId.Account) ?? null }, { label: 'Avatars', - method: ServiceId.Avatars, - value: project?.serviceStatusForAvatars ?? null + method: ProjectServiceId.Avatars, + value: services.get(ProjectServiceId.Avatars) ?? null }, { label: 'Databases', - method: ServiceId.Databases, - value: project?.serviceStatusForDatabases ?? null + method: ProjectServiceId.Databases, + value: services.get(ProjectServiceId.Databases) ?? null }, { label: 'Functions', - method: ServiceId.Functions, - value: project?.serviceStatusForFunctions ?? null + method: ProjectServiceId.Functions, + value: services.get(ProjectServiceId.Functions) ?? null }, { label: 'Locale', - method: ServiceId.Locale, - value: project?.serviceStatusForLocale ?? null + method: ProjectServiceId.Locale, + value: services.get(ProjectServiceId.Locale) ?? null }, { label: 'Messaging', - method: ServiceId.Messaging, - value: project?.serviceStatusForMessaging ?? null + method: ProjectServiceId.Messaging, + value: services.get(ProjectServiceId.Messaging) ?? null }, { label: 'Migrations', - method: ServiceId.Migrations, - value: project?.serviceStatusForMigrations ?? null + method: ProjectServiceId.Migrations, + value: services.get(ProjectServiceId.Migrations) ?? null }, { label: 'Project', - method: ServiceId.Project, - value: project?.serviceStatusForProject ?? null + method: ProjectServiceId.Project, + value: services.get(ProjectServiceId.Project) ?? null }, // @todo Re-enable when Proxy is ready for public release. // { // label: 'Proxy', - // method: ServiceId.Proxy, + // method: ProjectServiceId.Proxy, // value: project?.serviceStatusForProxy ?? null // }, { label: 'Sites', - method: ServiceId.Sites, - value: project?.serviceStatusForSites ?? null + method: ProjectServiceId.Sites, + value: services.get(ProjectServiceId.Sites) ?? null }, { label: 'Storage', - method: ServiceId.Storage, - value: project?.serviceStatusForStorage ?? null + method: ProjectServiceId.Storage, + value: services.get(ProjectServiceId.Storage) ?? null }, { label: 'TablesDB', - method: ServiceId.Tablesdb, - value: project?.serviceStatusForTablesdb ?? null + method: ProjectServiceId.Tablesdb, + value: services.get(ProjectServiceId.Tablesdb) ?? null }, { label: 'Teams', - method: ServiceId.Teams, - value: project?.serviceStatusForTeams ?? null + method: ProjectServiceId.Teams, + value: services.get(ProjectServiceId.Teams) ?? null }, { label: 'Users', - method: ServiceId.Users, - value: project?.serviceStatusForUsers ?? null + method: ProjectServiceId.Users, + value: services.get(ProjectServiceId.Users) ?? null } // @todo Re-enable when VCS is ready for public release. // { // label: 'VCS', - // method: ServiceId.Vcs, + // method: ProjectServiceId.Vcs, // value: project?.serviceStatusForVcs ?? null // } ]; diff --git a/src/lib/stores/sdk.ts b/src/lib/stores/sdk.ts index aa80494850..47115c8174 100644 --- a/src/lib/stores/sdk.ts +++ b/src/lib/stores/sdk.ts @@ -2,16 +2,19 @@ import { isMultiRegionSupported, VARS } from '$lib/system'; import { registerImpersonationClients, restoreImpersonation } from '$lib/appwrite/impersonation'; import { Account, + Apps, Assistant, Avatars, Backups, Client, Console, + Embeddings, Functions, - Health, Locale, Messaging, Migrations, + Oauth2, + Organization, Project, Project as ProjectApi, Projects, @@ -28,6 +31,7 @@ import { Webhooks, Realtime, Organizations, + Usage, VectorsDB } from '@appwrite.io/console'; import { buildRegionalV1Endpoint } from '$lib/helpers/apiEndpoint'; @@ -47,9 +51,10 @@ function createConsoleSdk(client: Client) { return { client, account: new Account(client), + apps: new Apps(client), + oauth2: new Oauth2(client), avatars: new Avatars(client), functions: new Functions(client), - health: new Health(client), locale: new Locale(client), projects: new Projects(client), teams: new Teams(client), @@ -62,7 +67,19 @@ function createConsoleSdk(client: Client) { domains: new Domains(client), storage: new Storage(client), realtime: new Realtime(client), - organizations: new Organizations(client) + organizations: new Organizations(client), + organization(organizationId: string) { + const organizationClient = new Client(); + organizationClient.setEndpoint(client.config.endpoint); + if (client.config.project) { + organizationClient.setProject(client.config.project); + } + Object.assign(organizationClient.headers, client.getHeaders(), { + 'X-Appwrite-Organization': organizationId + }); + + return new Organization(organizationClient); + } }; } @@ -98,7 +115,6 @@ const sdkForProject = { avatars: new Avatars(clientProject), backups: new Backups(clientProject), functions: new Functions(clientProject), - health: new Health(clientProject), locale: new Locale(clientProject), messaging: new Messaging(clientProject), project: new Project(clientProject), @@ -114,6 +130,8 @@ const sdkForProject = { tablesDB: new TablesDB(clientProject), documentsDB: new DocumentsDB(clientProject), vectorsDB: new VectorsDB(clientProject), + embeddings: new Embeddings(clientProject), + usage: new Usage(clientProject), webhooks: new Webhooks(clientProject), console: new Console(clientProject) // for suggestions API }; diff --git a/src/lib/stores/sites.ts b/src/lib/stores/sites.ts index ef39511ee2..29d8113323 100644 --- a/src/lib/stores/sites.ts +++ b/src/lib/stores/sites.ts @@ -1,9 +1,3 @@ -import type { Models } from '@appwrite.io/console'; - -export type FrameworkAdapterWithStartCommand = Models.FrameworkAdapter & { - startCommand?: string; -}; - export function getFrameworkIcon(framework: string) { switch (true) { case framework.toLocaleLowerCase().includes('sveltekit'): diff --git a/src/lib/stores/windowFocus.ts b/src/lib/stores/windowFocus.ts deleted file mode 100644 index b0c28abca4..0000000000 --- a/src/lib/stores/windowFocus.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { readable, type Readable } from 'svelte/store'; - -function isCurrentWindowFocused(): boolean { - if (!window) return false; - if (!window.document) return false; - if (typeof window.document.hasFocus !== 'function') return false; - - return window.document.hasFocus(); -} - -export function windowFocusStore(): Readable { - const visibility = readable(isCurrentWindowFocused(), (set) => { - function handler() { - set(isCurrentWindowFocused()); - } - - if (window) { - window.addEventListener('focus', handler); - window.addEventListener('blur', handler); - - return () => { - window.removeEventListener('focus', handler); - window.removeEventListener('blur', handler); - }; - } - }); - - return visibility; -} diff --git a/src/routes/(console)/(migration-wizard)/step1.svelte b/src/routes/(console)/(migration-wizard)/step1.svelte index a42a8cf93f..7841d80291 100644 --- a/src/routes/(console)/(migration-wizard)/step1.svelte +++ b/src/routes/(console)/(migration-wizard)/step1.svelte @@ -22,8 +22,9 @@ projects = []; } else { loadingProjects = true; - projects = await sdk.forConsole.projects - .list({ + projects = await sdk.forConsole + .organization(orgId) + .listProjects({ queries: [Query.equal('teamId', orgId), Query.orderDesc('$createdAt')] }) .then((res) => res.projects); @@ -38,10 +39,9 @@ const beforeSubmit = async () => { if (projectType === 'existing') return; - const project = await sdk.forConsole.projects.create({ + const project = await sdk.forConsole.organization(selectedOrg).createProject({ projectId: ID.unique(), - name: newProjName, - teamId: selectedOrg + name: newProjName }); selectedProject.set(project.$id); }; diff --git a/src/routes/(console)/(migration-wizard)/wizard.svelte b/src/routes/(console)/(migration-wizard)/wizard.svelte index 13430e8988..8cb03f25b8 100644 --- a/src/routes/(console)/(migration-wizard)/wizard.svelte +++ b/src/routes/(console)/(migration-wizard)/wizard.svelte @@ -64,8 +64,9 @@ projects = []; } else { loadingProjects = true; - projects = await sdk.forConsole.projects - .list({ + projects = await sdk.forConsole + .organization(orgId) + .listProjects({ queries: [Query.equal('teamId', orgId), Query.orderDesc('$createdAt')] }) .then((res) => res.projects); @@ -88,10 +89,9 @@ creatingProject = true; try { - return await sdk.forConsole.projects.create({ + return await sdk.forConsole.organization(selectedOrg).createProject({ projectId: ID.unique(), name: newProjName, - teamId: selectedOrg, region: $selectedRegion }); } catch (error) { diff --git a/src/routes/(console)/+error.svelte b/src/routes/(console)/+error.svelte index 41863e61a4..a4b8533bd1 100644 --- a/src/routes/(console)/+error.svelte +++ b/src/routes/(console)/+error.svelte @@ -5,7 +5,12 @@ import { Button } from '$lib/elements/forms'; import { isVerifyEmailRedirectError } from '$lib/helpers/emailVerification'; import { Container } from '$lib/layout'; - import { Typography } from '@appwrite.io/pink-svelte'; + import { Badge, Layout, Typography } from '@appwrite.io/pink-svelte'; + + const isPaymentError = $derived(page.status === 402); + const billingUrl = $derived( + page.params.organization ? `${base}/organization-${page.params.organization}/billing` : null + ); $effect(() => { const verifyEmailPath = resolve('/verify-email'); @@ -15,15 +20,56 @@ }); - -
- {'status' in page.error - ? page.error.status || 'Invalid Argument' - : 'Invalid Argument'} - {page.error.message} -
-
- -
-
+{#if isPaymentError} +
+
+ + + + + Your organization has reached a billing limit + + {page.error.message} + +
+ + {#if billingUrl} + + {/if} + + +
+
+
+
+{:else} + +
+ {'status' in page.error + ? page.error.status || 'Invalid Argument' + : 'Invalid Argument'} + {page.error.message} +
+
+ +
+
+{/if} + + diff --git a/src/routes/(console)/+layout.svelte b/src/routes/(console)/+layout.svelte index 139f1883dc..b0f4267981 100644 --- a/src/routes/(console)/+layout.svelte +++ b/src/routes/(console)/+layout.svelte @@ -331,7 +331,6 @@ - import { Activity } from '$lib/layout'; - import type { PageData } from './$types'; - - export let data: PageData; - - - diff --git a/src/routes/(console)/account/activity/+page.ts b/src/routes/(console)/account/activity/+page.ts deleted file mode 100644 index 20e70bbf3a..0000000000 --- a/src/routes/(console)/account/activity/+page.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Query } from '@appwrite.io/console'; -import { sdk } from '$lib/stores/sdk'; -import { getLimit, getPage, pageToOffset } from '$lib/helpers/load'; -import { PAGE_LIMIT } from '$lib/constants'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ url, route }) => { - const page = getPage(url); - const limit = getLimit(url, route, PAGE_LIMIT); - const offset = pageToOffset(page, limit); - - return { - offset, - limit, - logs: await sdk.forConsole.account.listLogs({ - queries: [Query.offset(offset), Query.limit(limit)] - }) - }; -}; diff --git a/src/routes/(console)/account/applications/+page.svelte b/src/routes/(console)/account/applications/+page.svelte new file mode 100644 index 0000000000..a0a6277613 --- /dev/null +++ b/src/routes/(console)/account/applications/+page.svelte @@ -0,0 +1,111 @@ + + + + + Applications + + Applications you've authorized to access your Appwrite account. + + + + {#if data.connectedApps.length === 0} + + + + {:else} + + + Application + Authorized + + + {#each data.connectedApps as { identity, appId, app } (identity.$id)} + + + +
+ {#if app?.logoUri} + {app.name} + {:else} + + {/if} +
+ + + + {displayName(appId, app)} + + {#if app?.deviceFlow} + + {/if} + + {#if app?.tagline || app?.description} + + {app.tagline || app.description} + + {/if} + +
+
+ + {toLocaleDate(identity.$createdAt)} + + + + +
+ {/each} +
+ {/if} +
diff --git a/src/routes/(console)/account/applications/+page.ts b/src/routes/(console)/account/applications/+page.ts new file mode 100644 index 0000000000..c453ee958c --- /dev/null +++ b/src/routes/(console)/account/applications/+page.ts @@ -0,0 +1,28 @@ +import { Dependencies } from '$lib/constants'; +import { getOAuth2App } from '$lib/helpers/oauth2-cimd'; +import type { Models } from '@appwrite.io/console'; +import type { PageLoad } from './$types'; + +const OAUTH2_PREFIX = 'oauth2:'; + +export const load: PageLoad = async ({ depends, parent }) => { + depends(Dependencies.IDENTITIES); + + // Apps authorized through the console OAuth2 server (e.g. the Appwrite CLI via + // the device flow) are stored as `oauth2:` identities by the parent + // layout load. Resolve each to its app metadata for richer rendering. + const { identities } = await parent(); + const grants = (identities.identities as Models.Identity[]).filter((identity) => + identity.provider?.startsWith(OAUTH2_PREFIX) + ); + + const connectedApps = await Promise.all( + grants.map(async (identity) => { + const appId = identity.provider.slice(OAUTH2_PREFIX.length); + const app = await getOAuth2App(appId).catch(() => null); + return { identity, appId, app }; + }) + ); + + return { connectedApps }; +}; diff --git a/src/routes/(console)/account/header.svelte b/src/routes/(console)/account/header.svelte index 507dbfd912..f39da5c9a7 100644 --- a/src/routes/(console)/account/header.svelte +++ b/src/routes/(console)/account/header.svelte @@ -23,10 +23,9 @@ event: 'sessions' }, { - href: `${path}/activity`, - title: 'Activity', - event: 'activity', - hasChildren: true + href: `${path}/applications`, + title: 'Applications', + event: 'applications' }, { href: `${path}/organizations`, diff --git a/src/routes/(console)/account/identities.svelte b/src/routes/(console)/account/identities.svelte index c326fdc1a0..3e7b71747d 100644 --- a/src/routes/(console)/account/identities.svelte +++ b/src/routes/(console)/account/identities.svelte @@ -12,6 +12,12 @@ import { IconTrash } from '@appwrite.io/pink-icons-svelte'; import DualTimeView from '$lib/components/dualTimeView.svelte'; + // Apps authorized through the OAuth2 server use an `oauth2:` provider + // and are managed on the Applications tab; this list is sign-in identities only. + $: signInIdentities = $identities.filter( + (identity) => !identity.provider?.startsWith('oauth2:') + ); + async function deleteIdentity(id: string) { try { await sdk.forConsole.account.deleteIdentity({ identityId: id }); @@ -36,7 +42,7 @@ Identities are your connected GitHub accounts. You can sign in using these accounts. - {#if $identities.length === 0} + {#if signInIdentities.length === 0} Expiry Date - {#each $identities as identity (identity.$id)} + {#each signInIdentities as identity (identity.$id)} {@const provider = oAuthProviders[identity.provider]} diff --git a/src/routes/(console)/account/payments/+page.ts b/src/routes/(console)/account/payments/+page.ts index fb0cb2d96d..d1f05465f8 100644 --- a/src/routes/(console)/account/payments/+page.ts +++ b/src/routes/(console)/account/payments/+page.ts @@ -1,8 +1,12 @@ +import { redirect } from '@sveltejs/kit'; import { Dependencies } from '$lib/constants'; import { sdk } from '$lib/stores/sdk'; +import { isCloud } from '$lib/system'; import type { PageLoad } from './$types'; export const load: PageLoad = async ({ depends }) => { + if (!isCloud) redirect(302, '/'); + depends(Dependencies.PAYMENT_METHODS); depends(Dependencies.ADDRESS); diff --git a/src/routes/(console)/account/sessions/+page.svelte b/src/routes/(console)/account/sessions/+page.svelte index 30d1e7829f..56a5b44af0 100644 --- a/src/routes/(console)/account/sessions/+page.svelte +++ b/src/routes/(console)/account/sessions/+page.svelte @@ -25,6 +25,12 @@ export let data: PageData; + // OAuth2 app authorizations (e.g. the Appwrite CLI) are surfaced on the + // Applications tab, so keep them out of the browser-session list here. + $: visibleSessions = data.sessions.sessions.filter( + (session) => !session.provider?.startsWith('oauth2') + ); + function getBrowser(clientCode: string) { const code = clientCode.toLowerCase(); if (!isValueOfStringEnum(Browser, code)) return ''; @@ -111,7 +117,7 @@ IP - {#each data.sessions.sessions as session} + {#each visibleSessions as session} {@const browser = getBrowser(session.clientCode)} diff --git a/src/routes/(console)/bottomAlerts.ts b/src/routes/(console)/bottomAlerts.ts index 0e406c22a7..37790953df 100644 --- a/src/routes/(console)/bottomAlerts.ts +++ b/src/routes/(console)/bottomAlerts.ts @@ -1,33 +1,33 @@ import { isCloud } from '$lib/system'; import { isSameDay } from '$lib/helpers/date'; import { type BottomModalAlertItem, showBottomModalAlert } from '$lib/stores/bottom-alerts'; -import TerraformProvider from '$lib/images/promos/terraform-provider.png'; +import StateOfAppwriteSurvey from '$lib/images/promos/state-of-appwrite-survey.png'; const listOfPromotions: BottomModalAlertItem[] = []; if (isCloud) { - const terraformProviderPromo: BottomModalAlertItem = { - id: 'modal:terraform_provider_announcement', + const stateOfAppwriteSurveyPromo: BottomModalAlertItem = { + id: 'modal:state_of_appwrite_survey_announcement', src: { - dark: TerraformProvider, - light: TerraformProvider + dark: StateOfAppwriteSurvey, + light: StateOfAppwriteSurvey }, - title: 'Introducing Terraform support for Appwrite projects', + title: 'State of Appwrite Cloud', message: - 'Manage your entire Appwrite project as code with the official Terraform provider.', + 'Share your experience building with Appwrite Cloud and using AI tools, and help shape our product roadmap for 2026 and beyond.', plan: 'free', importance: 8, scope: 'everywhere', cta: { - text: 'Read announcement', - link: () => 'https://appwrite.io/blog/post/introducing-terraform-provider-for-appwrite', + text: 'Take the survey', + link: () => 'https://forms.gle/5cvWxTwhonoDCWsi7', external: true, hideOnClick: true, skipUpgradeRedirect: true }, show: true }; - listOfPromotions.push(terraformProviderPromo); + listOfPromotions.push(stateOfAppwriteSurveyPromo); } export function addBottomModalAlerts() { diff --git a/src/routes/(console)/onboarding/create-project/+page.svelte b/src/routes/(console)/onboarding/create-project/+page.svelte index f6ac36ce73..007c4e5f75 100644 --- a/src/routes/(console)/onboarding/create-project/+page.svelte +++ b/src/routes/(console)/onboarding/create-project/+page.svelte @@ -43,10 +43,9 @@ try { const teamId = data.organization.$id; - const project = await sdk.forConsole.projects.create({ + const project = await sdk.forConsole.organization(teamId).createProject({ projectId: projectId ?? ID.unique(), name: projectName, - teamId, region: isCloud ? projectRegion : undefined }); diff --git a/src/routes/(console)/onboarding/create-project/+page.ts b/src/routes/(console)/onboarding/create-project/+page.ts index ae88f54a85..1da073231a 100644 --- a/src/routes/(console)/onboarding/create-project/+page.ts +++ b/src/routes/(console)/onboarding/create-project/+page.ts @@ -63,7 +63,7 @@ export const load: PageLoad = async ({ parent }) => { const org = organizations.teams[0]; let projects: Models.ProjectList = null; try { - projects = await sdk.forConsole.projects.list({ + projects = await sdk.forConsole.organization(org.$id).listProjects({ queries: [Query.equal('teamId', org.$id), Query.limit(1), Query.select(['$id'])] }); } catch (e) { diff --git a/src/routes/(console)/organization-[organization]/+page.svelte b/src/routes/(console)/organization-[organization]/+page.svelte index 7c1d9f7c69..044e88d0bd 100644 --- a/src/routes/(console)/organization-[organization]/+page.svelte +++ b/src/routes/(console)/organization-[organization]/+page.svelte @@ -1,5 +1,6 @@ @@ -71,18 +97,41 @@ autofocus bind:value={email} /> + {#if isCloud} - - - - - - + {#if supportsProjectRoles} + + + - + {/if} + + {#if accessType === 'all' || !supportsProjectRoles} + + + + + + + + + {:else} + + {/if} {/if} + diff --git a/src/routes/(console)/organization-[organization]/createProject.svelte b/src/routes/(console)/organization-[organization]/createProject.svelte index 1951eb240a..47f0547ac5 100644 --- a/src/routes/(console)/organization-[organization]/createProject.svelte +++ b/src/routes/(console)/organization-[organization]/createProject.svelte @@ -27,10 +27,9 @@ try { disabled = true; showSubmissionLoader = true; - const project = await sdk.forConsole.projects.create({ + const project = await sdk.forConsole.organization(teamId).createProject({ projectId: id || ID.unique(), - name, - teamId + name }); show = false; dispatch('created', project); diff --git a/src/routes/(console)/organization-[organization]/createProjectCloud.svelte b/src/routes/(console)/organization-[organization]/createProjectCloud.svelte index f558211997..375eb588a8 100644 --- a/src/routes/(console)/organization-[organization]/createProjectCloud.svelte +++ b/src/routes/(console)/organization-[organization]/createProjectCloud.svelte @@ -39,10 +39,9 @@ showSubmissionLoader = true; try { - project = await sdk.forConsole.projects.create({ + project = await sdk.forConsole.organization(teamId).createProject({ projectId: projectId ?? ID.unique(), name: projectName, - teamId, region: projectRegion }); diff --git a/src/routes/(console)/organization-[organization]/domains/recordsCard.svelte b/src/routes/(console)/organization-[organization]/domains/recordsCard.svelte index edfec5903d..e03f8848fb 100644 --- a/src/routes/(console)/organization-[organization]/domains/recordsCard.svelte +++ b/src/routes/(console)/organization-[organization]/domains/recordsCard.svelte @@ -34,7 +34,7 @@ async function verifyStatus() { try { - domain = await sdk.forConsole.domains.updateNameservers({ domainId: domain.$id }); + domain = await sdk.forConsole.domains.verifyNameservers({ domainId: domain.$id }); verified = domain.nameservers.toLowerCase() === 'appwrite'; if (verified) { addNotification({ diff --git a/src/routes/(console)/organization-[organization]/domains/retryDomainModal.svelte b/src/routes/(console)/organization-[organization]/domains/retryDomainModal.svelte index 5dab1876e8..b3caa21c87 100644 --- a/src/routes/(console)/organization-[organization]/domains/retryDomainModal.svelte +++ b/src/routes/(console)/organization-[organization]/domains/retryDomainModal.svelte @@ -29,7 +29,7 @@ async function retryDomain() { try { error = null; - const domain = await sdk.forConsole.domains.updateNameservers({ + const domain = await sdk.forConsole.domains.verifyNameservers({ domainId: selectedDomain.$id }); diff --git a/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/download/+page.ts b/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/download/+page.ts index 3a0e31cbd3..ba7fd03259 100644 --- a/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/download/+page.ts +++ b/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/download/+page.ts @@ -1,4 +1,5 @@ import { getApiEndpoint, sdk } from '$lib/stores/sdk'; +import { createImpersonatedResourceUrl } from '$lib/appwrite/impersonation'; import { redirect } from '@sveltejs/kit'; import type { PageLoad } from './$types'; @@ -12,6 +13,8 @@ export const load: PageLoad = async ({ params }) => { return redirect( 302, - `${endpoint}/organizations/${params.organization}/invoices/${invoice.$id}/download` + createImpersonatedResourceUrl( + `${endpoint}/organizations/${params.organization}/invoices/${invoice.$id}/download` + ) ); }; diff --git a/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts b/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts index 3a4576785e..9351393ae1 100644 --- a/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts +++ b/src/routes/(console)/organization-[organization]/invoices/[invoiceId]/view/+page.ts @@ -1,4 +1,5 @@ import { getApiEndpoint, sdk } from '$lib/stores/sdk'; +import { createImpersonatedResourceUrl } from '$lib/appwrite/impersonation'; import { redirect } from '@sveltejs/kit'; import type { PageLoad } from './$types'; @@ -13,6 +14,8 @@ export const load: PageLoad = async ({ params }) => { return redirect( 302, - `${endpoint}/organizations/${params.organization}/invoices/${invoice.$id}/view` + createImpersonatedResourceUrl( + `${endpoint}/organizations/${params.organization}/invoices/${invoice.$id}/view` + ) ); }; diff --git a/src/routes/(console)/organization-[organization]/members/+page.svelte b/src/routes/(console)/organization-[organization]/members/+page.svelte index d422cfb810..c9dc6a50be 100644 --- a/src/routes/(console)/organization-[organization]/members/+page.svelte +++ b/src/routes/(console)/organization-[organization]/members/+page.svelte @@ -6,7 +6,14 @@ import { base } from '$app/paths'; import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; import Upgrade from '$lib/components/roles/upgrade.svelte'; - import { getServiceLimit, readOnly, getRoleLabel } from '$lib/stores/billing'; + import { + getServiceLimit, + readOnly, + getRoleLabel, + isProjectSpecificRole, + parseProjectRole + } from '$lib/stores/billing'; + import { BODY_TOOLTIP_MAX_WIDTH, BODY_TOOLTIP_WRAPPER_STYLE @@ -53,6 +60,8 @@ $: isLimited = limit !== 0 && limit < Infinity; $: isButtonDisabled = isCloud && (($readOnly && !GRACE_PERIOD_OVERRIDE) || (isLimited && memberCount >= limit)); + $: supportsOrgRoles = isCloud && !!$currentPlan?.supportsOrganizationRoles; + $: supportsProjectRoles = isCloud && !!$currentPlan?.supportsProjectSpecificRoles; const resend = async (member: Models.Membership) => { try { @@ -149,7 +158,52 @@ - {member.roles.map((role) => getRoleLabel(role)).join(', ')} + {#if supportsProjectRoles && member.roles.some(isProjectSpecificRole)} + {@const projectRoles = member.roles.filter(isProjectSpecificRole)} + {@const firstRole = projectRoles[0]} + {@const firstParsed = parseProjectRole(firstRole)} + {@const firstProject = firstParsed + ? data.orgProjects?.projects?.find( + (p) => p.$id === firstParsed.projectId + ) + : null} + {@const overflow = projectRoles.slice(1)} + + + {#if overflow.length > 0} + + + +
+ + {#each overflow as overflowRole} + {@const p = parseProjectRole(overflowRole)} + {@const proj = p + ? data.orgProjects?.projects?.find( + (x) => x.$id === p.projectId + ) + : null} + + {getRoleLabel(overflowRole)}: {proj?.name ?? + p?.projectId} + + {/each} + +
+
+
+ {/if} +
+ {:else} + {member.roles.map((r) => getRoleLabel(r)).join(', ')} + {/if}
- {#if isCloud && $currentPlan?.supportsOrganizationRoles} + {#if supportsOrgRoles || supportsProjectRoles} { diff --git a/src/routes/(console)/organization-[organization]/members/+page.ts b/src/routes/(console)/organization-[organization]/members/+page.ts index af5d80817f..9d1dd1cf74 100644 --- a/src/routes/(console)/organization-[organization]/members/+page.ts +++ b/src/routes/(console)/organization-[organization]/members/+page.ts @@ -4,7 +4,8 @@ import { sdk } from '$lib/stores/sdk'; import { Query } from '@appwrite.io/console'; import type { PageLoad } from './$types'; -export const load: PageLoad = async ({ url, params, route, depends }) => { +export const load: PageLoad = async ({ url, params, route, depends, parent }) => { + await parent(); depends(Dependencies.ORGANIZATION); depends(Dependencies.MEMBERS); @@ -13,14 +14,25 @@ export const load: PageLoad = async ({ url, params, route, depends }) => { const limit = getLimit(url, route, PAGE_LIMIT); const offset = pageToOffset(page, limit); + const [organizationMembers, orgProjects] = await Promise.all([ + sdk.forConsole.teams.listMemberships({ + teamId: params.organization, + queries: [Query.limit(limit), Query.offset(offset)], + search + }), + sdk.forConsole + .organization(params.organization) + .listProjects({ + queries: [Query.limit(100), Query.equal('teamId', params.organization)] + }) + .catch(() => null) + ]); + return { offset, limit, search, - organizationMembers: await sdk.forConsole.teams.listMemberships({ - teamId: params.organization, - queries: [Query.limit(limit), Query.offset(offset)], - search - }) + organizationMembers, + orgProjects }; }; diff --git a/src/routes/(console)/organization-[organization]/members/edit.svelte b/src/routes/(console)/organization-[organization]/members/edit.svelte index ce2dc701a4..65aeceffae 100644 --- a/src/routes/(console)/organization-[organization]/members/edit.svelte +++ b/src/routes/(console)/organization-[organization]/members/edit.svelte @@ -1,56 +1,91 @@ - - - - - - - - + + {#if supportsProjectRoles} + + + + + {/if} + + {#if accessType === 'all' || !supportsProjectRoles} + + + + + + + + + {:else} + + {/if} + diff --git a/src/routes/(console)/organization-[organization]/projectAccessSelector.svelte b/src/routes/(console)/organization-[organization]/projectAccessSelector.svelte new file mode 100644 index 0000000000..17e4013899 --- /dev/null +++ b/src/routes/(console)/organization-[organization]/projectAccessSelector.svelte @@ -0,0 +1,183 @@ + + + + {#each projectAccess as access, i} + +
{ + if (!rowOptions[i]?.length) loadProjects(i); + }} + oninput={(e) => { + if (e.target instanceof HTMLInputElement) { + getDebouncedSearch(i)(e.target.value); + } + }}> + onProjectSelected(i)} /> +
+
+ +
+
+ +
+
+ {/each} +
+ +
+
diff --git a/src/routes/(console)/organization-[organization]/settings/+page.ts b/src/routes/(console)/organization-[organization]/settings/+page.ts index c275d01955..bb7fb6b878 100644 --- a/src/routes/(console)/organization-[organization]/settings/+page.ts +++ b/src/routes/(console)/organization-[organization]/settings/+page.ts @@ -3,14 +3,25 @@ import { Dependencies } from '$lib/constants'; import { sdk } from '$lib/stores/sdk'; import { Addon, Query } from '@appwrite.io/console'; import { isCloud } from '$lib/system'; +import { redirect } from '@sveltejs/kit'; +import { resolve } from '$app/paths'; export const load: PageLoad = async ({ depends, params, parent }) => { - const { countryList, locale } = await parent(); + const { countryList, locale, roles } = await parent(); + + if (isCloud && !roles.includes('owner')) { + redirect( + 303, + resolve('/(console)/organization-[organization]', { + organization: params.organization + }) + ); + } depends(Dependencies.ORGANIZATION); depends(Dependencies.ADDONS); const [projects, invoices, addons, addonPrice] = await Promise.all([ - sdk.forConsole.projects.list({ + sdk.forConsole.organization(params.organization).listProjects({ queries: [Query.equal('teamId', params.organization), Query.select(['$id', 'name'])] }), isCloud diff --git a/src/routes/(console)/organization-[organization]/settings/deleteOrganizationEstimation.svelte b/src/routes/(console)/organization-[organization]/settings/deleteOrganizationEstimation.svelte deleted file mode 100644 index 14ae7d8bcb..0000000000 --- a/src/routes/(console)/organization-[organization]/settings/deleteOrganizationEstimation.svelte +++ /dev/null @@ -1,18 +0,0 @@ - - -{#if estimation} - {#if estimation.unpaidInvoices?.length > 0} - - This organization has unresolved invoices that must be settled before it can be deleted. - Please review and resolve these invoices to proceed. - - - - {/if} -{/if} diff --git a/src/routes/(console)/organization-[organization]/settings/deleteOrganizationModal.svelte b/src/routes/(console)/organization-[organization]/settings/deleteOrganizationModal.svelte index 51a1d483aa..6962fb8d3a 100644 --- a/src/routes/(console)/organization-[organization]/settings/deleteOrganizationModal.svelte +++ b/src/routes/(console)/organization-[organization]/settings/deleteOrganizationModal.svelte @@ -14,7 +14,6 @@ import { formatCurrency } from '$lib/helpers/numbers'; import { billingIdToPlan } from '$lib/stores/billing'; import { Table, Tabs, Alert } from '@appwrite.io/pink-svelte'; - import DeleteOrganizationEstimation from './deleteOrganizationEstimation.svelte'; import type { Models } from '@appwrite.io/console'; export let showDelete = false; @@ -23,7 +22,6 @@ let error: string = null; let selectedTab = 'projects'; let organizationName: string = null; - let estimation: Models.EstimationDeleteOrganization; async function deleteOrg() { try { @@ -76,21 +74,6 @@ $: if (!showDelete) { // reset on close. organizationName = ''; - } else { - getEstimate(); - } - - async function getEstimate() { - if (isCloud) { - try { - error = ''; - estimation = await sdk.forConsole.organizations.estimationDeleteOrganization({ - organizationId: $organization.$id - }); - } catch (e) { - error = e.message; - } - } } @@ -114,60 +97,53 @@ This action is irreversible. {/if}

- - {#if estimation && (estimation.unpaidInvoices.length > 0 || estimation.unpaidInvoices.some((invoice) => invoice.grossAmount > 0))} - - {:else} - {#if $projects.total > 0} - - {#each tabs as { name, label, total }} - (selectedTab = name)} - active={selectedTab === name}> - {label.desktop} ({total}) - + {#if $projects.total > 0} + + {#each tabs as { name, label, total }} + (selectedTab = name)} + active={selectedTab === name}> + {label.desktop} ({total}) + + {/each} + + {#if selectedTab === 'projects'} + + + Projects + Last updated + + {#each $projects.projects as project} + + {project.name} + {toLocaleDate(project.$updatedAt)} + + {/each} + + {:else} + + + Members + Last updated + + {#each $members.memberships as membership} + + {membership.userName} + {toLocaleDate(membership.$updatedAt)} + {/each} - - {#if selectedTab === 'projects'} - - - Projects - Last updated - - {#each $projects.projects as project} - - {project.name} - {toLocaleDate(project.$updatedAt)} - - {/each} - - {:else} - - - Members - Last updated - - {#each $members.memberships as membership} - - {membership.userName} - {toLocaleDate(membership.$updatedAt)} - - {/each} - - {/if} + {/if} - {/if} + + {/if} + + +
+ +
+ +{:else if page.error.type === 'general_resource_blocked'}
diff --git a/src/routes/(console)/project-[region]-[project]/+layout.ts b/src/routes/(console)/project-[region]-[project]/+layout.ts index 8da91fdd80..74f3e071bf 100644 --- a/src/routes/(console)/project-[region]-[project]/+layout.ts +++ b/src/routes/(console)/project-[region]-[project]/+layout.ts @@ -8,7 +8,7 @@ import { get } from 'svelte/store'; import { headerAlert } from '$lib/stores/headerAlert'; import PaymentFailed from '$lib/components/billing/alerts/paymentFailed.svelte'; import { loadAvailableRegions } from '$routes/(console)/regions'; -import { type Models, Platform } from '@appwrite.io/console'; +import { Query, type Models, Platform } from '@appwrite.io/console'; import { redirect } from '@sveltejs/kit'; import { resolve } from '$app/paths'; import { generateFingerprintToken } from '$lib/helpers/fingerprint'; @@ -19,7 +19,20 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => { const { plansInfo, organizations, preferences: prefs } = await parent(); depends(Dependencies.PROJECT); - const project = await sdk.forConsole.projects.get({ projectId: params.project }); + const projectSdk = sdk.forProject(params.region, params.project).project; + let project: Models.Project; + try { + project = await projectSdk.get(); + } catch { + // project is inaccessible (deleted, wrong region, etc.) — go back to last known org + const lastOrg = prefs?.organization; + redirect( + 303, + lastOrg + ? resolve('/(console)/organization-[organization]', { organization: lastOrg }) + : resolve('/(console)') + ); + } if (project.status !== 'active' && project.status !== 'paused') { // project isn't active, redirect back to organizations page redirect( @@ -40,20 +53,25 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => { // organization can be null if not in the filtered list! const includedInBasePlans = plansInfo.has(organization?.billingPlanId); - const [org, rawRegionalConsoleVariables, rolesResult] = await Promise.all([ - !organization - ? // TODO: @itznotabug - teams.get with Models.Organization? - (sdk.forConsole.teams.get({ teamId: project.teamId }) as Promise) - : organization, - sdk.forConsoleIn(project.region).console.variables(), - isCloud - ? sdk.forConsole.organizations.getScopes({ - organizationId: project.teamId - }) - : null, - - loadAvailableRegions(project.teamId) - ]); + const [org, rawRegionalConsoleVariables, rolesResult, platformList, keyList] = + await Promise.all([ + !organization + ? // TODO: @itznotabug - teams.get with Models.Organization? + (sdk.forConsole.teams.get({ + teamId: project.teamId + }) as Promise) + : organization, + sdk.forConsoleIn(project.region).console.variables(), + isCloud + ? sdk.forConsole.organizations.getScopes({ + organizationId: project.teamId, + projectId: params.project + }) + : null, + projectSdk.listPlatforms({ queries: [Query.limit(1)] }), + projectSdk.listKeys({ queries: [Query.limit(1)] }), + loadAvailableRegions(project.teamId) + ]); const regionalConsoleVariables = normalizeConsoleVariables(rawRegionalConsoleVariables); @@ -122,6 +140,8 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => { return { project, + platforms: platformList, + keys: keyList, organization, regionalConsoleVariables, roles, diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/googleOAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/googleOAuth.svelte new file mode 100644 index 0000000000..12bcf06c55 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/auth/(providers)/googleOAuth.svelte @@ -0,0 +1,193 @@ + + + +

+ To use Google authentication in your application, first fill in this form. For more info you + can + visit the docs. +

+ + + + {#if appIdParam} + + {/if} + + {#if !showSecretInput} +
+ (showSecretInput = true)}> + Update Client Secret + +
+ {:else} + + + + + Client Secret + + + + This field is write-only. Enter a new value to update it. + + + + + + + + + + + {/if} + + + + + + + To complete set up, add this OAuth2 redirect URI to your Google app configuration. + + + + + + + +
diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/googlePromptPicker.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/googlePromptPicker.svelte new file mode 100644 index 0000000000..f7f04d9abb --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/auth/(providers)/googlePromptPicker.svelte @@ -0,0 +1,41 @@ + + + + Prompt + + {#each options as option (option.val)} + toggle(option.val)}> + {option.label} + + {/each} + + diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/mainOAuth.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/mainOAuth.svelte index acc3a90c55..1b6e93eb9a 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/(providers)/mainOAuth.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/(providers)/mainOAuth.svelte @@ -3,13 +3,19 @@ import { CopyInput, Modal } from '$lib/components'; import { Button, + InputNumber, InputPassword, InputSwitch, InputText, InputTextarea } from '$lib/elements/forms'; import { updateOAuth } from '../updateOAuth'; - import { OAuthProvider, type Models, type Models as ConsoleModels } from '@appwrite.io/console'; + import { + OAuthProvider, + ProjectOAuth2OidcPrompt, + type Models as ConsoleModels + } from '@appwrite.io/console'; + import type { AuthProvider } from '../updateOAuth'; import { oAuthProviders } from '$lib/stores/oauth-providers'; import { Accordion, @@ -24,11 +30,12 @@ } from '@appwrite.io/pink-svelte'; import { IconDocument, IconPencil, IconUpload, IconX } from '@appwrite.io/pink-icons-svelte'; import { getApiEndpoint } from '$lib/stores/sdk'; + import OidcPromptPicker from './oidcPromptPicker.svelte'; const projectId = page.params.project; const region = page.params.region; - export let provider: Models.AuthProvider; + export let provider: AuthProvider; export let show = false; export let parameters: ConsoleModels.ConsoleOAuth2ProviderParameter[] = []; @@ -39,18 +46,25 @@ let showSecretInput = false; let p8PasteMode: Record = {}; let error: string; - let initializedProvider: Models.AuthProvider | null = null; + let initializedProvider: AuthProvider | null = null; let initialEnabled = false; let initialAppId: string | null = null; let initialDetailValues: Record = {}; + let oidcPrompt: ProjectOAuth2OidcPrompt[] = []; + let initialOidcPrompt: ProjectOAuth2OidcPrompt[] = []; + let oidcMaxAge: number | null = null; + let initialOidcMaxAge: number | null = null; + $: isOidc = provider?.key === OAuthProvider.Oidc; $: appIdParam = parameters.length >= 1 ? parameters[0] : null; $: additionalParams = parameters.slice(1); $: detailParams = additionalParams.filter((param) => !isSecretParam(param.$id)); $: secretParams = additionalParams.filter((param) => isSecretParam(param.$id)); $: basicDetailParams = provider?.key === OAuthProvider.Oidc - ? detailParams.filter((param) => !isOidcAdvancedParam(param.$id)) + ? detailParams.filter( + (param) => !isOidcAdvancedParam(param.$id) && !isOidcCustomParam(param.$id) + ) : detailParams; $: advancedDetailParams = provider?.key === OAuthProvider.Oidc @@ -65,11 +79,16 @@ normalizeFieldValue(fieldValues[param.$id]) !== (initialDetailValues[param.$id] ?? '') ); }); + $: hasOidcChanges = + isOidc && + ([...oidcPrompt].sort().join(',') !== [...initialOidcPrompt].sort().join(',') || + (oidcMaxAge ?? 0) !== (initialOidcMaxAge ?? 0)); $: nothingChanged = enabled === initialEnabled && normalizeFieldValue(appId) === normalizeFieldValue(initialAppId) && !hasSecretInput && - !hasDetailChanges; + !hasDetailChanges && + !hasOidcChanges; $: oAuthProvider = oAuthProviders[provider.key]; $: secretCardTitle = secretParams.length === 1 ? primaryName(secretParams[0]?.name ?? '') : 'Credentials'; @@ -89,6 +108,19 @@ ); p8PasteMode = {}; showSecretInput = !appId || (provider.key === OAuthProvider.Apple && !providerKeyId); + if (provider.key === OAuthProvider.Oidc) { + const raw = provider as Record; + initialOidcPrompt = Array.isArray(raw['prompt']) + ? ([...(raw['prompt'] as ProjectOAuth2OidcPrompt[])] as ProjectOAuth2OidcPrompt[]) + : []; + initialOidcMaxAge = + typeof raw['maxAge'] === 'number' && raw['maxAge'] > 0 ? raw['maxAge'] : null; + } else { + initialOidcPrompt = []; + initialOidcMaxAge = null; + } + oidcPrompt = [...initialOidcPrompt]; + oidcMaxAge = initialOidcMaxAge; error = undefined; } @@ -147,7 +179,12 @@ } function isOidcAdvancedParam(id: string): boolean { - return id === 'authorizationURL' || id === 'tokenUrl' || id === 'userInfoUrl'; + return id !== 'wellKnownURL' && id.toLowerCase().includes('url'); + } + + // prompt and maxAge get dedicated controls in the Advanced section + function isOidcCustomParam(id: string): boolean { + return id === 'prompt' || id === 'maxAge'; } async function handleP8FileUpload(id: string, event: Event) { @@ -197,6 +234,8 @@ appId, secret: buildSecret(), details: buildDetails(), + promptValues: isOidc ? oidcPrompt : undefined, + maxAge: isOidc ? (oidcMaxAge ?? 0) : undefined, enabled }); @@ -244,21 +283,6 @@ bind:value={fieldValues[param.$id]} /> {/each} - {#if advancedDetailParams.length > 0} - - - {#each advancedDetailParams as param} - - {/each} - - - {/if} - {#if secretParams.length > 0} {#if !showSecretInput}
@@ -371,6 +395,32 @@ {/if} {/if} + {#if advancedDetailParams.length > 0 || isOidc} + + + {#each advancedDetailParams as param} + + {/each} + {#if isOidc} + + + {/if} + + + {/if} + To complete set up, add this OAuth2 redirect URI to your {provider.name} app configuration. diff --git a/src/routes/(console)/project-[region]-[project]/auth/(providers)/oidcPromptPicker.svelte b/src/routes/(console)/project-[region]-[project]/auth/(providers)/oidcPromptPicker.svelte new file mode 100644 index 0000000000..6cbc733fbc --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/auth/(providers)/oidcPromptPicker.svelte @@ -0,0 +1,42 @@ + + + + Prompt + + {#each options as option (option.val)} + toggle(option.val)}> + {option.label} + + {/each} + + diff --git a/src/routes/(console)/project-[region]-[project]/auth/+layout.svelte b/src/routes/(console)/project-[region]-[project]/auth/+layout.svelte index 2c8c7a904d..ddfdd3d56a 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/+layout.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/+layout.svelte @@ -58,16 +58,6 @@ rank: 1, disabled: page.url.pathname.endsWith('teams') }, - { - label: 'Go to usage', - keys: ['g', 'u'], - callback: async () => { - await goto(withPath(authProjectRoute, '/usage')); - }, - group: 'navigation', - rank: 1, - disabled: page.url.pathname.endsWith('usage') - }, { label: 'Go to security', keys: ['g', 'e'], diff --git a/src/routes/(console)/project-[region]-[project]/auth/header.svelte b/src/routes/(console)/project-[region]-[project]/auth/header.svelte index bb425c2b54..4c2cddbb39 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/header.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/header.svelte @@ -34,12 +34,6 @@ event: 'templates', disabled: !$canWriteProjects }, - { - href: `${path}/usage`, - title: 'Usage', - hasChildren: true, - event: 'usage' - }, { href: `${path}/settings`, title: 'Settings', diff --git a/src/routes/(console)/project-[region]-[project]/auth/security/+page.svelte b/src/routes/(console)/project-[region]-[project]/auth/security/+page.svelte index 254fef0f74..47ea7b2505 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/security/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/security/+page.svelte @@ -7,17 +7,40 @@ import UpdateSessionLength from './updateSessionLength.svelte'; import UpdateSessionsLimit from './updateSessionsLimit.svelte'; import PasswordPolicies from './passwordPolicies.svelte'; + import PasswordStrengthPolicy from './passwordStrengthPolicy.svelte'; + import UpdateMfaFactors from './updateMfaFactors.svelte'; import SessionSecurity from './sessionSecurity.svelte'; + import UpdateSignupEmailSecurity from './updateSignupEmailSecurity.svelte'; + import { isCloud } from '$lib/system'; let { data }: PageProps = $props(); - - - - - + + + + + + {#if data.mfaFactorsPolicy} + + {/if} + {#if isCloud} + + {/if} + - + diff --git a/src/routes/(console)/project-[region]-[project]/auth/security/+page.ts b/src/routes/(console)/project-[region]-[project]/auth/security/+page.ts new file mode 100644 index 0000000000..9c0e81528b --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/auth/security/+page.ts @@ -0,0 +1,84 @@ +import { Dependencies } from '$lib/constants'; +import { sdk } from '$lib/stores/sdk'; +import { ProjectPolicyId, type Models } from '@appwrite.io/console'; +import type { PageLoad } from './$types'; + +type EnabledPolicy = { + $id: string; + enabled: boolean; +}; + +const ProjectEmailPolicyId = { + DenyAliasedEmail: 'deny-aliased-email', + DenyDisposableEmail: 'deny-disposable-email', + DenyFreeEmail: 'deny-free-email', + DenyCorporateEmail: 'deny-corporate-email' +} as const; + +type ProjectPolicy = Models.PolicyList['policies'][number] | EnabledPolicy; +type EmailPolicyId = (typeof ProjectEmailPolicyId)[keyof typeof ProjectEmailPolicyId]; + +const getDefaultEnabledPolicy = (policyId: EmailPolicyId): EnabledPolicy => ({ + $id: policyId, + enabled: false +}); + +const getDefaultPasswordStrengthPolicy = (): Models.PolicyPasswordStrength => ({ + $id: ProjectPolicyId.Passwordstrength, + min: 8, + uppercase: false, + lowercase: false, + number: false, + symbols: false +}); + +export const load: PageLoad = async ({ depends, params }) => { + depends(Dependencies.PROJECT); + + const { policies } = await sdk.forProject(params.region, params.project).project.listPolicies(); + const policiesById = Object.fromEntries( + (policies as ProjectPolicy[]).map((policy) => [policy.$id, policy]) + ) as Partial>; + + return { + mfaFactorsPolicy: policiesById[ProjectPolicyId.Mfafactors] as + | Models.PolicyMfaFactors + | undefined, + membershipPrivacyPolicy: policiesById[ + ProjectPolicyId.Membershipprivacy + ] as Models.PolicyMembershipPrivacy, + passwordDictionaryPolicy: policiesById[ + ProjectPolicyId.Passworddictionary + ] as Models.PolicyPasswordDictionary, + passwordHistoryPolicy: policiesById[ + ProjectPolicyId.Passwordhistory + ] as Models.PolicyPasswordHistory, + passwordStrengthPolicy: + (policiesById[ProjectPolicyId.Passwordstrength] as Models.PolicyPasswordStrength) ?? + getDefaultPasswordStrengthPolicy(), + passwordPersonalDataPolicy: policiesById[ + ProjectPolicyId.Passwordpersonaldata + ] as Models.PolicyPasswordPersonalData, + sessionAlertPolicy: policiesById[ProjectPolicyId.Sessionalert] as Models.PolicySessionAlert, + sessionDurationPolicy: policiesById[ + ProjectPolicyId.Sessionduration + ] as Models.PolicySessionDuration, + sessionInvalidationPolicy: policiesById[ + ProjectPolicyId.Sessioninvalidation + ] as Models.PolicySessionInvalidation, + sessionLimitPolicy: policiesById[ProjectPolicyId.Sessionlimit] as Models.PolicySessionLimit, + userLimitPolicy: policiesById[ProjectPolicyId.Userlimit] as Models.PolicyUserLimit, + denyAliasedEmailPolicy: + (policiesById[ProjectEmailPolicyId.DenyAliasedEmail] as EnabledPolicy) ?? + getDefaultEnabledPolicy(ProjectEmailPolicyId.DenyAliasedEmail), + denyDisposableEmailPolicy: + (policiesById[ProjectEmailPolicyId.DenyDisposableEmail] as EnabledPolicy) ?? + getDefaultEnabledPolicy(ProjectEmailPolicyId.DenyDisposableEmail), + denyFreeEmailPolicy: + (policiesById[ProjectEmailPolicyId.DenyFreeEmail] as EnabledPolicy) ?? + getDefaultEnabledPolicy(ProjectEmailPolicyId.DenyFreeEmail), + denyCorporateEmailPolicy: + (policiesById[ProjectEmailPolicyId.DenyCorporateEmail] as EnabledPolicy) ?? + getDefaultEnabledPolicy(ProjectEmailPolicyId.DenyCorporateEmail) + }; +}; diff --git a/src/routes/(console)/project-[region]-[project]/auth/security/passwordPolicies.svelte b/src/routes/(console)/project-[region]-[project]/auth/security/passwordPolicies.svelte index 6ddb4a4a47..b59d65469e 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/security/passwordPolicies.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/security/passwordPolicies.svelte @@ -8,82 +8,113 @@ import { sdk } from '$lib/stores/sdk'; import { Typography, Link, Layout } from '@appwrite.io/pink-svelte'; import type { Models } from '@appwrite.io/console'; - import { onMount } from 'svelte'; let { - project + project, + dictionaryPolicy, + historyPolicy, + personalDataPolicy }: { project: Models.Project; + dictionaryPolicy: Models.PolicyPasswordDictionary; + historyPolicy: Models.PolicyPasswordHistory; + personalDataPolicy: Models.PolicyPasswordPersonalData; } = $props(); - let lastValidLimit = $state(5); - let passwordHistory = $state(5); - let passwordDictionary = $state(false); - let passwordHistoryEnabled = $state(false); - let authPersonalDataCheck = $state(false); - - onMount(() => { - // update initial states here in onMount. - const historyValue = project.authPasswordHistory; - if (historyValue && historyValue > 0) { - passwordHistory = historyValue; - lastValidLimit = historyValue; - } + const getInitialHistoryLimit = () => (historyPolicy.total > 0 ? historyPolicy.total : 5); + const getInitialHistoryEnabled = () => historyPolicy.total > 0; + const getInitialDictionary = () => dictionaryPolicy.enabled; + const getInitialPersonalDataCheck = () => personalDataPolicy.enabled; - passwordHistoryEnabled = (historyValue ?? 0) !== 0; - passwordDictionary = project.authPasswordDictionary ?? false; - authPersonalDataCheck = project.authPersonalDataCheck ?? false; - }); + let savedHistoryLimit = $state(getInitialHistoryLimit()); + let savedHistoryEnabled = $state(getInitialHistoryEnabled()); + let savedDictionary = $state(getInitialDictionary()); + let savedPersonalDataCheck = $state(getInitialPersonalDataCheck()); + + let lastValidHistoryLimit = $state(getInitialHistoryLimit()); + let passwordHistoryLimit = $state(getInitialHistoryLimit()); + let passwordDictionary = $state(getInitialDictionary()); + let passwordHistoryEnabled = $state(getInitialHistoryEnabled()); + let authPersonalDataCheck = $state(getInitialPersonalDataCheck()); $effect(() => { // restore last valid limit when enabling - if (passwordHistoryEnabled && passwordHistory < 1) { - passwordHistory = lastValidLimit; + if (passwordHistoryEnabled && passwordHistoryLimit < 1) { + passwordHistoryLimit = lastValidHistoryLimit; + } + + if (passwordHistoryLimit > 0) { + lastValidHistoryLimit = passwordHistoryLimit; } }); const hasChanges = $derived.by(() => { - const dictChanged = passwordDictionary !== (project.authPasswordDictionary ?? false); - const dataCheckChanged = authPersonalDataCheck !== (project.authPersonalDataCheck ?? false); - const historyChanged = - passwordHistoryEnabled !== ((project.authPasswordHistory ?? 0) !== 0); + const dictChanged = passwordDictionary !== savedDictionary; + const dataCheckChanged = authPersonalDataCheck !== savedPersonalDataCheck; + const historyChanged = passwordHistoryEnabled !== savedHistoryEnabled; const limitChanged = - passwordHistoryEnabled && - Number(passwordHistory) !== (project.authPasswordHistory ?? 0); + passwordHistoryEnabled && Number(passwordHistoryLimit) !== savedHistoryLimit; return historyChanged || dictChanged || dataCheckChanged || limitChanged; }); async function updatePasswordPolicies() { + let currentSubmit = Submit.AuthPasswordHistoryUpdate; + let hasAppliedServerChange = false; + try { const projectSdk = sdk.forProject(project.region, project.$id).project; - await projectSdk.updatePasswordHistoryPolicy({ - total: passwordHistoryEnabled ? passwordHistory : 0 - }); - - await projectSdk.updatePasswordDictionaryPolicy({ - enabled: passwordDictionary - }); - - await projectSdk.updatePasswordPersonalDataPolicy({ - enabled: authPersonalDataCheck - }); + if ( + passwordHistoryEnabled !== savedHistoryEnabled || + (passwordHistoryEnabled && Number(passwordHistoryLimit) !== savedHistoryLimit) + ) { + currentSubmit = Submit.AuthPasswordHistoryUpdate; + await projectSdk.updatePasswordHistoryPolicy({ + total: passwordHistoryEnabled ? passwordHistoryLimit : null + }); + hasAppliedServerChange = true; + trackEvent(Submit.AuthPasswordHistoryUpdate); + } + + if (passwordDictionary !== savedDictionary) { + currentSubmit = Submit.AuthPasswordDictionaryUpdate; + await projectSdk.updatePasswordDictionaryPolicy({ + enabled: passwordDictionary + }); + hasAppliedServerChange = true; + trackEvent(Submit.AuthPasswordDictionaryUpdate); + } + + if (authPersonalDataCheck !== savedPersonalDataCheck) { + currentSubmit = Submit.AuthPersonalDataCheckUpdate; + await projectSdk.updatePasswordPersonalDataPolicy({ + enabled: authPersonalDataCheck + }); + hasAppliedServerChange = true; + trackEvent(Submit.AuthPersonalDataCheckUpdate); + } + + savedHistoryLimit = passwordHistoryLimit; + savedHistoryEnabled = passwordHistoryEnabled; + savedDictionary = passwordDictionary; + savedPersonalDataCheck = authPersonalDataCheck; await invalidate(Dependencies.PROJECT); addNotification({ type: 'success', message: 'Updated password policies.' }); - trackEvent(Submit.AuthPasswordHistoryUpdate); - trackEvent(Submit.AuthPasswordDictionaryUpdate); - trackEvent(Submit.AuthPersonalDataCheckUpdate); } catch (error) { + if (hasAppliedServerChange) { + await invalidate(Dependencies.PROJECT); + } + addNotification({ type: 'error', message: error.message }); - trackError(error, Submit.AuthPasswordHistoryUpdate); + trackError(error, currentSubmit); } } @@ -110,7 +141,7 @@ autofocus label="Limit" id="password-history" - bind:value={passwordHistory} + bind:value={passwordHistoryLimit} helper="Maximum 20 passwords." /> {/if} diff --git a/src/routes/(console)/project-[region]-[project]/auth/security/passwordStrengthPolicy.svelte b/src/routes/(console)/project-[region]-[project]/auth/security/passwordStrengthPolicy.svelte new file mode 100644 index 0000000000..caaf7085bb --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/auth/security/passwordStrengthPolicy.svelte @@ -0,0 +1,134 @@ + + + + + Password strength + Set the minimum requirements users must meet when creating or changing a password. + + + +
+ + + + + Passwords must be between 8 and 256 characters. + + + +
+ + + Character requirements + +
+ + + + +
+
+
+
+ + + + +
+ + + diff --git a/src/routes/(console)/project-[region]-[project]/auth/security/sessionSecurity.svelte b/src/routes/(console)/project-[region]-[project]/auth/security/sessionSecurity.svelte index f9924befb4..ef395b3ef6 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/security/sessionSecurity.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/security/sessionSecurity.svelte @@ -10,20 +10,27 @@ import type { Models } from '@appwrite.io/console'; import { onMount } from 'svelte'; - let { project }: { project: Models.Project } = $props(); + let { + project, + sessionAlertPolicy, + sessionInvalidationPolicy + }: { + project: Models.Project; + sessionAlertPolicy: Models.PolicySessionAlert; + sessionInvalidationPolicy: Models.PolicySessionInvalidation; + } = $props(); let authSessionAlerts = $state(false); let sessionInvalidation = $state(false); onMount(() => { - authSessionAlerts = project?.authSessionAlerts ?? false; - sessionInvalidation = project?.authInvalidateSessions ?? false; + authSessionAlerts = sessionAlertPolicy.enabled; + sessionInvalidation = sessionInvalidationPolicy.enabled; }); const hasChanges = $derived.by(() => { - const alertsChanged = authSessionAlerts !== (project?.authSessionAlerts ?? false); - const invalidationChanged = - sessionInvalidation !== (project?.authInvalidateSessions ?? false); + const alertsChanged = authSessionAlerts !== sessionAlertPolicy.enabled; + const invalidationChanged = sessionInvalidation !== sessionInvalidationPolicy.enabled; return alertsChanged || invalidationChanged; }); diff --git a/src/routes/(console)/project-[region]-[project]/auth/security/updateMembershipPrivacy.svelte b/src/routes/(console)/project-[region]-[project]/auth/security/updateMembershipPrivacy.svelte index 074a39c7de..dd16a25a4b 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/security/updateMembershipPrivacy.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/security/updateMembershipPrivacy.svelte @@ -10,23 +10,25 @@ import type { Models } from '@appwrite.io/console'; const { - project + project, + policy }: { project: Models.Project; + policy: Models.PolicyMembershipPrivacy; } = $props(); - let authMembershipsMfa = $state(project?.authMembershipsMfa ?? true); - let authMembershipsUserId = $state(project?.authMembershipsUserId ?? true); - let authMembershipsUserName = $state(project?.authMembershipsUserName ?? true); - let authMembershipsUserEmail = $state(project?.authMembershipsUserEmail ?? true); - let authMembershipsUserPhone = $state(project?.authMembershipsUserPhone ?? true); + let authMembershipsMfa = $state(policy.userMFA); + let authMembershipsUserId = $state(policy.userId); + let authMembershipsUserName = $state(policy.userName); + let authMembershipsUserEmail = $state(policy.userEmail); + let authMembershipsUserPhone = $state(policy.userPhone); const isSubmitDisabled = $derived( - authMembershipsUserId === (project?.authMembershipsUserId ?? true) && - authMembershipsUserName === (project?.authMembershipsUserName ?? true) && - authMembershipsUserEmail === (project?.authMembershipsUserEmail ?? true) && - authMembershipsUserPhone === (project?.authMembershipsUserPhone ?? true) && - authMembershipsMfa === (project?.authMembershipsMfa ?? true) + authMembershipsUserId === policy.userId && + authMembershipsUserName === policy.userName && + authMembershipsUserEmail === policy.userEmail && + authMembershipsUserPhone === policy.userPhone && + authMembershipsMfa === policy.userMFA ); async function updateMembershipsPrivacy() { diff --git a/src/routes/(console)/project-[region]-[project]/auth/security/updateMfaFactors.svelte b/src/routes/(console)/project-[region]-[project]/auth/security/updateMfaFactors.svelte new file mode 100644 index 0000000000..b435aad413 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/auth/security/updateMfaFactors.svelte @@ -0,0 +1,92 @@ + + +
+ + MFA factors + Choose which factors your users can use to complete a multi-factor authentication challenge. Recovery + codes always remain available as a fallback. + + + + + + + + + + +
diff --git a/src/routes/(console)/project-[region]-[project]/auth/security/updateMockNumbers.svelte b/src/routes/(console)/project-[region]-[project]/auth/security/updateMockNumbers.svelte index 3a7242cf4a..daebe7a8c0 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/security/updateMockNumbers.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/security/updateMockNumbers.svelte @@ -1,6 +1,6 @@ + +
+ + Email policies + Control which email addresses can be used for user creation and email updates. This does not affect + session creation (sign in) + + + + + Block email addresses of free email providers. For example: user@gmail.com + + + + + + + + + + Block emails with aliases, tags, subaddresses, or any other + provider-specific email variations. For example: user+folder1@gmail.com + + + + + + + + + Block temporary and disposable email providers. For example: alex9734@mailinator.com + + + + + + + + + Only allow corporate email addresses. Blocks free providers and + disposable emails. For example: user@gmail.com + + + + + + + + + + +
diff --git a/src/routes/(console)/project-[region]-[project]/auth/security/updateUsersLimit.svelte b/src/routes/(console)/project-[region]-[project]/auth/security/updateUsersLimit.svelte index 63a51144e3..ee522ea8b9 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/security/updateUsersLimit.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/security/updateUsersLimit.svelte @@ -11,28 +11,27 @@ import type { Models } from '@appwrite.io/console'; let { - project + project, + policy }: { project: Models.Project; + policy: Models.PolicyUserLimit; } = $props(); let maxUsersInputField: HTMLInputElement | null = $state(null); - let value = $state(project?.authLimit !== 0 ? 'limited' : 'unlimited'); - let newLimit = $state(project?.authLimit !== 0 ? project?.authLimit : 100); + let value = $state(policy.total !== 0 ? 'limited' : 'unlimited'); + let newLimit = $state(policy.total !== 0 ? policy.total : 100); const isLimited = $derived(value === 'limited'); const btnDisabled = $derived.by(() => { - return ( - (!isLimited && project?.authLimit === 0) || - (isLimited && project?.authLimit === newLimit) - ); + return (!isLimited && policy.total === 0) || (isLimited && policy.total === newLimit); }); async function updateLimit() { try { await sdk.forProject(project.region, project.$id).project.updateUserLimitPolicy({ - total: isLimited ? newLimit : 0 + total: isLimited ? newLimit : null }); await invalidate(Dependencies.PROJECT); addNotification({ diff --git a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte index 83b6c3e4ed..049601f524 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.svelte @@ -2,7 +2,7 @@ import { invalidate } from '$app/navigation'; import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; import { CardGrid } from '$lib/components'; - import { InputSwitch } from '$lib/elements/forms'; + import { InputSearch, InputSwitch } from '$lib/elements/forms'; import Button from '$lib/elements/forms/button.svelte'; import { Container } from '$lib/layout'; import { app } from '$lib/stores/app'; @@ -10,7 +10,7 @@ import { addNotification } from '$lib/stores/notifications'; import { oAuthProviders } from '$lib/stores/oauth-providers'; import { sdk } from '$lib/stores/sdk'; - import { AuthMethod as MethodId, type Models } from '@appwrite.io/console'; + import { ProjectAuthMethodId } from '@appwrite.io/console'; import { base } from '$app/paths'; import { Avatar, @@ -24,6 +24,7 @@ } from '@appwrite.io/pink-svelte'; import { Dependencies } from '$lib/constants'; import type { PageProps } from './$types'; + import type { AuthProvider } from '../updateOAuth'; import { SvelteSet } from 'svelte/reactivity'; import { get } from 'svelte/store'; @@ -34,11 +35,12 @@ const consoleParamsMap = $derived(data.consoleParamsMap); let showProvider = $state(false); - let selectedProvider: Models.AuthProvider | null = $state(null); + let selectedProvider: AuthProvider | null = $state(null); + let oauthProviderSearch = $state(''); let isUpdatingAllAuthMethods = $state(false); let showUpdateAuthMethodsDialog = $state(false); let updateAuthMethodsEnabledMode = $state(null); - let apiAuthMethodUpdates = new SvelteSet(); + let apiAuthMethodUpdates = new SvelteSet(); const isAnyAuthMethodUpdating = $derived(apiAuthMethodUpdates.size > 0); const isAnyUpdateInProgress = $derived(isUpdatingAllAuthMethods || isAnyAuthMethodUpdating); @@ -55,6 +57,27 @@ const shouldDisableEnableAllButton = $derived(isAnyUpdateInProgress || allAuthMethodsEnabled); const shouldDisableDisableAllButton = $derived(isAnyUpdateInProgress || allAuthMethodsDisabled); + const filteredOAuthProviders = $derived.by(() => { + const search = oauthProviderSearch.trim().toLowerCase(); + + return resolvedOAuthProviders + .filter((provider) => { + const oAuthProvider = oAuthProviders[provider.key]; + if (!oAuthProvider || oAuthProvider.internal) return false; + if (provider.key === 'mock' || provider.name === 'Mock') return false; + if (!search) return true; + + return ( + provider.name.toLowerCase().includes(search) || + provider.key.toLowerCase().includes(search) + ); + }) + .sort((a, b) => { + if (a.enabled !== b.enabled) return a.enabled ? -1 : 1; + + return a.name.localeCompare(b.name, undefined, { sensitivity: 'base' }); + }); + }); async function authUpdate(box: AuthMethod) { apiAuthMethodUpdates.add(box.method); @@ -204,13 +227,18 @@ - OAuth2 Providers -
    - {#each resolvedOAuthProviders - .filter((p) => p.key !== 'mock' && p.name !== 'Mock') - .sort( (a, b) => (a.enabled === b.enabled ? 0 : a.enabled ? -1 : 1) ) as provider} - {@const oAuthProvider = oAuthProviders[provider.key]} - {#if oAuthProvider && !oAuthProvider.internal} +
    + OAuth2 Providers + +
    + {#if filteredOAuthProviders.length} +
      + {#each filteredOAuthProviders as provider (provider.key)} + {@const oAuthProvider = oAuthProviders[provider.key]} { @@ -240,9 +268,13 @@ content={provider.enabled ? 'enabled' : 'disabled'} /> - {/if} - {/each} -
    + {/each} +
+ {:else} +
+ No OAuth2 providers match your search. +
+ {/if}
@@ -291,9 +323,37 @@ min-width: 0; } + .oauth-providers-header { + align-items: center; + display: flex; + gap: var(--space-4); + justify-content: space-between; + } + + .oauth-providers-search { + max-width: 20rem; + width: 100%; + } + + .oauth-providers-empty { + align-items: center; + display: flex; + justify-content: flex-start; + padding: var(--space-4) 0; + } + @media (max-width: 768px) { .auth-methods-grid { grid-template-columns: 1fr; } + + .oauth-providers-header { + align-items: stretch; + flex-direction: column; + } + + .oauth-providers-search { + width: 100%; + } } diff --git a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.ts b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.ts index 0aa058f7e7..5b95fd590a 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/settings/+page.ts +++ b/src/routes/(console)/project-[region]-[project]/auth/settings/+page.ts @@ -1,25 +1,9 @@ import { Dependencies } from '$lib/constants'; import { oAuthProviders } from '$lib/stores/oauth-providers'; import { sdk } from '$lib/stores/sdk'; -import type { Models, Models as ConsoleModels } from '@appwrite.io/console'; +import type { Models as ConsoleModels } from '@appwrite.io/console'; import type { PageLoad } from './$types'; - -/** Extract the appId equivalent from a typed OAuth2 provider model. */ -function extractAppId(p: Record): string { - return (p['clientId'] ?? - p['appId'] ?? - p['oauthClientId'] ?? - p['oauth2ClientId'] ?? - p['applicationId'] ?? - p['serviceId'] ?? - p['apiKey'] ?? - p['publicKey'] ?? - p['appKey'] ?? - p['keyString'] ?? - p['customerKey'] ?? - p['key'] ?? - '') as string; -} +import type { AuthProvider } from '../updateOAuth'; export const load: PageLoad = async ({ depends, params }) => { depends(Dependencies.PROJECT); @@ -34,19 +18,13 @@ export const load: PageLoad = async ({ depends, params }) => { consoleParamsMap.set(cp.$id, cp.parameters ?? []); } - const oauthProviders: Models.AuthProvider[] = providerList.providers + const oauthProviders: AuthProvider[] = providerList.providers .filter((p) => p.$id !== 'mock') - .map((p) => { - const raw = p as unknown as Record; - return { - ...raw, - key: p.$id, - name: oAuthProviders[p.$id]?.name ?? p.$id, - appId: extractAppId(raw), - secret: '', - enabled: p.enabled - }; - }); + .map((p) => ({ + ...p, + key: p.$id, + name: oAuthProviders[p.$id]?.name ?? p.$id + })); return { oauthProviders, consoleParamsMap }; }; diff --git a/src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/activity/+page.svelte b/src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/activity/+page.svelte deleted file mode 100644 index f805a79f04..0000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/activity/+page.svelte +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/activity/+page.ts b/src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/activity/+page.ts deleted file mode 100644 index 6e680410c0..0000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/activity/+page.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Query } from '@appwrite.io/console'; -import { sdk } from '$lib/stores/sdk'; -import { getLimit, getPage, pageToOffset } from '$lib/helpers/load'; -import { PAGE_LIMIT } from '$lib/constants'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ params, url, route }) => { - const page = getPage(url); - const limit = getLimit(url, route, PAGE_LIMIT); - const offset = pageToOffset(page, limit); - - return { - offset, - limit, - logs: await sdk.forProject(params.region, params.project).teams.listLogs({ - teamId: params.team, - queries: [Query.limit(limit), Query.offset(offset)] - }) - }; -}; diff --git a/src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/header.svelte b/src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/header.svelte index b6bab1f33a..b97c2b0f74 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/header.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/teams/team-[team]/header.svelte @@ -18,12 +18,6 @@ title: 'Members', event: 'members', hasChildren: true - }, - { - href: `${path}/activity`, - title: 'Activity', - event: 'activity', - hasChildren: true } ]; diff --git a/src/routes/(console)/project-[region]-[project]/auth/templates/+page.svelte b/src/routes/(console)/project-[region]-[project]/auth/templates/+page.svelte index 4d43e0ab4a..3069dc0be0 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/templates/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/templates/+page.svelte @@ -1,5 +1,9 @@
@@ -109,13 +141,15 @@ bind:value={$emailTemplate.replyToEmail} id="replyToEmail" label="Reply to email" - placeholder="noreply@appwrite.io" /> + placeholder="noreply@appwrite.io" + disabled={!isSmtpEnabled} /> + placeholder="Enter reply to name" + disabled={!isSmtpEnabled} /> {#if children}

@@ -155,6 +189,9 @@

+
diff --git a/src/routes/(console)/project-[region]-[project]/auth/templates/emailVerificationTemplate.svelte b/src/routes/(console)/project-[region]-[project]/auth/templates/emailVerificationTemplate.svelte index 8d88c7805c..4f2675d9f6 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/templates/emailVerificationTemplate.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/templates/emailVerificationTemplate.svelte @@ -7,14 +7,18 @@ import { addNotification } from '$lib/stores/notifications'; import { Submit, trackError, trackEvent } from '$lib/actions/analytics'; import { Layout, Card } from '@appwrite.io/pink-svelte'; - import { EmailTemplateLocale, EmailTemplateType, type Models } from '@appwrite.io/console'; + import { + ProjectEmailTemplateLocale, + ProjectEmailTemplateId, + type Models + } from '@appwrite.io/console'; export let loading = false; export let project: Models.Project; export let localeCodes: Models.LocaleCode[]; let isUpdating = false; - let locale = EmailTemplateLocale.En; + let locale = ProjectEmailTemplateLocale.En; async function onLocaleChange() { const timeout = setTimeout(() => { @@ -24,12 +28,15 @@ const template = await loadEmailTemplate( project.region, project.$id, - EmailTemplateType.Verification, + ProjectEmailTemplateId.Verification, locale ); emailTemplate.set(template); $baseEmailTemplate = { ...$emailTemplate }; - trackEvent(Submit.EmailChangeLocale, { locale, type: EmailTemplateType.Verification }); + trackEvent(Submit.EmailChangeLocale, { + locale, + type: ProjectEmailTemplateId.Verification + }); } catch (error) { trackError(error, Submit.EmailChangeLocale); addNotification({ diff --git a/src/routes/(console)/project-[region]-[project]/auth/templates/store.ts b/src/routes/(console)/project-[region]-[project]/auth/templates/store.ts index 52bdaa70d5..164bc0353a 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/templates/store.ts +++ b/src/routes/(console)/project-[region]-[project]/auth/templates/store.ts @@ -1,5 +1,9 @@ import { writable } from 'svelte/store'; -import { EmailTemplateType, type EmailTemplateLocale, type Models } from '@appwrite.io/console'; +import { + ProjectEmailTemplateId, + type ProjectEmailTemplateLocale, + type Models +} from '@appwrite.io/console'; // component imports import Email2FaTemplate from './email2FATemplate.svelte'; @@ -11,9 +15,9 @@ import EmailVerificationTemplate from './emailVerificationTemplate.svelte'; import EmailSessionAlertTemplate from './emailSessionAlertTemplate.svelte'; export type EmailTemplateForm = Models.EmailTemplate & { - type: EmailTemplateType | null; - templateId: EmailTemplateType | string | null; - locale: EmailTemplateLocale | string | null; + type: ProjectEmailTemplateId | null; + templateId: ProjectEmailTemplateId | string | null; + locale: ProjectEmailTemplateLocale | string | null; }; export const emailTemplate = writable({ @@ -42,44 +46,44 @@ export const baseEmailTemplate = writable({ export const templates = [ { - key: EmailTemplateType.Verification, + key: ProjectEmailTemplateId.Verification, title: 'Verification', description: 'Send a verification email to users that sign in with their email and password.', component: EmailVerificationTemplate }, { - key: EmailTemplateType.MagicSession, + key: ProjectEmailTemplateId.MagicSession, title: 'Magic URL', description: 'Send an email to users that sign in with a magic URL.', component: EmailMagicUrlTemplate }, { - key: EmailTemplateType.OtpSession, + key: ProjectEmailTemplateId.OtpSession, title: 'OTP session', description: 'Send an email to users that sign in with a email OTP.', component: EmailOtpSessionTemplate }, { - key: EmailTemplateType.Recovery, + key: ProjectEmailTemplateId.Recovery, title: 'Reset password', description: 'Send a recovery email to users that forget their password.', component: EmailRecoveryTemplate }, { - key: EmailTemplateType.Invitation, + key: ProjectEmailTemplateId.Invitation, title: 'Invite user', description: 'Send an invitation email to become a member of your project.', component: EmailInviteTemplate }, { - key: EmailTemplateType.MfaChallenge, + key: ProjectEmailTemplateId.MfaChallenge, title: '2FA verification', description: 'Send a two-factor authentication email to a user.', component: Email2FaTemplate }, { - key: EmailTemplateType.SessionAlert, + key: ProjectEmailTemplateId.SessionAlert, title: 'Session alert', description: 'Send an email to users when a new session is created.', component: EmailSessionAlertTemplate, diff --git a/src/routes/(console)/project-[region]-[project]/auth/updateOAuth.ts b/src/routes/(console)/project-[region]-[project]/auth/updateOAuth.ts index 3931406c3e..9c777c1dc7 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/updateOAuth.ts +++ b/src/routes/(console)/project-[region]-[project]/auth/updateOAuth.ts @@ -4,16 +4,30 @@ import { Dependencies } from '$lib/constants'; import { isValueOfStringEnum } from '$lib/helpers/types'; import { addNotification } from '$lib/stores/notifications'; import { sdk } from '$lib/stores/sdk'; -import { OAuthProvider, type Models } from '@appwrite.io/console'; +import { + OAuthProvider, + ProjectOAuth2GooglePrompt, + ProjectOAuth2OidcPrompt, + type Models as ConsoleModels +} from '@appwrite.io/console'; + +type ProjectOAuthProvider = ConsoleModels.OAuth2ProviderList['providers'][number]; + +export type AuthProvider = ProjectOAuthProvider & { + key: ProjectOAuthProvider['$id']; + name: string; +}; type Args = { region: string; projectId: string; - provider: Models.AuthProvider; + provider: AuthProvider; appId: string | null; - secret: string; + secret: string | null; details: Record; enabled: boolean; + promptValues?: ProjectOAuth2GooglePrompt[] | ProjectOAuth2OidcPrompt[]; + maxAge?: number; }; type Return = { @@ -21,7 +35,7 @@ type Return = { message?: string; }; -function parseSecret(secret: string) { +function parseSecret(secret: string | null) { if (!secret) return {}; try { @@ -38,7 +52,9 @@ async function updateProjectOAuth({ appId, secret, details, - enabled + enabled, + promptValues, + maxAge }: Args) { const projectSdk = sdk.forProject(region, projectId).project; const parsedSecret = parseSecret(secret); @@ -73,6 +89,12 @@ async function updateProjectOAuth({ p8File: getSecret('p8File'), enabled }); + case OAuthProvider.Appwrite: + return projectSdk.updateOAuth2Appwrite({ + clientId: getAppId(), + clientSecret: getSecret(), + enabled + }); case OAuthProvider.Auth0: return projectSdk.updateOAuth2Auth0({ clientId: getAppId(), @@ -177,6 +199,7 @@ async function updateProjectOAuth({ return projectSdk.updateOAuth2Google({ clientId: getAppId(), clientSecret: getSecret(), + prompt: (promptValues as ProjectOAuth2GooglePrompt[]) ?? [], enabled }); case OAuthProvider.Keycloak: @@ -220,6 +243,8 @@ async function updateProjectOAuth({ authorizationURL: getDetail('authorizationURL'), tokenURL: getDetail('tokenUrl'), userInfoURL: getDetail('userInfoUrl'), + prompt: (promptValues as ProjectOAuth2OidcPrompt[]) ?? [], + maxAge: maxAge ?? 0, enabled }); case OAuthProvider.Okta: @@ -338,14 +363,26 @@ export async function updateOAuth({ appId, secret, details, - enabled + enabled, + promptValues, + maxAge }: Args): Promise { try { if (!isValueOfStringEnum(OAuthProvider, provider.key)) { throw new Error(`Invalid OAuth2 provider: ${provider.key}`); } - await updateProjectOAuth({ region, projectId, provider, appId, secret, details, enabled }); + await updateProjectOAuth({ + region, + projectId, + provider, + appId, + secret, + details, + enabled, + promptValues, + maxAge + }); await invalidate(Dependencies.PROJECT); addNotification({ diff --git a/src/routes/(console)/project-[region]-[project]/auth/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[region]-[project]/auth/usage/[[period]]/+page.svelte deleted file mode 100644 index 9879c54e4d..0000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/usage/[[period]]/+page.svelte +++ /dev/null @@ -1,20 +0,0 @@ - - - - - diff --git a/src/routes/(console)/project-[region]-[project]/auth/usage/[[period]]/+page.ts b/src/routes/(console)/project-[region]-[project]/auth/usage/[[period]]/+page.ts deleted file mode 100644 index 7356f8c309..0000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/usage/[[period]]/+page.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { isValueOfStringEnum } from '$lib/helpers/types'; -import { sdk } from '$lib/stores/sdk'; -import { UsageRange } from '@appwrite.io/console'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ params }) => { - const period = isValueOfStringEnum(UsageRange, params.period) - ? params.period - : UsageRange.ThirtyDays; - - return { - ...(await sdk.forProject(params.region, params.project).users.getUsage({ range: period })) - }; -}; diff --git a/src/routes/(console)/project-[region]-[project]/auth/user-[user]/activity/+page.svelte b/src/routes/(console)/project-[region]-[project]/auth/user-[user]/activity/+page.svelte deleted file mode 100644 index 0aa88a0c18..0000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/user-[user]/activity/+page.svelte +++ /dev/null @@ -1,8 +0,0 @@ - - - diff --git a/src/routes/(console)/project-[region]-[project]/auth/user-[user]/activity/+page.ts b/src/routes/(console)/project-[region]-[project]/auth/user-[user]/activity/+page.ts deleted file mode 100644 index 9106c57d20..0000000000 --- a/src/routes/(console)/project-[region]-[project]/auth/user-[user]/activity/+page.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { Query } from '@appwrite.io/console'; -import { sdk } from '$lib/stores/sdk'; -import { getLimit, getPage, pageToOffset } from '$lib/helpers/load'; -import { PAGE_LIMIT } from '$lib/constants'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ params, url, route }) => { - const page = getPage(url); - const limit = getLimit(url, route, PAGE_LIMIT); - const offset = pageToOffset(page, limit); - return { - offset, - limit, - logs: await sdk.forProject(params.region, params.project).users.listLogs({ - userId: params.user, - queries: [Query.limit(limit), Query.offset(offset)] - }) - }; -}; diff --git a/src/routes/(console)/project-[region]-[project]/auth/user-[user]/header.svelte b/src/routes/(console)/project-[region]-[project]/auth/user-[user]/header.svelte index f11425ba94..b944378aac 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/user-[user]/header.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/user-[user]/header.svelte @@ -32,12 +32,6 @@ href: `${path}/sessions`, title: 'Sessions', event: 'sessions' - }, - { - href: `${path}/activity`, - title: 'Activity', - event: 'activity', - hasChildren: true } ]; diff --git a/src/routes/(console)/project-[region]-[project]/auth/user-[user]/updateStatus.svelte b/src/routes/(console)/project-[region]-[project]/auth/user-[user]/updateStatus.svelte index ffbd35e642..59a425cd94 100644 --- a/src/routes/(console)/project-[region]-[project]/auth/user-[user]/updateStatus.svelte +++ b/src/routes/(console)/project-[region]-[project]/auth/user-[user]/updateStatus.svelte @@ -52,7 +52,7 @@ await invalidate(Dependencies.USER); addNotification({ message: `${$user.name || $user.email || $user.phone || 'The account'} has been ${ - $user.phoneVerification ? 'unverified' : 'verified' + !$user.phoneVerification ? 'unverified' : 'verified' }`, type: 'success' }); diff --git a/src/routes/(console)/project-[region]-[project]/createVariableModal.svelte b/src/routes/(console)/project-[region]-[project]/createVariableModal.svelte index 13f9544d22..4136fcb186 100644 --- a/src/routes/(console)/project-[region]-[project]/createVariableModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/createVariableModal.svelte @@ -9,12 +9,14 @@ import { Alert, Layout, Selector, Button as PinkButton, Icon } from '@appwrite.io/pink-svelte'; import { Link } from '$lib/elements'; import { IconPlus, IconX } from '@appwrite.io/pink-icons-svelte'; + import { validateVariables } from '$lib/helpers/variables'; export let isGlobal: boolean; export let product: 'function' | 'site' = 'function'; export let showCreate = false; let newVariables: Partial[] = [{ key: '', value: '' }]; let secret = false; + let error = ''; const dispatch = createEventDispatcher(); @@ -26,12 +28,16 @@ if (secret) { newVariables = newVariables.map((variable) => ({ ...variable, secret: true })); } - newVariables.forEach((variable) => { - if (('' + variable.value).length > 8192) { - throw new Error(`Variable ${variable.key} is longer than 8192 allowed characters`); - } - }); - dispatch('created', newVariables); + + const filled = newVariables.filter((variable) => variable.key || variable.value); + + const validationError = validateVariables(filled); + if (validationError) { + error = validationError; + return; + } + + dispatch('created', filled); close(); } @@ -48,6 +54,7 @@ @@ -81,6 +88,7 @@ label={`${i === 0 ? 'Value' : ''}`} placeholder="Enter value" bind:value={pair.value} + autocomplete="new-password" minlength={0} /> - import { goto } from '$app/navigation'; import { page } from '$app/state'; import { DatabasesPanel } from '$lib/commandCenter/panels'; - import { resolveRoute, withPath } from '$lib/stores/navigation'; import { addSubPanel, registerCommands, updateCommandGroupRanks } from '$lib/commandCenter'; let { children } = $props(); - const databasesProjectRoute = $derived.by(() => { - return resolveRoute('/(console)/project-[region]-[project]/databases', page.params); - }); - $effect(() => { $registerCommands([ - { - label: 'Go to usage', - callback: () => { - goto(withPath(databasesProjectRoute, 'usage')); - }, - keys: ['g', 'u'], - disabled: - page.url.pathname.includes('usage') || page.url.pathname.includes('database-'), - group: 'databases' - }, { label: 'Find databases', callback: () => { diff --git a/src/routes/(console)/project-[region]-[project]/databases/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/+page.ts index 642f277e3d..e219c48f93 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/+page.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/+page.ts @@ -6,7 +6,7 @@ import { timeFromNow } from '$lib/helpers/date'; import type { PageLoad, RouteParams } from './$types'; import { isSelfHosted } from '$lib/system'; import { isCloud } from '$lib/system'; -import { useDatabaseSdk } from '$database/(entity)'; +import { toDatabaseType, useDatabaseSdk } from '$database/(entity)'; export const load: PageLoad = async ({ url, route, depends, params, parent }) => { depends(Dependencies.DATABASES); @@ -62,7 +62,7 @@ async function fetchDatabasesAndBackups( databases.databases.map(async ({ $id, type }) => { const res = await databaseSdk.listEntities({ databaseId: $id, - databaseType: type, + databaseType: toDatabaseType(type), queries: [Query.limit(1), Query.orderDesc('')] }); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/terminology.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/terminology.ts index 02fb339a2a..d803b9e0b3 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/terminology.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/helpers/terminology.ts @@ -1,15 +1,27 @@ import type { Page } from '@sveltejs/kit'; import { capitalize, plural } from '$lib/helpers/string'; -import { AppwriteException, type TablesDBIndexType, type Models } from '@appwrite.io/console'; +import { + AppwriteException, + type DatabaseType as SdkDatabaseType, + type TablesDBIndexType, + type Models +} from '@appwrite.io/console'; import type { Attributes, Collection, Columns, Table } from '$database/store'; import type { Term, TerminologyResult, TerminologyShape } from '$database/(entity)/helpers/types'; type BaseTerminology = typeof baseTerminology; type ImplementedDBTypes = Omit; -/* manual type for the time being because vectorsdb is pending */ -export type DatabaseType = 'legacy' | 'tablesdb' | 'documentsdb' | 'vectorsdb'; +/** + * The SDK also reports the raw dedicated backings (`mysql`, `postgresql`, `mongodb`), which the + * console has no UI for. Extracting from the SDK keeps the supported set from drifting silently: + * a renamed or dropped SDK value removes the member here and breaks every `case` that uses it. + */ +export type DatabaseType = Extract< + `${SdkDatabaseType}`, + 'legacy' | 'tablesdb' | 'documentsdb' | 'vectorsdb' +>; export type CollectionDatabaseType = Extract; export const DEFAULT_VECTOR_DIMENSION = 768; @@ -73,6 +85,22 @@ export const baseTerminology = { } } as const; +function isSupportedDatabaseType(type: string): type is DatabaseType { + return Object.hasOwn(baseTerminology, type); +} + +/** + * Narrows an API reported database type down to the ones this console implements. + * Throws on the rest, matching how every dispatcher in `sdk.ts` rejects an unknown type. + */ +export function toDatabaseType(type: Models.Database['type'] | DatabaseType): DatabaseType { + if (!isSupportedDatabaseType(type)) { + throw new AppwriteException(`Unsupported database type: ${type}`, 500); + } + + return type; +} + const createTerm = (singular: string, pluralForm: string): Term => { return { singular, plural: pluralForm }; }; @@ -152,15 +180,13 @@ export function toSupportiveRecord(raw: Record | Models.Document | Models.Row): * Use `getTerminologies()` instead when in `database-[database]` routes where context is available. */ export function useTerminology(pageOrType: Page | DatabaseType): TerminologyResult { - const type = - typeof pageOrType === 'object' - ? (pageOrType.data?.database?.type as DatabaseType) - : pageOrType; - if (!type) { + const rawType = typeof pageOrType === 'object' ? pageOrType.data?.database?.type : pageOrType; + if (!rawType) { // strict check because this should always be available! throw new AppwriteException('Database type is required', 500); } + const type = toDatabaseType(rawType); const dbTerminologies = terminologyData[type] || {}; const strictSchema = type === 'legacy' || type === 'tablesdb'; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/index.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/index.ts index 8437673d36..e2964fbdd6 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/index.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/index.ts @@ -7,6 +7,5 @@ export * from './views/settings'; export { default as Header } from './views/header.svelte'; export { default as Breadcrumbs } from './views/breadcrumbs.svelte'; -export { default as Usage } from './views/usage/view.svelte'; export { default as CreateEntity } from './views/create.svelte'; export { default as FailedModal } from './views/failedModal.svelte'; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/activity.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/activity.svelte deleted file mode 100644 index 041709ba44..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/activity.svelte +++ /dev/null @@ -1,74 +0,0 @@ - - -{#if loading} -
- - -
-{:else if recordActivityLogs} -
- -
-{/if} - - diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/index.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/index.ts index 640842e601..5ad0a27296 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/index.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/field/index.ts @@ -1,3 +1,2 @@ -export { default as RecordActivity } from './activity.svelte'; export { default as CsvDisabled } from './csvDisabled.svelte'; export { default as EditRecordPermissions } from './editPermissions.svelte'; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/indexes/create.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/indexes/create.svelte index ae49e46d5d..c3d236045d 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/indexes/create.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/indexes/create.svelte @@ -57,7 +57,12 @@ .map((field) => ({ value: field.key, label: field.key, - leadingIcon: baseColumnOptions.find((option) => option.type === field.type)?.icon + leadingIcon: baseColumnOptions.find( + (option) => + option.type === field.type && + option.format === + ('format' in field && field.format ? field.format : undefined) + )?.icon })) ); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/sheetOptions.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/sheetOptions.svelte index 35a9268880..f6326b4208 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/sheetOptions.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/layouts/sheetOptions.svelte @@ -13,7 +13,6 @@ | 'update' | 'duplicate-row' | 'permissions' - | 'activity' | 'copy-url' | 'copy-json' // | 'copy-snippet' @@ -26,7 +25,6 @@ import { IconArrowLeft, IconArrowRight, - IconChartBar, IconClipboardCopy, IconDuplicate, IconKey, @@ -68,7 +66,6 @@ { label: 'Duplicate', icon: IconDuplicate, action: 'duplicate-row' }, { divider: true }, { label: 'Manage permissions', icon: IconKey, action: 'permissions' }, - { label: 'View activity', icon: IconChartBar, action: 'activity' }, { divider: true }, { label: 'Copy URL', icon: IconLink, action: 'copy-url' }, { label: 'Copy as JSON', icon: IconClipboardCopy, action: 'copy-json' }, diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/usage/view.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/usage/view.svelte deleted file mode 100644 index c47c8da008..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/(entity)/views/usage/view.svelte +++ /dev/null @@ -1,47 +0,0 @@ - - -
- - - -
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.svelte index 5109887944..05312ab837 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+layout.svelte @@ -147,18 +147,6 @@ keys: ['g', 'c'], group: 'databases' }, - { - label: 'Go to usage', - callback() { - goto( - `${base}/project-${page.params.region}-${project}/databases/database-${databaseId}/usage` - ); - }, - disabled: - page.url.pathname.includes('/usage') || page.url.pathname.includes('table-'), - keys: ['g', 'u'], - group: 'databases' - }, { label: 'Go to backups', callback() { diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte index 60e1c90a8a..a27474f205 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/+page.svelte @@ -109,7 +109,8 @@ href="https://appwrite.io/docs/products/databases/databases" text event="empty_documentation" - ariaLabel="create {entityLower.singular}">Documentation + ariaLabel="read {entityLower.singular} documentation" + >Documentation {#if $canWriteTables} to add customized backup policies. + external + href="https://appwrite.io/contact-us/enterprise" + >Upgrade to Enterprise to add customized backup policies. {:else} @@ -268,11 +264,10 @@ Daily backups are retained for 7 days. - { - isShowing = false; - goto(getChangePlanUrl(project.teamId)); - }}>Upgrade your plan + Upgrade to Enterprise to add customized backup policies. diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/embeddingModal.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/embeddingModal.svelte index 51d427291b..5269113176 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/embeddingModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/embeddingModal.svelte @@ -27,7 +27,7 @@ try { const response = await sdk .forProject(page.params.region, page.params.project) - .vectorsDB.createTextEmbeddings({ texts: [content.trim()] }); + .embeddings.createTextEmbeddings({ texts: [content.trim()] }); const embedding = response?.embeddings?.[0]?.embedding; if (embedding?.length) { diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/view.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/view.svelte index 6c3432a643..bf53caa0b9 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/view.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/(components)/editor/view.svelte @@ -20,6 +20,8 @@ lineNumbers, highlightActiveLine, highlightActiveLineGutter, + type Command, + type KeyBinding, type ViewUpdate } from '@codemirror/view'; import { history, undo } from '@codemirror/commands'; @@ -147,6 +149,8 @@ const wrapCompartment = new Compartment(); const readOnlyCompartment = new Compartment(); + const unfoldAllCommand: Command = (view) => unfoldAll(view as never); + const foldAllCommand: Command = (view) => foldAll(view as never); let tooltipMessage = $state('Copy document'); @@ -942,7 +946,7 @@ // JSON5 linter using the parse cache; preserves errorInPlace behavior. async function json5Linter(view: EditorView): Promise { if (isUpdatingFromEditor) return []; - const result = await baseJson5Linter(view); + const result = await baseJson5Linter(view as never); if (!result.length) { errorMessage = null; return []; @@ -1198,17 +1202,17 @@ { key: 'Mod-=', preventDefault: true, - run: unfoldAll + run: unfoldAllCommand }, { key: 'Mod-+', preventDefault: true, - run: unfoldAll + run: unfoldAllCommand }, { key: 'Mod--', preventDefault: true, - run: foldAll + run: foldAllCommand }, { key: 'Mod-a', @@ -1244,7 +1248,7 @@ } } ]), - keymap.of(secondaryKeymaps), + keymap.of(secondaryKeymaps as readonly KeyBinding[]), json5(), customSyntaxHighlighting, customTheme, diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+layout.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+layout.svelte index abae1c2562..6db36f36d6 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+layout.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+layout.svelte @@ -42,7 +42,6 @@ import { sleep } from '$lib/helpers/promises'; import { hash } from '$lib/helpers/string'; import { - documentActivitySheet, documentPermissionSheet, noSqlDocument, showCreateIndexSheet @@ -50,7 +49,7 @@ import { SideSheet, EditRecordPermissions, - RecordActivity, + toDatabaseType, useDatabaseSdk, DEFAULT_VECTOR_DIMENSION, type Field, @@ -79,6 +78,7 @@ let editRecordPermissions: EditRecordPermissions; $: collection = data.collection; + $: databaseType = toDatabaseType(data.database.type); $: basePath = resolveRoute( '/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]', page.params @@ -139,24 +139,6 @@ disabled: page.url.pathname.endsWith('indexes'), group: 'collections' }, - { - label: 'Go to activity', - keys: ['g', 'c'], - callback() { - goto(withPath(basePath, '/activity')); - }, - disabled: page.url.pathname.endsWith('activity'), - group: 'collections' - }, - { - label: 'Go to usage', - keys: ['g', 'u'], - callback() { - goto(withPath(basePath, '/usage')); - }, - disabled: page.url.pathname.endsWith('usage'), - group: 'collections' - }, { label: 'Go to settings', keys: ['g', 's'], @@ -209,11 +191,7 @@ }); async function handleCreateIndex(index: Index) { - const databaseSdk = useDatabaseSdk( - page.params.region, - page.params.project, - data.database.type - ); + const databaseSdk = useDatabaseSdk(page.params.region, page.params.project, databaseType); await databaseSdk.createIndex({ databaseId: page.params.database, @@ -279,8 +257,7 @@ const { rows, ids } = generateFakeRecords($randomDataModalState.value, fields); documentIds = ids; - const dbType = data.database?.type; - const isVectorsDb = dbType === 'vectorsdb'; + const isVectorsDb = databaseType === 'vectorsdb'; const dimension = collection?.dimension ?? DEFAULT_VECTOR_DIMENSION; // For vectorsdb, wrap fields in metadata and add empty embeddings @@ -352,10 +329,6 @@ bind:record={$documentPermissionSheet.document} /> - - - - { const { database } = await parent(); depends(Dependencies.COLLECTION); - const databaseSdk = useDatabaseSdk(params.region, params.project, database.type); + const databaseSdk = useDatabaseSdk( + params.region, + params.project, + toDatabaseType(database.type) + ); const collection = await databaseSdk.getEntity({ databaseId: params.database, diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte index 017e1a03a0..ec2e127667 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/+page.svelte @@ -38,7 +38,7 @@ import { invalidate } from '$app/navigation'; import { hash } from '$lib/helpers/string'; import { Dependencies } from '$lib/constants'; - import { EmptySheet, EmptySheetCards } from '$database/(entity)'; + import { EmptySheet, EmptySheetCards, toDatabaseType } from '$database/(entity)'; import { isCollectionsJsonImportInProgress, noSqlDocument, @@ -55,6 +55,8 @@ const filterColumns = writable([]); + const databaseType = $derived(toDatabaseType(data.database.type)); + let isRefreshing = $state(false); let showImportJson = $state(false); let showImportOptions = $state(false); @@ -105,7 +107,8 @@ .migrations.createJSONImport({ bucketId: pendingFile.bucketId, fileId: pendingFile.$id, - resourceId: `${page.params.database}:${page.params.collection}`, + databaseId: page.params.database, + collectionId: page.params.collection, internalFile: pendingLocalFile, onDuplicate: importOnDuplicate }); @@ -328,7 +331,7 @@ {/snippet} {:else} - + {#snippet actions()} { const { collection, database } = await parent(); @@ -20,7 +20,26 @@ export const load: PageLoad = async ({ params, depends, url, route, parent }) => queries.set(parsedQueries); const currentSort = extractSortFromQueries(parsedQueries); - const collectionSdk = getCollectionService(params.region, params.project, database.type); + const collectionSdk = getCollectionService( + params.region, + params.project, + toDatabaseType(database.type) + ); + + const documentsPage = await loadGridRows( + collection, + (includeRelationships) => + buildGridQueries(limit, offset, parsedQueries, collection, includeRelationships), + async (queries) => { + const response = await collectionSdk.listDocuments({ + databaseId: params.database, + collectionId: params.collection, + queries + }); + + return { total: response.total, rows: response.documents }; + } + ); return { offset, @@ -29,10 +48,6 @@ export const load: PageLoad = async ({ params, depends, url, route, parent }) => query, currentSort, parsedQueries, - documents: await collectionSdk.listDocuments({ - databaseId: params.database, - collectionId: params.collection, - queries: buildGridQueries(limit, offset, parsedQueries, collection) - }) + documents: { total: documentsPage.total, documents: documentsPage.rows } }; }; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/activity/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/activity/+page.svelte deleted file mode 100644 index 849d38953b..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/activity/+page.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - -
- -
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/activity/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/activity/+page.ts deleted file mode 100644 index 5a3883762a..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/activity/+page.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { sdk } from '$lib/stores/sdk'; -import type { PageLoad } from './$types'; -import { PAGE_LIMIT } from '$lib/constants'; -import { Query } from '@appwrite.io/console'; -import { getLimit, getPage, pageToOffset } from '$lib/helpers/load'; - -export const load: PageLoad = async ({ params, url, route }) => { - const page = getPage(url); - const limit = getLimit(url, route, PAGE_LIMIT); - const offset = pageToOffset(page, limit); - - return { - offset, - limit, - logs: await sdk.forProject(params.region, params.project).tablesDB.listTableLogs({ - databaseId: params.database, - tableId: params.collection, - queries: [Query.limit(limit), Query.offset(offset)] - }) - }; -}; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/export/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/export/+page.svelte index a4a2b7e9aa..9d19f13b9c 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/export/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/export/+page.svelte @@ -56,7 +56,8 @@ await sdk .forProject(page.params.region, page.params.project) .migrations.createJSONExport({ - resourceId: `${page.params.database}:${page.params.collection}`, + databaseId: page.params.database, + collectionId: page.params.collection, filename: filename, columns: [], queries: exportWithFilters ? Array.from(localQueries.values()) : [], diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/header.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/header.svelte index bfeef04331..d696482302 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/header.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/header.svelte @@ -27,18 +27,6 @@ title: 'Indexes', event: 'indexes' }, - { - href: `${path}/activity`, - title: 'Activity', - event: 'activity', - hasChildren: true - }, - { - href: `${path}/usage`, - title: 'Usage', - event: 'usage', - hasChildren: true - }, { href: `${path}/settings`, title: 'Settings', diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/indexes/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/indexes/+page.svelte index ce5f1aaad6..e8f79981f0 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/indexes/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/indexes/+page.svelte @@ -6,6 +6,7 @@ Indexes, EmptySheet, EmptySheetCards, + toDatabaseType, useDatabaseSdk } from '$database/(entity)'; import { IconPlus } from '@appwrite.io/pink-icons-svelte'; @@ -15,7 +16,8 @@ let createIndexRef: CreateIndexForm; - const databaseSdk = useDatabaseSdk(page.params.region, page.params.project, data.database.type); + const databaseType = $derived(toDatabaseType(data.database.type)); + const databaseSdk = useDatabaseSdk(page.params.region, page.params.project, databaseType); async function onCreateIndex(index: CreateIndexesCallbackType) { await databaseSdk.createIndex({ @@ -46,14 +48,14 @@ {#snippet createIndexForm()} {/snippet} {#snippet emptyIndexesSheetView(toggle)} - + {#snippet actions()} void } | undefined; @@ -431,11 +431,6 @@ selectedDocumentForDelete = document.$id; showDelete = true; } - - if (action === 'activity') { - $documentActivitySheet.show = true; - $documentActivitySheet.document = document; - } } // possibly for auto-save! diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/store.ts index be4fcf1fb9..0f48e9490d 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/store.ts @@ -95,11 +95,6 @@ export const documentPermissionSheet = writable({ document: null as Models.Document }); -export const documentActivitySheet = writable({ - show: false, - document: null as Models.Document -}); - export const showCreateIndexSheet = writable<{ show: boolean; column?: string; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/usage/[[period]]/+page.svelte deleted file mode 100644 index 472f1e4f77..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/usage/[[period]]/+page.svelte +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/usage/[[period]]/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/usage/[[period]]/+page.ts deleted file mode 100644 index 5345ceb82b..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/collection-[collection]/usage/[[period]]/+page.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { isValueOfStringEnum } from '$lib/helpers/types'; -import { sdk } from '$lib/stores/sdk'; -import { UsageRange } from '@appwrite.io/console'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ params }) => { - const period = isValueOfStringEnum(UsageRange, params.period) - ? params.period - : UsageRange.ThirtyDays; - - return { - ...(await sdk.forProject(params.region, params.project).documentsDB.getCollectionUsage({ - databaseId: params.database, - collectionId: params.collection, - range: period - })) - }; -}; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte index 1d3ded6c0d..7bd3d0756a 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/header.svelte @@ -34,12 +34,6 @@ event: 'backups', hasChildren: true }, - { - href: withPath(baseDatabasePath, '/usage'), - title: 'Usage', - event: 'usage', - hasChildren: true - }, { href: withPath(baseDatabasePath, '/settings'), event: 'settings', diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/store.ts index a34a5d001d..c8c6ba7e33 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/store.ts @@ -1,9 +1,10 @@ import { writable } from 'svelte/store'; import type { Column } from '$lib/helpers/types'; -import { IconChartBar, IconCloudUpload, IconCog } from '@appwrite.io/pink-icons-svelte'; +import { IconCloudUpload, IconCog } from '@appwrite.io/pink-icons-svelte'; import { resolveRoute, withPath } from '$lib/stores/navigation'; import type { Page } from '@sveltejs/kit'; -import { type Models, Query } from '@appwrite.io/console'; +import { AppwriteException, type Models, Query } from '@appwrite.io/console'; +import { chunks } from '$lib/helpers/array'; import type { Entity, Field } from '$database/(entity)'; import { isRelationship } from '$database/table-[table]/rows/store'; import type { TagValue } from '$lib/components/filters/store'; @@ -104,7 +105,6 @@ export const customRetainingOptions = [ export const databaseSubNavigationItems = [ { title: 'Backups', href: 'backups', icon: IconCloudUpload }, - { title: 'Usage', href: 'usage', icon: IconChartBar }, { title: 'Settings', href: 'settings', icon: IconCog } ]; @@ -179,7 +179,8 @@ export function buildGridQueries( limit: number, offset: number, parsedQueries: Map, - table: Entity + table: Entity, + includeRelationships: boolean = true ) { const hasOrderQuery = Array.from(parsedQueries.values()).some( (q) => q.includes('orderAsc') || q.includes('orderDesc') @@ -192,7 +193,75 @@ export function buildGridQueries( queryArray.push(Query.orderDesc('')); } - queryArray.push(...parsedQueries.values(), ...buildWildcardEntitiesQuery(table)); + queryArray.push( + ...parsedQueries.values(), + ...(includeRelationships ? buildWildcardEntitiesQuery(table) : [Query.select(['*'])]) + ); return queryArray; } + +const RELATIONSHIP_CHUNK_SIZE = 10; + +function isTooManyQueryValues(error: unknown): boolean { + return ( + error instanceof AppwriteException && /greater than \d+ values/i.test(error.message ?? '') + ); +} + +type EntityRows = { total: number; rows: T[] }; + +/** + * Loads a page of the grid, falling back to smaller relationship batches when + * the API trips its own 500 value limit resolving them for the whole page. + */ +export async function loadGridRows( + entity: Entity, + buildQueries: (includeRelationships: boolean) => string[], + fetchRows: (queries: string[]) => Promise> +): Promise> { + try { + return await fetchRows(buildQueries(true)); + } catch (error) { + if (!isTooManyQueryValues(error)) throw error; + + const page = await fetchRows(buildQueries(false)); + + return { + total: page.total, + rows: await populateRelationships(entity, page.rows, fetchRows) + }; + } +} + +async function populateRelationships( + entity: Entity, + rows: T[], + fetchRows: (queries: string[]) => Promise> +): Promise { + const relationshipQueries = buildWildcardEntitiesQuery(entity); + + if (relationshipQueries.length <= 1 || rows.length === 0) return rows; + + const populated = new Map(); + + await Promise.all( + chunks(rows, RELATIONSHIP_CHUNK_SIZE).map(async (chunk) => { + const rowIds = chunk.map((row) => row.$id); + + try { + const response = await fetchRows([ + Query.equal('$id', rowIds), + Query.limit(rowIds.length), + ...relationshipQueries + ]); + + response.rows.forEach((row) => populated.set(row.$id, row)); + } catch { + // keep the unpopulated rows for this chunk! + } + }) + ); + + return rows.map((row) => populated.get(row.$id) ?? row); +} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte index 8c80436072..57e32165ba 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.svelte @@ -29,7 +29,6 @@ databaseRowSheetOptions, showCreateColumnSheet, showCreateIndexSheet, - rowActivitySheet, databaseRelatedRowSheetOptions, rowPermissionSheet, showRowCreateSheet @@ -50,7 +49,6 @@ import { CreateIndex, EditRecordPermissions, - RecordActivity, SideSheet, type Field, useTerminology @@ -206,24 +204,6 @@ disabled: page.url.pathname.endsWith('indexes'), group: 'tables' }, - { - label: 'Go to activity', - keys: ['g', 'c'], - callback() { - goto(withPath(basePath, '/activity')); - }, - disabled: page.url.pathname.endsWith('activity'), - group: 'tables' - }, - { - label: 'Go to usage', - keys: ['g', 'u'], - callback() { - goto(withPath(basePath, '/usage')); - }, - disabled: page.url.pathname.endsWith('usage'), - group: 'tables' - }, { label: 'Go to settings', keys: ['g', 's'], @@ -593,10 +573,6 @@ bind:arePermsDisabled={editRowPermissionsDisabled} />
- - - - diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.ts index cd5d75e6db..021c3c00a5 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+layout.ts @@ -1,7 +1,7 @@ import Header from './header.svelte'; import type { LayoutLoad } from './$types'; import { Dependencies } from '$lib/constants'; -import { Breadcrumbs, useDatabaseSdk } from '$database/(entity)'; +import { Breadcrumbs, toDatabaseType, useDatabaseSdk } from '$database/(entity)'; import { guardResourceBlock } from '$lib/helpers/project'; export const load: LayoutLoad = async ({ params, depends, parent }) => { @@ -9,7 +9,11 @@ export const load: LayoutLoad = async ({ params, depends, parent }) => { depends(Dependencies.TABLE); guardResourceBlock(project, ['tables', 'collections'], params.table); - const databaseSdk = useDatabaseSdk(params.region, params.project, database.type); + const databaseSdk = useDatabaseSdk( + params.region, + params.project, + toDatabaseType(database.type) + ); const table = await databaseSdk.getEntity({ databaseId: params.database, diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte index f1fe008679..89444b447a 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.svelte @@ -139,7 +139,8 @@ .migrations.createCSVImport({ bucketId: pendingFile.bucketId, fileId: pendingFile.$id, - resourceId: `${page.params.database}:${page.params.table}`, + databaseId: page.params.database, + collectionId: page.params.table, internalFile: pendingLocalFile, onDuplicate: importOnDuplicate }); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.ts index 7ccffdf996..a584f612b3 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/+page.ts @@ -3,7 +3,7 @@ import { getLimit, getPage, getQuery, getView, pageToOffset, View } from '$lib/h import { sdk } from '$lib/stores/sdk'; import type { PageLoad } from './$types'; import { queries, queryParamToMap } from '$lib/components/filters'; -import { buildGridQueries, extractSortFromQueries } from '$database/store'; +import { buildGridQueries, extractSortFromQueries, loadGridRows } from '$database/store'; export const load: PageLoad = async ({ params, depends, url, route, parent }) => { const { table } = await parent(); @@ -28,10 +28,16 @@ export const load: PageLoad = async ({ params, depends, url, route, parent }) => query, currentSort, parsedQueries, - rows: await sdk.forProject(params.region, params.project).tablesDB.listRows({ - databaseId: params.database, - tableId: params.table, - queries: buildGridQueries(limit, offset, parsedQueries, table) - }) + rows: await loadGridRows( + table, + (includeRelationships) => + buildGridQueries(limit, offset, parsedQueries, table, includeRelationships), + (queries) => + sdk.forProject(params.region, params.project).tablesDB.listRows({ + databaseId: params.database, + tableId: params.table, + queries + }) + ) }; }; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/activity/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/activity/+page.svelte deleted file mode 100644 index 849d38953b..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/activity/+page.svelte +++ /dev/null @@ -1,14 +0,0 @@ - - -
- -
diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/activity/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/activity/+page.ts deleted file mode 100644 index fd816c1c08..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/activity/+page.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Query } from '@appwrite.io/console'; -import { sdk } from '$lib/stores/sdk'; -import { getLimit, getPage, pageToOffset } from '$lib/helpers/load'; -import { PAGE_LIMIT } from '$lib/constants'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ params, url, route }) => { - const page = getPage(url); - const limit = getLimit(url, route, PAGE_LIMIT); - const offset = pageToOffset(page, limit); - - return { - offset, - limit, - logs: await sdk.forProject(params.region, params.project).tablesDB.listTableLogs({ - databaseId: params.database, - tableId: params.table, - queries: [Query.limit(limit), Query.offset(offset)] - }) - }; -}; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte index 5c457edce1..3f54139a63 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/+page.svelte @@ -515,26 +515,30 @@ {columnType.toLowerCase()} - - {@const isActuallyIndexed = - isId || $indexes.some((index) => index.columns.includes(column.key))} - - - {@const checked = isId || isActuallyIndexed || !!columnIndexMap[column.key]} - - { - if (!isActuallyIndexed) { - if (e.detail) { - columnIndexMap[column.key] = true; - $showCreateIndexSheet.show = true; - $showCreateIndexSheet.column = column.key; + {#if !isRelationship(column)} + + {@const isActuallyIndexed = + isId || + $indexes.some((index) => index.columns.includes(column.key))} + + + {@const checked = + isId || isActuallyIndexed || !!columnIndexMap[column.key]} + + { + if (!isActuallyIndexed) { + if (e.detail) { + columnIndexMap[column.key] = true; + $showCreateIndexSheet.show = true; + $showCreateIndexSheet.column = column.key; + } } - } - }} /> + }} /> + {/if} {@const _default = column.required diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/line.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/line.svelte index b14357e0d1..e533fb987b 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/line.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/line.svelte @@ -61,7 +61,7 @@ savedDefault = data.default; data.default = null; } else { - data.default = savedDefault ?? getDefaultSpatialData('linestring'); + data.default = (savedDefault ?? getDefaultSpatialData('linestring')) as number[][]; } } @@ -100,7 +100,7 @@ onMount(() => { if (!editing) { - savedDefault = getDefaultSpatialData('linestring'); + savedDefault = getDefaultSpatialData('linestring') as number[][]; defaultChecked = false; $required = false; } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/point.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/point.svelte index 27b5b75cf0..0230bf1a72 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/point.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/point.svelte @@ -64,7 +64,7 @@ savedDefault = data.default; data.default = null; } else { - data.default = savedDefault ?? getDefaultSpatialData('point'); + data.default = (savedDefault ?? getDefaultSpatialData('point')) as number[]; } } @@ -93,7 +93,7 @@ onMount(() => { if (!editing) { - savedDefault = getDefaultSpatialData('point'); + savedDefault = getDefaultSpatialData('point') as number[]; defaultChecked = false; $required = false; } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/polygon.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/polygon.svelte index fbc5a4e497..2a083fffb3 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/polygon.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/columns/polygon.svelte @@ -64,7 +64,7 @@ savedDefault = data.default; data.default = null; } else { - data.default = savedDefault ?? getDefaultSpatialData('polygon'); + data.default = (savedDefault ?? getDefaultSpatialData('polygon')) as number[][][]; } } @@ -114,7 +114,7 @@ onMount(() => { if (!editing) { - savedDefault = getDefaultSpatialData('polygon'); + savedDefault = getDefaultSpatialData('polygon') as number[][][]; defaultChecked = false; $required = false; } diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export/+page.svelte index 9ed600090f..8291162dbb 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/export/+page.svelte @@ -101,7 +101,8 @@ await sdk .forProject(page.params.region, page.params.project) .migrations.createCSVExport({ - resourceId: `${page.params.database}:${page.params.table}`, + databaseId: page.params.database, + collectionId: page.params.table, filename: filename, columns: selectedCols, queries: exportWithFilters ? Array.from(localQueries.values()) : [], diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/header.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/header.svelte index fd5d1e1f0c..5c4463f04b 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/header.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/header.svelte @@ -32,18 +32,6 @@ title: 'Indexes', event: 'indexes' }, - { - href: `${path}/activity`, - title: 'Activity', - event: 'activity', - hasChildren: true - }, - { - href: `${path}/usage`, - title: 'Usage', - event: 'usage', - hasChildren: true - }, { href: `${path}/settings`, title: 'Settings', diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/activity.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/activity.svelte deleted file mode 100644 index d7d37451f1..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/activity.svelte +++ /dev/null @@ -1,68 +0,0 @@ - - -{#if loading} -
- - -
-{:else if rowActivityLogs} -
- -
-{/if} - - diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte index 37947fefe3..1f385d75ab 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/columns/column.svelte @@ -88,7 +88,7 @@ {:else} { + it('converts local datetime-local strings to UTC ISO for datetime fields', () => { + const utc = '2026-01-01T00:00:00.000Z'; + const local = toLocalDateTimeISO(utc); + const fields = [{ key: 'startAt', type: 'datetime' }] as Field[]; + + const payload = buildPayload(fields, { startAt: local, name: 'unchanged' }); + + expect(payload.startAt).toBe(new Date(local).toISOString()); + expect(payload.name).toBe('unchanged'); + }); + + it('round-trips an unchanged datetime through local display encoding', () => { + const utc = '2026-01-01T00:00:00.000Z'; + const fields = [{ key: 'startAt', type: 'datetime' }] as Field[]; + + const payload = buildPayload(fields, { startAt: toLocalDateTimeISO(utc) }); + + expect(payload.startAt).toBe(new Date(utc).toISOString()); + }); + + it('converts datetime arrays element-wise', () => { + const utc = '2026-01-01T00:00:00.000Z'; + const local = toLocalDateTimeISO(utc); + const fields = [{ key: 'times', type: 'datetime', array: true }] as Field[]; + + const payload = buildPayload(fields, { times: [local, null] }); + + expect(payload.times).toEqual([new Date(local).toISOString(), null]); + }); + + it('leaves null and empty datetime values alone', () => { + const fields = [{ key: 'startAt', type: 'datetime' }] as Field[]; + + expect(buildPayload(fields, { startAt: null }).startAt).toBeNull(); + expect(buildPayload(fields, { startAt: '' }).startAt).toBe(''); + }); + + it('still stringifies bigint fields', () => { + const fields = [{ key: 'count', type: 'bigint' }] as Field[]; + + expect(buildPayload(fields, { count: 42n }).count).toBe('42'); + }); +}); diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts index ee1686c119..7073594645 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/rows/store.ts @@ -65,6 +65,29 @@ function castBigIntValue(value: RowValue): RowValue { return String(value); } +/** + * Datetime inputs are shown as timezone-less local ISO strings (see + * `toLocalDateTimeISO`). Convert them back to UTC before the API call so + * unchanged fields do not drift by the browser's UTC offset on every update. + */ +function castDatetimeValue(value: RowValue): RowValue { + if (value === null || value === undefined || value === '') { + return value; + } + + if (typeof value !== 'string') { + return value; + } + + const date = new Date(value); + + if (isNaN(date.getTime())) { + return value; + } + + return date.toISOString(); +} + export function buildPayload>( fields: Field[] | undefined, row: T @@ -72,18 +95,19 @@ export function buildPayload>( const payload = structuredClone(row) as Record; for (const field of fields ?? []) { - if (field.type !== 'bigint') { + if (field.type !== 'bigint' && field.type !== 'datetime') { continue; } const value = payload[field.key]; + const cast = field.type === 'bigint' ? castBigIntValue : castDatetimeValue; if (field.array && Array.isArray(value)) { - payload[field.key] = value.map((item) => castBigIntValue(item)); + payload[field.key] = value.map((item) => cast(item)); continue; } - payload[field.key] = castBigIntValue(value); + payload[field.key] = cast(value); } return payload as T; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/sheetOptions.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/sheetOptions.svelte index ee0b793f79..c55ceae9b6 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/sheetOptions.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/sheetOptions.svelte @@ -13,7 +13,6 @@ | 'update' | 'duplicate-row' | 'permissions' - | 'activity' | 'copy-url' | 'copy-json' // | 'copy-snippet' @@ -26,7 +25,6 @@ import { IconArrowLeft, IconArrowRight, - IconChartBar, IconClipboardCopy, IconDuplicate, IconKey, @@ -69,7 +67,6 @@ { label: 'Duplicate', icon: IconDuplicate, action: 'duplicate-row' }, { divider: true }, { label: 'Manage permissions', icon: IconKey, action: 'permissions' }, - { label: 'View activity', icon: IconChartBar, action: 'activity' }, { divider: true }, { label: 'Copy URL', icon: IconLink, action: 'copy-url' }, { label: 'Copy as JSON', icon: IconClipboardCopy, action: 'copy-json' }, diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte index 45744342ad..517c40b279 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/spreadsheet.svelte @@ -31,7 +31,6 @@ columnsWidth, showCreateIndexSheet, Deletion, - rowActivitySheet, paginatedRows, paginatedRowsLoading, databaseRelatedRowSheetOptions, @@ -99,6 +98,7 @@ expandTabs, type Columns, buildWildcardEntitiesQuery, + loadGridRows, type SortState, randomDataModalState, spreadsheetLoading, @@ -427,16 +427,23 @@ async function handleDelete() { showDelete = false; let hadErrors = false; + const rowIdsToDelete = selectedRowForDelete ? [selectedRowForDelete] : [...selectedRows]; + const deletedRowsCount = rowIdsToDelete.length || 1; try { - if (selectedRowForDelete) { + $spreadsheetLoading = true; + selectedRows = []; + selectedRowForDelete = null; + spreadsheetRenderKey.set(hash(rowIdsToDelete)); + + if (rowIdsToDelete.length === 1) { await sdk.forProject(page.params.region, page.params.project).tablesDB.deleteRow({ databaseId, tableId, - rowId: selectedRowForDelete + rowId: rowIdsToDelete[0] }); } else { - if (selectedRows.length) { + if (rowIdsToDelete.length) { const hasAnyRelationships = table.fields.some(isRelationship) ?? false; const tablesSDK = sdk.forProject( @@ -445,7 +452,7 @@ ).tablesDB; if (hasAnyRelationships) { - for (const batch of chunks(selectedRows)) { + for (const batch of chunks(rowIdsToDelete)) { try { await Promise.all( batch.map((rowId) => @@ -469,7 +476,7 @@ }); } } else { - for (const batch of chunks(selectedRows, 100)) { + for (const batch of chunks(rowIdsToDelete, 100)) { await tablesSDK.deleteRows({ databaseId, tableId, @@ -487,17 +494,11 @@ // error is already shown above! addNotification({ type: 'success', - message: `${selectedRows.length ? selectedRows.length : 1} row${selectedRows.length > 1 ? 's' : ''} deleted` + message: `${deletedRowsCount} row${deletedRowsCount > 1 ? 's' : ''} deleted` }); } - spreadsheetRenderKey.set( - hash([ - data.rows.total.toString(), - ...(selectedRows as string[]), - selectedRowForDelete - ]) - ); + spreadsheetRenderKey.set(hash([data.rows.total.toString(), ...rowIdsToDelete])); } catch (error) { addNotification({ type: 'error', message: error.message }); trackError(error, Submit.RowDelete); @@ -505,6 +506,7 @@ selectedRows = []; showDelete = false; selectedRowForDelete = null; + $spreadsheetLoading = false; } } @@ -563,6 +565,7 @@ return; } if (action === 'update') { + $databaseColumnSheetOptions.column = column; $databaseColumnSheetOptions.show = true; $databaseColumnSheetOptions.isEdit = true; $databaseColumnSheetOptions.title = 'Update column'; @@ -675,32 +678,34 @@ showDelete = true; selectedRowForDelete = row.$id; } - - if (action === 'activity') { - $rowActivitySheet.row = row; - $rowActivitySheet.show = true; - } } } - async function updateRowContents(row: Models.Row) { + async function updateRowContents(row: Models.Row): Promise { try { const payload = buildPayload(table.fields, row); - await sdk.forProject(page.params.region, page.params.project).tablesDB.updateRow({ - databaseId, - tableId: table.$id, - rowId: row.$id, - data: payload, - permissions: row.$permissions - }); + const updated = await sdk + .forProject(page.params.region, page.params.project) + .tablesDB.updateRow({ + databaseId, + tableId: table.$id, + rowId: row.$id, + data: payload, + permissions: row.$permissions + }); + + // Keep client-side relationship expansions; refresh system fields from the API + // so columns like $updatedAt reflect the write (inline edit does not invalidate Dependencies). + row.$updatedAt = updated.$updatedAt; + row.$permissions = updated.$permissions; trackEvent(Submit.RowUpdate); addNotification({ message: 'Row has been updated', type: 'success' }); - return true; + return row; } catch (error) { addNotification({ message: error.message, @@ -725,22 +730,26 @@ } const parsedQueries = data.parsedQueries; - const filterQueries = parsedQueries.size ? data.parsedQueries.values() : []; + // materialized: the fallback in `loadGridRows` builds the queries more than once. + const filterQueries = parsedQueries.size ? Array.from(data.parsedQueries.values()) : []; $paginatedRowsLoading = true; - const loadedRows = await sdk - .forProject(page.params.region, page.params.project) - .tablesDB.listRows({ - databaseId, - tableId, - queries: [ - getCorrectOrderQuery(), - Query.limit(SPREADSHEET_PAGE_LIMIT), - Query.offset(pageToOffset(pageNumber, SPREADSHEET_PAGE_LIMIT)), - ...filterQueries /* filter queries */, - ...buildWildcardEntitiesQuery(table) - ] - }); + const loadedRows = await loadGridRows( + table, + (includeRelationships) => [ + getCorrectOrderQuery(), + Query.limit(SPREADSHEET_PAGE_LIMIT), + Query.offset(pageToOffset(pageNumber, SPREADSHEET_PAGE_LIMIT)), + ...filterQueries /* filter queries */, + ...(includeRelationships + ? buildWildcardEntitiesQuery(table) + : [Query.select(['*'])]) + ], + (queries) => + sdk + .forProject(page.params.region, page.params.project) + .tablesDB.listRows({ databaseId, tableId, queries }) + ); paginatedRows.setPage(pageNumber, loadedRows.rows); $paginatedRowsLoading = false; @@ -756,18 +765,21 @@ paginatedRows.setMaxPage(targetPageNum); $paginatedRowsLoading = true; - const loadedRows = await sdk - .forProject(page.params.region, page.params.project) - .tablesDB.listRows({ - databaseId, - tableId, - queries: [ - getCorrectOrderQuery(), - Query.limit(SPREADSHEET_PAGE_LIMIT), - Query.offset(pageToOffset(targetPageNum, SPREADSHEET_PAGE_LIMIT)), - ...buildWildcardEntitiesQuery(table) - ] - }); + const loadedRows = await loadGridRows( + table, + (includeRelationships) => [ + getCorrectOrderQuery(), + Query.limit(SPREADSHEET_PAGE_LIMIT), + Query.offset(pageToOffset(targetPageNum, SPREADSHEET_PAGE_LIMIT)), + ...(includeRelationships + ? buildWildcardEntitiesQuery(table) + : [Query.select(['*'])]) + ], + (queries) => + sdk + .forProject(page.params.region, page.params.project) + .tablesDB.listRows({ databaseId, tableId, queries }) + ); paginatedRows.setPage(targetPageNum, loadedRows.rows); $paginatedRowsLoading = false; @@ -1119,7 +1131,8 @@ {@const value = row[columnId]} {@const formatted = formatColumn(row[columnId])} {@const isEmptyArray = formatted === 'Empty'} - {@const isDatetimeAttribute = rowColumn.type === 'datetime'} + {@const isDatetimeAttribute = + rowColumn?.type === 'datetime'} {@const isEncryptedAttribute = isTextType(rowColumn) && 'encrypt' in rowColumn && @@ -1173,12 +1186,13 @@ {row} column={rowColumn} onRowStructureUpdate={async (row) => { - const success = await updateRowContents(row); - if (success) { + const updated = await updateRowContents(row); + if (updated) { // database update succeeded! - paginatedRows.update(index, row); + paginatedRows.update(index, updated); + return true; } - return success; + return false; }} noInlineEdit={isRelatedToMany && hasItems} onChange={(row) => paginatedRows.update(index, row)} diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts index 3928be3f57..26c9efdc23 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/store.ts @@ -143,11 +143,6 @@ export enum Deletion { restrict = 'Row can not be deleted' } -export const rowActivitySheet = writable({ - show: false, - row: null as Models.Row -}); - export const rowPermissionSheet = writable({ show: false, row: null as Models.Row diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/usage/[[period]]/+page.svelte deleted file mode 100644 index a8d8fdb0b0..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/usage/[[period]]/+page.svelte +++ /dev/null @@ -1,11 +0,0 @@ - - - diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/usage/[[period]]/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/usage/[[period]]/+page.ts deleted file mode 100644 index 2881862b8f..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/table-[table]/usage/[[period]]/+page.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { isValueOfStringEnum } from '$lib/helpers/types'; -import { sdk } from '$lib/stores/sdk'; -import { UsageRange } from '@appwrite.io/console'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ params }) => { - const period = isValueOfStringEnum(UsageRange, params.period) - ? params.period - : UsageRange.ThirtyDays; - - return { - ...(await sdk.forProject(params.region, params.project).tablesDB.getTableUsage({ - databaseId: params.database, - tableId: params.table, - range: period - })) - }; -}; diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.svelte deleted file mode 100644 index 3563aba6ed..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.svelte +++ /dev/null @@ -1,41 +0,0 @@ - - - - - diff --git a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.ts deleted file mode 100644 index 9391c5451a..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/database-[database]/usage/[[period]]/+page.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { isValueOfStringEnum } from '$lib/helpers/types'; -import { sdk } from '$lib/stores/sdk'; -import { UsageRange } from '@appwrite.io/console'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ params }) => { - const period = isValueOfStringEnum(UsageRange, params.period) - ? params.period - : UsageRange.ThirtyDays; - - return { - ...(await sdk.forProject(params.region, params.project).tablesDB.getUsage({ - databaseId: params.database, - range: period - })) - }; -}; diff --git a/src/routes/(console)/project-[region]-[project]/databases/header.svelte b/src/routes/(console)/project-[region]-[project]/databases/header.svelte index 796c86d09f..edaaeb32ef 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/header.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/header.svelte @@ -14,12 +14,6 @@ title: 'Databases', event: 'databases', hasChildren: true - }, - { - href: `${path}/usage`, - title: 'Usage', - event: 'usage', - hasChildren: true } ]; diff --git a/src/routes/(console)/project-[region]-[project]/databases/store.ts b/src/routes/(console)/project-[region]-[project]/databases/store.ts index 79d0aa31c2..05d7e32127 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/store.ts +++ b/src/routes/(console)/project-[region]-[project]/databases/store.ts @@ -2,7 +2,6 @@ import { isCloud } from '$lib/system'; import { writable } from 'svelte/store'; import type { Column } from '$lib/helpers/types'; import type { Models } from '@appwrite.io/console'; -import type { DatabaseType } from '$database/(entity)'; export const columns = writable( isCloud @@ -24,7 +23,7 @@ export const columns = writable( ); export function getDatabaseTypeTitle(database: Models.Database) { - switch (database.type as DatabaseType) { + switch (database.type) { default: case 'legacy': case 'tablesdb': diff --git a/src/routes/(console)/project-[region]-[project]/databases/table.svelte b/src/routes/(console)/project-[region]-[project]/databases/table.svelte index 9d408cba2f..445641a11b 100644 --- a/src/routes/(console)/project-[region]-[project]/databases/table.svelte +++ b/src/routes/(console)/project-[region]-[project]/databases/table.svelte @@ -3,7 +3,7 @@ import { columns, getDatabaseTypeTitle } from './store'; import { Id } from '$lib/components'; import type { Models } from '@appwrite.io/console'; - import { useTerminology } from '$database/(entity)'; + import { toDatabaseType, useTerminology } from '$database/(entity)'; import DualTimeView from '$lib/components/dualTimeView.svelte'; import { resolveRoute, withPath } from '$lib/stores/navigation'; import { IconExclamation } from '@appwrite.io/pink-icons-svelte'; @@ -35,7 +35,7 @@ } function getEntityUrl(database: Models.Database, entityId: string) { - const terminology = useTerminology(database.type); + const terminology = useTerminology(toDatabaseType(database.type)); const entityType = terminology.entity.lower.singular; return withPath( diff --git a/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.svelte b/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.svelte deleted file mode 100644 index d0b84609a2..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.svelte +++ /dev/null @@ -1,69 +0,0 @@ - - - - -
- goto(`${usagePath}/${e.detail}`)} - id="period" - options={[ - { - label: '24 hours', - value: '24h' - }, - { - label: '30 days', - value: '30d' - }, - { - label: '90 days', - value: '90d' - } - ]} - value={page.params.period ?? '30d'} /> -
- - -
-
diff --git a/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.ts b/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.ts deleted file mode 100644 index 359a5153e0..0000000000 --- a/src/routes/(console)/project-[region]-[project]/databases/usage/[[period]]/+page.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { isValueOfStringEnum } from '$lib/helpers/types'; -import { sdk } from '$lib/stores/sdk'; -import { UsageRange } from '@appwrite.io/console'; -import type { PageLoad } from './$types'; - -export const load: PageLoad = async ({ params }) => { - const period = isValueOfStringEnum(UsageRange, params.period) - ? params.period - : UsageRange.ThirtyDays; - - return { - ...(await sdk - .forProject(params.region, params.project) - .tablesDB.listUsage({ range: period })) - }; -}; diff --git a/src/routes/(console)/project-[region]-[project]/functions/+layout.ts b/src/routes/(console)/project-[region]-[project]/functions/+layout.ts index b22ab7609f..f2442d6bf0 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/+layout.ts +++ b/src/routes/(console)/project-[region]-[project]/functions/+layout.ts @@ -4,26 +4,36 @@ import { sdk } from '$lib/stores/sdk'; import { Query } from '@appwrite.io/console'; import { Dependencies } from '$lib/constants'; import { isCloud } from '$lib/system'; +import { trimLeadingDisabledSpecifications } from '$lib/helpers/specifications'; import type { LayoutLoad } from './$types'; export const load: LayoutLoad = async ({ depends, params }) => { depends(Dependencies.FUNCTION_INSTALLATIONS); - const [runtimesList, installations, specificationsList] = await Promise.all([ - sdk.forProject(params.region, params.project).functions.listRuntimes(), - sdk - .forProject(params.region, params.project) - .vcs.listInstallations({ queries: [Query.limit(100)] }), - isCloud - ? sdk.forProject(params.region, params.project).functions.listSpecifications() - : Promise.resolve({ specifications: [], total: 0 }) - ]); + const [runtimesList, installations, buildSpecificationsList, runtimeSpecificationsList] = + await Promise.all([ + sdk.forProject(params.region, params.project).functions.listRuntimes(), + sdk + .forProject(params.region, params.project) + .vcs.listInstallations({ queries: [Query.limit(100)] }), + isCloud + ? sdk + .forProject(params.region, params.project) + .functions.listSpecifications({ type: 'builds' }) + : Promise.resolve({ specifications: [], total: 0 }), + isCloud + ? sdk + .forProject(params.region, params.project) + .functions.listSpecifications({ type: 'runtimes' }) + : Promise.resolve({ specifications: [], total: 0 }) + ]); return { header: Header, breadcrumbs: Breadcrumbs, runtimesList, installations, - specificationsList + specificationsList: trimLeadingDisabledSpecifications(buildSpecificationsList), + runtimeSpecificationsList }; }; diff --git a/src/routes/(console)/project-[region]-[project]/functions/create-function/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/create-function/+page.svelte index a9c2e00cd3..b83d890df0 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/create-function/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/create-function/+page.svelte @@ -85,7 +85,7 @@
diff --git a/src/routes/(console)/project-[region]-[project]/functions/create-function/deploy/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/create-function/deploy/+page.svelte index 200e0575d8..cb7a36047b 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/create-function/deploy/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/create-function/deploy/+page.svelte @@ -11,7 +11,12 @@ import { Fieldset, Layout, Icon, Input, Tag } from '@appwrite.io/pink-svelte'; import { IconGithub, IconPencil } from '@appwrite.io/pink-icons-svelte'; import { onMount } from 'svelte'; - import { ID, Runtime, TemplateReferenceType, type Scopes } from '@appwrite.io/console'; + import { + ID, + Runtime, + TemplateReferenceType, + type ProjectKeyScopes + } from '@appwrite.io/console'; import { CustomId } from '$lib/components'; import { getIconFromRuntime } from '$lib/stores/runtimes'; import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; @@ -20,6 +25,7 @@ import { getLatestTag } from '$lib/helpers/github'; import { writable } from 'svelte/store'; import Link from '$lib/elements/link.svelte'; + import { validateVariables } from '$lib/helpers/variables'; let { data @@ -39,7 +45,7 @@ let specification = $state(''); let runtime = $state(); let installCommand = $state(''); - let selectedScopes = $state([]); + let selectedScopes = $state([]); let rootDir = $state(data.repository?.rootDirectory); let variables = $state>([]); @@ -92,6 +98,13 @@ $isSubmitting = true; try { + // Reject an unusable key before the resource is created, so a + // rejected variable can't leave a half-configured resource behind. + const validationError = validateVariables(variables); + if (validationError) { + throw new Error(validationError); + } + if (!latestTag) { latestTag = await getLatestTag(data.repository.owner, data.repository.name); } diff --git a/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte index 1e72962068..f49a5ded72 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/create-function/manual/+page.svelte @@ -28,6 +28,7 @@ import { humanFileSize } from '$lib/helpers/sizeConvertion'; import { currentPlan } from '$lib/stores/organization'; import { uploader } from '$lib/stores/uploader'; + import { validateVariables } from '$lib/helpers/variables'; export let data; @@ -69,6 +70,13 @@ let func: Models.Function | null = null; try { + // Reject an unusable key before the resource is created, so a + // rejected variable can't leave a half-configured resource behind. + const validationError = validateVariables(variables); + if (validationError) { + throw new Error(validationError); + } + func = await sdk.forProject(page.params.region, page.params.project).functions.create({ functionId: id || ID.unique(), name, diff --git a/src/routes/(console)/project-[region]-[project]/functions/create-function/repository-[repository]/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/create-function/repository-[repository]/+page.svelte index 0e022aabcc..0444fb1bd9 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/create-function/repository-[repository]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/create-function/repository-[repository]/+page.svelte @@ -22,7 +22,11 @@ import RepoCard from './repoCard.svelte'; import { getIconFromRuntime } from '$lib/stores/runtimes'; import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; - import { normalizeDetectedVariables, mergeVariables } from '$lib/helpers/variables'; + import { + normalizeDetectedVariables, + mergeVariables, + validateVariables + } from '$lib/helpers/variables'; export let data; @@ -104,6 +108,13 @@ async function create() { try { + // Reject an unusable key before the resource is created, so a + // rejected variable can't leave a half-configured resource behind. + const validationError = validateVariables(variables); + if (validationError) { + throw new Error(validationError); + } + const func = await sdk .forProject(page.params.region, page.params.project) .functions.create({ diff --git a/src/routes/(console)/project-[region]-[project]/functions/create-function/template-[template]/+page.svelte b/src/routes/(console)/project-[region]-[project]/functions/create-function/template-[template]/+page.svelte index 4a46da427b..2a09f68146 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/create-function/template-[template]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/create-function/template-[template]/+page.svelte @@ -20,7 +20,7 @@ Runtime, TemplateReferenceType, type Models, - type Scopes + type ProjectKeyScopes } from '@appwrite.io/console'; import { ConnectBehaviour, @@ -38,6 +38,7 @@ import { getIconFromRuntime } from '$lib/stores/runtimes'; import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; import type { PageData } from './$types'; + import { validateVariables } from '$lib/helpers/variables'; let { data }: { data: PageData } = $props(); @@ -71,7 +72,7 @@ let showConfig = $state(false); let silentMode = $state(false); let entrypoint = $state(''); - let selectedScopes = $state([]); + let selectedScopes = $state([]); let execute = $state(true); let variables = $state[]>([]); let specification = $state(untrack(() => specificationOptions[0]?.value || '')); @@ -148,6 +149,15 @@ return; } else { try { + // Reject an unusable key before the resource is created, so a + // rejected variable can't leave a half-configured resource behind. + const validationError = validateVariables( + variables.map((variable) => ({ key: variable.name, value: variable.value })) + ); + if (validationError) { + throw new Error(validationError); + } + const rt = data.template.runtimes.find((r) => r.name === runtime); const func = await sdk diff --git a/src/routes/(console)/project-[region]-[project]/functions/create-function/template-[template]/permissions.svelte b/src/routes/(console)/project-[region]-[project]/functions/create-function/template-[template]/permissions.svelte index 3392f994ec..3cf7cf2c87 100644 --- a/src/routes/(console)/project-[region]-[project]/functions/create-function/template-[template]/permissions.svelte +++ b/src/routes/(console)/project-[region]-[project]/functions/create-function/template-[template]/permissions.svelte @@ -1,16 +1,16 @@ - +
diff --git a/src/routes/(console)/project-[region]-[project]/overview/api-keys/+page.ts b/src/routes/(console)/project-[region]-[project]/overview/api-keys/+page.ts index 7628733e69..025777c187 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/api-keys/+page.ts +++ b/src/routes/(console)/project-[region]-[project]/overview/api-keys/+page.ts @@ -1,10 +1,21 @@ -import { Dependencies } from '$lib/constants'; +import { CARD_LIMIT, Dependencies } from '$lib/constants'; +import { getLimit, getPage, pageToOffset } from '$lib/helpers/load'; import { sdk } from '$lib/stores/sdk'; +import { Query } from '@appwrite.io/console'; import type { PageLoad } from './$types'; -export const load: PageLoad = async ({ params, depends }) => { +export const load: PageLoad = async ({ params, depends, route, url }) => { depends(Dependencies.KEYS); + const projectSdk = sdk.forProject(params.region, params.project).project; + const page = getPage(url); + const limit = getLimit(url, route, CARD_LIMIT); + const offset = pageToOffset(page, limit); + return { - keys: await sdk.forProject(params.region, params.project).project.listKeys() + limit, + offset, + keys: await projectSdk.listKeys({ + queries: [Query.limit(limit), Query.offset(offset)] + }) }; }; diff --git a/src/routes/(console)/project-[region]-[project]/overview/api-keys/scopes.svelte b/src/routes/(console)/project-[region]-[project]/overview/api-keys/scopes.svelte index 08963ba286..06f9de2e9e 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/api-keys/scopes.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/api-keys/scopes.svelte @@ -1,31 +1,3 @@ - - diff --git a/src/routes/(console)/project-[region]-[project]/overview/context.ts b/src/routes/(console)/project-[region]-[project]/overview/context.ts index 6edf531490..6467f23a00 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/context.ts +++ b/src/routes/(console)/project-[region]-[project]/overview/context.ts @@ -1,8 +1,8 @@ import { getContext, type Component } from 'svelte'; import type { Writable } from 'svelte/store'; -export type OverviewActionContext = Writable; +export type OverviewActionContext = Writable; -export function setOverviewAction(component: Component) { +export function setOverviewAction(component: Component | null) { getContext('overview-action').set(component); } diff --git a/src/routes/(console)/project-[region]-[project]/overview/dev-keys/+page.svelte b/src/routes/(console)/project-[region]-[project]/overview/dev-keys/+page.svelte index cd3f896e29..1ec0399b82 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/dev-keys/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/dev-keys/+page.svelte @@ -1,11 +1,27 @@ -
+ + + + As of July 22, 2026, creating new dev keys is paused. Existing dev keys keep working + until September 1, 2026. Learn more in the + + changelog + . + + + +
+ diff --git a/src/routes/(console)/project-[region]-[project]/overview/dev-keys/action.svelte b/src/routes/(console)/project-[region]-[project]/overview/dev-keys/action.svelte deleted file mode 100644 index 5dda98b434..0000000000 --- a/src/routes/(console)/project-[region]-[project]/overview/dev-keys/action.svelte +++ /dev/null @@ -1,81 +0,0 @@ - - -{#if $canWriteKeys} - - - - - - Bypass Appwrite rate limits and CORS errors in your development environment. - - - - - - - - - - - - - - -{/if} diff --git a/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte b/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte index 4abffc8ae1..d0798f371a 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/overview/platforms/+page.svelte @@ -93,7 +93,8 @@ import { type DeleteOperationState, type DeleteOperation, - MultiSelectionTable + MultiSelectionTable, + PaginationWithLimit } from '$lib/components'; import { sdk } from '$lib/stores/sdk'; import { Submit, trackError } from '$lib/actions/analytics'; @@ -200,6 +201,11 @@ {/each} {/snippet} + {:else} { - const { project } = await parent(); +export const load: PageLoad = async ({ depends, params, route, url }) => { + depends(Dependencies.PROJECT); + const page = getPage(url); + const limit = getLimit(url, route, CARD_LIMIT); + const offset = pageToOffset(page, limit); + return { - platforms: { - platforms: project.platforms, - total: project.platforms.length - } + limit, + offset, + platforms: await sdk.forProject(params.region, params.project).project.listPlatforms({ + queries: [Query.limit(limit), Query.offset(offset)] + }) }; }; diff --git a/src/routes/(console)/project-[region]-[project]/overview/store.ts b/src/routes/(console)/project-[region]-[project]/overview/store.ts index 2e3171c0f5..8a4d86e5e3 100644 --- a/src/routes/(console)/project-[region]-[project]/overview/store.ts +++ b/src/routes/(console)/project-[region]-[project]/overview/store.ts @@ -1,6 +1,6 @@ import { sdk } from '$lib/stores/sdk'; import { cachedStore } from '$lib/helpers/cache'; -import { get, readable, writable, type Writable } from 'svelte/store'; +import { get, readable } from 'svelte/store'; import type { Models, ProjectUsageRange } from '@appwrite.io/console'; import { page } from '$app/state'; import type { Column } from '$lib/helpers/types'; @@ -25,8 +25,6 @@ export const usage = cachedStore< }; }); -export const showDevKeysCreateModal: Writable = writable(false); - export const devKeyColumns = readable([ { id: 'name', title: 'Name', type: 'string', width: { min: 120 } }, { id: 'last_accessed', title: 'Last accessed', type: 'datetime', width: { min: 120 } }, diff --git a/src/routes/(console)/project-[region]-[project]/rawVariableEditor.svelte b/src/routes/(console)/project-[region]-[project]/rawVariableEditor.svelte index cdd8899927..b1c3b79b23 100644 --- a/src/routes/(console)/project-[region]-[project]/rawVariableEditor.svelte +++ b/src/routes/(console)/project-[region]-[project]/rawVariableEditor.svelte @@ -6,6 +6,7 @@ import { addNotification } from '$lib/stores/notifications'; import type { Models } from '@appwrite.io/console'; import { parse } from '$lib/helpers/envfile'; + import { validateVariables } from '$lib/helpers/variables'; import { Icon, InlineCode, Layout, Tabs } from '@appwrite.io/pink-svelte'; import { InputTextarea } from '$lib/elements/forms'; import { @@ -35,7 +36,7 @@ ) => Promise; export let sdkUpdateVariable: ( variableId: string, - key: string, + key: string | undefined, value: string, secret?: boolean ) => Promise; @@ -74,10 +75,10 @@ } function validateEntries(entries: DraftVariable[]) { - for (const { key, value } of entries) { - if (value.length > 8192) { - throw new Error(`Variable ${key} is longer than 8192 allowed characters`); - } + const validationError = validateVariables(entries); + + if (validationError) { + throw new Error(validationError); } } @@ -146,22 +147,30 @@ const editableVariables = variableList.variables.filter((variable) => !variable.secret); const secretVariables = variableList.variables.filter((variable) => variable.secret); - await Promise.all( + const existingKeys = editableVariables.map((variable) => variable.key); + const existingResults = await Promise.allSettled( editableVariables.map(async (variable) => { const newValue = vars[variable.key] ?? null; + // Claim the key up front. A rejected write must not leave it + // behind for the second pass, which would retry it as a new + // variable and send the stored key along with it. + delete vars[variable.key]; + if (newValue === null) { await sdkDeleteVariable(variable.$id); } else if (newValue !== variable.value) { - await sdkUpdateVariable(variable.$id, variable.key, newValue, false); + // The key is unchanged here, so leave it out and let + // the API keep the stored one. + await sdkUpdateVariable(variable.$id, undefined, newValue, false); } - delete vars[variable.key]; }) ); // Add new variables, skipping keys that exist in secret variables - await Promise.all( - Object.keys(vars).map(async (key) => { + const newKeys = Object.keys(vars); + const newResults = await Promise.allSettled( + newKeys.map(async (key) => { const existingVariable = variableList.variables.find( (variable) => variable.key === key ); @@ -178,6 +187,22 @@ await sdkCreateVariable(key, vars[key], false); }) ); + + // Every variable is written on its own, so name the keys that + // failed rather than surfacing a single rejection. + const failed = [ + ...existingResults.map((result, index) => + result.status === 'rejected' ? existingKeys[index] : null + ), + ...newResults.map((result, index) => + result.status === 'rejected' ? newKeys[index] : null + ) + ].filter(Boolean); + + if (failed.length) { + throw new Error(`Failed to update variables: ${failed.join(', ')}`); + } + // Ensure secret variables are preserved variableList.variables = [ ...secretVariables, diff --git a/src/routes/(console)/project-[region]-[project]/settings/+page.svelte b/src/routes/(console)/project-[region]-[project]/settings/+page.svelte index 3961307590..d5ce61951c 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/+page.svelte @@ -18,8 +18,14 @@ import UpdateVariables from '../updateVariables.svelte'; import { page } from '$app/state'; import UpdateLabels from './updateLabels.svelte'; + import PremiumGeoDB from './premiumGeoDB.svelte'; + import UpdateOAuth2Server from './updateOAuth2Server.svelte'; + import { isCloud } from '$lib/system'; import type { PageData } from './$types'; import { Alert } from '@appwrite.io/pink-svelte'; + import { flags } from '$lib/flags'; + import { user } from '$lib/stores/user'; + import { organization } from '$lib/stores/organization'; let { data }: { data: PageData } = $props(); @@ -95,8 +101,14 @@ + {#if flags.oauth2Server({ account: $user, organization: $organization })} + + {/if} + {#if isCloud && $canWriteProjects} + + {/if} { depends(Dependencies.PROJECT_VARIABLES); depends(Dependencies.PROJECT_INSTALLATIONS); + depends(Dependencies.ADDONS); const limit = PAGE_LIMIT; const offset = Number(url.searchParams.get('offset') ?? 0); const variablesOffset = Number(url.searchParams.get('variablesOffset') ?? 0); const projectSdk = sdk.forProject(params.region, params.project); - const [variablesResult, installationsResult] = await Promise.allSettled([ - projectSdk.projectApi.listVariables({ - queries: [Query.limit(limit), Query.offset(variablesOffset)] - }), - projectSdk.vcs.listInstallations({ - queries: [Query.limit(limit), Query.offset(offset)] - }) - ]); + const [variablesResult, installationsResult, addonsResult, addonPriceResult] = + await Promise.allSettled([ + projectSdk.projectApi.listVariables({ + queries: [Query.limit(limit), Query.offset(variablesOffset)] + }), + projectSdk.vcs.listInstallations({ + queries: [Query.limit(limit), Query.offset(offset)] + }), + isCloud + ? sdk + .forConsoleIn(params.region) + .projects.listAddons({ projectId: params.project }) + .catch(() => null) + : Promise.resolve(null), + isCloud + ? sdk + .forConsoleIn(params.region) + .projects.getAddonPrice({ + projectId: params.project, + addon: Addon.Premiumgeodb + }) + .catch(() => null) + : Promise.resolve(null) + ]); const variables = variablesResult.status === 'fulfilled' ? variablesResult.value : (() => { - // Read-only users can be blocked from write-adjacent settings APIs. - // Only silence those permission errors so genuine load failures still surface. if (!isReadonlySettingsPermissionError(variablesResult.reason)) { throw variablesResult.reason; } @@ -45,8 +61,6 @@ export const load: PageLoad = async ({ depends, url, params }) => { installationsResult.status === 'fulfilled' ? installationsResult.value : (() => { - // Read-only users can be blocked from write-adjacent settings APIs. - // Only silence those permission errors so genuine load failures still surface. if (!isReadonlySettingsPermissionError(installationsResult.reason)) { throw installationsResult.reason; } @@ -57,11 +71,16 @@ export const load: PageLoad = async ({ depends, url, params }) => { }; })(); + const addons = addonsResult.status === 'fulfilled' ? addonsResult.value : null; + const addonPrice = addonPriceResult.status === 'fulfilled' ? addonPriceResult.value : null; + return { limit, offset, variablesOffset, variables, - installations + installations, + addons, + addonPrice }; }; diff --git a/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.svelte b/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.svelte index b32e4ff1b9..bcbf75a4be 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/domains/add-domain/verify-[domain]/+page.svelte @@ -61,7 +61,7 @@ const apexDomain = getApexDomain(proxyRule.domain); const domain = data.domainsList.domains.find((d) => d.domain === apexDomain); if (isCloud && domain) { - await sdk.forConsole.domains.updateNameservers({ + await sdk.forConsole.domains.verifyNameservers({ domainId: domain.$id }); } diff --git a/src/routes/(console)/project-[region]-[project]/settings/domains/retryDomainModal.svelte b/src/routes/(console)/project-[region]-[project]/settings/domains/retryDomainModal.svelte index 20f895674f..9e2fd2eb05 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/domains/retryDomainModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/domains/retryDomainModal.svelte @@ -57,7 +57,7 @@ const apexDomain = getApexDomain(selectedProxyRule.domain); const domain = domainsList?.domains.find((d) => d.domain === apexDomain); if (isCloud && domain) { - await sdk.forConsole.domains.updateNameservers({ + await sdk.forConsole.domains.verifyNameservers({ domainId: domain.$id }); } diff --git a/src/routes/(console)/project-[region]-[project]/settings/migrations/+page.svelte b/src/routes/(console)/project-[region]-[project]/settings/migrations/+page.svelte index fc54b8ba64..fca01d2357 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/migrations/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/migrations/+page.svelte @@ -14,7 +14,7 @@ import Details from './details.svelte'; import ExportModal from './exportModal.svelte'; import { readOnly } from '$lib/stores/billing'; - import { ID, Scopes, type Models } from '@appwrite.io/console'; + import { ID, ProjectKeyScopes, type Models } from '@appwrite.io/console'; import { canWriteProjects } from '$lib/stores/roles'; import { IconCloud, @@ -92,23 +92,23 @@ keyId: ID.unique(), name: `[AUTO-GENERATED] Migration ${new Date().toISOString()}`, scopes: [ - Scopes.UsersRead, - Scopes.TeamsRead, - Scopes.DatabasesRead, - Scopes.CollectionsRead /* legacy */, - Scopes.AttributesRead /* legacy */, - Scopes.IndexesRead, - Scopes.DocumentsRead /* legacy */, - Scopes.TablesRead, - Scopes.ColumnsRead, - Scopes.RowsRead, - Scopes.FilesRead, - Scopes.BucketsRead, - Scopes.FunctionsRead, - Scopes.ExecutionsRead, - Scopes.LocaleRead, - Scopes.AvatarsRead, - Scopes.HealthRead + ProjectKeyScopes.UsersRead, + ProjectKeyScopes.TeamsRead, + ProjectKeyScopes.DatabasesRead, + ProjectKeyScopes.CollectionsRead /* legacy */, + ProjectKeyScopes.AttributesRead /* legacy */, + ProjectKeyScopes.IndexesRead, + ProjectKeyScopes.DocumentsRead /* legacy */, + ProjectKeyScopes.TablesRead, + ProjectKeyScopes.ColumnsRead, + ProjectKeyScopes.RowsRead, + ProjectKeyScopes.FilesRead, + ProjectKeyScopes.BucketsRead, + ProjectKeyScopes.FunctionsRead, + ProjectKeyScopes.ExecutionsRead, + ProjectKeyScopes.LocaleRead, + ProjectKeyScopes.AvatarsRead, + ProjectKeyScopes.HealthRead ] }); diff --git a/src/routes/(console)/project-[region]-[project]/settings/migrations/exportModal.svelte b/src/routes/(console)/project-[region]-[project]/settings/migrations/exportModal.svelte index e707021275..879d838efc 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/migrations/exportModal.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/migrations/exportModal.svelte @@ -10,7 +10,7 @@ import { sdk } from '$lib/stores/sdk'; import { user } from '$lib/stores/user'; import { organization } from '$lib/stores/organization'; - import { ID, Scopes } from '@appwrite.io/console'; + import { ID, ProjectKeyScopes } from '@appwrite.io/console'; export let show = false; @@ -94,28 +94,28 @@ keyId: ID.unique(), name: `[AUTO-GENERATED] Migration ${new Date().toISOString()}`, scopes: [ - Scopes.UsersRead, - Scopes.TeamsRead, - Scopes.DatabasesRead, - Scopes.CollectionsRead /* legacy */, - Scopes.AttributesRead /* legacy */, - Scopes.IndexesRead, - Scopes.DocumentsRead /* legacy */, - Scopes.TablesRead, - Scopes.ColumnsRead, - Scopes.RowsRead, - Scopes.FilesRead, - Scopes.BucketsRead, - Scopes.FunctionsRead, - Scopes.ExecutionsRead, - Scopes.SitesRead, - Scopes.ProvidersRead, - Scopes.TopicsRead, - Scopes.SubscribersRead, - Scopes.MessagesRead, - Scopes.LocaleRead, - Scopes.AvatarsRead, - Scopes.HealthRead + ProjectKeyScopes.UsersRead, + ProjectKeyScopes.TeamsRead, + ProjectKeyScopes.DatabasesRead, + ProjectKeyScopes.CollectionsRead /* legacy */, + ProjectKeyScopes.AttributesRead /* legacy */, + ProjectKeyScopes.IndexesRead, + ProjectKeyScopes.DocumentsRead /* legacy */, + ProjectKeyScopes.TablesRead, + ProjectKeyScopes.ColumnsRead, + ProjectKeyScopes.RowsRead, + ProjectKeyScopes.FilesRead, + ProjectKeyScopes.BucketsRead, + ProjectKeyScopes.FunctionsRead, + ProjectKeyScopes.ExecutionsRead, + ProjectKeyScopes.SitesRead, + ProjectKeyScopes.ProvidersRead, + ProjectKeyScopes.TopicsRead, + ProjectKeyScopes.SubscribersRead, + ProjectKeyScopes.MessagesRead, + ProjectKeyScopes.LocaleRead, + ProjectKeyScopes.AvatarsRead, + ProjectKeyScopes.HealthRead ] }); diff --git a/src/routes/(console)/project-[region]-[project]/settings/premiumGeoDB.svelte b/src/routes/(console)/project-[region]-[project]/settings/premiumGeoDB.svelte new file mode 100644 index 0000000000..c2124d4289 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/premiumGeoDB.svelte @@ -0,0 +1,280 @@ + + + + Premium Geo DB + Give your project richer location intelligence on every user. Tailor pricing by region, surface the + right currency and language, comply with local regulations, and spot suspicious sign-ins before they + cause damage — all without leaving Appwrite. + + +
+ Premium Geo DB +
+ {#if !planSupportsPremiumGeoDB && canUpgradeToPremiumGeoDB} +

+ Premium Geo DB is not available on your current plan. Upgrade your plan to + enable it. +

+ + {:else if !planSupportsPremiumGeoDB} +

+ Premium Geo DB is not available on your current plan. +

+ {:else if isPending} +
+ +
+

+ A payment is awaiting confirmation. If you've completed authentication, click + refresh to check the payment status. +

+ + {:else if isActive} +
+ {#if isScheduledForRemoval} + + {:else} + + {/if} +
+

+ {#if monthlyPriceLabel} + Premium Geo DB is enabled for this project at {monthlyPriceLabel}/month. + {:else} + Premium Geo DB is enabled for this project. + {/if} +

+ {#if isScheduledForRemoval} +

+ Premium Geo DB will be removed at the end of your current billing cycle. +

+ + {:else} + + {/if} + {:else} +

+ Enable Premium Geo DB for this project to collect detailed geolocation data on + every request.{#if monthlyPriceLabel} + This addon costs {monthlyPriceLabel}/month, prorated for your current + billing cycle. + {:else} + Billed prorated for your current cycle. + {/if} +

+ + {/if} +
+
+
+ + + +{#if premiumGeoDBAddon} + +{/if} diff --git a/src/routes/(console)/project-[region]-[project]/settings/premiumGeoDBDisableModal.svelte b/src/routes/(console)/project-[region]-[project]/settings/premiumGeoDBDisableModal.svelte new file mode 100644 index 0000000000..98a36efec6 --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/premiumGeoDBDisableModal.svelte @@ -0,0 +1,54 @@ + + + +

+ Are you sure you want to disable the Premium Geo DB addon? The addon will remain active + until the end of your current billing cycle and will not be renewed. +

+ + + + + +
diff --git a/src/routes/(console)/project-[region]-[project]/settings/premiumGeoDBEnableModal.svelte b/src/routes/(console)/project-[region]-[project]/settings/premiumGeoDBEnableModal.svelte new file mode 100644 index 0000000000..4fb52a373b --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/premiumGeoDBEnableModal.svelte @@ -0,0 +1,195 @@ + + + + {#if addonPrice} +

+ By clicking Enable, the amount of + {formatCurrency(addonPrice.monthlyPrice)} will be added to your subscription and + your payment method will be charged + {formatCurrency(addonPrice.proratedAmount)} immediately for the remaining days in your + billing cycle. +

+ {:else} +

+ By clicking Enable, your payment method will be charged for the prorated amount + for the remaining days in your billing cycle, and the addon will be added to this + project's subscription for future cycles. +

+ {/if} +

+ Premium Geo DB enriches session and request data with premium geolocation details including + timezone, postal code, ISP, connection type, and organization. +

+ + {#if addonPrice} +
+
+ {addonPrice.name} + {formatCurrency(addonPrice.monthlyPrice)} / month +
+
+
+ Due today (prorated) + {formatCurrency(addonPrice.proratedAmount)} +
+

+ * Plus applicable tax and fees +

+
+ {/if} + + + + + +
+ + diff --git a/src/routes/(console)/project-[region]-[project]/settings/smtp/+page.svelte b/src/routes/(console)/project-[region]-[project]/settings/smtp/+page.svelte index 8fec9ffdab..6c48a2ce7c 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/smtp/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/smtp/+page.svelte @@ -12,7 +12,7 @@ import { resolve } from '$app/paths'; import deepEqual from 'deep-equal'; import { currentPlan } from '$lib/stores/organization'; - import { type Secure } from '@appwrite.io/console'; + import { type ProjectSMTPSecure } from '@appwrite.io/console'; import InputSelect from '$lib/elements/forms/inputSelect.svelte'; import { getChangePlanUrl } from '$lib/stores/billing'; import { Link, Selector, Alert } from '@appwrite.io/pink-svelte'; @@ -21,7 +21,7 @@ const { data }: PageProps = $props(); - const { project } = data; + const project = $derived(data.project); let enabled: boolean = $state(false); @@ -44,31 +44,35 @@ { value: '', label: 'None' } ]; + function normalizeSecure(v: string): string { + return v === 'tls' || v === 'ssl' ? v : ''; + } + const isButtonDisabled = $derived.by(() => { return deepEqual( { enabled, - senderName, - senderEmail, - replyToEmail, - replyToName, - host, - port: port ?? '', - username, - password, + senderName: senderName ?? '', + senderEmail: senderEmail ?? '', + replyToEmail: replyToEmail ?? '', + replyToName: replyToName ?? '', + host: host ?? '', + port: port ?? null, + username: username ?? '', + password: password ?? '', secure }, { - enabled: project.smtpEnabled, - senderName: project.smtpSenderName, - senderEmail: project.smtpSenderEmail, - replyToEmail: project.smtpReplyToEmail, - replyToName: project.smtpReplyToName, - host: project.smtpHost, - port: project.smtpPort, - username: project.smtpUsername, - password: project.smtpPassword, - secure: project.smtpSecure + enabled: project.smtpEnabled ?? false, + senderName: project.smtpSenderName ?? '', + senderEmail: project.smtpSenderEmail ?? '', + replyToEmail: project.smtpReplyToEmail ?? '', + replyToName: project.smtpReplyToName ?? '', + host: project.smtpHost ?? '', + port: project.smtpPort ?? null, + username: project.smtpUsername ?? '', + password: project.smtpPassword ?? '', + secure: normalizeSecure(project.smtpSecure ?? '') } ); }); @@ -77,15 +81,15 @@ try { await sdk.forProject(project.region, project.$id).project.updateSMTP({ enabled, - senderName: senderName || undefined, - senderEmail: senderEmail || undefined, - replyToEmail: replyToEmail || undefined, - replyToName: replyToName || undefined, - host: host || undefined, - port: port || undefined, - username: username || undefined, - password: password || undefined, - secure: secure ? (secure as Secure) : undefined + senderName: senderName ?? undefined, + senderEmail: senderEmail ?? undefined, + replyToEmail: replyToEmail ?? undefined, + replyToName: replyToName ?? undefined, + host: host ?? undefined, + port: port ?? undefined, + username: username ?? undefined, + password: password ?? undefined, + secure: secure ? (secure as ProjectSMTPSecure) : undefined }); invalidate(Dependencies.PROJECT); @@ -105,29 +109,15 @@ $effect(() => { enabled = project.smtpEnabled ?? false; - senderName = project.smtpSenderName; - senderEmail = project.smtpSenderEmail; - replyToEmail = project.smtpReplyToEmail; - replyToName = project.smtpReplyToName; - host = project.smtpHost; - port = project.smtpPort; - username = project.smtpUsername; - password = project.smtpPassword; - secure = project.smtpSecure === 'tls' ? 'tls' : project.smtpSecure === 'ssl' ? 'ssl' : ''; - }); - - $effect(() => { - if (!enabled) { - senderName = ''; - senderEmail = ''; - replyToEmail = ''; - replyToName = ''; - host = ''; - port = null; - username = ''; - password = ''; - secure = ''; - } + senderName = project.smtpSenderName ?? ''; + senderEmail = project.smtpSenderEmail ?? ''; + replyToEmail = project.smtpReplyToEmail ?? ''; + replyToName = project.smtpReplyToName ?? ''; + host = project.smtpHost ?? ''; + port = project.smtpPort ?? null; + username = project.smtpUsername ?? ''; + password = project.smtpPassword ?? ''; + secure = normalizeSecure(project.smtpSecure ?? ''); }); @@ -212,7 +202,7 @@ placeholder="Enter password" /> diff --git a/src/routes/(console)/project-[region]-[project]/settings/updateName.svelte b/src/routes/(console)/project-[region]-[project]/settings/updateName.svelte index 4db3c2cf3b..a727870098 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/updateName.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/updateName.svelte @@ -21,7 +21,7 @@ async function updateName() { try { - await sdk.forConsole.projects.update({ + await sdk.forConsole.organization($project.teamId).updateProject({ projectId: $project.$id, name }); diff --git a/src/routes/(console)/project-[region]-[project]/settings/updateOAuth2Server.svelte b/src/routes/(console)/project-[region]-[project]/settings/updateOAuth2Server.svelte new file mode 100644 index 0000000000..b37b32daaf --- /dev/null +++ b/src/routes/(console)/project-[region]-[project]/settings/updateOAuth2Server.svelte @@ -0,0 +1,296 @@ + + +
+ + OAuth2 server + Configure your project as an OAuth2 authorization server. When enabled, external applications + can authenticate users through your project using the OAuth2 protocol. + + + + {#if enabled} + + + + The consent screen URL shown to users during the OAuth2 authorization + flow. + + + + + + + OAuth2 scopes this server will accept. Up to 100 scopes, each up to 128 + characters long. + + + + + + + Confidential clients + + Server-side apps that authenticate with a client secret. + + + +
+ + +
+ +
+ + +
+ + + + + + + Public clients + + SPAs, mobile, and native apps that cannot keep a client secret. + + + +
+ + +
+ +
+ + +
+ {/if} +
+ + + +
+ + + diff --git a/src/routes/(console)/project-[region]-[project]/settings/updateProtocols.svelte b/src/routes/(console)/project-[region]-[project]/settings/updateProtocols.svelte index 52f607ee93..133fa568e5 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/updateProtocols.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/updateProtocols.svelte @@ -11,18 +11,18 @@ import Button from '$lib/elements/forms/button.svelte'; import { Dialog, Divider, Layout, Spinner } from '@appwrite.io/pink-svelte'; import { SvelteSet } from 'svelte/reactivity'; - import { ProtocolId } from '@appwrite.io/console'; + import { ProjectProtocolId } from '@appwrite.io/console'; import { get } from 'svelte/store'; import { canWriteProjects } from '$lib/stores/roles'; let isUpdatingAllProtocols = $state(false); let showUpdateProtocolDialog = $state(false); let updateProtocolsEnabledMode = $state(null); - let apiProtocolUpdates = new SvelteSet(); - const protocolDescriptions: Record = { - [ProtocolId.Rest]: 'Standard HTTP API requests from client SDKs.', - [ProtocolId.Graphql]: 'GraphQL API access for queries and mutations.', - [ProtocolId.Websocket]: 'Realtime subscriptions over WebSocket connections.' + let apiProtocolUpdates = new SvelteSet(); + const protocolDescriptions: Record = { + [ProjectProtocolId.Rest]: 'Standard HTTP API requests from client SDKs.', + [ProjectProtocolId.Graphql]: 'GraphQL API access for queries and mutations.', + [ProjectProtocolId.Websocket]: 'Realtime subscriptions over WebSocket connections.' }; const isAnyProtocolUpdating = $derived(apiProtocolUpdates.size > 0); const isAnyUpdateInProgress = $derived(isUpdatingAllProtocols || isAnyProtocolUpdating); diff --git a/src/routes/(console)/project-[region]-[project]/settings/updateServices.svelte b/src/routes/(console)/project-[region]-[project]/settings/updateServices.svelte index 8a262f66df..4fd64ca71e 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/updateServices.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/updateServices.svelte @@ -10,7 +10,7 @@ import { project } from '../store'; import Button from '$lib/elements/forms/button.svelte'; import { Dialog, Divider, Layout, Spinner } from '@appwrite.io/pink-svelte'; - import type { ServiceId } from '@appwrite.io/console'; + import type { ProjectServiceId } from '@appwrite.io/console'; import { get } from 'svelte/store'; import { SvelteSet } from 'svelte/reactivity'; @@ -20,7 +20,7 @@ let showUpdateServiceDialog = $state(false); let updateServicesEnabledMode = $state(null); - let apiServiceUpdates = new SvelteSet(); + let apiServiceUpdates = new SvelteSet(); const isAnyServiceUpdating = $derived(apiServiceUpdates.size > 0); const isAnyUpdateInProgress = $derived(isUpdatingAllServices || isAnyServiceUpdating); diff --git a/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.svelte b/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.svelte index b6d5350784..86f229c05b 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.svelte @@ -12,7 +12,7 @@ import { bytesToSize, humanFileSize, mbSecondsToGBHours } from '$lib/helpers/sizeConvertion'; import { BarChart, Legend } from '$lib/charts'; import { formatNum } from '$lib/helpers/string'; - import { total } from '$lib/layout/usage.svelte'; + import { total } from '$lib/layout/usageHelpers'; import { base } from '$app/paths'; import { formatCurrency, formatNumberWithCommas, clampMin } from '$lib/helpers/numbers'; import { getCountryName } from '$lib/helpers/diallingCodes.js'; @@ -49,11 +49,11 @@ $: legendData = [ { name: 'Reads', - value: clampMin(data.usage.databasesReads.reduce((sum, item) => sum + item.value, 0)) + value: clampMin((dbReads ?? []).reduce((sum, item) => sum + item.value, 0)) }, { name: 'Writes', - value: clampMin(data.usage.databasesWrites.reduce((sum, item) => sum + item.value, 0)) + value: clampMin((dbWrites ?? []).reduce((sum, item) => sum + item.value, 0)) } ]; @@ -196,11 +196,11 @@ series={[ { name: 'Reads', - data: [...dbReads.map((e) => [e.date, e.value])] + data: [...(dbReads ?? []).map((e) => [e.date, e.value])] }, { name: 'Writes', - data: [...dbWrites.map((e) => [e.date, e.value])] + data: [...(dbWrites ?? []).map((e) => [e.date, e.value])] } ]} /> @@ -321,13 +321,13 @@ data: [...executions.map((e) => [e.date, e.value])] } ]} /> - {#if data.usage.executionsBreakdown.length > 0} + {#if data.executionsBreakdown?.length > 0} Function Usage - {#each data.usage.executionsBreakdown as func} + {#each data.executionsBreakdown as func} @@ -579,7 +579,7 @@

- {#if data.usage.authPhoneCountryBreakdown.length > 0} + {#if data.usage.authPhoneCountryBreakdown?.length > 0} diff --git a/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.ts b/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.ts index 0efb7c6020..3a365a155e 100644 --- a/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.ts +++ b/src/routes/(console)/project-[region]-[project]/settings/usage/[[invoice]]/+page.ts @@ -1,6 +1,7 @@ import { sdk } from '$lib/stores/sdk'; +import { Submit, trackError } from '$lib/actions/analytics'; import type { PageLoad } from './$types'; -import { accumulateUsage } from '$lib/sdk/usage'; +import { accumulateUsage, listExecutionsBreakdown, type ExecutionsBreakdown } from '$lib/sdk/usage'; import { type Models, Query } from '@appwrite.io/console'; export const load: PageLoad = async ({ params, parent }) => { @@ -35,12 +36,19 @@ export const load: PageLoad = async ({ params, parent }) => { } } - const [invoices, usage] = await Promise.all([ + const [invoices, usage, executionsBreakdown] = await Promise.all([ sdk.forConsole.organizations.listInvoices({ organizationId: organization.$id, queries: [Query.orderDesc('from')] }), - sdk.forProject(region, project).project.getUsage({ startDate, endDate }) + sdk.forProject(region, project).project.getUsage({ startDate, endDate }), + listExecutionsBreakdown(region, project, startDate, endDate).catch( + (error): ExecutionsBreakdown[] => { + // supplementary to the executions chart, so never fail the page for it + trackError(error, Submit.ProjectUsageExecutionsBreakdown); + return []; + } + ) ]); if (currentAggregation) { @@ -70,6 +78,7 @@ export const load: PageLoad = async ({ params, parent }) => { usage, invoices, currentInvoice, - currentAggregation + currentAggregation, + executionsBreakdown }; }; diff --git a/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte b/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte index c0190429db..d3b6e657fa 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/(components)/deploymentActionMenu.svelte @@ -17,6 +17,7 @@ import { ActionMenu, Icon, Tooltip } from '@appwrite.io/pink-svelte'; import { getEffectiveBuildStatus } from '$lib/helpers/buildTimeout'; import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; + import { impersonatedResourceUrl } from '$lib/appwrite/impersonation'; export let selectedDeployment: Models.Deployment; export let deployment: Models.Deployment; @@ -28,21 +29,23 @@ export let inCard = false; function getOutputDownload(deploymentId: string) { - return ( + return $impersonatedResourceUrl( sdk.forProject(page.params.region, page.params.project).sites.getDeploymentDownload({ siteId: page.params.site, deploymentId: deploymentId, type: DeploymentDownloadType.Output - }) + '&mode=admin' + }), + { mode: 'admin' } ); } function getSourceDownload(deploymentId: string) { - return ( + return $impersonatedResourceUrl( sdk.forProject(page.params.region, page.params.project).sites.getDeploymentDownload({ siteId: page.params.site, deploymentId: deploymentId, type: DeploymentDownloadType.Source - }) + '&mode=admin' + }), + { mode: 'admin' } ); } diff --git a/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte b/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte index f852159000..294027c171 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/(components)/siteCard.svelte @@ -27,6 +27,7 @@ import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; import { regionalProtocol } from '$routes/(console)/project-[region]-[project]/store'; import type { Snippet } from 'svelte'; + import { impersonatedResourceUrl } from '$lib/appwrite/impersonation'; let { site, @@ -71,13 +72,15 @@ } function getFilePreview(fileId: string) { - return sdk.forConsoleIn(page.params.region).storage.getFilePreview({ - bucketId: 'screenshots', - fileId, - width: 1024, - height: 576, - output: ImageFormat.Avif - }); + return $impersonatedResourceUrl( + sdk.forConsoleIn(page.params.region).storage.getFilePreview({ + bucketId: 'screenshots', + fileId, + width: 1024, + height: 576, + output: ImageFormat.Avif + }) + ); } diff --git a/src/routes/(console)/project-[region]-[project]/sites/create-site/configuration.svelte b/src/routes/(console)/project-[region]-[project]/sites/create-site/configuration.svelte index f6d8129d64..73e1eea7c5 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/create-site/configuration.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/create-site/configuration.svelte @@ -3,16 +3,15 @@ import { Fieldset, Layout, Accordion } from '@appwrite.io/pink-svelte'; import type { Models } from '@appwrite.io/console'; import { iconPath } from '$lib/stores/app'; - import { getFrameworkIcon, type FrameworkAdapterWithStartCommand } from '$lib/stores/sites'; + import { getFrameworkIcon } from '$lib/stores/sites'; import { EnvironmentVariables } from '$lib/components/variables'; export let frameworks: Models.Framework[]; export let selectedFramework: Models.Framework; $: frameworkData = frameworks.find((framework) => framework.key === selectedFramework?.key); - $: adapterData = (frameworkData?.adapters.find((adapter) => adapter.key === 'ssr') ?? - frameworkData?.adapters.find( - (adapter) => adapter.key === 'static' - )) as FrameworkAdapterWithStartCommand; + $: adapterData = + frameworkData?.adapters.find((adapter) => adapter.key === 'ssr') ?? + frameworkData?.adapters.find((adapter) => adapter.key === 'static'); export let variables: Partial[] = []; export let isLoading = false; @@ -28,8 +27,8 @@ $: if (frameworkData && adapterDefaultsKey !== lastAdapterDefaultsKey) { installCommand = adapterData?.installCommand ?? ''; buildCommand = adapterData?.buildCommand ?? ''; - startCommand = adapterData?.startCommand ?? ''; outputDirectory = adapterData?.outputDirectory ?? ''; + startCommand = ''; lastAdapterDefaultsKey = adapterDefaultsKey; } @@ -92,16 +91,7 @@ id="startCommand" label="Start command" bind:value={startCommand} - placeholder={adapterData?.startCommand || - 'Enter start command'} /> - + placeholder="Enter start command" /> {/if} diff --git a/src/routes/(console)/project-[region]-[project]/sites/create-site/deploy/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/create-site/deploy/+page.svelte index fa75d27942..79c4c28f0f 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/create-site/deploy/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/create-site/deploy/+page.svelte @@ -27,7 +27,7 @@ import { writable } from 'svelte/store'; import { getLatestTag } from '$lib/helpers/github'; import Link from '$lib/elements/link.svelte'; - import type { FrameworkAdapterWithStartCommand } from '$lib/stores/sites'; + import { validateVariables } from '$lib/helpers/variables'; let { data @@ -94,7 +94,6 @@ const adapter = fw.adapters[0]; installCommand = adapter.installCommand || ''; buildCommand = adapter.buildCommand || ''; - startCommand = (adapter as FrameworkAdapterWithStartCommand).startCommand || ''; outputDirectory = adapter.outputDirectory || ''; } } @@ -124,7 +123,6 @@ const adapter = fw.adapters[0]; installCommand = adapter.installCommand || ''; buildCommand = adapter.buildCommand || ''; - startCommand = (adapter as FrameworkAdapterWithStartCommand).startCommand || ''; outputDirectory = adapter.outputDirectory || ''; } } @@ -147,6 +145,13 @@ $isSubmitting = true; try { + // Reject an unusable key before the resource is created, so a + // rejected variable can't leave a half-configured resource behind. + const validationError = validateVariables(variables); + if (validationError) { + throw new Error(validationError); + } + // Create site with build configuration let site = await sdk.forProject(page.params.region, page.params.project).sites.create({ siteId: id || ID.unique(), @@ -264,7 +269,8 @@ label="Framework" placeholder="Select framework" bind:value={framework} - options={frameworkSelectOptions} /> + options={frameworkSelectOptions} + on:change={() => (startCommand = '')} /> diff --git a/src/routes/(console)/project-[region]-[project]/sites/create-site/manual/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/create-site/manual/+page.svelte index f2da210d04..46dc627892 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/create-site/manual/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/create-site/manual/+page.svelte @@ -26,7 +26,7 @@ import { currentPlan } from '$lib/stores/organization'; import Domain from '../domain.svelte'; import { uploader } from '$lib/stores/uploader'; - import type { FrameworkAdapterWithStartCommand } from '$lib/stores/sites'; + import { validateVariables } from '$lib/helpers/variables'; export let data; let showExitModal = false; @@ -41,10 +41,10 @@ let framework: Models.Framework = data.frameworks.frameworks?.find((f) => f.key === 'other') ?? data.frameworks.frameworks?.[0]; - let adapter = framework?.adapters[0] as FrameworkAdapterWithStartCommand; + let adapter = framework?.adapters[0]; let installCommand = adapter?.installCommand; let buildCommand = adapter?.buildCommand; - let startCommand = adapter?.startCommand; + let startCommand = ''; let outputDirectory = adapter?.outputDirectory; let variables: Partial[] = []; let files: FileList; @@ -60,6 +60,13 @@ let site: Models.Site | null = null; try { + // Reject an unusable key before the resource is created, so a + // rejected variable can't leave a half-configured resource behind. + const validationError = validateVariables(variables); + if (validationError) { + throw new Error(validationError); + } + if (!domainIsValid) { addNotification({ type: 'error', diff --git a/src/routes/(console)/project-[region]-[project]/sites/create-site/repositories/repository-[repository]/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/create-site/repositories/repository-[repository]/+page.svelte index aca5fe7bb3..aa0f25a0c9 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/create-site/repositories/repository-[repository]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/create-site/repositories/repository-[repository]/+page.svelte @@ -27,8 +27,11 @@ import Configuration from '../../configuration.svelte'; import Domain from '../../domain.svelte'; import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; - import { normalizeDetectedVariables, mergeVariables } from '$lib/helpers/variables'; - import type { FrameworkAdapterWithStartCommand } from '$lib/stores/sites'; + import { + normalizeDetectedVariables, + mergeVariables, + validateVariables + } from '$lib/helpers/variables'; export let data; let showExitModal = false; @@ -39,12 +42,12 @@ let name = ''; let id = ID.unique(); let framework: Models.Framework = data.frameworks.frameworks.find((f) => f.key === 'other'); - let adapter = framework?.adapters[0] as FrameworkAdapterWithStartCommand; + let adapter = framework?.adapters[0]; let branch: string; let rootDir = './'; let installCommand = adapter?.installCommand; let buildCommand = adapter?.buildCommand; - let startCommand = adapter?.startCommand; + let startCommand = ''; let outputDirectory = adapter?.outputDirectory; let variables: Partial[] = []; let silentMode = false; @@ -83,10 +86,9 @@ if (!framework) { framework = data.frameworks.frameworks.find((f) => f.key === 'other'); } - adapter = framework?.adapters[0] as FrameworkAdapterWithStartCommand; + adapter = framework?.adapters[0]; installCommand = adapter?.installCommand; buildCommand = adapter?.buildCommand; - startCommand = adapter?.startCommand; outputDirectory = adapter?.outputDirectory; const detectedVariables = normalizeDetectedVariables(response?.variables); if (detectedVariables.length) { @@ -113,6 +115,13 @@ return; } try { + // Reject an unusable key before the resource is created, so a + // rejected variable can't leave a half-configured resource behind. + const validationError = validateVariables(variables); + if (validationError) { + throw new Error(validationError); + } + const fr = Object.values(Framework).find((f) => f === framework.key); const buildRuntime = Object.values(BuildRuntime).find( (f) => f === framework.buildRuntime diff --git a/src/routes/(console)/project-[region]-[project]/sites/create-site/templates/template-[template]/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/create-site/templates/template-[template]/+page.svelte index a11121d55c..006003d846 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/create-site/templates/template-[template]/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/create-site/templates/template-[template]/+page.svelte @@ -45,6 +45,7 @@ import { getFrameworkIcon } from '$lib/stores/sites'; import { regionalConsoleVariables } from '$routes/(console)/project-[region]-[project]/store'; import { getTemplateSourceUrl } from '$lib/helpers/templateSource'; + import { validateVariables } from '$lib/helpers/variables'; export let data; @@ -117,6 +118,15 @@ return; } else { try { + // Reject an unusable key before the resource is created, so a + // rejected variable can't leave a half-configured resource behind. + const validationError = validateVariables( + variables.map((variable) => ({ key: variable.name, value: variable.value })) + ); + if (validationError) { + throw new Error(validationError); + } + const fr = Object.values(Framework).find((f) => f === framework.key); const buildRuntime = Object.values(BuildRuntime).find( (f) => f === framework.buildRuntime diff --git a/src/routes/(console)/project-[region]-[project]/sites/grid.svelte b/src/routes/(console)/project-[region]-[project]/sites/grid.svelte index 99029389ea..704c20a165 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/grid.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/grid.svelte @@ -14,6 +14,7 @@ import { IconExclamation } from '@appwrite.io/pink-icons-svelte'; import { Link } from '$lib/elements'; import { getFrameworkIcon } from '$lib/stores/sites'; + import { impersonatedResourceUrl } from '$lib/appwrite/impersonation'; export let siteList: Models.SiteList; @@ -33,13 +34,15 @@ } function getFilePreview(fileId: string) { - return sdk.forConsoleIn(page.params.region).storage.getFilePreview({ - bucketId: 'screenshots', - fileId, - width: 1024, - height: 576, - output: ImageFormat.Avif - }); + return $impersonatedResourceUrl( + sdk.forConsoleIn(page.params.region).storage.getFilePreview({ + bucketId: 'screenshots', + fileId, + width: 1024, + height: 576, + output: ImageFormat.Avif + }) + ); } diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/+layout.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/+layout.svelte index 64a7454fa3..a0452b110d 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/+layout.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/+layout.svelte @@ -90,18 +90,6 @@ rank: 10, disabled: page.url.pathname.endsWith('deployments') }, - { - label: 'Go to usage', - callback() { - goto( - `${base}/project-${$project.region}-${$project.$id}/sites/site-${page.params.site}/usage` - ); - }, - keys: ['g', 'u'], - group: 'navigation', - rank: 10, - disabled: page.url.pathname.endsWith('usage') - }, { label: 'Go to logs', callback() { diff --git a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/+page.svelte b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/+page.svelte index fb7bcb49f9..d922137577 100644 --- a/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/+page.svelte +++ b/src/routes/(console)/project-[region]-[project]/sites/site-[site]/deployments/+page.svelte @@ -2,7 +2,7 @@ import { PaginationWithLimit, EmptyFilter, Empty } from '$lib/components'; import { Button } from '$lib/elements/forms'; import { Container, ResponsiveContainerHeader } from '$lib/layout'; - import { Adapter, BuildRuntime, Framework, type Models } from '@appwrite.io/console'; + import { Adapter, BuildRuntime, Framework, Query, type Models } from '@appwrite.io/console'; import { View } from '$lib/helpers/load'; import { ActionMenu, Alert, Icon, Layout, Popover } from '@appwrite.io/pink-svelte'; import Table from './table.svelte'; @@ -10,7 +10,6 @@ import CreateGitDeploymentModal from './createGitDeploymentModal.svelte'; import { columns } from './store'; import CreateManualDeploymentModal from './createManualDeploymentModal.svelte'; - import DeploymentMetrics from './deploymentMetrics.svelte'; import { IconPlus } from '@appwrite.io/pink-icons-svelte'; import { onMount } from 'svelte'; import { realtime, sdk } from '$lib/stores/sdk'; @@ -43,13 +42,22 @@ async function connect(selectedInstallationId: string, selectedRepository: string) { let nextBranch = data.site?.providerBranch ?? 'main'; try { - const branchList = await sdk - .forProject(page.params.region, page.params.project) - .vcs.listRepositoryBranches({ - installationId: selectedInstallationId, - providerRepositoryId: selectedRepository - }); - const sorted = sortBranches(branchList.branches); + const allBranches = []; + let offset = 0; + const limit = 100; + while (true) { + const { branches, total } = await sdk + .forProject(page.params.region, page.params.project) + .vcs.listRepositoryBranches({ + installationId: selectedInstallationId, + providerRepositoryId: selectedRepository, + queries: [Query.limit(limit), Query.offset(offset)] + }); + allBranches.push(...branches); + if (allBranches.length >= total || branches.length < limit) break; + offset += limit; + } + const sorted = sortBranches(allBranches); nextBranch = sorted.find((branch) => branch.name === data.site?.providerBranch)?.name ?? sorted.find((branch) => branch.name === 'main' || branch.name === 'master')?.name ?? @@ -114,8 +122,6 @@ {/if} {/if} - - b.name === site.providerBranch) - ? site.providerBranch - : (sorted[0]?.name ?? null); - - if (!branch) { - branch = 'main'; - } - return sorted; + branch = site.providerBranch || 'main'; } catch { return; } @@ -85,8 +69,8 @@ siteId: site.$id, name: site.name, framework: site.framework as Framework, - enabled: site.enabled || undefined, - logging: site.logging || undefined, + enabled: site.enabled ?? undefined, + logging: site.logging ?? undefined, timeout: site.timeout || undefined, installCommand: site.installCommand || undefined, buildCommand: site.buildCommand || undefined, @@ -98,8 +82,9 @@ installationId: $installation.$id || undefined, providerRepositoryId: selectedRepository || undefined, providerBranch: branch || undefined, - providerSilentMode: site.providerSilentMode || undefined, - providerRootDirectory: site.providerRootDirectory || undefined + providerSilentMode: site.providerSilentMode ?? undefined, + providerRootDirectory: site.providerRootDirectory || undefined, + deploymentRetention: site.deploymentRetention ?? undefined }); } if (commit) { @@ -167,18 +152,7 @@ - {:then branches} - {@const options = - branches - ?.map((branch) => { - return { - value: branch.name, - label: branch.name - }; - }) - ?.sort((a, b) => { - return a.label > b.label ? 1 : -1; - }) ?? []} + {:then} - { - branch = event.detail.value; - }} - {options} /> + branch = event.detail; + }} /> - {seo.title} - - - -
-
-

- {title} - -

- -
-
- {#if variant === 'owner'} -

Share your card

- {:else if variant === 'external'} -

Share card

- {/if} - {#if variant === 'external'} - Claim your card - {/if} -
-
- The front of the card -
    -
  • - - - Tweet it - -
  • - {#if variant === 'owner'} -
  • - -
  • - {/if} -
  • - -
  • -
- -
-
- {#if !cardActive} -
- -
- {/if} - {#if browser} - - {/if} -
- {#if cardActive} -
(cardActive = false)} - on:keydown={() => { - /* no-op */ - }} - transition:fade - role="button" - tabindex="0"> -
- {/if} -
- -
-
- - -
- -
- - - -
- - diff --git a/src/routes/(public)/card/[uid]/+page.ts b/src/routes/(public)/card/[uid]/+page.ts deleted file mode 100644 index 86bc963642..0000000000 --- a/src/routes/(public)/card/[uid]/+page.ts +++ /dev/null @@ -1,57 +0,0 @@ -import { getApiEndpoint } from '$lib/stores/sdk'; -import { redirect } from '@sveltejs/kit'; - -function getCardImgUrls(userId: string, endpoint: string) { - const resolved = endpoint; - - const frontImg = `${resolved}/cards/cloud?userId=${userId}`; - const backImg = `${resolved}/cards/cloud-back?userId=${userId}`; - const ogImg = `${resolved}/cards/cloud-og?userId=${userId}`; - - return { frontImg, backImg, ogImg }; -} - -async function urlContentToDataUri(url: string): Promise { - const res = await fetch(url); - const blob = await res.blob(); - - return await new Promise((callback) => { - const reader = new FileReader(); - reader.onload = function () { - if (typeof this.result !== 'string') return ''; - callback(this.result); - }; - reader.readAsDataURL(blob); - }); -} - -export async function load({ params, parent }) { - const { account } = await parent(); - const endpoint = getApiEndpoint(); - const userId = params.uid; - const { frontImg, backImg } = getCardImgUrls(userId, endpoint); - - try { - const res = await fetch(frontImg); - - if (!res.ok) { - redirect(303, '/'); - } - - return { - userId: params.uid, - base64: { - front: await urlContentToDataUri(frontImg), - back: await urlContentToDataUri(backImg) - }, - isOwner: account && account.$id === userId, - imgUrls: { - frontImg, - backImg - } - }; - } catch (e) { - console.error(e); - redirect(303, '/'); - } -} diff --git a/src/routes/(public)/card/helpers.ts b/src/routes/(public)/card/helpers.ts deleted file mode 100644 index 7b3e292f90..0000000000 --- a/src/routes/(public)/card/helpers.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { getApiEndpoint } from '$lib/stores/sdk'; - -export function getCardImgUrls(userId: string, endpoint: string) { - const resolved = endpoint; - - const frontImg = `${resolved}/cards/cloud?userId=${userId}`; - const backImg = `${resolved}/cards/cloud-back?userId=${userId}`; - const ogImg = `${resolved}/cards/cloud-og?userId=${userId}`; - - return { frontImg, backImg, ogImg }; -} - -export function getCampaignImageUrl(image: string) { - const endpoint = getApiEndpoint(); - const url = new URL(image, endpoint); - return url.toString(); -} diff --git a/src/routes/(public)/functions/deploy/+page.svelte b/src/routes/(public)/functions/deploy/+page.svelte index 53ba37ece0..f548edfe61 100644 --- a/src/routes/(public)/functions/deploy/+page.svelte +++ b/src/routes/(public)/functions/deploy/+page.svelte @@ -42,7 +42,7 @@ async function fetchProjects() { loadingProjects = true; - projects = await sdk.forConsole.projects.list({ + projects = await sdk.forConsole.organization(selectedOrg).listProjects({ queries: [ Query.equal('teamId', selectedOrg), Query.orderDesc(''), @@ -58,10 +58,9 @@ if (selectedProject === null) { try { loadingProjects = true; - const project = await sdk.forConsole.projects.create({ + const project = await sdk.forConsole.organization(selectedOrg).createProject({ projectId: id ?? ID.unique(), name: projectName, - teamId: selectedOrg, region: isCloud ? (region as Region) : undefined }); diff --git a/src/routes/(public)/oauth2/+layout.svelte b/src/routes/(public)/oauth2/+layout.svelte new file mode 100644 index 0000000000..5486d5be35 --- /dev/null +++ b/src/routes/(public)/oauth2/+layout.svelte @@ -0,0 +1,69 @@ + + +
+
+
+ +
+
+
+ POWERED BY + {#if $app.themeInUse === 'dark'} + Appwrite Logo + {:else} + Appwrite Logo + {/if} +
+
+ + diff --git a/src/routes/(public)/oauth2/consent-card.svelte b/src/routes/(public)/oauth2/consent-card.svelte new file mode 100644 index 0000000000..583e2a8c07 --- /dev/null +++ b/src/routes/(public)/oauth2/consent-card.svelte @@ -0,0 +1,1520 @@ + + +{#snippet editorGroup( + tierKey: 'project' | 'organization', + heading: string, + note: string, + rows: EditorRow[], + selection: TierSelection +)} + {#if rows.length > 0} +
+
+
+ + +
+ {note} +
+ {#if tierPermissionsOpen(tierKey)} +
    + {#each rows as row (row.resource)} + {@const state = rowState(selection, row.resource)} +
  • + + + + {row.title} + {#if row.hasRead && row.hasWrite} + + + + + {:else} + + {row.access} + + {/if} + + {#if row.description} + {row.description} + {/if} + +
  • + {/each} +
+ {/if} +
+ {/if} +{/snippet} + + + + + + diff --git a/src/routes/(public)/oauth2/consent/+page.svelte b/src/routes/(public)/oauth2/consent/+page.svelte new file mode 100644 index 0000000000..0599bd277e --- /dev/null +++ b/src/routes/(public)/oauth2/consent/+page.svelte @@ -0,0 +1,378 @@ + + + + Authorize application - Appwrite + + + + + diff --git a/src/routes/(public)/oauth2/device/+page.svelte b/src/routes/(public)/oauth2/device/+page.svelte new file mode 100644 index 0000000000..15e0c43c03 --- /dev/null +++ b/src/routes/(public)/oauth2/device/+page.svelte @@ -0,0 +1,283 @@ + + + + Connect a device - Appwrite + + +
+
+ {#if phase === 'loading'} +
+ +
+ {:else if phase === 'enter-code'} + +
+ + +
+ +
+ + + {hasPrefilledCode ? 'Confirm your code' : 'Connect a device'} + + + {hasPrefilledCode + ? 'Make sure this matches the code shown on your device, then continue.' + : 'Enter the code shown on your device to continue.'} + + +
+ + + + { + code = normalizeUserCode(e.currentTarget.value); + error = null; + }} + placeholder="XXXXXXXX" + autofocus + autocomplete="off" + autocapitalize="characters" + spellcheck="false" + maxlength={12} + disabled={submitting} + class="code-input" /> + {#if error} + + {error} + + {/if} + + + + + {#if account} + + Signed in as + {account.email || account.name}. + + {/if} +
+ +
+ {:else if phase === 'consent' && grant && app} + + {:else if phase === 'approved' || phase === 'denied'} + + {/if} +
+
+ + diff --git a/src/routes/(public)/oauth2/errors.ts b/src/routes/(public)/oauth2/errors.ts new file mode 100644 index 0000000000..c91075e574 --- /dev/null +++ b/src/routes/(public)/oauth2/errors.ts @@ -0,0 +1,18 @@ +/** + * Exception `type` values returned by the OAuth2 endpoints. The SDK does not + * export these, so they are mirrored here. + */ +export const OAuth2ErrorType = { + /** + * Covers every dead request_uri handle case (expired, consumed, malformed). + */ + INVALID_REQUEST: 'oauth2_invalid_request' +} as const; + +export const OAuth2ErrorMessage = { + AUTHORIZE_FAILED: 'Could not start authorization.', + GRANT_INVALID: 'This authorization request is invalid or has expired.', + HANDLE_EXPIRED: + 'This sign-in request has expired. Return to the application and try connecting again.', + MISSING_REQUEST: 'Missing authorization request. Open this page from an application sign-in.' +} as const; diff --git a/src/routes/(public)/oauth2/outcome-card.svelte b/src/routes/(public)/oauth2/outcome-card.svelte new file mode 100644 index 0000000000..986fcf03bc --- /dev/null +++ b/src/routes/(public)/oauth2/outcome-card.svelte @@ -0,0 +1,282 @@ + + + +
+
+
+ {#if appLogoUrl} + {appName} + {:else} +
{appInitial}
+ {/if} + {#if accountLabel} + + + + + + + + + {:else} + + + + {/if} +
+ +
+ {title} + + {message} + +
+
+ +
+ {#if approved && redirectUrl} + +

It's safe to close this tab.

+ {/if} + +

+ + {#if approved} + You can revoke access anytime in your account settings + {:else} + {appName} was not given access to your account + {/if} +

+
+
+
+ + diff --git a/src/routes/(public)/oauth2/resource-selector.svelte b/src/routes/(public)/oauth2/resource-selector.svelte new file mode 100644 index 0000000000..1f458097c7 --- /dev/null +++ b/src/routes/(public)/oauth2/resource-selector.svelte @@ -0,0 +1,493 @@ + + +
+
+ + {#if isEmpty} + + {/if} + {summary} + {#if isDefault} + Default + {/if} + + +
+ + {#if expanded} +
+ {#if wildcard} +
+ + +
+ {/if} + + {#if specificIds.length > 0} +
+ {#each specificIds as id (id)} + {@const r = labelFor(id)} + + {r.name} + {#if r.region} + + {/if} + + + {/each} +
+ {/if} + + {#if searchable} + +
    + {#if searching} +
  • + {:else if suggestions.length === 0} +
  • + {term.trim() + ? `No matching ${pluralLabel}` + : `Type to search ${pluralLabel}`} +
  • + {:else} + {#each suggestions as r (r.id)} +
  • + +
  • + {/each} + {#if loadingMore} +
  • + {/if} + {/if} +
+ {/if} +
+ {/if} +
+ + diff --git a/src/routes/(public)/sites/deploy/+page.svelte b/src/routes/(public)/sites/deploy/+page.svelte index 659ef140d3..7007f8c210 100644 --- a/src/routes/(public)/sites/deploy/+page.svelte +++ b/src/routes/(public)/sites/deploy/+page.svelte @@ -47,7 +47,7 @@ async function fetchProjects() { loadingProjects = true; - projects = await sdk.forConsole.projects.list({ + projects = await sdk.forConsole.organization(selectedOrg).listProjects({ queries: [ Query.equal('teamId', selectedOrg), Query.orderDesc(''), @@ -63,10 +63,9 @@ if (selectedProject === null) { try { loadingProjects = true; - const project = await sdk.forConsole.projects.create({ + const project = await sdk.forConsole.organization(selectedOrg).createProject({ projectId: id ?? ID.unique(), name: projectName, - teamId: selectedOrg, region: isCloud ? (region as Region) : undefined }); diff --git a/src/routes/(public)/template-[template]/+page.svelte b/src/routes/(public)/template-[template]/+page.svelte index 6ef3da9c7e..dc1d54b101 100644 --- a/src/routes/(public)/template-[template]/+page.svelte +++ b/src/routes/(public)/template-[template]/+page.svelte @@ -54,7 +54,7 @@ } async function fetchProjects() { - projects = await sdk.forConsole.projects.list({ + projects = await sdk.forConsole.organization(selectedOrg).listProjects({ queries: [ Query.equal('teamId', selectedOrg), Query.orderDesc(''), @@ -75,10 +75,9 @@ async function handleSubmit() { if (selectedProject === null) { try { - const p = await sdk.forConsole.projects.create({ + const p = await sdk.forConsole.organization(selectedOrg).createProject({ projectId: id ?? ID.unique(), name: projectName, - teamId: selectedOrg, region: isCloud ? (region as Region) : undefined }); trackEvent(Submit.ProjectCreate, { diff --git a/src/routes/+layout.svelte b/src/routes/+layout.svelte index 07ff6a6612..9a024b821d 100644 --- a/src/routes/+layout.svelte +++ b/src/routes/+layout.svelte @@ -58,7 +58,11 @@ } if (ref || referrer || utmSource || utmCampaign || utmMedium) { - sdk.forConsole.sources.create(ref, referrer, utmSource, utmCampaign, utmMedium); + // fire-and-forget: swallow failures so a blocked request doesn't + // surface as an unhandled rejection + sdk.forConsole.sources + .create(ref, referrer, utmSource, utmCampaign, utmMedium) + .catch(() => {}); } if (referrer || ref) {