From e3e74d90b83f8ecaf1857ff214464543b0fb668e Mon Sep 17 00:00:00 2001 From: KyleTryon Date: Sat, 19 Sep 2026 19:55:31 -0400 Subject: [PATCH 1/2] chore!: prepare release with ingestion hardening and dependency updates Fix feed starvation, fence concurrent fetches, expose feed health, and use stable article cursors. Harden authentication and outbound requests, improve article UI behavior, and consolidate shared logic. Include migrations 0012 through 0014 and a release runbook covering backups, rollout, verification, and rollback. BREAKING CHANGE: require Node.js 24 and pnpm 12.4.2, replace numeric article cursors, and enforce public feed destinations and a 5 MiB response limit. Apply migrations before deploying matching API and frontend versions. --- .env.example | 3 + .github/actions/setup/action.yml | 8 +- .github/workflows/ci-reusable.yml | 26 +- .github/workflows/ci-tricorder.yml | 40 +- .github/workflows/deploy-cloudflare.yml | 53 +- .github/workflows/deploy-staging.yml | 55 +- .github/workflows/docker-publish.yml | 24 +- .github/workflows/docker-test.yml | 4 +- .github/workflows/publish-tricorder.yml | 20 +- .nvmrc | 1 + README.md | 2 +- docker-compose.yml | 3 + docs/dependency-updates.md | 134 + docs/deployment.md | 20 +- docs/developer/email-system.md | 24 +- docs/developer/project-integration.md | 4 +- docs/developer/public-feeds.md | 13 +- docs/guides/features/rate-limiting.md | 24 +- docs/release-checklist.md | 90 + docs/staging-setup.md | 12 +- env.example | 3 + package.json | 46 +- packages/api/.env.example | 3 + packages/api/Dockerfile | 8 +- packages/api/README.md | 12 +- packages/api/drizzle/0012_overrated_toxin.sql | 6 + .../api/drizzle/0013_feed_fetch_attempts.sql | 3 + .../api/drizzle/0014_feed_reliability.sql | 13 + packages/api/drizzle/meta/0012_snapshot.json | 2241 +++ packages/api/drizzle/meta/0013_snapshot.json | 2253 +++ packages/api/drizzle/meta/0014_snapshot.json | 2337 +++ packages/api/drizzle/meta/_journal.json | 21 + packages/api/eslint.config.js | 14 +- packages/api/package.json | 80 +- packages/api/scripts/wipe-staging.sql | 2 + packages/api/src/adapters/sentry-telemetry.ts | 2 +- packages/api/src/auth/README.md | 2 +- packages/api/src/auth/better-auth.ts | 166 +- packages/api/src/auth/rate-limit.ts | 42 + packages/api/src/auth/security.ts | 12 +- packages/api/src/cli/clear-articles.ts | 2 +- packages/api/src/cli/create-admin.ts | 4 +- .../api/src/config/__tests__/sentry.test.ts | 20 +- packages/api/src/config/sentry.ts | 36 +- .../api/src/cron/__tests__/executor.test.ts | 32 +- .../api/src/cron/__tests__/handlers.test.ts | 98 +- .../api/src/cron/__tests__/scheduler.test.ts | 8 +- packages/api/src/cron/executor.ts | 30 +- packages/api/src/cron/handlers.ts | 137 +- packages/api/src/cron/scheduler.ts | 8 +- packages/api/src/cron/schedules.ts | 6 + packages/api/src/db/__tests__/client.test.ts | 2 +- .../db/__tests__/feed-fetch-attempts.test.ts | 28 + packages/api/src/db/__tests__/helpers.test.ts | 2 +- .../src/db/__tests__/staging-reset.test.ts | 47 + packages/api/src/db/client.ts | 2 +- packages/api/src/db/helpers.ts | 44 +- packages/api/src/db/migrate-local.ts | 2 +- packages/api/src/db/schema.ts | 28 +- packages/api/src/db/schemas.zod.ts | 18 +- packages/api/src/db/transformers.ts | 89 +- packages/api/src/entries/cloudflare.ts | 6 +- packages/api/src/entries/node.ts | 54 +- packages/api/src/hono/app.ts | 94 +- .../api/src/routers/__tests__/admin.test.ts | 6 +- .../__tests__/articles-audio-progress.test.ts | 4 +- .../routers/__tests__/articles-counts.test.ts | 51 +- .../__tests__/articles-filters.test.ts | 11 +- .../__tests__/articles-helpers.test.ts | 4 +- .../articles-multi-page-integration.test.ts | 4 +- .../__tests__/articles-pagination.test.ts | 67 +- .../src/routers/__tests__/auth-login.test.ts | 8 +- .../api/src/routers/__tests__/auth.test.ts | 18 +- .../batch-query-undefined-input.test.ts | 6 +- .../src/routers/__tests__/categories.test.ts | 2 +- .../api/src/routers/__tests__/feeds.test.ts | 4 +- .../__tests__/http-integration.test.ts | 25 +- .../api/src/routers/__tests__/plans.test.ts | 4 +- .../__tests__/review-regressions.test.ts | 289 + .../__tests__/subscriptions-discover.test.ts | 126 +- .../subscriptions-immediate-fetch.test.ts | 26 +- .../subscriptions-opml-filters.test.ts | 108 +- .../routers/__tests__/userSettings.test.ts | 4 +- packages/api/src/routers/admin.ts | 32 +- packages/api/src/routers/articles-helpers.ts | 25 +- packages/api/src/routers/articles.ts | 545 +- packages/api/src/routers/auth.ts | 243 +- packages/api/src/routers/categories.ts | 16 +- packages/api/src/routers/feeds.ts | 347 +- packages/api/src/routers/plans.ts | 8 +- packages/api/src/routers/subscriptions.ts | 222 +- packages/api/src/routers/userSettings.ts | 12 +- .../api/src/services/__tests__/email.test.ts | 5 +- .../feed-description-cleanup.test.ts | 174 +- .../__tests__/feed-reliability.test.ts | 149 + .../__tests__/global-settings.test.ts | 4 +- .../api/src/services/__tests__/limits.test.ts | 4 +- .../services/__tests__/rate-limiter.test.ts | 2 +- .../services/__tests__/rss-fetcher-hn.test.ts | 6 +- .../__tests__/rss-fetcher-itunes.test.ts | 18 +- .../services/__tests__/rss-fetcher.test.ts | 115 +- packages/api/src/services/admin-init.ts | 49 +- .../api/src/services/ai-category-suggester.ts | 4 +- packages/api/src/services/article-filters.ts | 94 + .../api/src/services/category-discovery.ts | 75 +- .../atom-link-extractor.test.ts | 58 +- .../atom-link-extractor.ts | 6 +- .../html-pattern-extractor.test.ts | 90 +- .../html-pattern-extractor.ts | 6 +- .../services/comment-link-extraction/index.ts | 4 +- .../integration.test.ts | 100 +- .../comment-link-extraction/registry.test.ts | 62 +- .../comment-link-extraction/registry.ts | 6 +- .../rss-element-extractor.test.ts | 40 +- .../rss-element-extractor.ts | 6 +- .../services/comment-link-extraction/types.ts | 16 +- .../src/services/email-templates/layout.tsx | 2 +- .../email-templates/password-reset.tsx | 2 +- .../services/email-templates/verification.tsx | 2 +- .../src/services/email-templates/welcome.tsx | 2 +- packages/api/src/services/email.ts | 6 +- packages/api/src/services/favicon-fetcher.ts | 7 +- .../feed-discovery/apple-discovery.ts | 7 +- .../services/feed-discovery/feed-validator.ts | 21 +- .../src/services/feed-discovery/registry.ts | 2 +- .../feed-discovery/standard-discovery.ts | 8 +- .../api/src/services/feed-discovery/types.ts | 4 +- packages/api/src/services/feed-health.ts | 62 + packages/api/src/services/global-settings.ts | 5 +- packages/api/src/services/limits.ts | 7 +- packages/api/src/services/plans.ts | 4 +- packages/api/src/services/public-feed.ts | 133 + packages/api/src/services/rate-limiter.ts | 2 +- packages/api/src/services/rss-fetcher.ts | 449 +- packages/api/src/services/user-init.ts | 94 +- packages/api/src/services/xml-generator.ts | 4 +- packages/api/src/test/README.md | 8 +- packages/api/src/test/helpers.test.ts | 21 + packages/api/src/test/helpers.ts | 8 +- packages/api/src/test/mocks.ts | 11 + packages/api/src/test/setup.ts | 4 +- packages/api/src/trpc/__tests__/init.test.ts | 14 +- packages/api/src/trpc/context.ts | 25 +- packages/api/src/trpc/init.ts | 39 +- packages/api/src/trpc/router.ts | 16 +- packages/api/src/types/better-auth.ts | 4 +- packages/api/src/types/feed.ts | 10 +- packages/api/src/types/index.ts | 9 +- packages/api/src/types/pagination.ts | 15 +- .../api/src/utils/__tests__/base-url.test.ts | 2 +- .../utils/__tests__/domain-checker.test.ts | 4 +- .../src/utils/__tests__/feed-utils.test.ts | 64 + .../__tests__/http-transport.node.test.ts | 26 + .../__tests__/http-transport.response.test.ts | 36 + .../src/utils/__tests__/safe-fetch.test.ts | 95 + packages/api/src/utils/base-url.ts | 2 +- packages/api/src/utils/db-metrics.ts | 2 +- packages/api/src/utils/domain-checker.ts | 4 +- packages/api/src/utils/feed-utils.ts | 41 + .../src/utils/http-transport.cloudflare.ts | 7 + packages/api/src/utils/http-transport.node.ts | 54 + packages/api/src/utils/metrics.ts | 2 +- packages/api/src/utils/og-image-fetcher.ts | 3 +- packages/api/src/utils/public-url.ts | 38 + packages/api/src/utils/safe-fetch.ts | 32 + packages/api/src/utils/sentry.cloudflare.ts | 2 +- packages/api/src/utils/sentry.node.ts | 2 +- packages/api/src/utils/sentry.noop.ts | 10 +- packages/api/tsconfig.json | 25 +- packages/api/tsconfig.node.json | 10 + packages/api/tsup.config.ts | 13 +- packages/api/vitest.config.ts | 35 +- packages/app/Dockerfile | 7 +- packages/app/README.md | 2 +- packages/app/eslint.config.js | 20 +- packages/app/package.json | 127 +- .../__tests__/routes/debug-sentry.test.tsx | 6 +- .../__tests__/offline-indicator.test.tsx | 8 +- .../src/components/admin/users/columns.tsx | 7 +- .../admin/users/data-table-column-header.tsx | 7 +- .../admin/users/data-table-faceted-filter.tsx | 7 +- .../admin/users/data-table-pagination.tsx | 16 +- .../admin/users/data-table-toolbar.tsx | 11 +- .../admin/users/data-table-view-options.tsx | 9 +- .../admin/users/data-table.test.tsx | 66 + .../src/components/admin/users/data-table.tsx | 43 +- .../components/admin/users/table-features.ts | 34 + .../animate-ui/components/buttons/button.tsx | 1 - .../animate-ui/components/radix/accordion.tsx | 1 - .../components/radix/alert-dialog.tsx | 2 - .../animate-ui/components/radix/checkbox.tsx | 2 - .../animate-ui/components/radix/dialog.tsx | 1 - .../components/radix/dropdown-menu.tsx | 2 - .../animate-ui/components/radix/progress.tsx | 2 - .../animate-ui/components/radix/sheet.tsx | 2 - .../animate-ui/primitives/buttons/button.tsx | 1 - .../app/__tests__/article-item-audio.test.tsx | 13 +- .../app/__tests__/article-item.test.tsx | 13 +- .../app/__tests__/feed-health-status.test.tsx | 43 + .../app/animated-article-list.test.tsx | 19 +- .../components/app/animated-article-list.tsx | 12 +- .../components/app/app-sidebar-role.test.tsx | 8 +- .../src/components/app/app-sidebar.test.tsx | 163 +- .../src/components/app/article-item-audio.tsx | 6 +- .../src/components/app/article-item.test.tsx | 21 +- .../app/src/components/app/article-item.tsx | 28 +- .../src/components/app/feed-health-status.tsx | 38 + .../components/app/import-preview-dialog.tsx | 13 +- .../app/src/components/app/nav-user.test.tsx | 16 +- .../app/subscription-category-selector.tsx | 4 +- .../app/subscription-filter-manager.test.tsx | 9 +- .../app/subscription-filter-manager.tsx | 4 +- .../__tests__/trpc-provider-offline.test.tsx | 6 +- .../src/components/provider/trpc-provider.tsx | 53 +- .../__tests__/pwa-install-card.test.tsx | 1 - .../components/settings/usage-quota-item.tsx | 2 +- packages/app/src/components/ui/chart.tsx | 17 +- .../contexts/__tests__/audio-context.test.tsx | 2 +- .../hooks/__tests__/use-media-query.test.ts | 4 +- .../hooks/__tests__/use-pwa-install.test.ts | 11 - .../src/hooks/__tests__/use-swipeable.test.ts | 2 +- .../app/src/hooks/use-auto-save-settings.ts | 2 +- .../app/src/hooks/use-controlled-state.tsx | 6 +- packages/app/src/hooks/use-mobile.ts | 20 +- packages/app/src/hooks/use-pwa-install.ts | 5 +- .../src/lib/__tests__/article-links.test.ts | 26 + .../lib/__tests__/get-strict-context.test.tsx | 1 - packages/app/src/lib/__tests__/utils.test.ts | 9 +- packages/app/src/lib/api/query-options.ts | 47 + packages/app/src/lib/api/trpc.ts | 5 + packages/app/src/lib/auth-client.ts | 8 +- .../__tests__/review-regressions.test.tsx | 136 + .../lib/hooks/__tests__/useArticles.test.tsx | 28 +- .../src/lib/hooks/__tests__/useAuth.test.tsx | 2 +- .../useUserSettings-offline.test.tsx | 130 +- packages/app/src/lib/hooks/useArticles.ts | 50 +- .../app/src/lib/hooks/useAudioProgress.ts | 6 +- packages/app/src/lib/hooks/useData.ts | 39 +- packages/app/src/lib/themes/README.md | 7 +- packages/app/src/lib/utils.ts | 46 +- .../app/src/lib/utils/__tests__/date.test.ts | 10 + packages/app/src/lib/utils/colors.ts | 2 +- packages/app/src/lib/utils/date.ts | 7 +- packages/app/src/pwa-register.ts | 2 + packages/app/src/routes/__root.tsx | 9 +- .../routes/app/__tests__/articles.test.tsx | 118 + .../src/routes/app/__tests__/route.test.tsx | 10 +- .../src/routes/app/admin/blocked-domains.tsx | 47 +- packages/app/src/routes/app/admin/index.tsx | 2 +- .../app/src/routes/app/admin/settings.tsx | 2 +- packages/app/src/routes/app/admin/users.tsx | 35 +- packages/app/src/routes/app/articles.tsx | 428 +- packages/app/src/routes/app/categories.tsx | 3 +- packages/app/src/routes/app/index.tsx | 4 +- packages/app/src/routes/app/route.tsx | 16 +- packages/app/src/routes/app/subscriptions.tsx | 212 +- packages/app/src/routes/register.tsx | 5 +- packages/app/src/test/fixtures.ts | 120 + packages/app/src/test/setup.ts | 9 +- packages/app/tsconfig.app.json | 8 +- packages/app/tsconfig.json | 1 - packages/app/vite.config.ts | 45 +- packages/tricorder/package.json | 20 +- packages/tricorder/src/browser.ts | 2 +- packages/tricorder/src/core/registry.ts | 14 +- packages/tricorder/src/core/types.ts | 1 + packages/tricorder/src/index.ts | 42 +- .../tricorder/src/services/apple-discovery.ts | 6 +- packages/tricorder/src/services/index.ts | 6 +- .../src/services/reddit-discovery.ts | 4 +- .../src/services/standard-discovery.ts | 7 +- .../__tests__/read-feed-response.test.ts | 46 + .../src/utils/__tests__/url-normalize.test.ts | 2 +- packages/tricorder/src/utils/feed-metadata.ts | 33 + packages/tricorder/src/utils/index.ts | 10 +- .../tricorder/src/utils/read-feed-response.ts | 33 + .../__tests__/feed-validator.test.ts | 60 +- .../src/validators/feed-validator.ts | 25 +- packages/tricorder/src/validators/index.ts | 2 +- packages/tricorder/tsconfig.json | 4 +- pnpm-lock.yaml | 13864 ++++++++-------- pnpm-workspace.yaml | 13 + 282 files changed, 19040 insertions(+), 11163 deletions(-) create mode 100644 .nvmrc create mode 100644 docs/dependency-updates.md create mode 100644 docs/release-checklist.md create mode 100644 packages/api/drizzle/0012_overrated_toxin.sql create mode 100644 packages/api/drizzle/0013_feed_fetch_attempts.sql create mode 100644 packages/api/drizzle/0014_feed_reliability.sql create mode 100644 packages/api/drizzle/meta/0012_snapshot.json create mode 100644 packages/api/drizzle/meta/0013_snapshot.json create mode 100644 packages/api/drizzle/meta/0014_snapshot.json create mode 100644 packages/api/src/auth/rate-limit.ts create mode 100644 packages/api/src/cron/schedules.ts create mode 100644 packages/api/src/db/__tests__/feed-fetch-attempts.test.ts create mode 100644 packages/api/src/db/__tests__/staging-reset.test.ts create mode 100644 packages/api/src/routers/__tests__/review-regressions.test.ts create mode 100644 packages/api/src/services/__tests__/feed-reliability.test.ts create mode 100644 packages/api/src/services/article-filters.ts create mode 100644 packages/api/src/services/feed-health.ts create mode 100644 packages/api/src/services/public-feed.ts create mode 100644 packages/api/src/test/helpers.test.ts create mode 100644 packages/api/src/utils/__tests__/feed-utils.test.ts create mode 100644 packages/api/src/utils/__tests__/http-transport.node.test.ts create mode 100644 packages/api/src/utils/__tests__/http-transport.response.test.ts create mode 100644 packages/api/src/utils/__tests__/safe-fetch.test.ts create mode 100644 packages/api/src/utils/http-transport.cloudflare.ts create mode 100644 packages/api/src/utils/http-transport.node.ts create mode 100644 packages/api/src/utils/public-url.ts create mode 100644 packages/api/src/utils/safe-fetch.ts create mode 100644 packages/api/tsconfig.node.json create mode 100644 packages/app/src/components/admin/users/data-table.test.tsx create mode 100644 packages/app/src/components/admin/users/table-features.ts create mode 100644 packages/app/src/components/app/__tests__/feed-health-status.test.tsx create mode 100644 packages/app/src/components/app/feed-health-status.tsx create mode 100644 packages/app/src/lib/__tests__/article-links.test.ts create mode 100644 packages/app/src/lib/api/query-options.ts create mode 100644 packages/app/src/lib/hooks/__tests__/review-regressions.test.tsx create mode 100644 packages/app/src/routes/app/__tests__/articles.test.tsx create mode 100644 packages/app/src/test/fixtures.ts create mode 100644 packages/tricorder/src/utils/__tests__/read-feed-response.test.ts create mode 100644 packages/tricorder/src/utils/feed-metadata.ts create mode 100644 packages/tricorder/src/utils/read-feed-response.ts diff --git a/.env.example b/.env.example index 89c94618..22a5e34e 100644 --- a/.env.example +++ b/.env.example @@ -74,3 +74,6 @@ CORS_ORIGIN=http://localhost:5173 # Minimum: 5 minutes # Default: 60 minutes FETCH_INTERVAL_MINUTES=60 + +# Enable only behind a trusted proxy that overwrites client IP headers. +TRUST_PROXY_HEADERS=false diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 121a2035..fb744c15 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -5,22 +5,22 @@ inputs: node-version: description: "Node.js version" required: false - default: "20" + default: "24" pnpm-version: description: "pnpm version" required: false - default: "10.19.0" + default: "12.4.2" runs: using: "composite" steps: - name: Setup pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 with: version: ${{ inputs.pnpm-version }} - name: Setup Node.js - uses: actions/setup-node@v4 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ inputs.node-version }} cache: "pnpm" diff --git a/.github/workflows/ci-reusable.yml b/.github/workflows/ci-reusable.yml index 9e9496ca..0bfacc4c 100644 --- a/.github/workflows/ci-reusable.yml +++ b/.github/workflows/ci-reusable.yml @@ -29,8 +29,8 @@ on: type: string env: - PNPM_VERSION: 10.19.0 - NODE_VERSION: "20" + PNPM_VERSION: 12.4.2 + NODE_VERSION: "24" jobs: lint: @@ -38,7 +38,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm uses: ./.github/actions/setup @@ -57,7 +57,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm uses: ./.github/actions/setup @@ -73,7 +73,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm uses: ./.github/actions/setup @@ -95,7 +95,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm uses: ./.github/actions/setup @@ -111,7 +111,7 @@ jobs: - name: Upload API test coverage if: ${{ inputs.upload_coverage }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ inputs.pr_number && format('api-coverage-pr-{0}', inputs.pr_number) || 'api-coverage' }} path: packages/api/coverage @@ -119,7 +119,7 @@ jobs: - name: Upload API coverage to Codecov if: ${{ inputs.upload_coverage }} - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 with: token: ${{ secrets.CODECOV_TOKEN }} files: packages/api/coverage/lcov.info @@ -132,7 +132,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm uses: ./.github/actions/setup @@ -145,7 +145,7 @@ jobs: - name: Upload App test coverage if: ${{ inputs.upload_coverage }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ inputs.pr_number && format('app-coverage-pr-{0}', inputs.pr_number) || 'app-coverage' }} path: packages/app/coverage @@ -153,7 +153,7 @@ jobs: - name: Upload App coverage to Codecov if: ${{ inputs.upload_coverage }} - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 with: token: ${{ secrets.CODECOV_TOKEN }} files: packages/app/coverage/lcov.info @@ -166,7 +166,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm uses: ./.github/actions/setup @@ -185,7 +185,7 @@ jobs: - name: Upload build artifacts if: ${{ inputs.upload_artifacts }} - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: build-artifacts path: | diff --git a/.github/workflows/ci-tricorder.yml b/.github/workflows/ci-tricorder.yml index b84d39c8..9a928b97 100644 --- a/.github/workflows/ci-tricorder.yml +++ b/.github/workflows/ci-tricorder.yml @@ -24,8 +24,8 @@ on: workflow_dispatch: env: - PNPM_VERSION: 10.19.0 - NODE_VERSION: "20" + PNPM_VERSION: 12.4.2 + NODE_VERSION: "24" # Cancel in-progress runs when a new run is triggered concurrency: @@ -38,15 +38,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 with: version: ${{ env.PNPM_VERSION }} - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" @@ -62,15 +62,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 with: version: ${{ env.PNPM_VERSION }} - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" @@ -86,15 +86,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 with: version: ${{ env.PNPM_VERSION }} - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" @@ -110,15 +110,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 with: version: ${{ env.PNPM_VERSION }} - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" @@ -130,14 +130,14 @@ jobs: run: pnpm --filter @tuvixrss/tricorder test:coverage - name: Upload coverage - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: tricorder-coverage path: packages/tricorder/coverage retention-days: 7 - name: Upload coverage to Codecov - uses: codecov/codecov-action@v5 + uses: codecov/codecov-action@303a32d7a59b442fa8d48b6a1cc6825c09c847a5 # v7.1.1 with: token: ${{ secrets.CODECOV_TOKEN }} files: packages/tricorder/coverage/lcov.info @@ -150,15 +150,15 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 with: version: ${{ env.PNPM_VERSION }} - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" @@ -178,7 +178,7 @@ jobs: echo "✅ Package is ready for publishing" - name: Upload build artifacts - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: tricorder-dist path: packages/tricorder/dist diff --git a/.github/workflows/deploy-cloudflare.yml b/.github/workflows/deploy-cloudflare.yml index 05f1a3d5..cd69d237 100644 --- a/.github/workflows/deploy-cloudflare.yml +++ b/.github/workflows/deploy-cloudflare.yml @@ -15,8 +15,8 @@ concurrency: cancel-in-progress: false env: - PNPM_VERSION: 10.19.0 - NODE_VERSION: "20" + PNPM_VERSION: 12.4.2 + NODE_VERSION: "24" # Only run for app releases (v*), not package releases (@tuvixrss/*) # Package releases like @tuvixrss/tricorder@x.y.z should not trigger deployment @@ -54,7 +54,7 @@ jobs: SENTRY_DSN: ${{ secrets.SENTRY_DSN }} steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.event.release.tag_name || github.event.inputs.version || github.ref }} @@ -102,24 +102,6 @@ jobs: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - - name: Deploy to Cloudflare Workers - id: deploy - uses: cloudflare/wrangler-action@v3 - with: - apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} - accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - workingDirectory: packages/api - command: deploy - packageManager: pnpm - - - name: Output API deployment URL - if: success() - run: | - API_URL="https://${{ steps.worker-name.outputs.name }}.workers.dev" - echo "API_URL=$API_URL" >> $GITHUB_OUTPUT - echo "## API Deployment" >> $GITHUB_STEP_SUMMARY - echo "- **URL:** $API_URL" >> $GITHUB_STEP_SUMMARY - - name: Prepare D1 migrations if: success() working-directory: packages/api @@ -154,7 +136,7 @@ jobs: - name: Run database migrations if: success() - uses: cloudflare/wrangler-action@v3 + uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} @@ -171,6 +153,24 @@ jobs: rm -rf migrations echo "✅ Cleaned up migrations folder" + - name: Deploy to Cloudflare Workers + id: deploy + uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + workingDirectory: packages/api + command: deploy + packageManager: pnpm + + - name: Output API deployment URL + if: success() + run: | + API_URL="https://${{ steps.worker-name.outputs.name }}.workers.dev" + echo "API_URL=$API_URL" >> $GITHUB_OUTPUT + echo "## API Deployment" >> $GITHUB_STEP_SUMMARY + echo "- **URL:** $API_URL" >> $GITHUB_STEP_SUMMARY + deploy-app: name: Deploy App to Cloudflare Pages runs-on: ubuntu-latest @@ -180,7 +180,7 @@ jobs: name: production steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.event.release.tag_name || github.event.inputs.version || github.ref }} @@ -190,6 +190,9 @@ jobs: node-version: ${{ env.NODE_VERSION }} pnpm-version: ${{ env.PNPM_VERSION }} + - name: Build Tricorder + run: pnpm run build:tricorder + - name: Type check App run: pnpm run type-check:app @@ -260,7 +263,7 @@ jobs: - name: Deploy to Cloudflare Pages id: deploy-app - uses: cloudflare/wrangler-action@v3 + uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} @@ -285,7 +288,7 @@ jobs: name: production steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Create wrangler.toml from example uses: ./.github/actions/substitute-d1-database-id diff --git a/.github/workflows/deploy-staging.yml b/.github/workflows/deploy-staging.yml index 2d705683..af09e291 100644 --- a/.github/workflows/deploy-staging.yml +++ b/.github/workflows/deploy-staging.yml @@ -19,8 +19,8 @@ concurrency: cancel-in-progress: true env: - PNPM_VERSION: 10.19.0 - NODE_VERSION: "20" + PNPM_VERSION: 12.4.2 + NODE_VERSION: "24" jobs: deploy-api: @@ -32,7 +32,7 @@ jobs: SENTRY_DSN: ${{ secrets.SENTRY_DSN }} steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.event.inputs.branch }} @@ -83,24 +83,6 @@ jobs: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - - name: Deploy API to Cloudflare Workers (Staging) - uses: cloudflare/wrangler-action@v3 - with: - apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} - accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} - workingDirectory: packages/api - command: deploy --env staging - packageManager: pnpm - - - name: Output staging API URL - run: | - API_URL="https://${{ steps.worker-name.outputs.name }}.workers.dev" - echo "API URL: $API_URL" - echo "## Staging API Deployment" >> $GITHUB_STEP_SUMMARY - echo "- **Branch**: \`${{ github.event.inputs.branch }}\`" >> $GITHUB_STEP_SUMMARY - echo "- **Commit**: \`$(git rev-parse --short HEAD)\`" >> $GITHUB_STEP_SUMMARY - echo "- **URL**: $API_URL" >> $GITHUB_STEP_SUMMARY - - name: Wipe staging database working-directory: packages/api run: | @@ -124,7 +106,7 @@ jobs: echo "✅ Prepared $(ls migrations/*.sql | wc -l) migration file(s)" - name: Apply fresh migrations to staging - uses: cloudflare/wrangler-action@v3 + uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} @@ -148,6 +130,24 @@ jobs: CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }} CLOUDFLARE_ACCOUNT_ID: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + - name: Deploy API to Cloudflare Workers (Staging) + uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0 + with: + apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} + accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} + workingDirectory: packages/api + command: deploy --env staging + packageManager: pnpm + + - name: Output staging API URL + run: | + API_URL="https://${{ steps.worker-name.outputs.name }}.workers.dev" + echo "API URL: $API_URL" + echo "## Staging API Deployment" >> $GITHUB_STEP_SUMMARY + echo "- **Branch**: \`${{ github.event.inputs.branch }}\`" >> $GITHUB_STEP_SUMMARY + echo "- **Commit**: \`$(git rev-parse --short HEAD)\`" >> $GITHUB_STEP_SUMMARY + echo "- **URL**: $API_URL" >> $GITHUB_STEP_SUMMARY + deploy-app: name: Deploy App to Staging runs-on: ubuntu-latest @@ -156,7 +156,7 @@ jobs: name: staging steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: ref: ${{ github.event.inputs.branch }} @@ -166,6 +166,9 @@ jobs: node-version: ${{ env.NODE_VERSION }} pnpm-version: ${{ env.PNPM_VERSION }} + - name: Build Tricorder + run: pnpm run build:tricorder + - name: Type check App run: pnpm run type-check:app @@ -193,7 +196,7 @@ jobs: - name: Deploy App to Cloudflare Pages (Staging) id: deploy-app - uses: cloudflare/wrangler-action@v3 + uses: cloudflare/wrangler-action@ebbaa1584979971c8614a24965b4405ff95890e0 # v4.0.0 with: apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} @@ -204,7 +207,7 @@ jobs: - name: Output staging app URL run: | APP_URL="https://${{ secrets.STAGING_CLOUDFLARE_PAGES_PROJECT_NAME }}.pages.dev" - echo "App URL: $App_URL" + echo "App URL: $APP_URL" echo "## Staging App Deployment" >> $GITHUB_STEP_SUMMARY echo "- **Branch**: \`${{ github.event.inputs.branch }}\`" >> $GITHUB_STEP_SUMMARY echo "- **Commit**: \`$(git rev-parse --short HEAD)\`" >> $GITHUB_STEP_SUMMARY @@ -217,7 +220,7 @@ jobs: if: always() steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Deployment Summary run: | diff --git a/.github/workflows/docker-publish.yml b/.github/workflows/docker-publish.yml index acf18a6b..a9e89c61 100644 --- a/.github/workflows/docker-publish.yml +++ b/.github/workflows/docker-publish.yml @@ -54,13 +54,15 @@ jobs: packages: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.release.tag_name || github.event.inputs.version }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 - name: Log in to Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -68,7 +70,7 @@ jobs: - name: Extract metadata id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_API }} tags: | @@ -78,7 +80,7 @@ jobs: type=raw,value=latest - name: Build and push API image - uses: docker/build-push-action@v6 + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 with: context: . file: ./packages/api/Dockerfile @@ -99,13 +101,15 @@ jobs: packages: write steps: - name: Checkout repository - uses: actions/checkout@v4 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + ref: ${{ github.event.release.tag_name || github.event.inputs.version }} - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 - name: Log in to Container Registry - uses: docker/login-action@v3 + uses: docker/login-action@dbcb813823bdd20940b903addbd779551569679f # v4.6.0 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} @@ -113,7 +117,7 @@ jobs: - name: Extract metadata id: meta - uses: docker/metadata-action@v5 + uses: docker/metadata-action@dc802804100637a589fabce1cb79ff13a1411302 # v6.2.0 with: images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME_APP }} tags: | @@ -123,7 +127,7 @@ jobs: type=raw,value=latest - name: Build and push App image - uses: docker/build-push-action@v6 + uses: docker/build-push-action@c3c9e263c25d99ce0380d002d59b67737d91b0dc # v7.4.0 with: context: . file: ./packages/app/Dockerfile diff --git a/.github/workflows/docker-test.yml b/.github/workflows/docker-test.yml index 316d8ec4..66188437 100644 --- a/.github/workflows/docker-test.yml +++ b/.github/workflows/docker-test.yml @@ -30,10 +30,10 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v3 + uses: docker/setup-buildx-action@f87e5991a6d7451dcb8d9637bfbc97413f497069 # v4.4.1 - name: Build Docker images run: | diff --git a/.github/workflows/publish-tricorder.yml b/.github/workflows/publish-tricorder.yml index 9c404c2e..b8fd0d8a 100644 --- a/.github/workflows/publish-tricorder.yml +++ b/.github/workflows/publish-tricorder.yml @@ -25,8 +25,8 @@ on: default: false env: - PNPM_VERSION: 10.19.0 - NODE_VERSION: "20" + PNPM_VERSION: 12.4.2 + NODE_VERSION: "24" permissions: id-token: write # Required for OIDC trusted publishing @@ -63,15 +63,15 @@ jobs: (needs.check-package.result == 'skipped' || needs.check-package.outputs.should-publish == 'true') steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 with: version: ${{ env.PNPM_VERSION }} - name: Setup Node.js - uses: actions/setup-node@v6 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" @@ -100,7 +100,7 @@ jobs: npm pack --dry-run - name: Upload build artifacts - uses: actions/upload-artifact@v5 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: tricorder-dist path: packages/tricorder/dist @@ -117,15 +117,15 @@ jobs: url: https://www.npmjs.com/package/@tuvixrss/tricorder steps: - name: Checkout code - uses: actions/checkout@v6 + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 - name: Setup Node.js and pnpm - uses: pnpm/action-setup@v4 + uses: pnpm/action-setup@ea17c68df8912ef543352723c149a84f56e3d413 # v6.1.0 with: version: ${{ env.PNPM_VERSION }} - name: Setup Node.js with NPM registry - uses: actions/setup-node@v6 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ env.NODE_VERSION }} cache: "pnpm" @@ -206,7 +206,7 @@ jobs: - name: Create GitHub Release if: startsWith(github.ref, 'refs/tags/') && steps.check_version.outputs.already_published == 'false' - uses: actions/github-script@v8 + uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | const tagRef = context.ref.replace('refs/tags/', ''); diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 00000000..b7179aed --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +24.20.0 diff --git a/README.md b/README.md index abc63e7c..ffd14d7d 100644 --- a/README.md +++ b/README.md @@ -99,7 +99,7 @@ Visit `http://localhost:5173` and log in with your admin credentials. ### Development Setup -**Prerequisites:** Node.js 20+ (with pnpm), SQLite3 +**Prerequisites:** Node.js 24+ (with pnpm), SQLite3 ```bash pnpm install diff --git a/docker-compose.yml b/docker-compose.yml index 82a2a9c3..e3351fd1 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -19,6 +19,9 @@ services: - CORS_ORIGIN=${CORS_ORIGIN:-http://localhost:5173} - BASE_URL=${BASE_URL:-http://localhost:5173} - BETTER_AUTH_URL=${BETTER_AUTH_URL:-} + - API_URL=${API_URL:-http://localhost:3001} + - OPENAI_API_KEY=${OPENAI_API_KEY:-} + - TRUST_PROXY_HEADERS=${TRUST_PROXY_HEADERS:-false} - COOKIE_DOMAIN=${COOKIE_DOMAIN:-} - ALLOW_FIRST_USER_ADMIN=${ALLOW_FIRST_USER_ADMIN:-false} - ADMIN_USERNAME=${ADMIN_USERNAME:-} diff --git a/docs/dependency-updates.md b/docs/dependency-updates.md new file mode 100644 index 00000000..1f8532c8 --- /dev/null +++ b/docs/dependency-updates.md @@ -0,0 +1,134 @@ +# Dependency update and review — September 19, 2026 + +Updated workspace dependencies, the lockfile, GitHub Actions, CI, and Docker build tooling. Resolved the review findings and compatibility errors exposed by the upgrades. Changes are local and have not been deployed. + +## Breaking changes and deployment requirements + +- The application and development toolchain now require **Node.js 24+ and pnpm 12.4.2**. `.nvmrc` selects Node.js 24.20.0; CI and Docker use Node.js 24. +- Apply `packages/api/drizzle/0012_overrated_toxin.sql` before serving the updated API. It adds persistent authentication rate limits. Node startup applies migrations automatically; production and staging Cloudflare workflows now migrate before deploying the API. +- Apply `packages/api/drizzle/0013_feed_fetch_attempts.sql` before serving the updated API. It adds and backfills the separate feed-attempt scheduling timestamp. Batches now run every minute, with `fetchIntervalMinutes` applied per feed. +- Node deployments ignore forwarded client IP headers by default. Enable `TRUST_PROXY_HEADERS` only behind a trusted proxy that overwrites those headers. +- Feed discovery and fetching reject private network destinations, including redirects and Node DNS resolution to private addresses. +- Session cookie caching is disabled so revoked sessions and role changes take effect on the next request. +- Vite 8 updates the default browser compatibility baseline. See the [Vite migration guide](https://vite.dev/guide/migration). + +## Dependency updates + +| Area | Selected version | +| -------------------- | ---------------- | +| Vite / React | 8.3.0 / 19.3.0 | +| TanStack React Table | 9.2.4 | +| Better Auth | 1.7.5 | +| Feedsmith / Undici | 3.0.0 / 8.10.2 | +| React Email | 6.9.5 | +| ESLint / TypeScript | 10.10.0 / 6.0.3 | +| Vitest | 5.0.1 | +| better-sqlite3 | 13.0.3 | + +All workspace dependencies were checked against the npm registry, including major upgrades. Only two version families remain below the latest major, intentionally: + +- TypeScript 6.0.3: the latest typescript-eslint parser supports `>=4.8.4 <6.1.0`; TypeScript 7 is outside its supported range. See the [official compatibility matrix](https://typescript-eslint.io/users/dependency-versions/). +- Node type definitions 24.13.5: match the supported Node.js 24 runtime rather than advertising Node 26 APIs. + +Vitest 5, better-sqlite3 13, React 19.3, Feedsmith 3, and Vite 8.3 are installed with no peer dependency conflicts. Codecov, Docker build-push, and Docker Buildx GitHub Actions were updated to their latest public releases and pinned to immutable commit SHAs. Other Action pins were verified as current. + +Removed the deprecated Rolldown Vite alias and React Email component package, migrated to pnpm's `allowBuilds` configuration, and refreshed vulnerable transitive dependencies. See [pnpm build settings](https://pnpm.io/settings/build) for the package-manager change. + +## Fixes verified during the review + +- Hardened authentication, session handling, telemetry redaction, public URL fetching, and authorization checks. +- Corrected subscription pagination, query invalidation, article counts and filtering, bulk read updates, and public feed limits. +- Migrated Better Auth database options, TanStack Table state/features, and the Undici response adapter. +- Centralized feed metadata extraction and parser-derived types; corrected JSON Feed site URLs and Atom alternate-link selection. +- Fixed subscription discovery races, duplicate URL decoding, controlled-state synchronization, and chart tooltip typing. +- Restored route tests after the router plugin upgrade and grouped production bundles into smaller cacheable chunks. +- Fixed staging database resets to remove the new authentication table before replaying migrations. A regression test covers wiping a populated database and recreating it from the complete migration history. + +## September 19 review passes + +### Bugs and release tooling + +- Article counts now respect the same include/exclude content filters as the article list. Ordinary counts aggregate inside SQLite/D1 instead of transferring full article bodies four times. Filtered counts scan once in bounded chunks. +- Migrated Feedsmith 3 structured Atom titles, summaries and content, RSS authors, Dublin Core creators, and public type exports. Atom article links select the publisher's alternate link. See the [upstream migration guide](https://next.feedsmith.dev/migration/v2-to-v3). +- Public Sentry diagnostics are disabled outside development; HTTP 500 responses hide internal details in production. +- Server-side feed redirects share one timeout budget. Publisher links opened by article cards accept HTTP(S) only. +- Category discovery and subscription preview now include both feed-level and entry-level categories across RSS, Atom and JSON Feed. +- Fixed an error assertion helper that incorrectly passed when an operation did not throw. Released test focus before cleanup so jsdom does not send spurious window-blur events to the next Radix menu. +- Root route/icon generation scripts target the correct workspace package. `pnpm clean` preserves databases and removes all package build outputs. `clean:all` also removes Tricorder dependencies. +- Admin initialization failures are logged during Node startup instead of silently ignored. +- Tricorder emits Node-compatible ESM imports with `.js` extensions. Its compiler now uses NodeNext resolution to reject extensionless imports during builds and type checks; both published entry points were imported directly in Node. + +### UI enhancements + +- Loaded articles remain visible while counts are pending or unavailable and after a pagination error. +- Initial errors offer a retry action; pagination provides keyboard-accessible load-more and retry buttons with live status announcements. +- Mobile bulk actions have explicit accessible labels. The empty-state navigation uses one link rather than nested interactive controls. +- Shared date formatting handles invalid and future publication dates and correctly omits the suffix when requested. + +### DRY and efficiency + +- Shared feed metadata extraction between Tricorder validation and the API, and shared entry/category extraction between ingestion, category suggestions and AI context. +- Consolidated the four article panels into one rendering definition; only the active list mounts, with a single pagination observer. +- Reused the shared date formatter and article-query join helpers. +- Removed redundant reads before article-state upserts and bulk updates. SQLite's conflict clause preserves unchanged saved/audio state atomically; bulk IDs are deduplicated. + +## Additional breaking changes + +- Feedsmith 3 type exports use `RssFeed`, `AtomFeed`, `RdfFeed`, and `JsonFeed`; the old API type names are removed, without compatibility aliases. +- `/debug-sentry` returns HTTP 404 unless `NODE_ENV=development`. +- Test tooling uses Vitest 5; consumers of the discovery library must account for the Feedsmith 3 major dependency upgrade. + +## Validation + +Verified with Node.js 24.18.0 and pnpm 12.4.2: + +| Check | Result | +| -------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------ | +| Frozen lockfile installation and peer dependencies | Passed | +| Full tests and coverage | 1,560 passed, 5 existing skips across 104 test files | +| Combined coverage | 73.22% statements, 62.42% branches, 70.02% functions, 73.55% lines; configured thresholds passed | +| ESLint, Prettier, TypeScript | Passed | +| Production builds | Passed for Tricorder, Node API, and frontend/PWA | +| Cloudflare Worker bundle | Dry run passed; nothing deployed | +| Dependency audit | Zero reported vulnerabilities across 1,424 dependencies | +| Production API package | Assembled successfully; SQLite and bcrypt native-module smoke checks passed | +| Browser smoke tests | Desktop and 390px mobile layout, login, saved articles, share menu, keyboard pagination through 60 articles, and admin users table passed; no console errors | +| Tricorder ESM regression | Both built entry points import in Node; 46 library tests passed after the fix | +| Diff whitespace | Passed | + +The browser checks used a temporary local database with synthetic users and articles. Temporary servers were stopped afterward. + +Docker images could not be built because the local Docker daemon is unavailable. No production database or service was changed. + +## Production missing-article follow-up + +Sentry production logs on September 19 showed all 631 sources stale, with repeated batches reporting `0 succeeded, 20 failed out of 20`. The same failing sources repeatedly occupied the queue because selection was ordered by `lastFetched`, which never advanced on failures. This prevented healthy sources later in the queue from receiving articles. + +- Schedule by a separate indexed `lastFetchAttemptAt`, written before external work, including blocked or failing feeds. Preserve `lastFetched` as the successful-refresh timestamp. +- Retry failed feeds after the per-feed cooldown and rotate by oldest attempt, with source ID as a deterministic tie breaker. +- Process a bounded batch every minute. The configured refresh interval applies to each source rather than pausing the whole queue between 20-source batches. +- Propagate monitored RSS-handler failures without executing the same batch again through the SDK-import fallback. +- Migration `0013_feed_fetch_attempts.sql` backfills attempts from existing successful timestamps. No production changes were applied during the investigation. + +Evidence: production Sentry logs at `2026-09-19T18:51:52Z` reported `Starting fetch for 20 sources (631 stale feeds, 631 total...)`; repeated completion logs included `2026-09-19T18:52:04Z`, `18:36:52Z`, and `18:19:35Z`, each reporting 20 failures and zero successes. Repeated BleepingComputer HTTP 403 failures corroborated the lack of queue rotation. Queries used `sentry log list techsquidtv/tuvix-api --period 24h` with `environment:production`, `"Starting fetch"`, and `"Fetch complete"` filters. + +Subscription 71 could not be mapped to its source: the browser required login and the configured Cloudflare credentials were denied read access to the production D1 database. The queue bug is confirmed, but a source-specific diagnosis for that subscription remains unverified. Publisher-side 403 errors and invalid feed responses can still require individual attention after queue progress is restored. Articles that have already disappeared from a publisher's RSS feed cannot be recovered by this scheduler change alone. + +Follow-up validation passed: 1,566 tests across 105 files with five existing skips; lint, formatting, TypeScript, production builds, Worker dry run, and whitespace checks. This includes migration backfill, failed/blocked feed rotation, retry cooldown, batch cadence, and monitored-handler failure regressions. The coverage percentages above are from the release-review run before this follow-up. + +## Additional release hardening + +All six follow-up recommendations are implemented: + +1. Article writes ignore only the `(source_id, guid)` duplicate constraint. Other storage errors propagate, keep the previous successful-fetch timestamp, and record a failed attempt. Partially completed chunks can be retried without duplicate articles. Missing article identity and extraction errors also prevent a false successful refresh. +2. Feed attempts acquire an atomic database lease shared by cron and manual refreshes. Leases expire after two minutes, renew during longer ingestion, and use ownership tokens to prevent an expired worker from completing or releasing a replacement worker's lease. This coordinates Node and D1 workers without process-local locks. +3. Subscription cards show the last successful update, a safe failure description, consecutive failures, and the next retry. Failed attempts use exponential retry delays capped at 24 hours. Persistent batch health emits a Sentry error after three unsuccessful batches with errors or three successive backlog increases, with a shared 30-minute alert throttle. Delivery of Sentry notifications follows the project's existing alert rules; no external notification configuration was changed. +4. Article infinite scrolling now uses a structured `{ publishedAt, id }` cursor returned as `nextCursor`. It handles timestamp ties, null dates, deleted anchors, new articles, and read-state changes. Filtered scans also use keyset pagination internally. Explicit offset pagination remains for numbered-page callers; numeric article cursors are rejected. +5. A shared Tricorder response reader caps feed/discovery responses at 5 MiB before parsing, checks both declared and actual streamed sizes, and cancels oversized/erroring bodies. RSS ingestion, previews, subscription creation/import, and discovery use the same helper. +6. All three cron handlers share one monitoring wrapper and one schedule definition. Only SDK import failures bypass monitoring; task failures propagate once. Monitoring uses the actual one-minute, one-day, and seven-day execution intervals. + +**Deployment requirements:** Apply `0014_feed_reliability.sql` after migration 0013 before serving the API. Deploy the frontend and API together because article cursors and subscription health responses changed. There are no compatibility aliases for old article cursors. Feed responses above 5 MiB are now rejected. The retry policy can delay repeatedly failing feeds up to 24 hours; manual refreshes can still retry immediately when no active lease exists. + +The investigation and implementation have not changed production data, deployed services, or Sentry alert configuration. + +Validation for all six improvements: **1,584 tests passed across 108 files, five existing skips**. ESLint, Prettier, strict type checks, production builds, the Cloudflare Worker dry run, and diff whitespace checks passed. Automatic Node migrations were verified on the disposable smoke database. Browser checks confirmed feed health on desktop and 390px mobile, keyboard pagination through 60 articles using the new cursor, and no console errors. Temporary servers and browser tabs were closed afterward. diff --git a/docs/deployment.md b/docs/deployment.md index 0cbe00e9..4b2609c4 100644 --- a/docs/deployment.md +++ b/docs/deployment.md @@ -2,6 +2,8 @@ This guide covers development and release processes for both Docker Compose and Cloudflare (Workers + Pages) deployments. +For the next release, follow the [release checklist](release-checklist.md), including migrations 0012–0014, upgrade rehearsal, coordinated API/frontend deployment, and recovery checks. + ## Table of Contents - [TuvixRSS Deployment Guide](#tuvixrss-deployment-guide) @@ -107,7 +109,7 @@ Both deployments share the same codebase with runtime-specific adapters. | Feature | Docker Compose | Cloudflare Workers | | ------------- | ----------------------- | -------------------------------------- | -| Runtime | Node.js 20+ | Cloudflare Workers | +| Runtime | Node.js 24+ | Cloudflare Workers | | Database | SQLite (better-sqlite3) | D1 (Cloudflare's SQLite) | | Cron | node-cron | Workers Scheduled Events | | Rate Limiting | Disabled | Cloudflare Workers rate limit bindings | @@ -450,7 +452,7 @@ docker compose up -d - Multi-stage build (builder + production) - Build context: monorepo root (not `packages/api`) - Copies workspace files (`pnpm-workspace.yaml`, root `pnpm-lock.yaml`) -- Installs pnpm 10.19.0 +- Installs pnpm 12.3.4 - Installs dependencies for all needed packages (api + tricorder) - Runs migrations on startup - Exposes port 3001 @@ -574,7 +576,7 @@ docker compose up -d ### Prerequisites -- Node.js 20+ +- Node.js 24+ - pnpm - Cloudflare account ([Sign up](https://dash.cloudflare.com/sign-up)) - Wrangler CLI (`npm install -g wrangler` or use `npx wrangler`) @@ -797,7 +799,7 @@ npx wrangler secret put SENTRY_RELEASE #### Step 4: Database Migrations -**Note:** For first deployment, run migrations BEFORE deploying. For subsequent deployments, migrations can run before or after deployment (CI/CD runs them after deployment). +**Note:** Apply database migrations before deploying the API. CI/CD uses this order so new code can rely on the updated schema. Review migrations for compatibility with the currently running version before release. ```bash cd packages/api @@ -1439,8 +1441,8 @@ feature branch → PR → main → [Manual Deploy to Production] 2. Runs type checks and tests for API 3. Builds API 4. Creates `wrangler.toml` from `wrangler.example.toml` and substitutes `D1_DATABASE_ID` -5. Deploys API to Cloudflare Workers -6. Runs database migrations (after successful API deployment) +5. Runs database migrations +6. Deploys API to Cloudflare Workers after migrations succeed 7. Runs type checks and tests for App 8. Builds App (with `VITE_API_URL` from secrets) 9. Deploys App to Cloudflare Pages (after API deployment succeeds) @@ -1524,8 +1526,8 @@ Configure these in **Settings → Environments → production → Secrets**: - Runs type checks and tests for API - Builds API - Substitutes `D1_DATABASE_ID` in `wrangler.toml` using `envsubst` - - Deploys API to Cloudflare Workers - - Runs database migrations (after API deployment succeeds) + - Runs database migrations + - Deploys API to Cloudflare Workers after migrations succeed - Runs type checks and tests for App - Builds App with `VITE_API_URL` from secrets - Deploys App to Cloudflare Pages (only after API deployment succeeds) @@ -1649,7 +1651,7 @@ Configure these in **Settings → Environments → production → Secrets**: - Verify `D1_DATABASE_ID` secret is set correctly (workflow will fail if missing) - If migrations fail with error code 7403: API token lacks D1 permissions or database belongs to different account - Review Cloudflare dashboard for errors -- Ensure database migrations completed successfully (runs after API deployment) +- Ensure database migrations completed successfully (runs before API deployment) - Check that worker name in `wrangler.toml` matches your Cloudflare Worker **Coverage Not Showing:** diff --git a/docs/developer/email-system.md b/docs/developer/email-system.md index b6e084ef..de837790 100644 --- a/docs/developer/email-system.md +++ b/docs/developer/email-system.md @@ -431,24 +431,12 @@ export const MyEmail: React.FC> = ({ export default MyEmail; // Styles -const main = { - /* ... */ -}; -const container = { - /* ... */ -}; -const h1 = { - /* ... */ -}; -const text = { - /* ... */ -}; -const buttonContainer = { - /* ... */ -}; -const button = { - /* ... */ -}; +const main = {/* ... */}; +const container = {/* ... */}; +const h1 = {/* ... */}; +const text = {/* ... */}; +const buttonContainer = {/* ... */}; +const button = {/* ... */}; ``` ### Adding a New Email Type diff --git a/docs/developer/project-integration.md b/docs/developer/project-integration.md index d114cb84..3a4bf1f5 100644 --- a/docs/developer/project-integration.md +++ b/docs/developer/project-integration.md @@ -888,9 +888,7 @@ Content-Type: application/json [ { "result": { - "data": [ - /* articles */ - ] + "data": [/* articles */] } }, { diff --git a/docs/developer/public-feeds.md b/docs/developer/public-feeds.md index 614a4e14..a1c2c644 100644 --- a/docs/developer/public-feeds.md +++ b/docs/developer/public-feeds.md @@ -734,12 +734,13 @@ See [Rate Limiting Guide](./rate-limiting.md) for complete documentation. Users are limited in how many public feeds they can create based on their plan. **Default Limits**: -| Plan | Max Public Feeds | -|------|------------------| -| Free | 3 | -| Pro | 10 | -| Enterprise | 50 | -| Custom | Admin-defined | + +| Plan | Max Public Feeds | +| ---------- | ---------------- | +| Free | 3 | +| Pro | 10 | +| Enterprise | 50 | +| Custom | Admin-defined | ### Limit Enforcement diff --git a/docs/guides/features/rate-limiting.md b/docs/guides/features/rate-limiting.md index 76631b16..b3d058f7 100644 --- a/docs/guides/features/rate-limiting.md +++ b/docs/guides/features/rate-limiting.md @@ -163,11 +163,12 @@ wrangler deploy **Configuration**: Based on user's subscription plan **Default Limits by Plan**: -| Plan | Requests per Minute | Binding | -|------|---------------------|---------| -| Free | 60 | `FREE_API_RATE_LIMIT` | -| Pro | 180 | `PRO_API_RATE_LIMIT` | -| Enterprise/Admin | 600 | `ENTERPRISE_API_RATE_LIMIT` | + +| Plan | Requests per Minute | Binding | +| ---------------- | ------------------- | --------------------------- | +| Free | 60 | `FREE_API_RATE_LIMIT` | +| Pro | 180 | `PRO_API_RATE_LIMIT` | +| Enterprise/Admin | 600 | `ENTERPRISE_API_RATE_LIMIT` | **Endpoints Protected**: All authenticated tRPC procedures @@ -186,12 +187,13 @@ wrangler deploy **Configuration**: Based on feed owner's plan **Default Limits by Plan**: -| Plan | Requests per Minute | -|------|---------------------| -| Free | ~17 | -| Pro | ~167 | -| Enterprise | ~1,667 | -| Custom | Admin-defined | + +| Plan | Requests per Minute | +| ---------- | ------------------- | +| Free | ~17 | +| Pro | ~167 | +| Enterprise | ~1,667 | +| Custom | Admin-defined | **Key Features**: diff --git a/docs/release-checklist.md b/docs/release-checklist.md new file mode 100644 index 00000000..729daeb0 --- /dev/null +++ b/docs/release-checklist.md @@ -0,0 +1,90 @@ +# Release checklist: ingestion reliability and dependency upgrades + +This release fixes feed starvation, hardens ingestion and authentication, updates dependencies, and improves article pagination and feed health reporting. See [the review report](dependency-updates.md) for implementation details. Production deployment and migration are still pending. + +## Breaking changes + +- Require Node.js 24+ and pnpm 12.4.2; use the checked-in lockfile. +- Deploy API and frontend from the same release. Article cursors now contain a publication timestamp and ID; numeric cursors are no longer accepted. Open browser tabs may need a reload after deployment. +- Feed responses over 5 MiB and private-network feed destinations are rejected. +- Node trusts forwarded client IP headers only with `TRUST_PROXY_HEADERS` enabled. Enable it only behind a proxy that overwrites those headers. +- Session cookie caching is disabled so revocations and role changes take effect promptly. + +## 1. Review and validate the PR + +- [ ] Review the dependency changes, security changes, migration SQL, and API response changes. +- [ ] Run `pnpm install --frozen-lockfile`, `pnpm pre-check`, and `pnpm test` with the supported toolchain. +- [ ] Require CI success, including Docker validation. Local verification passed 1,584 tests across 108 files, with five existing skips; lint, formatting, types, builds, Worker dry-run, and desktop/mobile smoke checks passed. Docker validation remains pending because the local daemon was unavailable. +- [ ] Rehearse an upgrade on a disposable database with existing sources, articles, subscriptions, and read/saved state. Record row counts and representative timestamps before and after. Also verify a fresh installation. +- [ ] Check staging login/logout, article filters and pagination, read/saved state, feed refresh, error/retry display, and a healthy feed recovering after an induced failure. + +**Staging warning:** `deploy-staging.yml` always wipes its database, even when `seed_data` is false. It tests a fresh installation; it does not replace the preserved-data upgrade rehearsal. Use a separate disposable database for that rehearsal. Never run `wipe-staging.sql` against production. + +## 2. Migrate in order + +Apply all pending migrations through the migration runner, including any older unapplied files. Do not run these SQL files manually and then run the migration runner: that would leave its ledger inconsistent. + +| Migration | Change | Existing data | +| ------------------------------ | ------------------------------------------------------------------- | ------------------------------------------------------------------------------ | +| `0012_overrated_toxin.sql` | Adds persistent `auth_rate_limits` | Starts empty; no account data rewrite | +| `0013_feed_fetch_attempts.sql` | Adds `last_fetch_attempt_at` and its index | Backfills from `last_fetched`, preserving NULL and successful-fetch timestamps | +| `0014_feed_reliability.sql` | Adds `feed_fetch_health`, leases, retry time, failure message/count | New optional fields start NULL; consecutive failures start at zero | + +These are additive migrations. They do not delete articles or subscriptions and have no down migrations. Migration 0013 updates every existing source, so include its duration in the rehearsal. Do not regenerate or rename migration files after release. + +For a disposable local SQLite upgrade copy, use an absolute database path: + +```sh +DATABASE_PATH=/absolute/path/to/upgrade-copy.db pnpm db:migrate +``` + +Verify that migrations finish, existing row counts and read/saved state are preserved, and `last_fetch_attempt_at` initially matches `last_fetched`. Start the new API against that copy and verify it starts without pending migration errors. + +## 3. Prepare production + +- [ ] Select the release version and merged commit after PR approval. Record the currently deployed API and Pages versions (or Docker image digests) for rollback. +- [ ] Verify production Cloudflare credentials can access the intended D1 database with D1 edit permissions. Live D1 access was not available during local review, so production migration state and subscription 71 still require verification. +- [ ] Take and verify a current D1 backup/export or recovery point. Store backups securely outside the repository. For SQLite, stop writers and take a consistent backup, accounting for WAL files; do not copy only a live database file. +- [ ] Verify API/frontend environment configuration, Sentry release/environment values, and that existing Sentry alert rules deliver the new ingestion-health error to the intended destination. Code emits the error; it does not create alert rules. +- [ ] Schedule a brief coordinated API/frontend rollout. Avoid leaving an old frontend against the new cursor contract. + +With the production Wrangler configuration and credentials selected, the D1 preparation commands are: + +```sh +cd packages/api +mkdir -p migrations +cp drizzle/*.sql migrations/ +pnpm exec wrangler d1 migrations list tuvix --remote +pnpm exec wrangler d1 export tuvix --remote --output /secure/backup/location/tuvix-before-release.sql +``` + +Replace the backup path with an existing secure location. Review the database identity and pending migration list before release. The production workflow applies the migrations; do not apply them a second time manually. Remove the temporary `migrations/` directory after preparation. + +## 4. Release and deploy + +1. Merge the reviewed PR after required checks pass. Create the selected `vX.Y.Z` tag at that merged commit. +2. Publish the GitHub app release with the breaking changes and migration notes above. **Publishing triggers production Cloudflare deployment and Docker image publication.** Creating a draft PR or draft release does not perform this rollout. +3. Watch `deploy-cloudflare.yml`: API checks/build → D1 migrations → Worker deployment → frontend checks/build → Pages deployment. If migrations fail, stop and inspect the migration ledger; do not deploy the new API around that failure. +4. Watch `docker-publish.yml` and verify both images correspond to the same tag. Manual dispatch must also use that exact tag; both image builds now explicitly check out the requested version. +5. For self-hosted Node/Docker installations, back up the persistent database, stop the old services, and deploy matching API/app images. Node API startup applies pending migrations before serving traffic. Keep the persistent data volume intact. + +## 5. Verify recovery before declaring success + +- [ ] API `/health` responds successfully; login and authenticated article loading work after a browser reload. +- [ ] D1 migration list shows no pending migrations through 0014; source columns and the two new tables exist. +- [ ] Confirm each minute's fetch batches advance through different eligible sources. Healthy sources update `last_fetched`; failures update attempt/error/retry state without falsely advancing the last successful fetch. +- [ ] Confirm the stale backlog trends down across multiple batches. Publisher 403/invalid-feed failures may remain; they must no longer monopolize every batch. +- [ ] Open the originally reported subscription and confirm newly available articles arrive. Resolve its subscription ID to its source before diagnosing source-specific errors; subscription IDs and source IDs are different. +- [ ] Check filtered/unread article scrolling while marking articles read and while new articles arrive. Confirm no skipped pages, duplicate rows, or cursor errors. +- [ ] Verify read/saved state, feed health messages, manual retry, and responsive layouts. +- [ ] Inspect Sentry for ingestion/database errors and `RSS ingestion is stalled or falling behind`. Observe several batches and a normal per-feed refresh interval before closing the release. + +The scheduler cannot recover articles a publisher has already removed from its feed. Validate recovery against articles still present upstream; do not promise historical backfill from this migration. + +## 6. Failure and rollback + +- If migration fails, retain the old application, inspect applied migrations and schema, and fix forward. D1 can have earlier migrations applied when a later one fails; do not blindly replay raw SQL. +- If API or frontend deployment fails, finish the matching rollout promptly or restore both prior application versions. A successful Worker deployment followed by failed Pages deployment leaves mixed versions. +- Retain additive schema changes during an application rollback. Verify the previous application against the migrated rehearsal database before relying on rollback; schema additivity alone does not prove dependency/authentication compatibility. +- Restore a database backup only for confirmed data corruption or an unrecoverable migration problem, with writers stopped and explicit acceptance of losing changes since the backup. Routine application rollback should not restore old data. +- Rolling back the API also restores the old starvation behavior. Treat rollback as temporary and monitor the feed backlog until the corrected release is deployed. diff --git a/docs/staging-setup.md b/docs/staging-setup.md index 3a47fe78..9bc22128 100644 --- a/docs/staging-setup.md +++ b/docs/staging-setup.md @@ -105,12 +105,12 @@ wrangler secret put SENTRY_DSN --name tuvix-api-staging --env staging ### What Happens During Deployment -1. **Build & Test**: Runs linting, type checking, and tests -2. **Deploy API**: Deploys Worker to `tuvix-api-staging` -3. **Deploy App**: Deploys Pages to `tuvix-app-staging` -4. **Wipe Database**: Drops all tables from staging database -5. **Apply Migrations**: Runs all migrations from scratch -6. **Seed Data** (optional): Loads test data if selected +1. **Build & Test API**: Runs type checking, tests, and the API build +2. **Wipe Database**: Drops all tables from the staging database +3. **Apply Migrations**: Runs all migrations from scratch +4. **Seed Data** (optional): Loads test data if selected +5. **Deploy API**: Deploys Worker to `tuvix-api-staging` after database setup succeeds +6. **Build, Test & Deploy App**: Checks and builds the app, then deploys Pages to `tuvix-app-staging` ### Accessing Staging diff --git a/env.example b/env.example index ade79b36..e2af737c 100644 --- a/env.example +++ b/env.example @@ -96,3 +96,6 @@ ADMIN_PASSWORD=change-me-in-production # If not set, automatically uses VITE_API_URL origin + common fallbacks # Regex patterns: /^https:\/\/api\.example\.com$/ + +# Enable only behind a trusted proxy that overwrites client IP headers. +TRUST_PROXY_HEADERS=false diff --git a/package.json b/package.json index 87f1bc8c..fe3ab2c1 100644 --- a/package.json +++ b/package.json @@ -8,15 +8,15 @@ "build:api": "cd packages/api && pnpm run build", "build:app": "cd packages/app && pnpm run build", "build": "pnpm run build:tricorder && pnpm run build:api && pnpm run build:app", - "clean:all": "pnpm run clean && rm -rf node_modules packages/app/node_modules packages/api/node_modules", - "clean": "rm -rf packages/api/dist packages/app/dist data/*.db", + "clean:all": "pnpm run clean && rm -rf node_modules packages/app/node_modules packages/api/node_modules packages/tricorder/node_modules", + "clean": "rm -rf packages/api/dist packages/app/dist packages/tricorder/dist", "cleanup:all": "./scripts/cleanup-processes.sh --all", "cleanup": "./scripts/cleanup-processes.sh", "db:generate": "cd packages/api && pnpm run db:generate", "db:list-users:d1": "cd packages/api && bash scripts/list-users-d1.sh", "db:delete-non-admin-users:d1": "cd packages/api && bash scripts/delete-non-admin-users-d1.sh", "db:migrate:d1": "cd packages/api && pnpm run db:migrate:d1", - "db:migrate": "cd packages/api && pnpx tsx src/db/migrate-local.ts", + "db:migrate": "cd packages/api && pnpm exec tsx src/db/migrate-local.ts", "db:reset": "cd packages/api && pnpm run db:reset", "db:push": "cd packages/api && pnpm run db:push", "db:studio": "cd packages/api && pnpm run db:studio", @@ -32,8 +32,8 @@ "docker:test:ci": "docker compose -f docker-compose.yml -f docker-compose.test.yml up --abort-on-container-exit", "format": "prettier --write .", "format:check": "prettier --check .", - "generate:routes": "pnpm run --filter app generate:routes", - "generate:icons": "pnpm run --filter app generate:icons", + "generate:routes": "pnpm --filter @tuvixrss/app run generate:routes", + "generate:icons": "pnpm --filter @tuvixrss/app run generate:icons", "lint": "pnpm --filter @tuvixrss/tricorder lint && pnpm --filter @tuvixrss/api lint && pnpm --filter @tuvixrss/app lint", "lint:fix": "pnpm --filter @tuvixrss/tricorder lint --fix && pnpm --filter @tuvixrss/api lint --fix && pnpm --filter @tuvixrss/app lint --fix", "pre-check": "pnpm run lint && pnpm run format:check && pnpm run type-check && pnpm run build", @@ -42,14 +42,14 @@ "test:tricorder": "cd packages/tricorder && pnpm test", "test:api": "cd packages/api && pnpm test", "test:app": "cd packages/app && pnpm test", - "test:coverage:tricorder": "cd packages/tricorder && pnpm test:coverage || true", + "test:coverage:tricorder": "cd packages/tricorder && pnpm test:coverage", "test:coverage:api": "cd packages/api && pnpm test:coverage", "test:coverage:app": "cd packages/app && pnpm test:coverage", "test:coverage:generate": "pnpm run test:coverage:tricorder && pnpm run test:coverage:api && pnpm run test:coverage:app", "test:coverage:merge": "node scripts/merge-coverage.js", "test:coverage:report": "nyc report --reporter=html --reporter=text --reporter=text-summary --reporter=lcov --temp-dir=./coverage/.nyc_output --report-dir=./coverage", "test:coverage": "pnpm run test:coverage:generate && pnpm run test:coverage:merge && pnpm run test:coverage:report", - "test": "pnpm run test:api && pnpm run test:app", + "test": "pnpm run test:tricorder && pnpm run test:api && pnpm run test:app", "type-check:tricorder": "cd packages/tricorder && pnpm run type-check", "type-check:api": "cd packages/api && pnpm run type-check", "type-check:app": "cd packages/app && pnpm run type-check", @@ -57,7 +57,7 @@ "find-any-types": "node scripts/find-any-types.js", "check-types": "pnpm run type-check && pnpm run find-any-types", "email:preview": "cd packages/api && pnpm run email:preview", - "update:all": "pnpm update --latest -r" + "update:all": "pnpm update --latest -r --include-workspace-root" }, "keywords": [ "rss", @@ -67,27 +67,15 @@ ], "author": "", "license": "MIT", - "packageManager": "pnpm@10.19.0", - "pnpm": { - "overrides": { - "vite": "npm:rolldown-vite@7.2.7", - "esbuild": ">=0.25.0" - }, - "onlyBuiltDependencies": [ - "@swc/core", - "bcrypt", - "better-sqlite3", - "esbuild", - "msw", - "sharp", - "workerd" - ] - }, + "packageManager": "pnpm@12.4.2", "devDependencies": { - "concurrently": "^9.2.1", - "eslint-plugin-no-relative-import-paths": "^1.6.1", - "nyc": "^17.1.0", - "prettier": "^3.7.4", - "shadcn": "^3.5.1" + "concurrently": "^10.0.5", + "node-gyp": "^13.0.2", + "nyc": "^18.0.0", + "prettier": "^3.9.8", + "shadcn": "^4.21.0" + }, + "engines": { + "node": ">=24.0.0" } } diff --git a/packages/api/.env.example b/packages/api/.env.example index 2b3684d3..fc5177e7 100644 --- a/packages/api/.env.example +++ b/packages/api/.env.example @@ -23,3 +23,6 @@ JWT_SECRET= # Multiple origins (comma-separated): http://localhost:5173,https://example.com # Cloudflare Workers: Set to your frontend domain or * for same-domain service bindings CORS_ORIGIN=http://localhost:5173 + +# Enable only behind a trusted proxy that overwrites client IP headers. +TRUST_PROXY_HEADERS=false diff --git a/packages/api/Dockerfile b/packages/api/Dockerfile index dc2eeaca..6274e56b 100644 --- a/packages/api/Dockerfile +++ b/packages/api/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-alpine AS builder +FROM node:24-alpine AS builder WORKDIR /app @@ -7,7 +7,7 @@ WORKDIR /app RUN apk add --no-cache python3 make g++ # Install pnpm -RUN npm install -g pnpm@10.19.0 +RUN npm install -g pnpm@12.4.2 # Copy workspace files COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ @@ -31,7 +31,7 @@ RUN pnpm --filter @tuvixrss/api build # Use pnpm deploy to create a self-contained production package # This properly resolves workspace dependencies and includes only prod deps -# --legacy flag required for pnpm v10 without inject-workspace-packages +# Use the deploy mode for workspaces linked with symlinks instead of injected copies. RUN pnpm --filter @tuvixrss/api deploy /app/deploy --prod --legacy # Copy built artifacts to deploy directory @@ -39,7 +39,7 @@ RUN cp -r /app/packages/api/dist /app/deploy/dist && \ cp -r /app/packages/api/drizzle /app/deploy/drizzle # Production stage -FROM node:20-alpine +FROM node:24-alpine # Create non-root user FIRST (before any files to avoid permission layer bloat) RUN addgroup -g 1001 -S nodejs && \ diff --git a/packages/api/README.md b/packages/api/README.md index d4dc5380..0407ef66 100644 --- a/packages/api/README.md +++ b/packages/api/README.md @@ -78,7 +78,7 @@ packages/api/ ### Prerequisites -- Node.js 18+ (for Docker deployment) +- Node.js 24+ (for Docker deployment) - pnpm (package manager) - SQLite (for local development) @@ -521,3 +521,13 @@ Same as parent project (TuvixRSS) ✅ **Production Ready** - All core features are implemented and tested. The API is fully functional with complete CRUD operations for articles, subscriptions, categories, feeds, and user settings. All endpoints are documented and type-safe. + +## Security and upgrade notes + +Use Node.js 24 or newer. Apply migration `0012_overrated_toxin.sql` before starting this version. It adds persistent authentication attempt limits shared by all credential endpoints. Existing session-cookie caches are disabled so revoked sessions and role changes take effect on the next request. + +**Breaking change:** server-side feed discovery, fetching, and image requests reject private, loopback, and reserved network destinations, including redirects. Private-network feeds must be exposed through a public endpoint to be used. + +Node deployments ignore client-supplied IP forwarding headers by default. Set `TRUST_PROXY_HEADERS=true` only when the API is reachable exclusively through a trusted reverse proxy that overwrites these headers; otherwise the proxy's address shares one authentication limit. Cloudflare uses its platform-provided client address. + +Set `API_URL` (or `BETTER_AUTH_URL`) to the API's public origin. Frontend public-feed links use `VITE_API_URL`, with an optional `VITE_PUBLIC_URL` override. `BASE_URL` remains the frontend origin for email links. Set `OPENAI_API_KEY` in the Node/Docker environment to enable configured AI categorization. diff --git a/packages/api/drizzle/0012_overrated_toxin.sql b/packages/api/drizzle/0012_overrated_toxin.sql new file mode 100644 index 00000000..e69e0247 --- /dev/null +++ b/packages/api/drizzle/0012_overrated_toxin.sql @@ -0,0 +1,6 @@ +CREATE TABLE `auth_rate_limits` ( + `key` text PRIMARY KEY NOT NULL, + `attempts` integer NOT NULL, + `window_started_at` integer NOT NULL, + `locked_until` integer DEFAULT 0 NOT NULL +); diff --git a/packages/api/drizzle/0013_feed_fetch_attempts.sql b/packages/api/drizzle/0013_feed_fetch_attempts.sql new file mode 100644 index 00000000..fc4fbab0 --- /dev/null +++ b/packages/api/drizzle/0013_feed_fetch_attempts.sql @@ -0,0 +1,3 @@ +ALTER TABLE `sources` ADD `last_fetch_attempt_at` integer;--> statement-breakpoint +UPDATE `sources` SET `last_fetch_attempt_at` = `last_fetched`;--> statement-breakpoint +CREATE INDEX `idx_sources_last_fetch_attempt_at` ON `sources` (`last_fetch_attempt_at`); diff --git a/packages/api/drizzle/0014_feed_reliability.sql b/packages/api/drizzle/0014_feed_reliability.sql new file mode 100644 index 00000000..9161f281 --- /dev/null +++ b/packages/api/drizzle/0014_feed_reliability.sql @@ -0,0 +1,13 @@ +CREATE TABLE `feed_fetch_health` ( + `id` integer PRIMARY KEY NOT NULL, + `backlog` integer DEFAULT 0 NOT NULL, + `failing_batches` integer DEFAULT 0 NOT NULL, + `growing_batches` integer DEFAULT 0 NOT NULL, + `last_alert_at` integer +); +--> statement-breakpoint +ALTER TABLE `sources` ADD `fetch_lease_token` text;--> statement-breakpoint +ALTER TABLE `sources` ADD `fetch_lease_until` integer;--> statement-breakpoint +ALTER TABLE `sources` ADD `next_fetch_at` integer;--> statement-breakpoint +ALTER TABLE `sources` ADD `last_fetch_error` text;--> statement-breakpoint +ALTER TABLE `sources` ADD `consecutive_fetch_failures` integer DEFAULT 0 NOT NULL; \ No newline at end of file diff --git a/packages/api/drizzle/meta/0012_snapshot.json b/packages/api/drizzle/meta/0012_snapshot.json new file mode 100644 index 00000000..bd1f9cac --- /dev/null +++ b/packages/api/drizzle/meta/0012_snapshot.json @@ -0,0 +1,2241 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "3714a2ad-2162-4a45-961f-ae868cf669c2", + "prevId": "1d92c603-5368-4133-9cdc-916778226d19", + "tables": { + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "api_usage_log": { + "name": "api_usage_log", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status_code": { + "name": "status_code", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_api_usage_log_user_id": { + "name": "idx_api_usage_log_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_api_usage_log_created_at": { + "name": "idx_api_usage_log_created_at", + "columns": ["created_at"], + "isUnique": false + }, + "idx_api_usage_log_endpoint": { + "name": "idx_api_usage_log_endpoint", + "columns": ["endpoint"], + "isUnique": false + } + }, + "foreignKeys": { + "api_usage_log_user_id_user_id_fk": { + "name": "api_usage_log_user_id_user_id_fk", + "tableFrom": "api_usage_log", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "articles": { + "name": "articles", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "source_id": { + "name": "source_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guid": { + "name": "guid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "audio_url": { + "name": "audio_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "comment_link": { + "name": "comment_link", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_at": { + "name": "published_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_articles_source_id": { + "name": "idx_articles_source_id", + "columns": ["source_id"], + "isUnique": false + }, + "idx_articles_published_at": { + "name": "idx_articles_published_at", + "columns": ["published_at"], + "isUnique": false + }, + "idx_articles_guid": { + "name": "idx_articles_guid", + "columns": ["guid"], + "isUnique": false + }, + "idx_articles_audio_url": { + "name": "idx_articles_audio_url", + "columns": ["audio_url"], + "isUnique": false + }, + "idx_articles_source_published": { + "name": "idx_articles_source_published", + "columns": ["source_id", "published_at"], + "isUnique": false + }, + "articles_source_id_guid_unique": { + "name": "articles_source_id_guid_unique", + "columns": ["source_id", "guid"], + "isUnique": true + } + }, + "foreignKeys": { + "articles_source_id_sources_id_fk": { + "name": "articles_source_id_sources_id_fk", + "tableFrom": "articles", + "tableTo": "sources", + "columnsFrom": ["source_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "auth_rate_limits": { + "name": "auth_rate_limits", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "window_started_at": { + "name": "window_started_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "locked_until": { + "name": "locked_until", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "blocked_domains": { + "name": "blocked_domains", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "blocked_domains_domain_unique": { + "name": "blocked_domains_domain_unique", + "columns": ["domain"], + "isUnique": true + }, + "idx_blocked_domains_domain": { + "name": "idx_blocked_domains_domain", + "columns": ["domain"], + "isUnique": false + }, + "idx_blocked_domains_reason": { + "name": "idx_blocked_domains_reason", + "columns": ["reason"], + "isUnique": false + }, + "idx_blocked_domains_created_at": { + "name": "idx_blocked_domains_created_at", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "blocked_domains_created_by_user_id_fk": { + "name": "blocked_domains_created_by_user_id_fk", + "tableFrom": "blocked_domains", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "categories": { + "name": "categories", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_categories_user_id": { + "name": "idx_categories_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_categories_name": { + "name": "idx_categories_name", + "columns": ["name"], + "isUnique": false + }, + "idx_categories_user_id_name_normalized": { + "name": "idx_categories_user_id_name_normalized", + "columns": ["user_id", "LOWER(\"name\")"], + "isUnique": true + } + }, + "foreignKeys": { + "categories_user_id_user_id_fk": { + "name": "categories_user_id_user_id_fk", + "tableFrom": "categories", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feed_categories": { + "name": "feed_categories", + "columns": { + "feed_id": { + "name": "feed_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_feed_categories_feed_id": { + "name": "idx_feed_categories_feed_id", + "columns": ["feed_id"], + "isUnique": false + }, + "idx_feed_categories_category_id": { + "name": "idx_feed_categories_category_id", + "columns": ["category_id"], + "isUnique": false + } + }, + "foreignKeys": { + "feed_categories_feed_id_feeds_id_fk": { + "name": "feed_categories_feed_id_feeds_id_fk", + "tableFrom": "feed_categories", + "tableTo": "feeds", + "columnsFrom": ["feed_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "feed_categories_category_id_categories_id_fk": { + "name": "feed_categories_category_id_categories_id_fk", + "tableFrom": "feed_categories", + "tableTo": "categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "feed_categories_feed_id_category_id_pk": { + "columns": ["feed_id", "category_id"], + "name": "feed_categories_feed_id_category_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feeds": { + "name": "feeds", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "public": { + "name": "public", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_feeds_user_id": { + "name": "idx_feeds_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_feeds_slug": { + "name": "idx_feeds_slug", + "columns": ["slug"], + "isUnique": false + }, + "idx_feeds_created_at": { + "name": "idx_feeds_created_at", + "columns": ["created_at"], + "isUnique": false + }, + "feeds_user_id_slug_unique": { + "name": "feeds_user_id_slug_unique", + "columns": ["user_id", "slug"], + "isUnique": true + } + }, + "foreignKeys": { + "feeds_user_id_user_id_fk": { + "name": "feeds_user_id_user_id_fk", + "tableFrom": "feeds", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "global_settings": { + "name": "global_settings", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "max_login_attempts": { + "name": "max_login_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 5 + }, + "login_attempt_window_minutes": { + "name": "login_attempt_window_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 15 + }, + "lockout_duration_minutes": { + "name": "lockout_duration_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 30 + }, + "allow_registration": { + "name": "allow_registration", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "require_email_verification": { + "name": "require_email_verification", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "admin_bypass_email_verification": { + "name": "admin_bypass_email_verification", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "password_reset_token_expiry_hours": { + "name": "password_reset_token_expiry_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "fetch_interval_minutes": { + "name": "fetch_interval_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 60 + }, + "prune_days": { + "name": "prune_days", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 90 + }, + "last_rss_fetch_at": { + "name": "last_rss_fetch_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_prune_at": { + "name": "last_prune_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_token_cleanup_at": { + "name": "last_token_cleanup_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ai_enabled": { + "name": "ai_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "global_settings_updated_by_user_id_fk": { + "name": "global_settings_updated_by_user_id_fk", + "tableFrom": "global_settings", + "tableTo": "user", + "columnsFrom": ["updated_by"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "password_reset_tokens": { + "name": "password_reset_tokens", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "used": { + "name": "used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "password_reset_tokens_token_unique": { + "name": "password_reset_tokens_token_unique", + "columns": ["token"], + "isUnique": true + }, + "idx_password_reset_tokens_token": { + "name": "idx_password_reset_tokens_token", + "columns": ["token"], + "isUnique": false + }, + "idx_password_reset_tokens_user_id": { + "name": "idx_password_reset_tokens_user_id", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "password_reset_tokens_user_id_user_id_fk": { + "name": "password_reset_tokens_user_id_user_id_fk", + "tableFrom": "password_reset_tokens", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plans": { + "name": "plans", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "max_sources": { + "name": "max_sources", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "max_public_feeds": { + "name": "max_public_feeds", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "max_categories": { + "name": "max_categories", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "api_rate_limit_per_minute": { + "name": "api_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "public_feed_rate_limit_per_minute": { + "name": "public_feed_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "price_cents": { + "name": "price_cents", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "features": { + "name": "features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "public_feed_access_log": { + "name": "public_feed_access_log", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "feed_id": { + "name": "feed_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "accessed_at": { + "name": "accessed_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_public_feed_access_log_feed_id": { + "name": "idx_public_feed_access_log_feed_id", + "columns": ["feed_id"], + "isUnique": false + }, + "idx_public_feed_access_log_accessed_at": { + "name": "idx_public_feed_access_log_accessed_at", + "columns": ["accessed_at"], + "isUnique": false + } + }, + "foreignKeys": { + "public_feed_access_log_feed_id_feeds_id_fk": { + "name": "public_feed_access_log_feed_id_feeds_id_fk", + "tableFrom": "public_feed_access_log", + "tableTo": "feeds", + "columnsFrom": ["feed_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "security_audit_log": { + "name": "security_audit_log", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "success": { + "name": "success", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "idx_security_audit_log_user_id": { + "name": "idx_security_audit_log_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_security_audit_log_action": { + "name": "idx_security_audit_log_action", + "columns": ["action"], + "isUnique": false + }, + "idx_security_audit_log_created_at": { + "name": "idx_security_audit_log_created_at", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "security_audit_log_user_id_user_id_fk": { + "name": "security_audit_log_user_id_user_id_fk", + "tableFrom": "security_audit_log", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": ["token"], + "isUnique": true + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sources": { + "name": "sources", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "site_url": { + "name": "site_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_type": { + "name": "icon_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'auto'" + }, + "icon_updated_at": { + "name": "icon_updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_fetched": { + "name": "last_fetched", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "sources_url_unique": { + "name": "sources_url_unique", + "columns": ["url"], + "isUnique": true + }, + "idx_sources_url": { + "name": "idx_sources_url", + "columns": ["url"], + "isUnique": false + }, + "idx_sources_icon_url": { + "name": "idx_sources_icon_url", + "columns": ["icon_url"], + "isUnique": false + }, + "idx_sources_last_fetched": { + "name": "idx_sources_last_fetched", + "columns": ["last_fetched"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "subscription_categories": { + "name": "subscription_categories", + "columns": { + "subscription_id": { + "name": "subscription_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_subscription_categories_subscription_id": { + "name": "idx_subscription_categories_subscription_id", + "columns": ["subscription_id"], + "isUnique": false + }, + "idx_subscription_categories_category_id": { + "name": "idx_subscription_categories_category_id", + "columns": ["category_id"], + "isUnique": false + } + }, + "foreignKeys": { + "subscription_categories_subscription_id_subscriptions_id_fk": { + "name": "subscription_categories_subscription_id_subscriptions_id_fk", + "tableFrom": "subscription_categories", + "tableTo": "subscriptions", + "columnsFrom": ["subscription_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "subscription_categories_category_id_categories_id_fk": { + "name": "subscription_categories_category_id_categories_id_fk", + "tableFrom": "subscription_categories", + "tableTo": "categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "subscription_categories_subscription_id_category_id_pk": { + "columns": ["subscription_id", "category_id"], + "name": "subscription_categories_subscription_id_category_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "subscription_filters": { + "name": "subscription_filters", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "subscription_id": { + "name": "subscription_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "field": { + "name": "field", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "match_type": { + "name": "match_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pattern": { + "name": "pattern", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "case_sensitive": { + "name": "case_sensitive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_subscription_filters_subscription_id": { + "name": "idx_subscription_filters_subscription_id", + "columns": ["subscription_id"], + "isUnique": false + } + }, + "foreignKeys": { + "subscription_filters_subscription_id_subscriptions_id_fk": { + "name": "subscription_filters_subscription_id_subscriptions_id_fk", + "tableFrom": "subscription_filters", + "tableTo": "subscriptions", + "columnsFrom": ["subscription_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "subscriptions": { + "name": "subscriptions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_id": { + "name": "source_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "custom_title": { + "name": "custom_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "filter_enabled": { + "name": "filter_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "filter_mode": { + "name": "filter_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'include'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_subscriptions_user_id": { + "name": "idx_subscriptions_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_subscriptions_source_id": { + "name": "idx_subscriptions_source_id", + "columns": ["source_id"], + "isUnique": false + }, + "idx_subscriptions_user_source": { + "name": "idx_subscriptions_user_source", + "columns": ["user_id", "source_id"], + "isUnique": false + }, + "idx_subscriptions_user_created": { + "name": "idx_subscriptions_user_created", + "columns": ["user_id", "created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "subscriptions_user_id_user_id_fk": { + "name": "subscriptions_user_id_user_id_fk", + "tableFrom": "subscriptions", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "subscriptions_source_id_sources_id_fk": { + "name": "subscriptions_source_id_sources_id_fk", + "tableFrom": "subscriptions", + "tableTo": "sources", + "columnsFrom": ["source_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "usage_stats": { + "name": "usage_stats", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "source_count": { + "name": "source_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "public_feed_count": { + "name": "public_feed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "category_count": { + "name": "category_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "article_count": { + "name": "article_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_updated": { + "name": "last_updated", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "usage_stats_user_id_user_id_fk": { + "name": "usage_stats_user_id_user_id_fk", + "tableFrom": "usage_stats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_username": { + "name": "display_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "plan": { + "name": "plan", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'free'" + }, + "banned": { + "name": "banned", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": ["email"], + "isUnique": true + }, + "user_username_unique": { + "name": "user_username_unique", + "columns": ["username"], + "isUnique": true + }, + "idx_user_plan": { + "name": "idx_user_plan", + "columns": ["plan"], + "isUnique": false + }, + "idx_user_created_at": { + "name": "idx_user_created_at", + "columns": ["created_at"], + "isUnique": false + }, + "idx_user_last_seen_at": { + "name": "idx_user_last_seen_at", + "columns": ["last_seen_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_article_states": { + "name": "user_article_states", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "article_id": { + "name": "article_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "read": { + "name": "read", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "saved": { + "name": "saved", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "audio_position": { + "name": "audio_position", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "audio_duration": { + "name": "audio_duration", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "audio_completed_at": { + "name": "audio_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "audio_last_played_at": { + "name": "audio_last_played_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_user_article_states_user_id": { + "name": "idx_user_article_states_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_user_article_states_read": { + "name": "idx_user_article_states_read", + "columns": ["read"], + "isUnique": false + }, + "idx_user_article_states_saved": { + "name": "idx_user_article_states_saved", + "columns": ["saved"], + "isUnique": false + }, + "idx_user_article_states_audio_position": { + "name": "idx_user_article_states_audio_position", + "columns": ["audio_position"], + "isUnique": false + } + }, + "foreignKeys": { + "user_article_states_user_id_user_id_fk": { + "name": "user_article_states_user_id_user_id_fk", + "tableFrom": "user_article_states", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_article_states_article_id_articles_id_fk": { + "name": "user_article_states_article_id_articles_id_fk", + "tableFrom": "user_article_states", + "tableTo": "articles", + "columnsFrom": ["article_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_article_states_user_id_article_id_pk": { + "columns": ["user_id", "article_id"], + "name": "user_article_states_user_id_article_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_limits": { + "name": "user_limits", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "max_sources": { + "name": "max_sources", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "max_public_feeds": { + "name": "max_public_feeds", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "max_categories": { + "name": "max_categories", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "api_rate_limit_per_minute": { + "name": "api_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "public_feed_rate_limit_per_minute": { + "name": "public_feed_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_limits_user_id_user_id_fk": { + "name": "user_limits_user_id_user_id_fk", + "tableFrom": "user_limits", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_settings": { + "name": "user_settings", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "theme": { + "name": "theme", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'system'" + }, + "auto_age_days": { + "name": "auto_age_days", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 7 + }, + "default_filter": { + "name": "default_filter", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'all'" + }, + "share_email": { + "name": "share_email", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "share_hackernews": { + "name": "share_hackernews", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_reddit": { + "name": "share_reddit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_twitter": { + "name": "share_twitter", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_bluesky": { + "name": "share_bluesky", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_mastodon": { + "name": "share_mastodon", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_user_settings_user_id": { + "name": "idx_user_settings_user_id", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "user_settings_user_id_user_id_fk": { + "name": "user_settings_user_id_user_id_fk", + "tableFrom": "user_settings", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": { + "idx_categories_user_id_name_normalized": { + "columns": { + "LOWER(\"name\")": { + "isExpression": true + } + } + } + } + } +} diff --git a/packages/api/drizzle/meta/0013_snapshot.json b/packages/api/drizzle/meta/0013_snapshot.json new file mode 100644 index 00000000..b1f24731 --- /dev/null +++ b/packages/api/drizzle/meta/0013_snapshot.json @@ -0,0 +1,2253 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "66cdca36-c872-406c-a1c5-73e97836948a", + "prevId": "3714a2ad-2162-4a45-961f-ae868cf669c2", + "tables": { + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "api_usage_log": { + "name": "api_usage_log", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status_code": { + "name": "status_code", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_api_usage_log_user_id": { + "name": "idx_api_usage_log_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_api_usage_log_created_at": { + "name": "idx_api_usage_log_created_at", + "columns": ["created_at"], + "isUnique": false + }, + "idx_api_usage_log_endpoint": { + "name": "idx_api_usage_log_endpoint", + "columns": ["endpoint"], + "isUnique": false + } + }, + "foreignKeys": { + "api_usage_log_user_id_user_id_fk": { + "name": "api_usage_log_user_id_user_id_fk", + "tableFrom": "api_usage_log", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "articles": { + "name": "articles", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "source_id": { + "name": "source_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guid": { + "name": "guid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "audio_url": { + "name": "audio_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "comment_link": { + "name": "comment_link", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_at": { + "name": "published_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_articles_source_id": { + "name": "idx_articles_source_id", + "columns": ["source_id"], + "isUnique": false + }, + "idx_articles_published_at": { + "name": "idx_articles_published_at", + "columns": ["published_at"], + "isUnique": false + }, + "idx_articles_guid": { + "name": "idx_articles_guid", + "columns": ["guid"], + "isUnique": false + }, + "idx_articles_audio_url": { + "name": "idx_articles_audio_url", + "columns": ["audio_url"], + "isUnique": false + }, + "idx_articles_source_published": { + "name": "idx_articles_source_published", + "columns": ["source_id", "published_at"], + "isUnique": false + }, + "articles_source_id_guid_unique": { + "name": "articles_source_id_guid_unique", + "columns": ["source_id", "guid"], + "isUnique": true + } + }, + "foreignKeys": { + "articles_source_id_sources_id_fk": { + "name": "articles_source_id_sources_id_fk", + "tableFrom": "articles", + "tableTo": "sources", + "columnsFrom": ["source_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "auth_rate_limits": { + "name": "auth_rate_limits", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "window_started_at": { + "name": "window_started_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "locked_until": { + "name": "locked_until", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "blocked_domains": { + "name": "blocked_domains", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "blocked_domains_domain_unique": { + "name": "blocked_domains_domain_unique", + "columns": ["domain"], + "isUnique": true + }, + "idx_blocked_domains_domain": { + "name": "idx_blocked_domains_domain", + "columns": ["domain"], + "isUnique": false + }, + "idx_blocked_domains_reason": { + "name": "idx_blocked_domains_reason", + "columns": ["reason"], + "isUnique": false + }, + "idx_blocked_domains_created_at": { + "name": "idx_blocked_domains_created_at", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "blocked_domains_created_by_user_id_fk": { + "name": "blocked_domains_created_by_user_id_fk", + "tableFrom": "blocked_domains", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "categories": { + "name": "categories", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_categories_user_id": { + "name": "idx_categories_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_categories_name": { + "name": "idx_categories_name", + "columns": ["name"], + "isUnique": false + }, + "idx_categories_user_id_name_normalized": { + "name": "idx_categories_user_id_name_normalized", + "columns": ["user_id", "LOWER(\"name\")"], + "isUnique": true + } + }, + "foreignKeys": { + "categories_user_id_user_id_fk": { + "name": "categories_user_id_user_id_fk", + "tableFrom": "categories", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feed_categories": { + "name": "feed_categories", + "columns": { + "feed_id": { + "name": "feed_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_feed_categories_feed_id": { + "name": "idx_feed_categories_feed_id", + "columns": ["feed_id"], + "isUnique": false + }, + "idx_feed_categories_category_id": { + "name": "idx_feed_categories_category_id", + "columns": ["category_id"], + "isUnique": false + } + }, + "foreignKeys": { + "feed_categories_feed_id_feeds_id_fk": { + "name": "feed_categories_feed_id_feeds_id_fk", + "tableFrom": "feed_categories", + "tableTo": "feeds", + "columnsFrom": ["feed_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "feed_categories_category_id_categories_id_fk": { + "name": "feed_categories_category_id_categories_id_fk", + "tableFrom": "feed_categories", + "tableTo": "categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "feed_categories_feed_id_category_id_pk": { + "columns": ["feed_id", "category_id"], + "name": "feed_categories_feed_id_category_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feeds": { + "name": "feeds", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "public": { + "name": "public", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_feeds_user_id": { + "name": "idx_feeds_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_feeds_slug": { + "name": "idx_feeds_slug", + "columns": ["slug"], + "isUnique": false + }, + "idx_feeds_created_at": { + "name": "idx_feeds_created_at", + "columns": ["created_at"], + "isUnique": false + }, + "feeds_user_id_slug_unique": { + "name": "feeds_user_id_slug_unique", + "columns": ["user_id", "slug"], + "isUnique": true + } + }, + "foreignKeys": { + "feeds_user_id_user_id_fk": { + "name": "feeds_user_id_user_id_fk", + "tableFrom": "feeds", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "global_settings": { + "name": "global_settings", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "max_login_attempts": { + "name": "max_login_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 5 + }, + "login_attempt_window_minutes": { + "name": "login_attempt_window_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 15 + }, + "lockout_duration_minutes": { + "name": "lockout_duration_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 30 + }, + "allow_registration": { + "name": "allow_registration", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "require_email_verification": { + "name": "require_email_verification", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "admin_bypass_email_verification": { + "name": "admin_bypass_email_verification", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "password_reset_token_expiry_hours": { + "name": "password_reset_token_expiry_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "fetch_interval_minutes": { + "name": "fetch_interval_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 60 + }, + "prune_days": { + "name": "prune_days", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 90 + }, + "last_rss_fetch_at": { + "name": "last_rss_fetch_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_prune_at": { + "name": "last_prune_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_token_cleanup_at": { + "name": "last_token_cleanup_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ai_enabled": { + "name": "ai_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "global_settings_updated_by_user_id_fk": { + "name": "global_settings_updated_by_user_id_fk", + "tableFrom": "global_settings", + "tableTo": "user", + "columnsFrom": ["updated_by"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "password_reset_tokens": { + "name": "password_reset_tokens", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "used": { + "name": "used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "password_reset_tokens_token_unique": { + "name": "password_reset_tokens_token_unique", + "columns": ["token"], + "isUnique": true + }, + "idx_password_reset_tokens_token": { + "name": "idx_password_reset_tokens_token", + "columns": ["token"], + "isUnique": false + }, + "idx_password_reset_tokens_user_id": { + "name": "idx_password_reset_tokens_user_id", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "password_reset_tokens_user_id_user_id_fk": { + "name": "password_reset_tokens_user_id_user_id_fk", + "tableFrom": "password_reset_tokens", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plans": { + "name": "plans", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "max_sources": { + "name": "max_sources", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "max_public_feeds": { + "name": "max_public_feeds", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "max_categories": { + "name": "max_categories", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "api_rate_limit_per_minute": { + "name": "api_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "public_feed_rate_limit_per_minute": { + "name": "public_feed_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "price_cents": { + "name": "price_cents", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "features": { + "name": "features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "public_feed_access_log": { + "name": "public_feed_access_log", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "feed_id": { + "name": "feed_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "accessed_at": { + "name": "accessed_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_public_feed_access_log_feed_id": { + "name": "idx_public_feed_access_log_feed_id", + "columns": ["feed_id"], + "isUnique": false + }, + "idx_public_feed_access_log_accessed_at": { + "name": "idx_public_feed_access_log_accessed_at", + "columns": ["accessed_at"], + "isUnique": false + } + }, + "foreignKeys": { + "public_feed_access_log_feed_id_feeds_id_fk": { + "name": "public_feed_access_log_feed_id_feeds_id_fk", + "tableFrom": "public_feed_access_log", + "tableTo": "feeds", + "columnsFrom": ["feed_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "security_audit_log": { + "name": "security_audit_log", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "success": { + "name": "success", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "idx_security_audit_log_user_id": { + "name": "idx_security_audit_log_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_security_audit_log_action": { + "name": "idx_security_audit_log_action", + "columns": ["action"], + "isUnique": false + }, + "idx_security_audit_log_created_at": { + "name": "idx_security_audit_log_created_at", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "security_audit_log_user_id_user_id_fk": { + "name": "security_audit_log_user_id_user_id_fk", + "tableFrom": "security_audit_log", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": ["token"], + "isUnique": true + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sources": { + "name": "sources", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "site_url": { + "name": "site_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_type": { + "name": "icon_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'auto'" + }, + "icon_updated_at": { + "name": "icon_updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_fetched": { + "name": "last_fetched", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_fetch_attempt_at": { + "name": "last_fetch_attempt_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "sources_url_unique": { + "name": "sources_url_unique", + "columns": ["url"], + "isUnique": true + }, + "idx_sources_url": { + "name": "idx_sources_url", + "columns": ["url"], + "isUnique": false + }, + "idx_sources_icon_url": { + "name": "idx_sources_icon_url", + "columns": ["icon_url"], + "isUnique": false + }, + "idx_sources_last_fetched": { + "name": "idx_sources_last_fetched", + "columns": ["last_fetched"], + "isUnique": false + }, + "idx_sources_last_fetch_attempt_at": { + "name": "idx_sources_last_fetch_attempt_at", + "columns": ["last_fetch_attempt_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "subscription_categories": { + "name": "subscription_categories", + "columns": { + "subscription_id": { + "name": "subscription_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_subscription_categories_subscription_id": { + "name": "idx_subscription_categories_subscription_id", + "columns": ["subscription_id"], + "isUnique": false + }, + "idx_subscription_categories_category_id": { + "name": "idx_subscription_categories_category_id", + "columns": ["category_id"], + "isUnique": false + } + }, + "foreignKeys": { + "subscription_categories_subscription_id_subscriptions_id_fk": { + "name": "subscription_categories_subscription_id_subscriptions_id_fk", + "tableFrom": "subscription_categories", + "tableTo": "subscriptions", + "columnsFrom": ["subscription_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "subscription_categories_category_id_categories_id_fk": { + "name": "subscription_categories_category_id_categories_id_fk", + "tableFrom": "subscription_categories", + "tableTo": "categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "subscription_categories_subscription_id_category_id_pk": { + "columns": ["subscription_id", "category_id"], + "name": "subscription_categories_subscription_id_category_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "subscription_filters": { + "name": "subscription_filters", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "subscription_id": { + "name": "subscription_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "field": { + "name": "field", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "match_type": { + "name": "match_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pattern": { + "name": "pattern", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "case_sensitive": { + "name": "case_sensitive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_subscription_filters_subscription_id": { + "name": "idx_subscription_filters_subscription_id", + "columns": ["subscription_id"], + "isUnique": false + } + }, + "foreignKeys": { + "subscription_filters_subscription_id_subscriptions_id_fk": { + "name": "subscription_filters_subscription_id_subscriptions_id_fk", + "tableFrom": "subscription_filters", + "tableTo": "subscriptions", + "columnsFrom": ["subscription_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "subscriptions": { + "name": "subscriptions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_id": { + "name": "source_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "custom_title": { + "name": "custom_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "filter_enabled": { + "name": "filter_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "filter_mode": { + "name": "filter_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'include'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_subscriptions_user_id": { + "name": "idx_subscriptions_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_subscriptions_source_id": { + "name": "idx_subscriptions_source_id", + "columns": ["source_id"], + "isUnique": false + }, + "idx_subscriptions_user_source": { + "name": "idx_subscriptions_user_source", + "columns": ["user_id", "source_id"], + "isUnique": false + }, + "idx_subscriptions_user_created": { + "name": "idx_subscriptions_user_created", + "columns": ["user_id", "created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "subscriptions_user_id_user_id_fk": { + "name": "subscriptions_user_id_user_id_fk", + "tableFrom": "subscriptions", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "subscriptions_source_id_sources_id_fk": { + "name": "subscriptions_source_id_sources_id_fk", + "tableFrom": "subscriptions", + "tableTo": "sources", + "columnsFrom": ["source_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "usage_stats": { + "name": "usage_stats", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "source_count": { + "name": "source_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "public_feed_count": { + "name": "public_feed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "category_count": { + "name": "category_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "article_count": { + "name": "article_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_updated": { + "name": "last_updated", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "usage_stats_user_id_user_id_fk": { + "name": "usage_stats_user_id_user_id_fk", + "tableFrom": "usage_stats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_username": { + "name": "display_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "plan": { + "name": "plan", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'free'" + }, + "banned": { + "name": "banned", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": ["email"], + "isUnique": true + }, + "user_username_unique": { + "name": "user_username_unique", + "columns": ["username"], + "isUnique": true + }, + "idx_user_plan": { + "name": "idx_user_plan", + "columns": ["plan"], + "isUnique": false + }, + "idx_user_created_at": { + "name": "idx_user_created_at", + "columns": ["created_at"], + "isUnique": false + }, + "idx_user_last_seen_at": { + "name": "idx_user_last_seen_at", + "columns": ["last_seen_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_article_states": { + "name": "user_article_states", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "article_id": { + "name": "article_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "read": { + "name": "read", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "saved": { + "name": "saved", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "audio_position": { + "name": "audio_position", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "audio_duration": { + "name": "audio_duration", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "audio_completed_at": { + "name": "audio_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "audio_last_played_at": { + "name": "audio_last_played_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_user_article_states_user_id": { + "name": "idx_user_article_states_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_user_article_states_read": { + "name": "idx_user_article_states_read", + "columns": ["read"], + "isUnique": false + }, + "idx_user_article_states_saved": { + "name": "idx_user_article_states_saved", + "columns": ["saved"], + "isUnique": false + }, + "idx_user_article_states_audio_position": { + "name": "idx_user_article_states_audio_position", + "columns": ["audio_position"], + "isUnique": false + } + }, + "foreignKeys": { + "user_article_states_user_id_user_id_fk": { + "name": "user_article_states_user_id_user_id_fk", + "tableFrom": "user_article_states", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_article_states_article_id_articles_id_fk": { + "name": "user_article_states_article_id_articles_id_fk", + "tableFrom": "user_article_states", + "tableTo": "articles", + "columnsFrom": ["article_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_article_states_user_id_article_id_pk": { + "columns": ["user_id", "article_id"], + "name": "user_article_states_user_id_article_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_limits": { + "name": "user_limits", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "max_sources": { + "name": "max_sources", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "max_public_feeds": { + "name": "max_public_feeds", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "max_categories": { + "name": "max_categories", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "api_rate_limit_per_minute": { + "name": "api_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "public_feed_rate_limit_per_minute": { + "name": "public_feed_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_limits_user_id_user_id_fk": { + "name": "user_limits_user_id_user_id_fk", + "tableFrom": "user_limits", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_settings": { + "name": "user_settings", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "theme": { + "name": "theme", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'system'" + }, + "auto_age_days": { + "name": "auto_age_days", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 7 + }, + "default_filter": { + "name": "default_filter", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'all'" + }, + "share_email": { + "name": "share_email", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "share_hackernews": { + "name": "share_hackernews", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_reddit": { + "name": "share_reddit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_twitter": { + "name": "share_twitter", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_bluesky": { + "name": "share_bluesky", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_mastodon": { + "name": "share_mastodon", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_user_settings_user_id": { + "name": "idx_user_settings_user_id", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "user_settings_user_id_user_id_fk": { + "name": "user_settings_user_id_user_id_fk", + "tableFrom": "user_settings", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": { + "idx_categories_user_id_name_normalized": { + "columns": { + "LOWER(\"name\")": { + "isExpression": true + } + } + } + } + } +} diff --git a/packages/api/drizzle/meta/0014_snapshot.json b/packages/api/drizzle/meta/0014_snapshot.json new file mode 100644 index 00000000..c171b581 --- /dev/null +++ b/packages/api/drizzle/meta/0014_snapshot.json @@ -0,0 +1,2337 @@ +{ + "version": "6", + "dialect": "sqlite", + "id": "dc6c461f-e59d-4296-8628-383e9047e1b4", + "prevId": "66cdca36-c872-406c-a1c5-73e97836948a", + "tables": { + "account": { + "name": "account", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "account_id": { + "name": "account_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "provider_id": { + "name": "provider_id", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token": { + "name": "refresh_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "id_token": { + "name": "id_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "access_token_expires_at": { + "name": "access_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "refresh_token_expires_at": { + "name": "refresh_token_expires_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "account_user_id_user_id_fk": { + "name": "account_user_id_user_id_fk", + "tableFrom": "account", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "api_usage_log": { + "name": "api_usage_log", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "endpoint": { + "name": "endpoint", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "method": { + "name": "method", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "status_code": { + "name": "status_code", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "duration_ms": { + "name": "duration_ms", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_api_usage_log_user_id": { + "name": "idx_api_usage_log_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_api_usage_log_created_at": { + "name": "idx_api_usage_log_created_at", + "columns": ["created_at"], + "isUnique": false + }, + "idx_api_usage_log_endpoint": { + "name": "idx_api_usage_log_endpoint", + "columns": ["endpoint"], + "isUnique": false + } + }, + "foreignKeys": { + "api_usage_log_user_id_user_id_fk": { + "name": "api_usage_log_user_id_user_id_fk", + "tableFrom": "api_usage_log", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "articles": { + "name": "articles", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "source_id": { + "name": "source_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "guid": { + "name": "guid", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "link": { + "name": "link", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "author": { + "name": "author", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "image_url": { + "name": "image_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "audio_url": { + "name": "audio_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "comment_link": { + "name": "comment_link", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "published_at": { + "name": "published_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_articles_source_id": { + "name": "idx_articles_source_id", + "columns": ["source_id"], + "isUnique": false + }, + "idx_articles_published_at": { + "name": "idx_articles_published_at", + "columns": ["published_at"], + "isUnique": false + }, + "idx_articles_guid": { + "name": "idx_articles_guid", + "columns": ["guid"], + "isUnique": false + }, + "idx_articles_audio_url": { + "name": "idx_articles_audio_url", + "columns": ["audio_url"], + "isUnique": false + }, + "idx_articles_source_published": { + "name": "idx_articles_source_published", + "columns": ["source_id", "published_at"], + "isUnique": false + }, + "articles_source_id_guid_unique": { + "name": "articles_source_id_guid_unique", + "columns": ["source_id", "guid"], + "isUnique": true + } + }, + "foreignKeys": { + "articles_source_id_sources_id_fk": { + "name": "articles_source_id_sources_id_fk", + "tableFrom": "articles", + "tableTo": "sources", + "columnsFrom": ["source_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "auth_rate_limits": { + "name": "auth_rate_limits", + "columns": { + "key": { + "name": "key", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "attempts": { + "name": "attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "window_started_at": { + "name": "window_started_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "locked_until": { + "name": "locked_until", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "blocked_domains": { + "name": "blocked_domains", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "domain": { + "name": "domain", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "reason": { + "name": "reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_by": { + "name": "created_by", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "blocked_domains_domain_unique": { + "name": "blocked_domains_domain_unique", + "columns": ["domain"], + "isUnique": true + }, + "idx_blocked_domains_domain": { + "name": "idx_blocked_domains_domain", + "columns": ["domain"], + "isUnique": false + }, + "idx_blocked_domains_reason": { + "name": "idx_blocked_domains_reason", + "columns": ["reason"], + "isUnique": false + }, + "idx_blocked_domains_created_at": { + "name": "idx_blocked_domains_created_at", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "blocked_domains_created_by_user_id_fk": { + "name": "blocked_domains_created_by_user_id_fk", + "tableFrom": "blocked_domains", + "tableTo": "user", + "columnsFrom": ["created_by"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "categories": { + "name": "categories", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "color": { + "name": "color", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "icon": { + "name": "icon", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_categories_user_id": { + "name": "idx_categories_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_categories_name": { + "name": "idx_categories_name", + "columns": ["name"], + "isUnique": false + }, + "idx_categories_user_id_name_normalized": { + "name": "idx_categories_user_id_name_normalized", + "columns": ["user_id", "LOWER(\"name\")"], + "isUnique": true + } + }, + "foreignKeys": { + "categories_user_id_user_id_fk": { + "name": "categories_user_id_user_id_fk", + "tableFrom": "categories", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feed_categories": { + "name": "feed_categories", + "columns": { + "feed_id": { + "name": "feed_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_feed_categories_feed_id": { + "name": "idx_feed_categories_feed_id", + "columns": ["feed_id"], + "isUnique": false + }, + "idx_feed_categories_category_id": { + "name": "idx_feed_categories_category_id", + "columns": ["category_id"], + "isUnique": false + } + }, + "foreignKeys": { + "feed_categories_feed_id_feeds_id_fk": { + "name": "feed_categories_feed_id_feeds_id_fk", + "tableFrom": "feed_categories", + "tableTo": "feeds", + "columnsFrom": ["feed_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "feed_categories_category_id_categories_id_fk": { + "name": "feed_categories_category_id_categories_id_fk", + "tableFrom": "feed_categories", + "tableTo": "categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "feed_categories_feed_id_category_id_pk": { + "columns": ["feed_id", "category_id"], + "name": "feed_categories_feed_id_category_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feed_fetch_health": { + "name": "feed_fetch_health", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "backlog": { + "name": "backlog", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "failing_batches": { + "name": "failing_batches", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "growing_batches": { + "name": "growing_batches", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_alert_at": { + "name": "last_alert_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "feeds": { + "name": "feeds", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "slug": { + "name": "slug", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "public": { + "name": "public", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_feeds_user_id": { + "name": "idx_feeds_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_feeds_slug": { + "name": "idx_feeds_slug", + "columns": ["slug"], + "isUnique": false + }, + "idx_feeds_created_at": { + "name": "idx_feeds_created_at", + "columns": ["created_at"], + "isUnique": false + }, + "feeds_user_id_slug_unique": { + "name": "feeds_user_id_slug_unique", + "columns": ["user_id", "slug"], + "isUnique": true + } + }, + "foreignKeys": { + "feeds_user_id_user_id_fk": { + "name": "feeds_user_id_user_id_fk", + "tableFrom": "feeds", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "global_settings": { + "name": "global_settings", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "max_login_attempts": { + "name": "max_login_attempts", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 5 + }, + "login_attempt_window_minutes": { + "name": "login_attempt_window_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 15 + }, + "lockout_duration_minutes": { + "name": "lockout_duration_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 30 + }, + "allow_registration": { + "name": "allow_registration", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "require_email_verification": { + "name": "require_email_verification", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "admin_bypass_email_verification": { + "name": "admin_bypass_email_verification", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "password_reset_token_expiry_hours": { + "name": "password_reset_token_expiry_hours", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 1 + }, + "fetch_interval_minutes": { + "name": "fetch_interval_minutes", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 60 + }, + "prune_days": { + "name": "prune_days", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 90 + }, + "last_rss_fetch_at": { + "name": "last_rss_fetch_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_prune_at": { + "name": "last_prune_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_token_cleanup_at": { + "name": "last_token_cleanup_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ai_enabled": { + "name": "ai_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_by": { + "name": "updated_by", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "global_settings_updated_by_user_id_fk": { + "name": "global_settings_updated_by_user_id_fk", + "tableFrom": "global_settings", + "tableTo": "user", + "columnsFrom": ["updated_by"], + "columnsTo": ["id"], + "onDelete": "no action", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "password_reset_tokens": { + "name": "password_reset_tokens", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "used": { + "name": "used", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "password_reset_tokens_token_unique": { + "name": "password_reset_tokens_token_unique", + "columns": ["token"], + "isUnique": true + }, + "idx_password_reset_tokens_token": { + "name": "idx_password_reset_tokens_token", + "columns": ["token"], + "isUnique": false + }, + "idx_password_reset_tokens_user_id": { + "name": "idx_password_reset_tokens_user_id", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "password_reset_tokens_user_id_user_id_fk": { + "name": "password_reset_tokens_user_id_user_id_fk", + "tableFrom": "password_reset_tokens", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "plans": { + "name": "plans", + "columns": { + "id": { + "name": "id", + "type": "text", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "max_sources": { + "name": "max_sources", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "max_public_feeds": { + "name": "max_public_feeds", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "max_categories": { + "name": "max_categories", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "api_rate_limit_per_minute": { + "name": "api_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "public_feed_rate_limit_per_minute": { + "name": "public_feed_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "price_cents": { + "name": "price_cents", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "features": { + "name": "features", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "public_feed_access_log": { + "name": "public_feed_access_log", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "feed_id": { + "name": "feed_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "accessed_at": { + "name": "accessed_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_public_feed_access_log_feed_id": { + "name": "idx_public_feed_access_log_feed_id", + "columns": ["feed_id"], + "isUnique": false + }, + "idx_public_feed_access_log_accessed_at": { + "name": "idx_public_feed_access_log_accessed_at", + "columns": ["accessed_at"], + "isUnique": false + } + }, + "foreignKeys": { + "public_feed_access_log_feed_id_feeds_id_fk": { + "name": "public_feed_access_log_feed_id_feeds_id_fk", + "tableFrom": "public_feed_access_log", + "tableTo": "feeds", + "columnsFrom": ["feed_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "security_audit_log": { + "name": "security_audit_log", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "action": { + "name": "action", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "metadata": { + "name": "metadata", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "success": { + "name": "success", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": { + "idx_security_audit_log_user_id": { + "name": "idx_security_audit_log_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_security_audit_log_action": { + "name": "idx_security_audit_log_action", + "columns": ["action"], + "isUnique": false + }, + "idx_security_audit_log_created_at": { + "name": "idx_security_audit_log_created_at", + "columns": ["created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "security_audit_log_user_id_user_id_fk": { + "name": "security_audit_log_user_id_user_id_fk", + "tableFrom": "security_audit_log", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "set null", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "session": { + "name": "session", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "token": { + "name": "token", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "ip_address": { + "name": "ip_address", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_agent": { + "name": "user_agent", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "impersonated_by": { + "name": "impersonated_by", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "session_token_unique": { + "name": "session_token_unique", + "columns": ["token"], + "isUnique": true + } + }, + "foreignKeys": { + "session_user_id_user_id_fk": { + "name": "session_user_id_user_id_fk", + "tableFrom": "session", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "sources": { + "name": "sources", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "title": { + "name": "title", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "site_url": { + "name": "site_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_url": { + "name": "icon_url", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "icon_type": { + "name": "icon_type", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'auto'" + }, + "icon_updated_at": { + "name": "icon_updated_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fetch_lease_token": { + "name": "fetch_lease_token", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "fetch_lease_until": { + "name": "fetch_lease_until", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "next_fetch_at": { + "name": "next_fetch_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_fetch_error": { + "name": "last_fetch_error", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "consecutive_fetch_failures": { + "name": "consecutive_fetch_failures", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_fetched": { + "name": "last_fetched", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "last_fetch_attempt_at": { + "name": "last_fetch_attempt_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "sources_url_unique": { + "name": "sources_url_unique", + "columns": ["url"], + "isUnique": true + }, + "idx_sources_url": { + "name": "idx_sources_url", + "columns": ["url"], + "isUnique": false + }, + "idx_sources_icon_url": { + "name": "idx_sources_icon_url", + "columns": ["icon_url"], + "isUnique": false + }, + "idx_sources_last_fetched": { + "name": "idx_sources_last_fetched", + "columns": ["last_fetched"], + "isUnique": false + }, + "idx_sources_last_fetch_attempt_at": { + "name": "idx_sources_last_fetch_attempt_at", + "columns": ["last_fetch_attempt_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "subscription_categories": { + "name": "subscription_categories", + "columns": { + "subscription_id": { + "name": "subscription_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "category_id": { + "name": "category_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_subscription_categories_subscription_id": { + "name": "idx_subscription_categories_subscription_id", + "columns": ["subscription_id"], + "isUnique": false + }, + "idx_subscription_categories_category_id": { + "name": "idx_subscription_categories_category_id", + "columns": ["category_id"], + "isUnique": false + } + }, + "foreignKeys": { + "subscription_categories_subscription_id_subscriptions_id_fk": { + "name": "subscription_categories_subscription_id_subscriptions_id_fk", + "tableFrom": "subscription_categories", + "tableTo": "subscriptions", + "columnsFrom": ["subscription_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "subscription_categories_category_id_categories_id_fk": { + "name": "subscription_categories_category_id_categories_id_fk", + "tableFrom": "subscription_categories", + "tableTo": "categories", + "columnsFrom": ["category_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "subscription_categories_subscription_id_category_id_pk": { + "columns": ["subscription_id", "category_id"], + "name": "subscription_categories_subscription_id_category_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "subscription_filters": { + "name": "subscription_filters", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "subscription_id": { + "name": "subscription_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "field": { + "name": "field", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "match_type": { + "name": "match_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "pattern": { + "name": "pattern", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "case_sensitive": { + "name": "case_sensitive", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_subscription_filters_subscription_id": { + "name": "idx_subscription_filters_subscription_id", + "columns": ["subscription_id"], + "isUnique": false + } + }, + "foreignKeys": { + "subscription_filters_subscription_id_subscriptions_id_fk": { + "name": "subscription_filters_subscription_id_subscriptions_id_fk", + "tableFrom": "subscription_filters", + "tableTo": "subscriptions", + "columnsFrom": ["subscription_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "subscriptions": { + "name": "subscriptions", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "source_id": { + "name": "source_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "custom_title": { + "name": "custom_title", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "filter_enabled": { + "name": "filter_enabled", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "filter_mode": { + "name": "filter_mode", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'include'" + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_subscriptions_user_id": { + "name": "idx_subscriptions_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_subscriptions_source_id": { + "name": "idx_subscriptions_source_id", + "columns": ["source_id"], + "isUnique": false + }, + "idx_subscriptions_user_source": { + "name": "idx_subscriptions_user_source", + "columns": ["user_id", "source_id"], + "isUnique": false + }, + "idx_subscriptions_user_created": { + "name": "idx_subscriptions_user_created", + "columns": ["user_id", "created_at"], + "isUnique": false + } + }, + "foreignKeys": { + "subscriptions_user_id_user_id_fk": { + "name": "subscriptions_user_id_user_id_fk", + "tableFrom": "subscriptions", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "subscriptions_source_id_sources_id_fk": { + "name": "subscriptions_source_id_sources_id_fk", + "tableFrom": "subscriptions", + "tableTo": "sources", + "columnsFrom": ["source_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "usage_stats": { + "name": "usage_stats", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "source_count": { + "name": "source_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "public_feed_count": { + "name": "public_feed_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "category_count": { + "name": "category_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "article_count": { + "name": "article_count", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 0 + }, + "last_updated": { + "name": "last_updated", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "usage_stats_user_id_user_id_fk": { + "name": "usage_stats_user_id_user_id_fk", + "tableFrom": "usage_stats", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user": { + "name": "user", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "email_verified": { + "name": "email_verified", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "image": { + "name": "image", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "last_seen_at": { + "name": "last_seen_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "display_username": { + "name": "display_username", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "role": { + "name": "role", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "plan": { + "name": "plan", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": "'free'" + }, + "banned": { + "name": "banned", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": false + }, + "ban_reason": { + "name": "ban_reason", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "ban_expires": { + "name": "ban_expires", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + } + }, + "indexes": { + "user_email_unique": { + "name": "user_email_unique", + "columns": ["email"], + "isUnique": true + }, + "user_username_unique": { + "name": "user_username_unique", + "columns": ["username"], + "isUnique": true + }, + "idx_user_plan": { + "name": "idx_user_plan", + "columns": ["plan"], + "isUnique": false + }, + "idx_user_created_at": { + "name": "idx_user_created_at", + "columns": ["created_at"], + "isUnique": false + }, + "idx_user_last_seen_at": { + "name": "idx_user_last_seen_at", + "columns": ["last_seen_at"], + "isUnique": false + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_article_states": { + "name": "user_article_states", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "article_id": { + "name": "article_id", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "read": { + "name": "read", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "saved": { + "name": "saved", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "audio_position": { + "name": "audio_position", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false, + "default": 0 + }, + "audio_duration": { + "name": "audio_duration", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "audio_completed_at": { + "name": "audio_completed_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "audio_last_played_at": { + "name": "audio_last_played_at", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_user_article_states_user_id": { + "name": "idx_user_article_states_user_id", + "columns": ["user_id"], + "isUnique": false + }, + "idx_user_article_states_read": { + "name": "idx_user_article_states_read", + "columns": ["read"], + "isUnique": false + }, + "idx_user_article_states_saved": { + "name": "idx_user_article_states_saved", + "columns": ["saved"], + "isUnique": false + }, + "idx_user_article_states_audio_position": { + "name": "idx_user_article_states_audio_position", + "columns": ["audio_position"], + "isUnique": false + } + }, + "foreignKeys": { + "user_article_states_user_id_user_id_fk": { + "name": "user_article_states_user_id_user_id_fk", + "tableFrom": "user_article_states", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + }, + "user_article_states_article_id_articles_id_fk": { + "name": "user_article_states_article_id_articles_id_fk", + "tableFrom": "user_article_states", + "tableTo": "articles", + "columnsFrom": ["article_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": { + "user_article_states_user_id_article_id_pk": { + "columns": ["user_id", "article_id"], + "name": "user_article_states_user_id_article_id_pk" + } + }, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_limits": { + "name": "user_limits", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "max_sources": { + "name": "max_sources", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "max_public_feeds": { + "name": "max_public_feeds", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "max_categories": { + "name": "max_categories", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "api_rate_limit_per_minute": { + "name": "api_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "public_feed_rate_limit_per_minute": { + "name": "public_feed_rate_limit_per_minute", + "type": "integer", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "notes": { + "name": "notes", + "type": "text", + "primaryKey": false, + "notNull": false, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": {}, + "foreignKeys": { + "user_limits_user_id_user_id_fk": { + "name": "user_limits_user_id_user_id_fk", + "tableFrom": "user_limits", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "user_settings": { + "name": "user_settings", + "columns": { + "user_id": { + "name": "user_id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": false + }, + "theme": { + "name": "theme", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'system'" + }, + "auto_age_days": { + "name": "auto_age_days", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": 7 + }, + "default_filter": { + "name": "default_filter", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "'all'" + }, + "share_email": { + "name": "share_email", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": true + }, + "share_hackernews": { + "name": "share_hackernews", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_reddit": { + "name": "share_reddit", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_twitter": { + "name": "share_twitter", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_bluesky": { + "name": "share_bluesky", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "share_mastodon": { + "name": "share_mastodon", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + } + }, + "indexes": { + "idx_user_settings_user_id": { + "name": "idx_user_settings_user_id", + "columns": ["user_id"], + "isUnique": false + } + }, + "foreignKeys": { + "user_settings_user_id_user_id_fk": { + "name": "user_settings_user_id_user_id_fk", + "tableFrom": "user_settings", + "tableTo": "user", + "columnsFrom": ["user_id"], + "columnsTo": ["id"], + "onDelete": "cascade", + "onUpdate": "no action" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + }, + "verification": { + "name": "verification", + "columns": { + "id": { + "name": "id", + "type": "integer", + "primaryKey": true, + "notNull": true, + "autoincrement": true + }, + "identifier": { + "name": "identifier", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "value": { + "name": "value", + "type": "text", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "expires_at": { + "name": "expires_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false + }, + "created_at": { + "name": "created_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + }, + "updated_at": { + "name": "updated_at", + "type": "integer", + "primaryKey": false, + "notNull": true, + "autoincrement": false, + "default": "(cast(unixepoch('subsecond') * 1000 as integer))" + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {}, + "checkConstraints": {} + } + }, + "views": {}, + "enums": {}, + "_meta": { + "schemas": {}, + "tables": {}, + "columns": {} + }, + "internal": { + "indexes": { + "idx_categories_user_id_name_normalized": { + "columns": { + "LOWER(\"name\")": { + "isExpression": true + } + } + } + } + } +} diff --git a/packages/api/drizzle/meta/_journal.json b/packages/api/drizzle/meta/_journal.json index 1a39c9b3..32309203 100644 --- a/packages/api/drizzle/meta/_journal.json +++ b/packages/api/drizzle/meta/_journal.json @@ -85,6 +85,27 @@ "when": 1767813616227, "tag": "0011_freezing_firebrand", "breakpoints": true + }, + { + "idx": 12, + "version": "6", + "when": 1788799958702, + "tag": "0012_overrated_toxin", + "breakpoints": true + }, + { + "idx": 13, + "version": "6", + "when": 1789844832914, + "tag": "0013_feed_fetch_attempts", + "breakpoints": true + }, + { + "idx": 14, + "version": "6", + "when": 1789860494526, + "tag": "0014_feed_reliability", + "breakpoints": true } ] } diff --git a/packages/api/eslint.config.js b/packages/api/eslint.config.js index f417f4ca..25a77073 100644 --- a/packages/api/eslint.config.js +++ b/packages/api/eslint.config.js @@ -1,7 +1,6 @@ import eslintPluginDrizzle from "eslint-plugin-drizzle"; import typescriptEslint from "@typescript-eslint/eslint-plugin"; import tsParser from "@typescript-eslint/parser"; -import noRelativeImportPaths from "eslint-plugin-no-relative-import-paths"; import { fileURLToPath } from "url"; import { dirname } from "path"; @@ -23,7 +22,6 @@ export default [ plugins: { "@typescript-eslint": typescriptEslint, drizzle: eslintPluginDrizzle, - "no-relative-import-paths": noRelativeImportPaths, }, rules: { ...eslintPluginDrizzle.configs.recommended.rules, @@ -49,9 +47,17 @@ export default [ "@typescript-eslint/await-thenable": "error", "@typescript-eslint/require-await": "warn", // Enforce tsconfig path aliases, disallow ../ imports but allow same folder ./ - "no-relative-import-paths/no-relative-import-paths": [ + "no-restricted-imports": [ "error", - { allowSameFolder: true, rootDir: "src", prefix: "@" }, + { + patterns: [ + { + group: ["../**"], + message: + "Use the configured source path alias for parent imports.", + }, + ], + }, ], }, }, diff --git a/packages/api/package.json b/packages/api/package.json index 2b4c22b0..5d669b99 100644 --- a/packages/api/package.json +++ b/packages/api/package.json @@ -12,12 +12,12 @@ } }, "scripts": { - "dev": "tsx watch --env-file=.env --env-file=../../.env src/entries/node.ts", + "dev": "tsx --tsconfig tsconfig.node.json watch --env-file=.env --env-file=../../.env src/entries/node.ts", "dev:workers": "wrangler dev --persist-to .wrangler/state", "build": "tsup", "build:tsc": "tsc", "start": "node dist/entries/node.js", - "type-check": "tsc --noEmit", + "type-check": "tsc --noEmit && tsc --noEmit -p tsconfig.node.json", "test": "vitest run", "test:watch": "vitest", "test:coverage": "vitest run --coverage", @@ -42,54 +42,54 @@ "email:preview": "pnpm exec email dev --dir src/services/email-templates" }, "dependencies": { - "@ai-sdk/openai": "^3.0.7", - "@hono/node-server": "^1.19.6", - "@hono/trpc-server": "^0.4.1", - "@react-email/components": "^1.0.1", - "@sentry/cloudflare": "^10.26.0", - "@sentry/node": "^10.26.0", - "@trpc/server": "^11.7.2", + "@ai-sdk/openai": "^4.0.70", + "@hono/node-server": "^2.1.1", + "@hono/trpc-server": "^0.4.2", + "@sentry/cloudflare": "^10.75.0", + "@sentry/node": "^10.75.0", + "@trpc/server": "^11.19.0", "@tuvixrss/tricorder": "workspace:*", - "ai": "^6.0.19", + "ai": "^7.0.106", "bcrypt": "^6.0.0", - "better-auth": "^1.4.1", - "better-sqlite3": "^12.4.6", - "drizzle-orm": "^0.44.7", + "better-auth": "^1.7.5", + "better-sqlite3": "^13.0.3", + "drizzle-orm": "^0.45.2", "drizzle-zod": "^0.8.3", - "eslint-plugin-drizzle": "^0.2.3", - "feedsmith": "^2.6.0", - "hono": "^4.10.6", - "node-cron": "^4.2.1", - "react-email": "^5.0.5", - "resend": "^6.5.2", - "sanitize-html": "^2.17.0", + "feedsmith": "^3.0.0", + "hono": "^4.13.8", + "ipaddr.js": "2.5.0", + "node-cron": "^4.6.0", + "react-email": "^6.9.5", + "resend": "^6.28.1", + "sanitize-html": "^2.17.7", "superjson": "^2.2.6", - "zod": "^4.1.12" + "undici": "8.10.2", + "zod": "^4.6.5" }, "devDependencies": { - "@cloudflare/workers-types": "^4.20251121.0", - "@react-email/preview-server": "5.0.5", + "@cloudflare/workers-types": "^5.20260918.1", "@types/bcrypt": "^6.0.0", - "@types/better-sqlite3": "^7.6.13", - "@types/node": "^24.10.1", + "@types/better-sqlite3": "^9.6.0", + "@types/node": "^24.13.5", "@types/node-cron": "^3.0.11", - "@types/react": "^19.2.6", - "@types/sanitize-html": "^2.16.0", - "@typescript-eslint/eslint-plugin": "^8.47.0", - "@typescript-eslint/parser": "^8.47.0", - "@vitest/coverage-v8": "^4.0.13", - "drizzle-kit": "^0.31.7", - "eslint": "^9.39.1", - "knip": "^5.70.1", - "prettier": "^3.6.2", - "react": "^19.2.0", + "@types/react": "^19.3.0", + "@types/sanitize-html": "^2.16.1", + "@typescript-eslint/eslint-plugin": "^8.70.0", + "@typescript-eslint/parser": "^8.70.0", + "@vitest/coverage-v8": "^5.0.1", + "drizzle-kit": "^0.31.10", + "eslint": "^10.10.0", + "eslint-plugin-drizzle": "^0.2.3", + "knip": "^6.37.0", + "prettier": "^3.9.8", + "react": "^19.3.0", "tsup": "^8.5.1", - "tsx": "^4.20.6", - "typescript": "^5.9.3", - "vitest": "^4.0.13", - "wrangler": "^4.50.0" + "tsx": "^4.23.13", + "typescript": "~6.0.3", + "vitest": "^5.0.1", + "wrangler": "^4.135.0" }, "engines": { - "node": ">=20.0.0" + "node": ">=24.0.0" } } diff --git a/packages/api/scripts/wipe-staging.sql b/packages/api/scripts/wipe-staging.sql index 76d55dff..81e30044 100644 --- a/packages/api/scripts/wipe-staging.sql +++ b/packages/api/scripts/wipe-staging.sql @@ -1,3 +1,4 @@ +DROP TABLE IF EXISTS feed_fetch_health; -- ============================================================================ -- Wipe Staging Database -- ============================================================================ @@ -74,6 +75,7 @@ DROP TABLE IF EXISTS categories; DROP TABLE IF EXISTS blocked_domains; -- Drop auth tables (reference user) +DROP TABLE IF EXISTS auth_rate_limits; DROP TABLE IF EXISTS session; DROP TABLE IF EXISTS account; DROP TABLE IF EXISTS verification; diff --git a/packages/api/src/adapters/sentry-telemetry.ts b/packages/api/src/adapters/sentry-telemetry.ts index 3bdc784f..9cee3503 100644 --- a/packages/api/src/adapters/sentry-telemetry.ts +++ b/packages/api/src/adapters/sentry-telemetry.ts @@ -4,7 +4,7 @@ * Implements TelemetryAdapter interface for Sentry observability. */ -import * as Sentry from "@/utils/sentry"; +import * as Sentry from "@api/utils/sentry"; import type { TelemetryAdapter } from "@tuvixrss/tricorder"; /** diff --git a/packages/api/src/auth/README.md b/packages/api/src/auth/README.md index f2424898..8334b1f8 100644 --- a/packages/api/src/auth/README.md +++ b/packages/api/src/auth/README.md @@ -92,7 +92,7 @@ Better Auth uses the `user` table as the single source of truth for user data. For tests that need password hashing: ```typescript -import { hashPassword } from "@/auth/password"; +import { hashPassword } from "@api/auth/password"; const hash = await hashPassword("TestPass123!"); ``` diff --git a/packages/api/src/auth/better-auth.ts b/packages/api/src/auth/better-auth.ts index ff190282..f2e8e078 100644 --- a/packages/api/src/auth/better-auth.ts +++ b/packages/api/src/auth/better-auth.ts @@ -10,22 +10,24 @@ import { drizzleAdapter } from "better-auth/adapters/drizzle"; import { username } from "better-auth/plugins"; import { admin } from "better-auth/plugins"; import { customSession } from "better-auth/plugins"; -import { createAuthMiddleware } from "better-auth/api"; -import { createDatabase } from "@/db/client"; +import { APIError, createAuthMiddleware } from "better-auth/api"; +import { initializeNewUser } from "@api/services/user-init"; +import { enforceAuthRateLimit } from "@api/auth/rate-limit"; +import { createDatabase } from "@api/db/client"; import { sendWelcomeEmail, sendPasswordResetEmail, sendVerificationEmail, -} from "@/services/email"; -import { logSecurityEvent } from "@/auth/security"; -import { getGlobalSettings } from "@/services/global-settings"; -import { getClientIp, getUserAgent, extractHeaders } from "@/auth/security"; +} from "@api/services/email"; +import { logSecurityEvent } from "@api/auth/security"; +import { getGlobalSettings } from "@api/services/global-settings"; +import { getClientIp, getUserAgent, extractHeaders } from "@api/auth/security"; import { eq } from "drizzle-orm"; -import * as schema from "@/db/schema"; -import type { Env } from "@/types"; -import type { BetterAuthUser } from "@/types/better-auth"; -import * as Sentry from "@/utils/sentry"; -import { emitCounter, emitDistribution } from "@/utils/metrics"; +import * as schema from "@api/db/schema"; +import type { Env } from "@api/types"; +import type { BetterAuthUser } from "@api/types/better-auth"; +import * as Sentry from "@api/utils/sentry"; +import { emitCounter, emitDistribution } from "@api/utils/metrics"; /** * Create Better Auth instance @@ -118,13 +120,7 @@ export function createAuth(env: Env, db?: ReturnType) { enabled: false, }, session: { - // Cookie cache reduces DB queries by storing session data in a signed cookie - // This replaces the React Query 15-minute staleTime optimization on the client - cookieCache: { - enabled: true, - maxAge: 15 * 60, // 15 minutes cache duration (in seconds) - strategy: "compact", // Most efficient: base64url + HMAC-SHA256 - }, + cookieCache: { enabled: false }, // Session expires after 7 days (Better Auth default) expiresIn: 60 * 60 * 24 * 7, // 7 days // Update session expiration every 24 hours when used @@ -133,7 +129,7 @@ export function createAuth(env: Env, db?: ReturnType) { advanced: { // Use integer IDs to match existing schema database: { - useNumberId: true, + generateId: "serial", }, // Configure IP address headers for Cloudflare ipAddress: { @@ -279,61 +275,60 @@ export function createAuth(env: Env, db?: ReturnType) { }), // Custom session plugin - includes banned status in session customSession(async ({ user, session }) => { - // Fetch banned status from database - // Note: This queries on every session check, but sessions are cached client-side - try { - const result = await database - .select() - .from(schema.user) - .where(eq(schema.user.id, Number(user.id))) - .limit(1); - - const banned = result[0]?.banned ?? false; - - return { - user: { - ...user, - banned, - }, - session, - }; - } catch (error) { - // Log error to Sentry but don't block session creation - Sentry.captureException(error, { - tags: { - component: "better-auth", - operation: "custom-session", - }, - extra: { - userId: user.id, - }, + const [record] = await database + .select() + .from(schema.user) + .where(eq(schema.user.id, Number(user.id))) + .limit(1); + if (!record) + throw new APIError("UNAUTHORIZED", { + message: "User no longer exists", }); - - // Fail open - return session without banned status - console.error("Failed to fetch user banned status:", error); - return { - user: { - ...user, - banned: false, - }, - session, - }; - } + return { + user: { + ...user, + username: record.username, + role: record.role, + plan: record.plan, + banned: record.banned ?? false, + }, + session, + }; }), ], - // Additional fields for custom user data - additionalFields: { - plan: { - type: "string", - required: false, - defaultValue: "free", - input: false, // Not editable via auth API + user: { + additionalFields: { + plan: { + type: "string", + required: false, + defaultValue: "free", + input: false, + }, }, }, - // Rate limiting disabled - using custom rate limiting system instead - rateLimit: { - enabled: false, + databaseHooks: { + user: { + create: { + after: async (user) => { + await initializeNewUser( + database, + Number(user.id), + env.ALLOW_FIRST_USER_ADMIN !== "false" + ); + const [record] = await database + .select() + .from(schema.user) + .where(eq(schema.user.id, Number(user.id))) + .limit(1); + if (record) + Object.assign(user, { role: record.role, plan: record.plan }); + }, + }, + }, }, + // All credential endpoints, including server-side calls, share the atomic + // database limiter in the before hook below. + rateLimit: { enabled: false }, // Email verification configuration emailVerification: { sendVerificationEmail: async ({ user, token }, _request) => { @@ -551,34 +546,23 @@ export function createAuth(env: Env, db?: ReturnType) { sendOnSignUp: true, // Callback checks requireEmailVerification setting dynamically autoSignInAfterVerification: true, expiresIn: 3600, // 1 hour - // Redirect to frontend after successful verification - callbackURL: frontendUrl, }, // Hooks for security audit logging and welcome emails hooks: { before: createAuthMiddleware(async (ctx) => { - // Check if registration is disabled before processing sign-up - if (ctx.path.startsWith("/sign-up")) { - try { - const settings = await getCachedSettings(); - if (!settings.allowRegistration) { - // Return error response to prevent registration - return { - status: 403, - body: JSON.stringify({ - error: { - message: "Registration is currently disabled", - }, - }), - }; - } - } catch (error) { - // If we can't check settings, allow registration (fail open for availability) - console.error("Failed to check registration settings:", error); + if ( + /^\/(sign-in|sign-up|request-password-reset|reset-password|send-verification-email|change-password)(\/|$)/.test( + ctx.path + ) + ) { + const settings = await getCachedSettings(); + await enforceAuthRateLimit(database, ctx.headers, settings); + if (ctx.path.startsWith("/sign-up") && !settings.allowRegistration) { + throw new APIError("FORBIDDEN", { + message: "Registration is currently disabled", + }); } } - // Continue with the request - return; }), after: createAuthMiddleware(async (ctx) => { // Handle sign-up events @@ -866,7 +850,7 @@ export function createAuth(env: Env, db?: ReturnType) { // Try to find user by email from request body try { - const body = ctx.context.body as { email?: string } | undefined; + const body = ctx.body as { email?: string } | undefined; const email = body?.email; if (email && typeof email === "string") { const [userRecord] = await database diff --git a/packages/api/src/auth/rate-limit.ts b/packages/api/src/auth/rate-limit.ts new file mode 100644 index 00000000..3ce6f6ff --- /dev/null +++ b/packages/api/src/auth/rate-limit.ts @@ -0,0 +1,42 @@ +import { APIError } from "better-auth/api"; +import { sql } from "drizzle-orm"; +import type { Database } from "@api/db/client"; +import { authRateLimits } from "@api/db/schema"; +import type { GlobalSettings } from "@api/services/global-settings"; +import { extractHeaders, getClientIp } from "./security"; + +/** Persist attempts across workers/restarts; a single upsert prevents races. */ +export async function enforceAuthRateLimit( + db: Database, + headers: Headers | undefined, + settings: GlobalSettings +): Promise { + const ip = getClientIp(extractHeaders(headers)) ?? "unidentified"; + const hash = await crypto.subtle.digest( + "SHA-256", + new TextEncoder().encode(ip) + ); + const key = Array.from(new Uint8Array(hash), (byte) => + byte.toString(16).padStart(2, "0") + ).join(""); + const now = Date.now(); + const window = settings.loginAttemptWindowMinutes * 60_000; + const reset = sql`((${authRateLimits.lockedUntil} > 0 AND ${authRateLimits.lockedUntil} <= ${now}) OR (${authRateLimits.lockedUntil} = 0 AND ${authRateLimits.windowStartedAt} <= ${now - window}))`; + const [result] = await db + .insert(authRateLimits) + .values({ key, attempts: 1, windowStartedAt: now, lockedUntil: 0 }) + .onConflictDoUpdate({ + target: authRateLimits.key, + set: { + attempts: sql`CASE WHEN ${reset} THEN 1 WHEN ${authRateLimits.lockedUntil} > ${now} THEN ${authRateLimits.attempts} ELSE ${authRateLimits.attempts} + 1 END`, + windowStartedAt: sql`CASE WHEN ${reset} THEN ${now} ELSE ${authRateLimits.windowStartedAt} END`, + lockedUntil: sql`CASE WHEN ${reset} THEN 0 WHEN ${authRateLimits.lockedUntil} > ${now} THEN ${authRateLimits.lockedUntil} WHEN ${authRateLimits.attempts} >= ${settings.maxLoginAttempts} THEN ${now + settings.lockoutDurationMinutes * 60_000} ELSE 0 END`, + }, + }) + .returning(); + if (!result || result.lockedUntil > now) { + throw new APIError("TOO_MANY_REQUESTS", { + message: "Too many authentication attempts. Please try again later.", + }); + } +} diff --git a/packages/api/src/auth/security.ts b/packages/api/src/auth/security.ts index 6015b071..ef3aab61 100644 --- a/packages/api/src/auth/security.ts +++ b/packages/api/src/auth/security.ts @@ -4,8 +4,8 @@ * Provides audit logging and request metadata extraction */ -import { securityAuditLog } from "@/db/schema"; -import type { Database } from "@/db/client"; +import { securityAuditLog } from "@api/db/schema"; +import type { Database } from "@api/db/client"; /** * Security audit event types @@ -98,9 +98,7 @@ export function getUserAgent( */ export function getRequestMetadata( reqHeaders: - | Headers - | Record - | undefined + Headers | Record | undefined ): { headers: Record; ipAddress: string | undefined; @@ -119,9 +117,7 @@ export function getRequestMetadata( */ export function extractHeaders( reqHeaders: - | Headers - | Record - | undefined + Headers | Record | undefined ): Record { const headers: Record = {}; diff --git a/packages/api/src/cli/clear-articles.ts b/packages/api/src/cli/clear-articles.ts index fd76eae2..926a2ade 100644 --- a/packages/api/src/cli/clear-articles.ts +++ b/packages/api/src/cli/clear-articles.ts @@ -11,7 +11,7 @@ import { drizzle } from "drizzle-orm/better-sqlite3"; import Database from "better-sqlite3"; import { sql } from "drizzle-orm"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; import { resolve } from "path"; import { existsSync } from "fs"; diff --git a/packages/api/src/cli/create-admin.ts b/packages/api/src/cli/create-admin.ts index 1f03f4a7..8321d09f 100644 --- a/packages/api/src/cli/create-admin.ts +++ b/packages/api/src/cli/create-admin.ts @@ -12,8 +12,8 @@ import { drizzle } from "drizzle-orm/better-sqlite3"; import Database from "better-sqlite3"; import { eq, sql } from "drizzle-orm"; -import * as schema from "@/db/schema"; -import { promoteToAdmin } from "@/services/admin-init"; +import * as schema from "@api/db/schema"; +import { promoteToAdmin } from "@api/services/admin-init"; import { resolve } from "path"; import { existsSync } from "fs"; diff --git a/packages/api/src/config/__tests__/sentry.test.ts b/packages/api/src/config/__tests__/sentry.test.ts index 7ed3091c..0e544843 100644 --- a/packages/api/src/config/__tests__/sentry.test.ts +++ b/packages/api/src/config/__tests__/sentry.test.ts @@ -6,7 +6,7 @@ import { describe, it, expect } from "vitest"; import { getSentryConfig } from "../sentry"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; describe("getSentryConfig", () => { it("should return null when DSN is not provided", () => { @@ -59,4 +59,22 @@ describe("getSentryConfig", () => { const config = getSentryConfig(env); expect(config?.environment).toBe("staging"); }); + it("removes credential-bearing request data and nested secrets", () => { + const config = getSentryConfig({ + RUNTIME: "nodejs", + BETTER_AUTH_SECRET: "test-secret", + SENTRY_DSN: "https://test@test.ingest.sentry.io/123", + }); + const event = config!.beforeSend({ + request: { + data: "password=secret", + headers: { cookie: "session=secret" }, + }, + extra: { + calls: [{ newPassword: "secret", token: "secret", operation: "reset" }], + }, + }); + expect(event).not.toHaveProperty("request"); + expect(event?.extra).toEqual({ calls: [{ operation: "reset" }] }); + }); }); diff --git a/packages/api/src/config/sentry.ts b/packages/api/src/config/sentry.ts index 6207c177..709e88e2 100644 --- a/packages/api/src/config/sentry.ts +++ b/packages/api/src/config/sentry.ts @@ -5,7 +5,7 @@ * Includes Span Metrics and Sentry Metrics configuration. */ -import type { Env } from "@/types"; +import type { Env } from "@api/types"; // Define types for Sentry callbacks interface SentryMetric { @@ -73,9 +73,8 @@ export function getSentryConfig(env: Env): Record | null { // Enable logs for better debugging enableLogs: true, - // Send default PII (request headers, IP) for better context - // Safe to enable because we filter sensitive fields via beforeSend callbacks - sendDefaultPii: true, + // Avoid automatic credential-bearing request metadata. + sendDefaultPii: false, // Debug mode (verbose logging - useful for development) debug: environment === "development", @@ -101,6 +100,12 @@ export function getSentryConfig(env: Env): Record | null { "user_email", "username", "password", + "currentPassword", + "newPassword", + "token", + "authorization", + "cookie", + "set-cookie", ]; // Remove any PII from metric attributes @@ -133,6 +138,12 @@ export function getSentryConfig(env: Env): Record | null { "user_email", "username", "password", + "currentPassword", + "newPassword", + "token", + "authorization", + "cookie", + "set-cookie", ]; // Helper to recursively remove PII from an object @@ -145,13 +156,22 @@ export function getSentryConfig(env: Env): Record | null { } // Recursively clean nested objects for (const [key, value] of Object.entries(cleaned)) { - if (value && typeof value === "object" && !Array.isArray(value)) { + if (Array.isArray(value)) { + cleaned[key] = value.map((item: unknown) => + item && typeof item === "object" + ? removePII(item as Record) + : item + ); + } else if (value && typeof value === "object") { cleaned[key] = removePII(value as Record); } } return cleaned; }; + // Request bodies, cookies, and query strings can contain credentials. + delete event.request; + // Remove PII from breadcrumbs if (event.breadcrumbs) { event.breadcrumbs = event.breadcrumbs.map((breadcrumb) => { @@ -190,6 +210,12 @@ export function getSentryConfig(env: Env): Record | null { "user_email", "username", "password", + "currentPassword", + "newPassword", + "token", + "authorization", + "cookie", + "set-cookie", ]; // Initialize data object if it doesn't exist diff --git a/packages/api/src/cron/__tests__/executor.test.ts b/packages/api/src/cron/__tests__/executor.test.ts index 9836b43d..1888ec87 100644 --- a/packages/api/src/cron/__tests__/executor.test.ts +++ b/packages/api/src/cron/__tests__/executor.test.ts @@ -7,10 +7,10 @@ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { executeScheduledTasks } from "../executor"; -import { createTestDb, cleanupTestDb } from "@/test/setup"; -import * as schema from "@/db/schema"; +import { createTestDb, cleanupTestDb } from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; // Mock handlers vi.mock("../handlers", () => ({ @@ -20,7 +20,7 @@ vi.mock("../handlers", () => ({ })); // Mock metrics -vi.mock("@/utils/metrics", () => ({ +vi.mock("@api/utils/metrics", () => ({ emitCounter: vi.fn(), })); @@ -75,7 +75,7 @@ describe("Cron Executor", () => { const result = await executeScheduledTasks(env, db); - expect(handleRSSFetch).toHaveBeenCalledWith(env); + expect(handleRSSFetch).toHaveBeenCalledWith(env, 60); expect(handleArticlePrune).toHaveBeenCalledWith(env); expect(handleTokenCleanup).toHaveBeenCalledWith(env); @@ -87,11 +87,11 @@ describe("Cron Executor", () => { }); it("should skip RSS fetch when interval not elapsed", async () => { - // Set lastRssFetchAt to recent time (5 minutes ago) - const fiveMinutesAgo = new Date(Date.now() - 5 * 60 * 1000); + // Do not run a second batch within the same minute. + const recentBatch = new Date(Date.now() - 15 * 1000); await db .update(schema.globalSettings) - .set({ lastRssFetchAt: fiveMinutesAgo }) + .set({ lastRssFetchAt: recentBatch }) .where(eq(schema.globalSettings.id, 1)); const { handleRSSFetch } = await import("../handlers"); @@ -115,7 +115,7 @@ describe("Cron Executor", () => { const result = await executeScheduledTasks(env, db); - expect(handleRSSFetch).toHaveBeenCalledWith(env); + expect(handleRSSFetch).toHaveBeenCalledWith(env, 60); expect(result.rssFetch.executed).toBe(true); }); @@ -199,30 +199,30 @@ describe("Cron Executor", () => { expect(settings?.lastTokenCleanupAt).not.toBeNull(); }); - it("should respect fetchIntervalMinutes setting", async () => { + it("drains another batch before the per-feed refresh interval elapses", async () => { // Set fetch interval to 30 minutes await db .update(schema.globalSettings) .set({ fetchIntervalMinutes: 30 }) .where(eq(schema.globalSettings.id, 1)); - // Set lastRssFetchAt to 35 minutes ago (should trigger) - const thirtyFiveMinutesAgo = new Date(Date.now() - 35 * 60 * 1000); + // Queue progress must continue despite the 30-minute per-feed interval. + const previousBatch = new Date(Date.now() - 2 * 60 * 1000); await db .update(schema.globalSettings) - .set({ lastRssFetchAt: thirtyFiveMinutesAgo }) + .set({ lastRssFetchAt: previousBatch }) .where(eq(schema.globalSettings.id, 1)); const { handleRSSFetch } = await import("../handlers"); const result = await executeScheduledTasks(env, db); - expect(handleRSSFetch).toHaveBeenCalled(); + expect(handleRSSFetch).toHaveBeenCalledWith(env, 30); expect(result.rssFetch.executed).toBe(true); }); it("should emit metrics for executed tasks", async () => { - const { emitCounter } = await import("@/utils/metrics"); + const { emitCounter } = await import("@api/utils/metrics"); await executeScheduledTasks(env, db); @@ -251,7 +251,7 @@ describe("Cron Executor", () => { }) .where(eq(schema.globalSettings.id, 1)); - const { emitCounter } = await import("@/utils/metrics"); + const { emitCounter } = await import("@api/utils/metrics"); await executeScheduledTasks(env, db); diff --git a/packages/api/src/cron/__tests__/handlers.test.ts b/packages/api/src/cron/__tests__/handlers.test.ts index cb59460e..81db7c48 100644 --- a/packages/api/src/cron/__tests__/handlers.test.ts +++ b/packages/api/src/cron/__tests__/handlers.test.ts @@ -5,25 +5,35 @@ */ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; -import { handleRSSFetch, handleArticlePrune } from "../handlers"; -import { createTestDb, cleanupTestDb, seedTestSource } from "@/test/setup"; -import * as schema from "@/db/schema"; +import { + handleRSSFetch, + handleArticlePrune, + handleTokenCleanup, +} from "../handlers"; +import { createTestDb, cleanupTestDb, seedTestSource } from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; + +vi.mock("@sentry/cloudflare", () => ({ + withMonitor: vi.fn((_name: string, handler: () => Promise) => + handler() + ), +})); // Mock dependencies -vi.mock("@/services/rss-fetcher", () => ({ +vi.mock("@api/services/rss-fetcher", () => ({ fetchAllFeeds: vi.fn(), })); -vi.mock("@/db/client", () => ({ +vi.mock("@api/db/client", () => ({ createDatabase: vi.fn(), })); -vi.mock("@/services/global-settings", async () => { +vi.mock("@api/services/global-settings", async () => { const actual = await vi.importActual< - typeof import("@/services/global-settings") - >("@/services/global-settings"); + typeof import("@api/services/global-settings") + >("@api/services/global-settings"); return { ...actual, getGlobalSettings: vi.fn().mockImplementation(actual.getGlobalSettings), @@ -42,7 +52,7 @@ describe("Cron Handlers", () => { } as Env; // Mock createDatabase to return our test db - const { createDatabase } = await import("@/db/client"); + const { createDatabase } = await import("@api/db/client"); vi.mocked(createDatabase).mockReturnValue(db as any); }); @@ -51,9 +61,51 @@ describe("Cron Handlers", () => { vi.clearAllMocks(); }); + it.each([ + ["rss-fetch", 1], + ["article-prune", 1440], + ["token-cleanup", 10080], + ] as const)( + "propagates %s failures once and monitors its actual interval", + async (name, minutes) => { + const { createDatabase } = await import("@api/db/client"); + const { withMonitor } = await import("@sentry/cloudflare"); + vi.mocked(createDatabase).mockImplementation(() => { + throw new Error("Unavailable database"); + }); + env.RUNTIME = "cloudflare"; + env.SENTRY_DSN = "https://public@example.com/1"; + const run = () => + name === "rss-fetch" + ? handleRSSFetch(env, 45) + : name === "article-prune" + ? handleArticlePrune(env) + : handleTokenCleanup(env); + await expect(run()).rejects.toThrow("Unavailable database"); + expect(createDatabase).toHaveBeenCalledTimes(1); + expect(withMonitor).toHaveBeenCalledWith(name, expect.any(Function), { + schedule: { type: "interval", value: minutes, unit: "minute" }, + }); + } + ); + describe("handleRSSFetch", () => { + it("does not execute a failed monitored batch twice", async () => { + const { fetchAllFeeds } = await import("@api/services/rss-fetcher"); + vi.mocked(fetchAllFeeds).mockRejectedValue( + new Error("Database unavailable") + ); + env.RUNTIME = "cloudflare"; + env.SENTRY_DSN = "https://public@example.com/1"; + + await expect(handleRSSFetch(env, 45)).rejects.toThrow( + "Database unavailable" + ); + expect(fetchAllFeeds).toHaveBeenCalledTimes(1); + }); + it("should successfully fetch all RSS feeds", async () => { - const { fetchAllFeeds } = await import("@/services/rss-fetcher"); + const { fetchAllFeeds } = await import("@api/services/rss-fetcher"); vi.mocked(fetchAllFeeds).mockResolvedValue({ processedCount: 5, successCount: 4, @@ -67,14 +119,16 @@ describe("Cron Handlers", () => { ], }); - await handleRSSFetch(env); + await handleRSSFetch(env, 45); - expect(fetchAllFeeds).toHaveBeenCalledWith(db); + expect(fetchAllFeeds).toHaveBeenCalledWith(db, { + stalenessThresholdMinutes: 45, + }); }); it("should log results when fetch completes", async () => { const consoleSpy = vi.spyOn(console, "log").mockImplementation(() => {}); - const { fetchAllFeeds } = await import("@/services/rss-fetcher"); + const { fetchAllFeeds } = await import("@api/services/rss-fetcher"); vi.mocked(fetchAllFeeds).mockResolvedValue({ processedCount: 3, successCount: 3, @@ -82,7 +136,7 @@ describe("Cron Handlers", () => { errors: [], }); - await handleRSSFetch(env); + await handleRSSFetch(env, 45); expect(consoleSpy).toHaveBeenCalledWith( "🔄 Starting scheduled RSS fetch..." @@ -100,11 +154,11 @@ describe("Cron Handlers", () => { const consoleErrorSpy = vi .spyOn(console, "error") .mockImplementation(() => {}); - const { fetchAllFeeds } = await import("@/services/rss-fetcher"); + const { fetchAllFeeds } = await import("@api/services/rss-fetcher"); const error = new Error("Database connection failed"); vi.mocked(fetchAllFeeds).mockRejectedValue(error); - await expect(handleRSSFetch(env)).rejects.toThrow( + await expect(handleRSSFetch(env, 45)).rejects.toThrow( "Database connection failed" ); expect(consoleErrorSpy).toHaveBeenCalledWith( @@ -146,10 +200,11 @@ describe("Cron Handlers", () => { }); // Reset mock to use real implementation (default behavior) - const { getGlobalSettings } = await import("@/services/global-settings"); + const { getGlobalSettings } = + await import("@api/services/global-settings"); const actual = await vi.importActual< - typeof import("@/services/global-settings") - >("@/services/global-settings"); + typeof import("@api/services/global-settings") + >("@api/services/global-settings"); vi.mocked(getGlobalSettings).mockReset(); vi.mocked(getGlobalSettings).mockImplementation(actual.getGlobalSettings); @@ -484,7 +539,8 @@ describe("Cron Handlers", () => { .mockImplementation(() => {}); // Mock getGlobalSettings to throw an error - const { getGlobalSettings } = await import("@/services/global-settings"); + const { getGlobalSettings } = + await import("@api/services/global-settings"); vi.mocked(getGlobalSettings).mockRejectedValue( new Error("Database connection failed") ); diff --git a/packages/api/src/cron/__tests__/scheduler.test.ts b/packages/api/src/cron/__tests__/scheduler.test.ts index c4eac180..c8f6ec16 100644 --- a/packages/api/src/cron/__tests__/scheduler.test.ts +++ b/packages/api/src/cron/__tests__/scheduler.test.ts @@ -7,8 +7,8 @@ import { describe, it, expect, beforeEach, vi, afterEach } from "vitest"; import { initCronJobs } from "../scheduler"; -import { createTestDb, cleanupTestDb } from "@/test/setup"; -import type { Env } from "@/types"; +import { createTestDb, cleanupTestDb } from "@api/test/setup"; +import type { Env } from "@api/types"; // Mock node-cron vi.mock("node-cron", () => ({ @@ -26,7 +26,7 @@ vi.mock("../executor", () => ({ }), })); -vi.mock("@/db/client", () => ({ +vi.mock("@api/db/client", () => ({ createDatabase: vi.fn(), })); @@ -43,7 +43,7 @@ describe("Cron Scheduler", () => { } as Env; // Mock createDatabase to return our test db - const { createDatabase } = await import("@/db/client"); + const { createDatabase } = await import("@api/db/client"); vi.mocked(createDatabase).mockReturnValue(db as any); // Get the mocked cron schedule function diff --git a/packages/api/src/cron/executor.ts b/packages/api/src/cron/executor.ts index b00de2b6..032a38e8 100644 --- a/packages/api/src/cron/executor.ts +++ b/packages/api/src/cron/executor.ts @@ -1,3 +1,4 @@ +import { CRON_SCHEDULES } from "./schedules"; /** * Cron Executor (Shared) * @@ -5,7 +6,7 @@ * Used by both Cloudflare Workers (scheduled events) and Node.js (node-cron). * * This ensures consistent behavior across runtimes: - * - RSS fetch: based on fetchIntervalMinutes from global_settings + * - RSS batches: every minute; individual feeds use fetchIntervalMinutes * - Article prune: every 24 hours * - Token cleanup: every 7 days (weekly) */ @@ -13,24 +14,25 @@ import { eq } from "drizzle-orm"; import type { DrizzleD1Database } from "drizzle-orm/d1"; import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; -import * as schema from "@/db/schema"; -import { getGlobalSettings } from "@/services/global-settings"; +import * as schema from "@api/db/schema"; +import { getGlobalSettings } from "@api/services/global-settings"; import { handleRSSFetch, handleArticlePrune, handleTokenCleanup, } from "./handlers"; -import { emitCounter } from "@/utils/metrics"; -import type { Env } from "@/types"; +import { emitCounter } from "@api/utils/metrics"; +import type { Env } from "@api/types"; // Generic database type that works with both D1 and better-sqlite3 type Database = - | DrizzleD1Database - | BetterSQLite3Database; + DrizzleD1Database | BetterSQLite3Database; // Interval constants -const PRUNE_INTERVAL_MS = 24 * 60 * 60 * 1000; // 24 hours -const TOKEN_CLEANUP_INTERVAL_MS = 7 * 24 * 60 * 60 * 1000; // 7 days +const RSS_BATCH_INTERVAL_MS = CRON_SCHEDULES["rss-fetch"].minutes * 60 * 1000; +const PRUNE_INTERVAL_MS = CRON_SCHEDULES["article-prune"].minutes * 60 * 1000; // 24 hours +const TOKEN_CLEANUP_INTERVAL_MS = + CRON_SCHEDULES["token-cleanup"].minutes * 60 * 1000; // 7 days /** * Result of executing scheduled tasks @@ -99,13 +101,13 @@ export async function executeScheduledTasks( tokenCleanup: { executed: false }, }; - // RSS Fetch - based on fetchIntervalMinutes from settings - const rssFetchIntervalMs = settings.fetchIntervalMinutes * 60 * 1000; - if (shouldRunTask(settings.lastRssFetchAt, rssFetchIntervalMs)) { + // Drain the bounded queue every minute. The configured refresh interval + // applies to each feed, not to the entire queue between batches. + if (shouldRunTask(settings.lastRssFetchAt, RSS_BATCH_INTERVAL_MS)) { console.log("🔄 Executing RSS fetch..."); emitCounter("cron.rss_fetch_triggered", 1, { status: "executed" }); - await handleRSSFetch(env); + await handleRSSFetch(env, settings.fetchIntervalMinutes); await updateCronTimestamp(db, "lastRssFetchAt", now); result.rssFetch.executed = true; @@ -114,7 +116,7 @@ export async function executeScheduledTasks( const minutesSinceLastFetch = Math.floor( (now.getTime() - settings.lastRssFetchAt.getTime()) / (60 * 1000) ); - result.rssFetch.skippedReason = `Last fetch was ${minutesSinceLastFetch} minutes ago (interval: ${settings.fetchIntervalMinutes} minutes)`; + result.rssFetch.skippedReason = `Last fetch was ${minutesSinceLastFetch} minutes ago (batch interval: 1 minute)`; console.log(`⏭️ Skipping RSS fetch: ${result.rssFetch.skippedReason}`); emitCounter("cron.rss_fetch_triggered", 1, { status: "skipped" }); } diff --git a/packages/api/src/cron/handlers.ts b/packages/api/src/cron/handlers.ts index c4f5188f..4cbe6fc5 100644 --- a/packages/api/src/cron/handlers.ts +++ b/packages/api/src/cron/handlers.ts @@ -1,3 +1,4 @@ +import { CRON_SCHEDULES } from "./schedules"; /** * Cron Job Handlers (Portable) * @@ -5,14 +6,14 @@ * The scheduler (node-cron or Workers scheduled events) calls these. */ -import { createDatabase } from "@/db/client"; -import { fetchAllFeeds } from "@/services/rss-fetcher"; -import { getGlobalSettings } from "@/services/global-settings"; -import { inArray, lt, or, isNull, and, eq } from "drizzle-orm"; -import * as schema from "@/db/schema"; -import type { Env } from "@/types"; -import { D1_MAX_PARAMETERS, chunkArray } from "@/db/utils"; -import { emitCounter, withTiming } from "@/utils/metrics"; +import { createDatabase } from "@api/db/client"; +import { fetchAllFeeds } from "@api/services/rss-fetcher"; +import { getGlobalSettings } from "@api/services/global-settings"; +import { sql, inArray, lt, or, isNull, and, eq } from "drizzle-orm"; +import * as schema from "@api/db/schema"; +import type { Env } from "@api/types"; +import { D1_MAX_PARAMETERS, chunkArray } from "@api/db/utils"; +import { emitCounter, withTiming } from "@api/utils/metrics"; /** * Fetch all RSS feeds @@ -21,13 +22,16 @@ import { emitCounter, withTiming } from "@/utils/metrics"; * - Node.js: node-cron scheduler (scheduler.ts) * - Workers: scheduled event (cloudflare.ts) */ -async function _handleRSSFetch(env: Env): Promise { +async function _handleRSSFetch( + env: Env, + stalenessThresholdMinutes: number +): Promise { console.log("🔄 Starting scheduled RSS fetch..."); const db = createDatabase(env); try { - const result = await fetchAllFeeds(db); + const result = await fetchAllFeeds(db, { stalenessThresholdMinutes }); console.log(`✅ RSS fetch completed:`, { processed: result.processedCount, @@ -72,6 +76,12 @@ async function _handleTokenCleanup(env: Env): Promise<{ .where(lt(schema.verification.expiresAt, new Date(cutoffTimestamp))) .returning(); + await db + .delete(schema.authRateLimits) + .where( + sql`${schema.authRateLimits.windowStartedAt} < ${cutoffTimestamp} AND ${schema.authRateLimits.lockedUntil} < ${Date.now()}` + ); + const deletedCount = deletedTokens.length; console.log( @@ -209,80 +219,45 @@ async function _handleArticlePrune(env: Env): Promise<{ ); } -// Export wrapped versions with Sentry monitoring (Cloudflare only) -// For Node.js, these will be used directly without monitoring -export async function handleRSSFetch(env: Env): Promise { - if (env.RUNTIME === "cloudflare" && env.SENTRY_DSN) { - try { - // Dynamic import for Cloudflare-only Sentry module - const Sentry = (await import("@sentry/cloudflare")) as { - withMonitor: ( - name: string, - handler: () => Promise, - options: { schedule: { type: string; value: string } } - ) => Promise; - }; - await Sentry.withMonitor("rss-fetch", () => _handleRSSFetch(env), { - schedule: { type: "crontab", value: "*/5 * * * *" }, - }); - return; - } catch { - // Sentry not available, use regular handler - } +/** Import failures may disable monitoring; task failures must never rerun work. */ +async function runMonitored( + env: Env, + name: keyof typeof CRON_SCHEDULES, + task: () => Promise +): Promise { + if (env.RUNTIME !== "cloudflare" || !env.SENTRY_DSN) return task(); + let sdk: typeof import("@sentry/cloudflare"); + try { + sdk = await import("@sentry/cloudflare"); + } catch { + return task(); } - return _handleRSSFetch(env); + return sdk.withMonitor(name, task, { + schedule: { + type: "interval", + value: CRON_SCHEDULES[name].minutes, + unit: "minute", + }, + }); } -export async function handleArticlePrune(env: Env): Promise<{ - deletedCount: number; -}> { - if (env.RUNTIME === "cloudflare" && env.SENTRY_DSN) { - try { - // Dynamic import for Cloudflare-only Sentry module - const Sentry = (await import("@sentry/cloudflare")) as { - withMonitor: ( - name: string, - handler: () => Promise, - options: { schedule: { type: string; value: string } } - ) => Promise; - }; - return await Sentry.withMonitor( - "article-prune", - () => _handleArticlePrune(env), - { - schedule: { type: "crontab", value: "0 2 * * *" }, - } - ); - } catch { - // Sentry not available, use regular handler - } - } - return _handleArticlePrune(env); +export function handleRSSFetch( + env: Env, + stalenessThresholdMinutes: number +): Promise { + return runMonitored(env, "rss-fetch", () => + _handleRSSFetch(env, stalenessThresholdMinutes) + ); } -export async function handleTokenCleanup(env: Env): Promise<{ - deletedCount: number; -}> { - if (env.RUNTIME === "cloudflare" && env.SENTRY_DSN) { - try { - // Dynamic import for Cloudflare-only Sentry module - const Sentry = (await import("@sentry/cloudflare")) as { - withMonitor: ( - name: string, - handler: () => Promise, - options: { schedule: { type: string; value: string } } - ) => Promise; - }; - return await Sentry.withMonitor( - "token-cleanup", - () => _handleTokenCleanup(env), - { - schedule: { type: "crontab", value: "0 * * * *" }, // Every hour - } - ); - } catch { - // Sentry not available, use regular handler - } - } - return _handleTokenCleanup(env); +export function handleArticlePrune( + env: Env +): Promise<{ deletedCount: number }> { + return runMonitored(env, "article-prune", () => _handleArticlePrune(env)); +} + +export function handleTokenCleanup( + env: Env +): Promise<{ deletedCount: number }> { + return runMonitored(env, "token-cleanup", () => _handleTokenCleanup(env)); } diff --git a/packages/api/src/cron/scheduler.ts b/packages/api/src/cron/scheduler.ts index 6eb912ab..c329141a 100644 --- a/packages/api/src/cron/scheduler.ts +++ b/packages/api/src/cron/scheduler.ts @@ -8,8 +8,8 @@ import cron from "node-cron"; import { executeScheduledTasks } from "./executor"; -import { createDatabase } from "@/db/client"; -import type { Env } from "@/types"; +import { createDatabase } from "@api/db/client"; +import type { Env } from "@api/types"; /** * Initialize cron jobs for Node.js runtime @@ -48,7 +48,9 @@ export async function initCronJobs(env: Env): Promise { console.log("✅ Cron scheduler initialized (polling every minute)"); console.log(" Tasks run based on timestamps in global_settings:"); - console.log(" - RSS fetch: based on fetchIntervalMinutes setting"); + console.log( + " - RSS batches: every minute; per-feed refresh uses fetchIntervalMinutes" + ); console.log(" - Article prune: every 24 hours"); console.log(" - Token cleanup: every 7 days"); diff --git a/packages/api/src/cron/schedules.ts b/packages/api/src/cron/schedules.ts new file mode 100644 index 00000000..8cdbdeca --- /dev/null +++ b/packages/api/src/cron/schedules.ts @@ -0,0 +1,6 @@ +/** Single source of truth for execution intervals and Sentry monitoring. */ +export const CRON_SCHEDULES = { + "rss-fetch": { minutes: 1 }, + "article-prune": { minutes: 24 * 60 }, + "token-cleanup": { minutes: 7 * 24 * 60 }, +} as const; diff --git a/packages/api/src/db/__tests__/client.test.ts b/packages/api/src/db/__tests__/client.test.ts index b2ac6f10..e82f19d9 100644 --- a/packages/api/src/db/__tests__/client.test.ts +++ b/packages/api/src/db/__tests__/client.test.ts @@ -4,7 +4,7 @@ import { describe, it, expect, afterEach, vi } from "vitest"; import { createDatabase } from "../client"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; import Database from "better-sqlite3"; import { existsSync, unlinkSync } from "fs"; import { tmpdir } from "os"; diff --git a/packages/api/src/db/__tests__/feed-fetch-attempts.test.ts b/packages/api/src/db/__tests__/feed-fetch-attempts.test.ts new file mode 100644 index 00000000..cc33b68b --- /dev/null +++ b/packages/api/src/db/__tests__/feed-fetch-attempts.test.ts @@ -0,0 +1,28 @@ +import { readFileSync } from "node:fs"; +import Database from "better-sqlite3"; +import { expect, it } from "vitest"; + +it("backfills scheduling attempts without changing successful fetch times", () => { + const db = new Database(":memory:"); + try { + db.exec(` + CREATE TABLE sources (id INTEGER PRIMARY KEY, last_fetched INTEGER); + INSERT INTO sources VALUES (1, 1700000000), (2, NULL); + `); + db.exec( + readFileSync( + new URL( + "../../../drizzle/0013_feed_fetch_attempts.sql", + import.meta.url + ), + "utf8" + ) + ); + expect(db.prepare("SELECT * FROM sources ORDER BY id").all()).toEqual([ + { id: 1, last_fetched: 1700000000, last_fetch_attempt_at: 1700000000 }, + { id: 2, last_fetched: null, last_fetch_attempt_at: null }, + ]); + } finally { + db.close(); + } +}); diff --git a/packages/api/src/db/__tests__/helpers.test.ts b/packages/api/src/db/__tests__/helpers.test.ts index 3fba53e4..86b23073 100644 --- a/packages/api/src/db/__tests__/helpers.test.ts +++ b/packages/api/src/db/__tests__/helpers.test.ts @@ -19,7 +19,7 @@ import { seedTestSubscription, seedTestCategory, seedTestArticle, -} from "@/test/setup"; +} from "@api/test/setup"; import * as schema from "../schema"; import { eq, and } from "drizzle-orm"; diff --git a/packages/api/src/db/__tests__/staging-reset.test.ts b/packages/api/src/db/__tests__/staging-reset.test.ts new file mode 100644 index 00000000..7e344035 --- /dev/null +++ b/packages/api/src/db/__tests__/staging-reset.test.ts @@ -0,0 +1,47 @@ +import { readFileSync } from "node:fs"; +import { fileURLToPath } from "node:url"; +import { migrate } from "drizzle-orm/better-sqlite3/migrator"; +import { describe, expect, it } from "vitest"; +import { createTestDb, seedTestUser } from "@api/test/setup"; +import { authRateLimits } from "@api/db/schema"; + +describe("staging database reset", () => { + it("can recreate a populated database from all migrations after a wipe", async () => { + const db = createTestDb(); + try { + await seedTestUser(db); + await db.insert(authRateLimits).values({ + key: "test-client", + attempts: 3, + windowStartedAt: 1, + }); + + const tables = () => + db.$client + .prepare<[], { name: string }>( + "SELECT name FROM sqlite_master WHERE type = 'table' AND name NOT GLOB 'sqlite_*' ORDER BY name" + ) + .all() + .map(({ name }) => name); + const originalTables = tables(); + + db.$client.exec( + readFileSync( + new URL("../../../scripts/wipe-staging.sql", import.meta.url), + "utf8" + ) + ); + expect(tables()).toEqual([]); + + migrate(db, { + migrationsFolder: fileURLToPath( + new URL("../../../drizzle/", import.meta.url) + ), + }); + expect(tables()).toEqual(originalTables); + expect(await db.select().from(authRateLimits)).toEqual([]); + } finally { + db.$client.close(); + } + }); +}); diff --git a/packages/api/src/db/client.ts b/packages/api/src/db/client.ts index 962f66ac..f14a0202 100644 --- a/packages/api/src/db/client.ts +++ b/packages/api/src/db/client.ts @@ -12,7 +12,7 @@ import Database from "better-sqlite3"; import * as fs from "fs"; import * as path from "path"; import * as schema from "./schema"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; export function createDatabase(env: Env) { const runtime = env.RUNTIME || "nodejs"; diff --git a/packages/api/src/db/helpers.ts b/packages/api/src/db/helpers.ts index f3271498..ce005d3e 100644 --- a/packages/api/src/db/helpers.ts +++ b/packages/api/src/db/helpers.ts @@ -7,10 +7,10 @@ import { TRPCError } from "@trpc/server"; import { eq, and, sql, type SQL } from "drizzle-orm"; -import type { Database } from "@/db/client"; +import type { Database } from "@api/db/client"; import type { SQLiteTable, SQLiteColumn } from "drizzle-orm/sqlite-core"; -import * as schema from "@/db/schema"; -import { withQueryMetrics } from "@/utils/db-metrics"; +import * as schema from "@api/db/schema"; +import { withQueryMetrics } from "@api/utils/db-metrics"; /** * Verify user owns a resource, throw NOT_FOUND if not @@ -309,10 +309,8 @@ export interface ArticleStateMetricsOptions { * Uses database upsert to handle both insert and update cases. * Includes database query metrics when operationName is provided. * - * **Note:** This function only manages `read` and `saved` fields. Audio-related - * fields (`audioPosition`, `audioDuration`, `audioCompletedAt`, `audioLastPlayedAt`) - * are NOT preserved by this function and should be managed separately via the - * dedicated audio progress endpoints. + * Only explicitly supplied flags are updated on conflict. Existing flags and + * audio progress are preserved atomically without a preceding read. * * @param db Database instance * @param userId User ID @@ -335,33 +333,6 @@ export async function upsertArticleState( updates: ArticleStateUpdate, options?: ArticleStateMetricsOptions ): Promise { - // Get existing state to preserve other flags - const selectQuery = async () => - db - .select() - .from(schema.userArticleStates) - .where( - and( - eq(schema.userArticleStates.userId, userId), - eq(schema.userArticleStates.articleId, articleId) - ) - ) - .limit(1); - - const existing = options?.operationName - ? await withQueryMetrics(`${options.operationName}.getState`, selectQuery, { - "db.table": "user_article_states", - "db.operation": "select", - "db.user_id": userId, - }) - : await selectQuery(); - - const currentRead = existing[0]?.read ?? false; - const currentSaved = existing[0]?.saved ?? false; - - const newRead = updates.read !== undefined ? updates.read : currentRead; - const newSaved = updates.saved !== undefined ? updates.saved : currentSaved; - // Build the set clause for updates (only include fields being changed) const setClause: Partial = { updatedAt: new Date(), @@ -375,8 +346,8 @@ export async function upsertArticleState( .values({ userId, articleId, - read: newRead, - saved: newSaved, + read: updates.read ?? false, + saved: updates.saved ?? false, }) .onConflictDoUpdate({ target: [ @@ -391,7 +362,6 @@ export async function upsertArticleState( "db.table": "user_article_states", "db.operation": "upsert", "db.user_id": userId, - "db.had_existing_state": existing.length > 0, }); } else { await executeUpsert(); diff --git a/packages/api/src/db/migrate-local.ts b/packages/api/src/db/migrate-local.ts index 05c3e23d..362816b5 100644 --- a/packages/api/src/db/migrate-local.ts +++ b/packages/api/src/db/migrate-local.ts @@ -11,7 +11,7 @@ import Database from "better-sqlite3"; import { existsSync, mkdirSync } from "fs"; import { dirname, resolve } from "path"; import { fileURLToPath } from "url"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; const __filename = fileURLToPath(import.meta.url); const __dirname = dirname(__filename); diff --git a/packages/api/src/db/schema.ts b/packages/api/src/db/schema.ts index 817be76f..2c7949fc 100644 --- a/packages/api/src/db/schema.ts +++ b/packages/api/src/db/schema.ts @@ -112,10 +112,12 @@ export const verification = sqliteTable("verification", { .notNull(), }); -// Rate limiting table removed - Better Auth rate limiting is disabled -// The rate_limit table was previously used by Better Auth for database-backed -// rate limiting, but we've disabled Better Auth's internal rate limiting -// in favor of our custom Cloudflare Workers rate limit bindings system. +export const authRateLimits = sqliteTable("auth_rate_limits", { + key: text("key").primaryKey(), + attempts: integer("attempts").notNull(), + windowStartedAt: integer("window_started_at").notNull(), + lockedUntil: integer("locked_until").notNull().default(0), +}); // ============================================================================ // SOURCES (RSS Feeds) @@ -134,7 +136,15 @@ export const sources = sqliteTable( enum: ["auto", "custom", "none"], }).default("auto"), iconUpdatedAt: integer("icon_updated_at", { mode: "timestamp" }), + fetchLeaseToken: text("fetch_lease_token"), + fetchLeaseUntil: integer("fetch_lease_until", { mode: "timestamp" }), + nextFetchAt: integer("next_fetch_at", { mode: "timestamp" }), + lastFetchError: text("last_fetch_error"), + consecutiveFetchFailures: integer("consecutive_fetch_failures") + .notNull() + .default(0), lastFetched: integer("last_fetched", { mode: "timestamp" }), + lastFetchAttemptAt: integer("last_fetch_attempt_at", { mode: "timestamp" }), createdAt: integer("created_at", { mode: "timestamp" }) .notNull() .$defaultFn(() => new Date()), @@ -146,6 +156,7 @@ export const sources = sqliteTable( index("idx_sources_url").on(table.url), index("idx_sources_icon_url").on(table.iconUrl), index("idx_sources_last_fetched").on(table.lastFetched), + index("idx_sources_last_fetch_attempt_at").on(table.lastFetchAttemptAt), ] ); @@ -697,3 +708,12 @@ export const blockedDomains = sqliteTable( index("idx_blocked_domains_created_at").on(table.createdAt), ] ); + +/** Persistent ingestion alert state, shared by workers and Node instances. */ +export const feedFetchHealth = sqliteTable("feed_fetch_health", { + id: integer("id").primaryKey(), + backlog: integer("backlog").notNull().default(0), + failingBatches: integer("failing_batches").notNull().default(0), + growingBatches: integer("growing_batches").notNull().default(0), + lastAlertAt: integer("last_alert_at", { mode: "timestamp" }), +}); diff --git a/packages/api/src/db/schemas.zod.ts b/packages/api/src/db/schemas.zod.ts index 29581412..e80c3823 100644 --- a/packages/api/src/db/schemas.zod.ts +++ b/packages/api/src/db/schemas.zod.ts @@ -47,7 +47,15 @@ export const updateUserSettingsSchema = insertUserSettingsSchema.partial(); // SOURCE SCHEMAS // ============================================================================ -export const selectSourceSchema = createSelectSchema(schema.sources); +// Fetch attempts are internal scheduler state, not successful refresh times. +export const selectSourceSchema = createSelectSchema(schema.sources).omit({ + lastFetchAttemptAt: true, + fetchLeaseToken: true, + fetchLeaseUntil: true, + nextFetchAt: true, + lastFetchError: true, + consecutiveFetchFailures: true, +}); export const insertSourceSchema = createInsertSchema(schema.sources, { url: (s) => s.url(), siteUrl: (s) => s.url().optional(), @@ -95,6 +103,12 @@ export const selectSubscriptionFilterSchema = createSelectSchema( export const subscriptionResponseSchema = selectSubscriptionSchema.extend({ source: selectSourceSchema.extend({ title: z.string(), + fetchHealth: createSelectSchema(schema.sources).pick({ + lastFetchAttemptAt: true, + nextFetchAt: true, + lastFetchError: true, + consecutiveFetchFailures: true, + }), }), categories: z.array(selectCategorySchema), filters: z.array(selectSubscriptionFilterSchema), @@ -129,7 +143,7 @@ export const articleWithSourceSchema = selectArticleSchema.extend({ }) .nullable() .optional(), - source: createSelectSchema(schema.sources).optional(), + source: selectSourceSchema, }); // ============================================================================ diff --git a/packages/api/src/db/transformers.ts b/packages/api/src/db/transformers.ts index e7c30d37..dd5aad5e 100644 --- a/packages/api/src/db/transformers.ts +++ b/packages/api/src/db/transformers.ts @@ -1,3 +1,5 @@ +import type { z } from "zod"; +import type { subscriptionResponseSchema } from "./schemas.zod"; /** * Database Row Transformers * @@ -5,9 +7,10 @@ * Includes N+1 query prevention through bulk fetching. */ +import { chunkArray, D1_MAX_PARAMETERS } from "@api/db/utils"; import { eq, inArray } from "drizzle-orm"; -import type { Database } from "@/db/client"; -import * as schema from "@/db/schema"; +import type { Database } from "@api/db/client"; +import * as schema from "@api/db/schema"; /** * Transform subscription filter row to properly typed filter @@ -49,16 +52,22 @@ export async function fetchSubscriptionCategories( return new Map(); } - const categoryLinks = await db - .select() - .from(schema.subscriptionCategories) - .innerJoin( - schema.categories, - eq(schema.subscriptionCategories.categoryId, schema.categories.id) - ) - .where( - inArray(schema.subscriptionCategories.subscriptionId, subscriptionIds) + const categoryLinks: { + subscription_categories: typeof schema.subscriptionCategories.$inferSelect; + categories: typeof schema.categories.$inferSelect; + }[] = []; + for (const ids of chunkArray(subscriptionIds, D1_MAX_PARAMETERS)) { + categoryLinks.push( + ...(await db + .select() + .from(schema.subscriptionCategories) + .innerJoin( + schema.categories, + eq(schema.subscriptionCategories.categoryId, schema.categories.id) + ) + .where(inArray(schema.subscriptionCategories.subscriptionId, ids))) ); + } // Group by subscription ID const categoriesMap = new Map< @@ -94,10 +103,15 @@ export async function fetchSubscriptionFilters( return new Map(); } - const filters = await db - .select() - .from(schema.subscriptionFilters) - .where(inArray(schema.subscriptionFilters.subscriptionId, subscriptionIds)); + const filters: (typeof schema.subscriptionFilters.$inferSelect)[] = []; + for (const ids of chunkArray(subscriptionIds, D1_MAX_PARAMETERS)) { + filters.push( + ...(await db + .select() + .from(schema.subscriptionFilters) + .where(inArray(schema.subscriptionFilters.subscriptionId, ids))) + ); + } // Group by subscription ID const filtersMap = new Map< @@ -135,31 +149,7 @@ export function buildSubscriptionResponse( source: typeof schema.sources.$inferSelect, categories: (typeof schema.categories.$inferSelect)[], filters: ReturnType[] -): { - id: number; - userId: number; - sourceId: number; - customTitle: string | null; - filterEnabled: boolean; - filterMode: "include" | "exclude"; - createdAt: Date; - updatedAt: Date; - source: { - id: number; - url: string; - title: string; - description: string | null; - siteUrl: string | null; - iconUrl: string | null; - iconType: "auto" | "custom" | "none" | null; - iconUpdatedAt: Date | null; - lastFetched: Date | null; - createdAt: Date; - updatedAt: Date; - }; - categories: (typeof schema.categories.$inferSelect)[]; - filters: ReturnType[]; -} { +): z.infer { return { id: subscription.id, userId: subscription.userId, @@ -179,6 +169,12 @@ export function buildSubscriptionResponse( iconType: source.iconType, iconUpdatedAt: source.iconUpdatedAt, lastFetched: source.lastFetched, + fetchHealth: { + lastFetchAttemptAt: source.lastFetchAttemptAt, + nextFetchAt: source.nextFetchAt, + lastFetchError: source.lastFetchError, + consecutiveFetchFailures: source.consecutiveFetchFailures, + }, createdAt: source.createdAt, updatedAt: source.updatedAt, }, @@ -202,10 +198,15 @@ export async function fetchFeedCategories( return new Map(); } - const categoryLinks = await db - .select() - .from(schema.feedCategories) - .where(inArray(schema.feedCategories.feedId, feedIds)); + const categoryLinks: (typeof schema.feedCategories.$inferSelect)[] = []; + for (const ids of chunkArray(feedIds, D1_MAX_PARAMETERS)) { + categoryLinks.push( + ...(await db + .select() + .from(schema.feedCategories) + .where(inArray(schema.feedCategories.feedId, ids))) + ); + } // Group by feed ID const categoriesMap = new Map(); diff --git a/packages/api/src/entries/cloudflare.ts b/packages/api/src/entries/cloudflare.ts index 23457d20..a46b4e10 100644 --- a/packages/api/src/entries/cloudflare.ts +++ b/packages/api/src/entries/cloudflare.ts @@ -5,9 +5,9 @@ */ import * as Sentry from "@sentry/cloudflare"; -import { createHonoApp } from "@/hono/app"; -import { getSentryConfig } from "@/config/sentry"; -import type { Env } from "@/types"; +import { createHonoApp } from "@api/hono/app"; +import { getSentryConfig } from "@api/config/sentry"; +import type { Env } from "@api/types"; /** * Prepare environment with D1 instrumentation diff --git a/packages/api/src/entries/node.ts b/packages/api/src/entries/node.ts index 0953d87d..1b7190e6 100644 --- a/packages/api/src/entries/node.ts +++ b/packages/api/src/entries/node.ts @@ -3,13 +3,13 @@ process.env.RUNTIME = "nodejs"; import * as Sentry from "@sentry/node"; import { serve } from "@hono/node-server"; -import { createHonoApp } from "@/hono/app"; -import { runMigrationsIfNeeded } from "@/db/migrate-local"; -import { initCronJobs } from "@/cron/scheduler"; -import { initializeAdmin } from "@/services/admin-init"; -import { createDatabase } from "@/db/client"; -import { getSentryConfig } from "@/config/sentry"; -import type { Env } from "@/types"; +import { createHonoApp } from "@api/hono/app"; +import { runMigrationsIfNeeded } from "@api/db/migrate-local"; +import { initCronJobs } from "@api/cron/scheduler"; +import { initializeAdmin } from "@api/services/admin-init"; +import { createDatabase } from "@api/db/client"; +import { getSentryConfig } from "@api/config/sentry"; +import type { Env } from "@api/types"; // Load environment const env: Env = { @@ -20,7 +20,10 @@ const env: Env = { CORS_ORIGIN: process.env.CORS_ORIGIN, NODE_ENV: process.env.NODE_ENV, BASE_URL: process.env.BASE_URL, - BETTER_AUTH_URL: process.env.BETTER_AUTH_URL || process.env.BASE_URL, + BETTER_AUTH_URL: process.env.BETTER_AUTH_URL, + API_URL: process.env.API_URL, + OPENAI_API_KEY: process.env.OPENAI_API_KEY, + TRUST_PROXY_HEADERS: process.env.TRUST_PROXY_HEADERS, COOKIE_DOMAIN: process.env.COOKIE_DOMAIN, RESEND_API_KEY: process.env.RESEND_API_KEY, EMAIL_FROM: process.env.EMAIL_FROM, @@ -105,6 +108,8 @@ void (async () => { .then((result) => { if (result.created) { console.log(`✅ ${result.message}`); + } else if (result.message.startsWith("Failed")) { + console.error(`❌ ${result.message}`); } }) .catch((error) => { @@ -113,11 +118,34 @@ void (async () => { // Start server const port = parseInt(env.PORT || "3001", 10); - serve({ fetch: app.fetch, port }, () => { - console.log(`🚀 Hono Server (Node.js) on http://localhost:${port}`); - console.log(`📊 Health: http://localhost:${port}/health`); - console.log(`🔌 tRPC: http://localhost:${port}/trpc`); - }); + serve( + { + fetch: (request, bindings) => { + // Proxy headers are attacker-controlled on a directly exposed Node API. + if (env.TRUST_PROXY_HEADERS === "true") + return app.fetch(request, bindings); + const headers = new Headers(request.headers); + for (const name of [ + "cf-connecting-ip", + "x-real-ip", + "x-forwarded-for", + "x-client-ip", + ]) + headers.delete(name); + headers.set( + "x-real-ip", + bindings.incoming.socket.remoteAddress ?? "unidentified" + ); + return app.fetch(new Request(request, { headers }), bindings); + }, + port, + }, + () => { + console.log(`🚀 Hono Server (Node.js) on http://localhost:${port}`); + console.log(`📊 Health: http://localhost:${port}/health`); + console.log(`🔌 tRPC: http://localhost:${port}/trpc`); + } + ); } catch (error) { console.error("❌ Failed to start:", error); process.exit(1); diff --git a/packages/api/src/hono/app.ts b/packages/api/src/hono/app.ts index 322a1de0..3ba0b9ee 100644 --- a/packages/api/src/hono/app.ts +++ b/packages/api/src/hono/app.ts @@ -2,10 +2,10 @@ import { Hono } from "hono"; import { cors } from "hono/cors"; import { trpcServer } from "@hono/trpc-server"; import { TRPCError } from "@trpc/server"; -import { appRouter } from "@/trpc/router"; -import { createContext } from "@/trpc/context"; -import type { Env } from "@/types"; -import type { BetterAuthUser, BetterAuthSession } from "@/types/better-auth"; +import { appRouter } from "@api/trpc/router"; +import { createContext } from "@api/trpc/context"; +import type { Env } from "@api/types"; +import type { BetterAuthUser, BetterAuthSession } from "@api/types/better-auth"; import type * as SentryNode from "@sentry/node"; import type * as SentryCloudflare from "@sentry/cloudflare"; @@ -64,7 +64,7 @@ export function createHonoApp(config: HonoAppConfig) { attributes: { "http.method": c.req.method, "http.route": c.req.path, - "http.url": c.req.url, + "http.url": `${new URL(c.req.url).origin}${c.req.path}`, }, }, async (span) => { @@ -166,7 +166,10 @@ export function createHonoApp(config: HonoAppConfig) { return c.json( { - error: err.message || "Internal server error", + error: + status >= 500 && env.NODE_ENV !== "development" + ? "Internal server error" + : err.message || "Internal server error", ...(env.NODE_ENV === "development" && { stack: err.stack }), }, status @@ -181,6 +184,7 @@ export function createHonoApp(config: HonoAppConfig) { // Debug Sentry - comprehensive diagnostics app.get("/debug-sentry", (c) => { const env = c.get("env"); + if (env.NODE_ENV !== "development") return c.notFound(); const sentry = c.get("sentry"); const runtime = c.get("runtime"); @@ -251,12 +255,6 @@ export function createHonoApp(config: HonoAppConfig) { const auth = createAuth(c.get("env")); const response = await auth.handler(c.req.raw); - // Log response headers (especially Set-Cookie) - const setCookieHeader = response.headers.get("set-cookie"); - if (setCookieHeader) { - console.log(`[Auth] 🍪 Setting cookies:`, setCookieHeader); - } - console.log(`[Auth] 📤 Response status: ${response.status}`); return response; }); @@ -270,8 +268,11 @@ export function createHonoApp(config: HonoAppConfig) { router: appRouter, // Cast to our typed Variables context - safe because this middleware runs // after our context-setting middleware above - createContext: (_opts, c) => - createContext(c as unknown as Parameters[0]), + createContext: (opts, c) => + createContext( + c as Parameters[0], + opts.resHeaders + ), onError: ({ error, type, path }) => { console.error("❌ tRPC Error:", { type, path, error }); // Note: Error capturing is handled in errorFormatter in trpc/init.ts @@ -282,44 +283,8 @@ export function createHonoApp(config: HonoAppConfig) { // Public RSS feeds app.get("/public/:username/:slug", async (c) => { const { username, slug } = c.req.param(); - const env = c.get("env"); - const { getUserLimits } = await import("../services/limits"); - const { checkPublicFeedRateLimit } = - await import("../services/rate-limiter"); - const schema = await import("../db/schema"); - const { sql, eq, and } = await import("drizzle-orm"); - const ctx = await createContext(c); - // Find user - const [user] = await ctx.db - .select() - .from(schema.user) - .where( - sql`COALESCE(${schema.user.username}, ${schema.user.name}) = ${username}` - ) - .limit(1); - - if (!user) { - return c.json({ error: "User not found" }, 404); - } - - // Rate limiting - const limits = await getUserLimits(ctx.db, user.id); - const rateLimitResult = await checkPublicFeedRateLimit( - env, - user.id, - user.plan || "free", - limits.publicFeedRateLimitPerMinute - ); - - if (!rateLimitResult.allowed) { - return c.json( - { error: "Rate limit exceeded", limit: rateLimitResult.limit }, - 429 - ); - } - // Get feed XML let xml: string; try { @@ -332,36 +297,13 @@ export function createHonoApp(config: HonoAppConfig) { if (error instanceof TRPCError && error.code === "NOT_FOUND") { return c.json({ error: error.message || "Feed not found" }, 404); } + if (error instanceof TRPCError && error.code === "TOO_MANY_REQUESTS") { + return c.json({ error: error.message }, 429); + } // Re-throw other errors to be handled by the generic error handler throw error; } - // Log access (awaited to ensure completion) - const [feed] = await ctx.db - .select() - .from(schema.feeds) - .where(and(eq(schema.feeds.userId, user.id), eq(schema.feeds.slug, slug))) - .limit(1); - - if (feed) { - const clientIP = - c.req.header("cf-connecting-ip") || - c.req.header("x-forwarded-for") || - "unknown"; - - try { - await ctx.db.insert(schema.publicFeedAccessLog).values({ - feedId: feed.id, - ipAddress: clientIP, - userAgent: c.req.header("user-agent") || null, - accessedAt: new Date(), - }); - } catch (error) { - // Log but don't fail the feed request - console.error("Failed to log feed access:", error); - } - } - c.header("Content-Type", "application/rss+xml; charset=utf-8"); c.header("Cache-Control", "public, max-age=300"); return c.body(xml); diff --git a/packages/api/src/routers/__tests__/admin.test.ts b/packages/api/src/routers/__tests__/admin.test.ts index 31136190..54a73e47 100644 --- a/packages/api/src/routers/__tests__/admin.test.ts +++ b/packages/api/src/routers/__tests__/admin.test.ts @@ -13,12 +13,12 @@ import { seedTestPlan, seedTestSource, seedTestSubscription, -} from "@/test/setup"; +} from "@api/test/setup"; import { adminRouter } from "../admin"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; // Mock Better Auth -vi.mock("@/auth/better-auth", () => ({ +vi.mock("@api/auth/better-auth", () => ({ createAuth: vi.fn(() => ({ api: { sendVerificationEmail: vi.fn().mockResolvedValue({ status: true }), diff --git a/packages/api/src/routers/__tests__/articles-audio-progress.test.ts b/packages/api/src/routers/__tests__/articles-audio-progress.test.ts index 32988ac9..c575cc96 100644 --- a/packages/api/src/routers/__tests__/articles-audio-progress.test.ts +++ b/packages/api/src/routers/__tests__/articles-audio-progress.test.ts @@ -11,8 +11,8 @@ import { seedTestUser, seedTestSource, seedTestSubscription, -} from "@/test/setup"; -import * as schema from "@/db/schema"; +} from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { articlesRouter } from "../articles"; import { eq, and } from "drizzle-orm"; diff --git a/packages/api/src/routers/__tests__/articles-counts.test.ts b/packages/api/src/routers/__tests__/articles-counts.test.ts index 9d331b09..df54ca33 100644 --- a/packages/api/src/routers/__tests__/articles-counts.test.ts +++ b/packages/api/src/routers/__tests__/articles-counts.test.ts @@ -6,14 +6,15 @@ */ import { describe, it, expect, beforeEach, afterEach } from "vitest"; +import { eq } from "drizzle-orm"; import { createTestDb, cleanupTestDb, seedTestUser, seedTestSource, seedTestSubscription, -} from "@/test/setup"; -import * as schema from "@/db/schema"; +} from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { articlesRouter } from "../articles"; describe("Articles Router - getCounts", () => { @@ -45,9 +46,9 @@ describe("Articles Router - getCounts", () => { return articlesRouter.createCaller({ db, user: { userId: testUser.id, username: "testuser", role: "user" }, - env: {} as any, + env: { SKIP_RATE_LIMIT: "true" }, headers: {}, - req: {} as any, + req: new Request("http://localhost/trpc"), }); } @@ -64,6 +65,48 @@ describe("Articles Router - getCounts", () => { await db.insert(schema.articles).values(articles); } + it.each(["include", "exclude"] as const)( + "counts only visible articles across chunks with %s filters", + async (filterMode) => { + await createArticles(250); + const [subscription] = await db.select().from(schema.subscriptions); + await db + .update(schema.subscriptions) + .set({ filterEnabled: true, filterMode }) + .where(eq(schema.subscriptions.id, subscription!.id)); + await db.insert(schema.subscriptionFilters).values({ + subscriptionId: subscription!.id, + field: "title", + matchType: "exact", + pattern: "Article 1", + }); + const [article] = await db + .select() + .from(schema.articles) + .where(eq(schema.articles.title, "Article 1")); + await db.insert(schema.userArticleStates).values({ + userId: testUser.id, + articleId: article!.id, + read: true, + saved: true, + }); + const counts = await createCaller().getCounts({}); + expect(counts).toEqual( + filterMode === "include" + ? { all: 1, read: 1, unread: 0, saved: 1 } + : { all: 249, read: 0, unread: 249, saved: 0 } + ); + const list = await createCaller().list({ limit: 100 }); + expect( + list.items.every((item) => + filterMode === "include" + ? item.title === "Article 1" + : item.title !== "Article 1" + ) + ).toBe(true); + } + ); + describe("Basic Counts", () => { it("should return zero counts when no articles exist", async () => { const caller = createCaller(); diff --git a/packages/api/src/routers/__tests__/articles-filters.test.ts b/packages/api/src/routers/__tests__/articles-filters.test.ts index e6eef4c9..468cab20 100644 --- a/packages/api/src/routers/__tests__/articles-filters.test.ts +++ b/packages/api/src/routers/__tests__/articles-filters.test.ts @@ -11,8 +11,8 @@ import { seedTestUser, seedTestSource, seedTestSubscription, -} from "@/test/setup"; -import * as schema from "@/db/schema"; +} from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { articlesRouter } from "../articles"; import { eq } from "drizzle-orm"; @@ -631,12 +631,15 @@ describe("Articles Router - Subscription Filters", () => { const caller = createCaller(); - const page1 = await caller.list({ limit: 1, cursor: 0 }); + const page1 = await caller.list({ limit: 1 }); expect(page1.items).toHaveLength(1); expect(page1.items[0].title).toBe("Needle 0"); expect(page1.hasMore).toBe(true); - const page2 = await caller.list({ limit: 1, cursor: 1 }); + const page2 = await caller.list({ + limit: 1, + cursor: page1.nextCursor ?? undefined, + }); expect(page2.items).toHaveLength(1); expect(page2.items[0].title).toBe("Needle 150"); expect(page2.hasMore).toBe(false); diff --git a/packages/api/src/routers/__tests__/articles-helpers.test.ts b/packages/api/src/routers/__tests__/articles-helpers.test.ts index 1ed16277..fe536cb7 100644 --- a/packages/api/src/routers/__tests__/articles-helpers.test.ts +++ b/packages/api/src/routers/__tests__/articles-helpers.test.ts @@ -11,8 +11,8 @@ import { seedTestUser, seedTestSource, seedTestSubscription, -} from "@/test/setup"; -import * as schema from "@/db/schema"; +} from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { buildArticlesBaseQuery, applyCategoryFilter, diff --git a/packages/api/src/routers/__tests__/articles-multi-page-integration.test.ts b/packages/api/src/routers/__tests__/articles-multi-page-integration.test.ts index 44daedac..7f731833 100644 --- a/packages/api/src/routers/__tests__/articles-multi-page-integration.test.ts +++ b/packages/api/src/routers/__tests__/articles-multi-page-integration.test.ts @@ -12,8 +12,8 @@ import { seedTestUser, seedTestSource, seedTestSubscription, -} from "@/test/setup"; -import * as schema from "@/db/schema"; +} from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { articlesRouter } from "../articles"; describe("Articles Router - Multi-Page Integration", () => { diff --git a/packages/api/src/routers/__tests__/articles-pagination.test.ts b/packages/api/src/routers/__tests__/articles-pagination.test.ts index bb3f9de9..a82f8d1d 100644 --- a/packages/api/src/routers/__tests__/articles-pagination.test.ts +++ b/packages/api/src/routers/__tests__/articles-pagination.test.ts @@ -11,8 +11,8 @@ import { seedTestUser, seedTestSource, seedTestSubscription, -} from "@/test/setup"; -import * as schema from "@/db/schema"; +} from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; import { articlesRouter } from "../articles"; @@ -75,6 +75,69 @@ describe("Articles Router - Pagination & Count", () => { }); } + describe("Stable article cursors", () => { + it("does not skip unread articles when earlier rows are read and new rows arrive", async () => { + await createArticles(5); + const caller = createCaller(); + const original = await caller.list({ limit: 100, read: false }); + const first = await caller.list({ limit: 2, read: false }); + expect(first.nextCursor).not.toBeNull(); + const firstId = first.items[0]!.id; + await db + .insert(schema.userArticleStates) + .values({ userId: testUser.id, articleId: firstId, read: true }); + await db.insert(schema.articles).values({ + sourceId: testSource.id, + guid: "arrived-later", + title: "Newest", + publishedAt: new Date(Date.now() + 60000), + }); + const next = await caller.list({ + limit: 100, + read: false, + cursor: first.nextCursor!, + }); + expect(next.items.map((a) => a.id)).toEqual( + original.items.slice(2).map((a) => a.id) + ); + expect(next.nextCursor).toBeNull(); + }); + + it("orders equal timestamps and null dates without losing rows", async () => { + await db.insert(schema.articles).values( + Array.from({ length: 6 }, (_, i) => ({ + sourceId: testSource.id, + guid: `ties-${i}`, + title: `Story ${i}`, + publishedAt: i < 3 ? new Date("2026-01-01T00:00:00Z") : null, + })) + ); + const caller = createCaller(); + const expected = await caller.list({ limit: 100 }); + const first = await caller.list({ limit: 2 }); + const second = await caller.list({ limit: 2, cursor: first.nextCursor! }); + const third = await caller.list({ limit: 2, cursor: second.nextCursor! }); + expect( + [...first.items, ...second.items, ...third.items].map((a) => a.id) + ).toEqual(expected.items.map((a) => a.id)); + expect(third.nextCursor).toBeNull(); + }); + + it("keeps the cursor valid after its anchor article is deleted", async () => { + await createArticles(5); + const caller = createCaller(); + const original = await caller.list({ limit: 100 }); + const first = await caller.list({ limit: 2 }); + await db + .delete(schema.articles) + .where(eq(schema.articles.id, first.nextCursor!.id)); + const next = await caller.list({ limit: 100, cursor: first.nextCursor! }); + expect(next.items.map((a) => a.id)).toEqual( + original.items.slice(2).map((a) => a.id) + ); + }); + }); + describe("Total Count Accuracy", () => { it("should return accurate total count without subscription filters", async () => { const caller = createCaller(); diff --git a/packages/api/src/routers/__tests__/auth-login.test.ts b/packages/api/src/routers/__tests__/auth-login.test.ts index df48e162..18182a60 100644 --- a/packages/api/src/routers/__tests__/auth-login.test.ts +++ b/packages/api/src/routers/__tests__/auth-login.test.ts @@ -6,9 +6,13 @@ */ import { describe, it, expect, beforeEach, afterEach } from "vitest"; -import { createTestDb, cleanupTestDb, seedGlobalSettings } from "@/test/setup"; +import { + createTestDb, + cleanupTestDb, + seedGlobalSettings, +} from "@api/test/setup"; import { authRouter } from "../auth"; -import { createAuth } from "@/auth/better-auth"; +import { createAuth } from "@api/auth/better-auth"; describe("Auth Login - Username and Email Support", () => { let db!: NonNullable>; diff --git a/packages/api/src/routers/__tests__/auth.test.ts b/packages/api/src/routers/__tests__/auth.test.ts index eabc0e4a..6e4e9ac9 100644 --- a/packages/api/src/routers/__tests__/auth.test.ts +++ b/packages/api/src/routers/__tests__/auth.test.ts @@ -10,14 +10,14 @@ import { cleanupTestDb, seedTestUser, seedGlobalSettings, -} from "@/test/setup"; +} from "@api/test/setup"; import { authRouter } from "../auth"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; // Mock email service -vi.mock("@/services/email", async () => { - const actual = await vi.importActual("@/services/email"); +vi.mock("@api/services/email", async () => { + const actual = await vi.importActual("@api/services/email"); return { ...actual, sendPasswordResetEmail: vi.fn(), @@ -131,7 +131,7 @@ describe("Auth Router", () => { describe("register", () => { it("should send welcome email on successful registration", async () => { - const { sendWelcomeEmail } = await import("@/services/email"); + const { sendWelcomeEmail } = await import("@api/services/email"); vi.mocked(sendWelcomeEmail).mockResolvedValue({ success: true }); const caller = authRouter.createCaller({ @@ -168,7 +168,7 @@ describe("Auth Router", () => { }); it("should succeed registration even if welcome email fails", async () => { - const { sendWelcomeEmail } = await import("@/services/email"); + const { sendWelcomeEmail } = await import("@api/services/email"); vi.mocked(sendWelcomeEmail).mockResolvedValue({ success: false, error: "Email service unavailable", @@ -279,7 +279,7 @@ describe("Auth Router", () => { }); it("should log email send result to security audit log", async () => { - const { sendPasswordResetEmail } = await import("@/services/email"); + const { sendPasswordResetEmail } = await import("@api/services/email"); vi.mocked(sendPasswordResetEmail).mockResolvedValue({ success: true }); const caller = authRouter.createCaller({ @@ -328,7 +328,7 @@ describe("Auth Router", () => { it("should log email failure to security audit log", async () => { // Mock sendPasswordResetEmail to fail - const { sendPasswordResetEmail } = await import("@/services/email"); + const { sendPasswordResetEmail } = await import("@api/services/email"); vi.mocked(sendPasswordResetEmail).mockResolvedValue({ success: false, error: "Email service error", @@ -386,7 +386,7 @@ describe("Auth Router", () => { }); it("should return success even when user does not exist (prevent enumeration)", async () => { - const { sendPasswordResetEmail } = await import("@/services/email"); + const { sendPasswordResetEmail } = await import("@api/services/email"); // Clear previous calls vi.mocked(sendPasswordResetEmail).mockClear(); diff --git a/packages/api/src/routers/__tests__/batch-query-undefined-input.test.ts b/packages/api/src/routers/__tests__/batch-query-undefined-input.test.ts index 03fb8135..bf5ded03 100644 --- a/packages/api/src/routers/__tests__/batch-query-undefined-input.test.ts +++ b/packages/api/src/routers/__tests__/batch-query-undefined-input.test.ts @@ -14,9 +14,9 @@ import { seedTestUser, seedTestSource, seedTestSubscription, -} from "@/test/setup"; -import { appRouter } from "@/trpc/router"; -import * as schema from "@/db/schema"; +} from "@api/test/setup"; +import { appRouter } from "@api/trpc/router"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; describe("Batch Query Input Handling (TUVIX-API-14)", () => { diff --git a/packages/api/src/routers/__tests__/categories.test.ts b/packages/api/src/routers/__tests__/categories.test.ts index f87824da..94d90600 100644 --- a/packages/api/src/routers/__tests__/categories.test.ts +++ b/packages/api/src/routers/__tests__/categories.test.ts @@ -10,7 +10,7 @@ import { cleanupTestDb, seedTestUser, seedTestCategory, -} from "@/test/setup"; +} from "@api/test/setup"; import { categoriesRouter } from "../categories"; describe("Categories Router", () => { diff --git a/packages/api/src/routers/__tests__/feeds.test.ts b/packages/api/src/routers/__tests__/feeds.test.ts index 4f93a629..b0014769 100644 --- a/packages/api/src/routers/__tests__/feeds.test.ts +++ b/packages/api/src/routers/__tests__/feeds.test.ts @@ -11,9 +11,9 @@ import { cleanupTestDb, seedTestUser, seedTestCategory, -} from "@/test/setup"; +} from "@api/test/setup"; import { feedsRouter } from "../feeds"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; // Helper to seed a test feed async function seedTestFeed( diff --git a/packages/api/src/routers/__tests__/http-integration.test.ts b/packages/api/src/routers/__tests__/http-integration.test.ts index 8c76a14e..184ab42e 100644 --- a/packages/api/src/routers/__tests__/http-integration.test.ts +++ b/packages/api/src/routers/__tests__/http-integration.test.ts @@ -8,9 +8,13 @@ */ import { describe, it, expect, beforeEach, afterEach } from "vitest"; -import { createTestDb, cleanupTestDb, seedGlobalSettings } from "@/test/setup"; -import { createHonoApp } from "@/hono/app"; -import type { Env } from "@/types"; +import { + createTestDb, + cleanupTestDb, + seedGlobalSettings, +} from "@api/test/setup"; +import { createHonoApp } from "@api/hono/app"; +import type { Env } from "@api/types"; import * as SentryNode from "@sentry/node"; /** @@ -65,6 +69,21 @@ describe("HTTP Integration - tRPC Batch Requests", () => { cleanupTestDb(db); }); + it("does not expose Sentry diagnostics outside development", async () => { + const response = await app.request("/debug-sentry"); + expect(response.status).toBe(404); + expect(await response.text()).not.toContain("sentryDsn"); + }); + + it("hides internal error details outside development", async () => { + app.get("/test-internal-error", () => { + throw new Error("sensitive database details"); + }); + const response = await app.request("/test-internal-error"); + expect(response.status).toBe(500); + expect(await response.json()).toEqual({ error: "Internal server error" }); + }); + it("should handle batch GET request without path truncation", async () => { // Simulate a tRPC batch request like the client sends const url = diff --git a/packages/api/src/routers/__tests__/plans.test.ts b/packages/api/src/routers/__tests__/plans.test.ts index ee26b646..24953f92 100644 --- a/packages/api/src/routers/__tests__/plans.test.ts +++ b/packages/api/src/routers/__tests__/plans.test.ts @@ -10,9 +10,9 @@ import { cleanupTestDb, seedTestUser, seedTestPlan, -} from "@/test/setup"; +} from "@api/test/setup"; import { plansRouter } from "../plans"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; describe("Plans Router", () => { diff --git a/packages/api/src/routers/__tests__/review-regressions.test.ts b/packages/api/src/routers/__tests__/review-regressions.test.ts new file mode 100644 index 00000000..a576d868 --- /dev/null +++ b/packages/api/src/routers/__tests__/review-regressions.test.ts @@ -0,0 +1,289 @@ +import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; +import { eq } from "drizzle-orm"; +import { createAuth } from "@api/auth/better-auth"; +import * as dbClient from "@api/db/client"; +import { initializeAdmin } from "@api/services/admin-init"; +import { appRouter } from "@api/trpc/router"; +import type { Context } from "@api/trpc/context"; +import type { Env } from "@api/types"; +import * as schema from "@api/db/schema"; +import { createTestDb, seedGlobalSettings } from "@api/test/setup"; + +vi.mock("@api/services/email", () => ({ + sendWelcomeEmail: vi.fn(async () => ({ success: true })), + sendVerificationEmail: vi.fn(async () => ({ success: true })), + sendPasswordResetEmail: vi.fn(async () => ({ success: true })), +})); + +describe("Review regression coverage", () => { + let db: ReturnType; + const env: Env = { + RUNTIME: "nodejs", + BETTER_AUTH_SECRET: "review-only-secret-at-least-32-characters-long", + BETTER_AUTH_URL: "http://localhost:3001", + BASE_URL: "http://localhost:5173", + CORS_ORIGIN: "http://localhost:5173", + ALLOW_FIRST_USER_ADMIN: "true", + SKIP_RATE_LIMIT: "true", + }; + + beforeEach(async () => { + db = createTestDb(); + await seedGlobalSettings(db); + }); + afterEach(() => { + vi.unstubAllGlobals(); + vi.restoreAllMocks(); + db.$client.close(); + }); + + function authRequest(path: string, body: Record) { + return createAuth(env, db).handler( + new Request(`http://localhost:3001/api/auth/${path}`, { + method: "POST", + headers: { + "content-type": "application/json", + origin: "http://localhost:5173", + }, + body: JSON.stringify(body), + }) + ); + } + const credentials = { + email: "review@example.com", + username: "reviewuser", + name: "reviewuser", + password: "ReviewPass123!", + }; + + it("native signup initializes the first administrator and settings", async () => { + const response = await authRequest("sign-up/email", credentials); + expect(response.status).toBe(200); + const [user] = await db.select().from(schema.user); + expect(user?.role).toBe("admin"); + expect(await db.select().from(schema.userSettings)).toHaveLength(1); + expect(await db.select().from(schema.usageStats)).toHaveLength(1); + }); + + it("disabled registration returns HTTP 403", async () => { + await db + .update(schema.globalSettings) + .set({ allowRegistration: false }) + .where(eq(schema.globalSettings.id, 1)); + const response = await authRequest("sign-up/email", credentials); + expect(response.status).toBe(403); + expect(await db.select().from(schema.user)).toHaveLength(0); + }); + + it("native login enforces persisted attempt limits", async () => { + await authRequest("sign-up/email", credentials); + await db + .update(schema.globalSettings) + .set({ maxLoginAttempts: 2 }) + .where(eq(schema.globalSettings.id, 1)); + await db.delete(schema.authRateLimits); + const statuses: number[] = []; + for (let attempt = 0; attempt < 4; attempt++) { + statuses.push( + ( + await authRequest("sign-in/email", { + email: credentials.email, + password: "wrong-password", + }) + ).status + ); + } + expect(statuses).toEqual([401, 401, 429, 429]); + }); + + async function caller() { + const [user] = await db + .insert(schema.user) + .values({ + name: "reader", + username: "reader", + email: "reader@example.com", + emailVerified: true, + }) + .returning(); + if (!user) throw new Error("Missing fixture user"); + const ctx: Context = { + db, + env, + user: { userId: user.id, username: "reader", role: "user" }, + headers: {}, + req: new Request("http://localhost:3001/trpc"), + cache: {}, + }; + return { user, api: appRouter.createCaller(ctx) }; + } + + it("public RSS respects subscription filters", async () => { + const { user, api } = await caller(); + const [source] = await db + .insert(schema.sources) + .values({ url: "https://example.com/feed", title: "Fixture" }) + .returning(); + if (!source) throw new Error("Missing fixture source"); + const [subscription] = await db + .insert(schema.subscriptions) + .values({ + userId: user.id, + sourceId: source.id, + filterEnabled: true, + filterMode: "exclude", + }) + .returning(); + if (!subscription) throw new Error("Missing fixture subscription"); + await db.insert(schema.subscriptionFilters).values({ + subscriptionId: subscription.id, + field: "title", + matchType: "contains", + pattern: "Excluded", + caseSensitive: false, + }); + await db.insert(schema.articles).values({ + sourceId: source.id, + guid: "fixture-guid", + title: "Excluded article", + link: "https://example.com/article", + }); + await db.insert(schema.feeds).values({ + userId: user.id, + slug: "feed", + title: "Public Feed", + public: true, + }); + expect((await api.articles.list({})).items).toHaveLength(0); + expect( + await api.feeds.getPublicXml({ username: "reader", slug: "feed" }) + ).not.toContain("Excluded article"); + }); + + it("feed preview rejects loopback before fetching", async () => { + const { api } = await caller(); + const fetchMock = vi.fn( + async () => new Response("not a feed", { status: 404 }) + ); + vi.stubGlobal("fetch", fetchMock); + await expect( + api.subscriptions.preview({ url: "http://127.0.0.1:8080/private" }) + ).rejects.toThrow(); + expect(fetchMock).not.toHaveBeenCalled(); + }); + + it("mark-all-read updates all unread articles and is idempotent", async () => { + const { user, api } = await caller(); + const [source] = await db + .insert(schema.sources) + .values({ url: "https://example.com/bulk-feed", title: "Fixture" }) + .returning(); + if (!source) throw new Error("Missing fixture source"); + await db + .insert(schema.subscriptions) + .values({ userId: user.id, sourceId: source.id }); + for (let index = 0; index < 1001; index++) { + await db.insert(schema.articles).values({ + sourceId: source.id, + guid: `bulk-${index}`, + title: `Article ${index}`, + }); + } + expect(await api.articles.markAllRead({})).toEqual({ updated: 1001 }); + expect(await api.articles.markAllRead({})).toEqual({ updated: 0 }); + const unread = await api.articles.list({ read: false }); + expect(unread.items).toHaveLength(0); + }); + + it("Cloudflare admin initialization uses the supplied database", async () => { + const createDatabase = vi + .spyOn(dbClient, "createDatabase") + .mockReturnValue(db); + const result = await initializeAdmin(db, { + ...env, + RUNTIME: "cloudflare", + ADMIN_USERNAME: "initialadmin", + ADMIN_EMAIL: "initialadmin@example.com", + ADMIN_PASSWORD: "AdminReview123!", + }); + expect(result.created).toBe(true); + expect(createDatabase).not.toHaveBeenCalled(); + }); + it("tRPC authentication forwards session cookies", async () => { + await caller(); + const responseHeaders = new Headers(); + const api = appRouter.createCaller({ + db, + env, + user: null, + headers: {}, + req: new Request("http://localhost:3001/trpc"), + cache: {}, + responseHeaders, + }); + await api.auth.register({ + email: "cookie@example.com", + username: "cookieuser", + password: "CookiePass123!", + }); + expect(responseHeaders.get("set-cookie")).toContain("session_token="); + }); + + it("rejects foreign categories before creating a feed", async () => { + const { api } = await caller(); + const [other] = await db + .insert(schema.user) + .values({ name: "other", username: "other", email: "other@example.com" }) + .returning(); + const [category] = await db + .insert(schema.categories) + .values({ userId: other!.id, name: "Private", color: "#123456" }) + .returning(); + await expect( + api.feeds.create({ + slug: "invalid", + title: "Invalid", + public: true, + categoryIds: [category!.id], + }) + ).rejects.toThrow(/Category/); + expect(await db.select().from(schema.feeds)).toHaveLength(0); + }); + it("public XML requests through tRPC cannot bypass the feed rate limit", async () => { + const { user } = await caller(); + await db.insert(schema.feeds).values({ + userId: user.id, + slug: "limited", + title: "Limited", + public: true, + }); + const limit = vi.fn(async () => ({ success: false })); + const api = appRouter.createCaller({ + db, + env: { ...env, RUNTIME: "cloudflare", FEED_RATE_LIMIT: { limit } }, + user: null, + headers: {}, + req: new Request("https://api.example.com/trpc"), + cache: {}, + }); + await expect( + api.feeds.getPublicXml({ username: "reader", slug: "limited" }) + ).rejects.toMatchObject({ code: "TOO_MANY_REQUESTS" }); + expect(limit).toHaveBeenCalledWith({ key: user.id.toString() }); + }); + + it("rejects a stale administrator role after demotion", async () => { + const { user } = await caller(); + const api = appRouter.createCaller({ + db, + env, + user: { userId: user.id, username: "reader", role: "admin" }, + headers: {}, + req: new Request("http://localhost:3001/trpc"), + cache: {}, + }); + await expect(api.admin.listUsers({})).rejects.toMatchObject({ + code: "FORBIDDEN", + }); + }); +}); diff --git a/packages/api/src/routers/__tests__/subscriptions-discover.test.ts b/packages/api/src/routers/__tests__/subscriptions-discover.test.ts index d1bb0005..93061f7f 100644 --- a/packages/api/src/routers/__tests__/subscriptions-discover.test.ts +++ b/packages/api/src/routers/__tests__/subscriptions-discover.test.ts @@ -1,3 +1,4 @@ +import { createFeedResponse } from "@api/test/mocks"; /** * Feed Discovery Tests * @@ -7,7 +8,7 @@ */ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; -import { createTestDb, cleanupTestDb, seedTestUser } from "@/test/setup"; +import { createTestDb, cleanupTestDb, seedTestUser } from "@api/test/setup"; import { subscriptionsRouter } from "../subscriptions"; describe("Feed Discovery - Deduplication", () => { @@ -32,10 +33,8 @@ describe("Feed Discovery - Deduplication", () => { * Helper to create a mock RSS feed response */ function createMockRssResponse(url: string, title: string = "Test Feed") { - return { - ok: true, - url: url, // Final URL after redirects - text: async () => ` + return createFeedResponse( + ` ${title} @@ -43,23 +42,23 @@ describe("Feed Discovery - Deduplication", () => { Test feed description `, - } as Response; + url + ) as Response; } /** * Helper to create a mock Atom feed response */ function createMockAtomResponse(url: string, title: string = "Test Feed") { - return { - ok: true, - url: url, - text: async () => ` + return createFeedResponse( + ` ${title} Test feed description `, - } as Response; + url + ) as Response; } /** @@ -72,10 +71,8 @@ describe("Feed Discovery - Deduplication", () => { `` ) .join("\n"); - return { - ok: true, - url: "https://example.com", - text: async () => ` + return createFeedResponse( + ` Example Site @@ -83,7 +80,8 @@ describe("Feed Discovery - Deduplication", () => { Content `, - } as Response; + "https://example.com" + ) as Response; } /** @@ -128,7 +126,7 @@ describe("Feed Discovery - Deduplication", () => { if (url.includes("/rss") && !url.includes("/feed")) { return Promise.resolve(mockResponses[1]); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve(mockResponses[mockResponses.length - 1]); } return Promise.resolve({ ok: false }); @@ -147,7 +145,7 @@ describe("Feed Discovery - Deduplication", () => { // Mock: All common paths fail, HTML has links that redirect to same feed (global.fetch as any).mockImplementation((url: string) => { - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve( createMockHtmlResponse([ "https://example.com/feed", @@ -195,7 +193,7 @@ describe("Feed Discovery - Deduplication", () => { ) ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve( createMockHtmlResponse([ "https://example.com/feed?utm_source=twitter", @@ -234,7 +232,7 @@ describe("Feed Discovery - Deduplication", () => { ) ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve( createMockHtmlResponse([ "https://example.com/feed?category=tech", @@ -272,7 +270,7 @@ describe("Feed Discovery - Deduplication", () => { createMockRssResponse("https://example.com/feed", "Feed") ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve(createMockHtmlResponse([])); } return Promise.resolve({ ok: false }); @@ -298,7 +296,7 @@ describe("Feed Discovery - Deduplication", () => { createMockRssResponse("https://Example.com/feed", "Feed") ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve(createMockHtmlResponse([])); } return Promise.resolve({ ok: false }); @@ -322,7 +320,7 @@ describe("Feed Discovery - Deduplication", () => { createMockRssResponse("https://example.com/feed.xml", "Feed") ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve(createMockHtmlResponse([])); } return Promise.resolve({ ok: false }); @@ -346,7 +344,7 @@ describe("Feed Discovery - Deduplication", () => { createMockRssResponse("https://example.com/feed", "RSS Feed") ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve(createMockHtmlResponse([])); } return Promise.resolve({ ok: false }); @@ -366,7 +364,7 @@ describe("Feed Discovery - Deduplication", () => { createMockAtomResponse("https://example.com/atom", "Atom Feed") ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve(createMockHtmlResponse([])); } return Promise.resolve({ ok: false }); @@ -424,7 +422,7 @@ describe("Feed Discovery - Deduplication", () => { ) ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve( createMockHtmlResponse([ "https://example.com/feed", @@ -465,20 +463,22 @@ describe("Feed Discovery - Deduplication", () => { (global.fetch as any).mockImplementation((url: string) => { // Both /atom and /atom.xml return 200 with same content if (url === "https://example.com/atom") { - return Promise.resolve({ - ok: true, - url: "https://example.com/atom", // No redirect - text: async () => atomFeedContent, - } as Response); + return Promise.resolve( + createFeedResponse( + atomFeedContent, + "https://example.com/atom" + ) as Response + ); } if (url === "https://example.com/atom.xml") { - return Promise.resolve({ - ok: true, - url: "https://example.com/atom.xml", // No redirect - text: async () => atomFeedContent, - } as Response); + return Promise.resolve( + createFeedResponse( + atomFeedContent, + "https://example.com/atom.xml" + ) as Response + ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve( createMockHtmlResponse(["https://example.com/atom.xml"]) ); @@ -518,20 +518,22 @@ describe("Feed Discovery - Deduplication", () => { (global.fetch as any).mockImplementation((url: string) => { if (url === "https://example.com/atom") { - return Promise.resolve({ - ok: true, - url: "https://example.com/atom", - text: async () => feed1Content, - } as Response); + return Promise.resolve( + createFeedResponse( + feed1Content, + "https://example.com/atom" + ) as Response + ); } if (url === "https://example.com/atom.xml") { - return Promise.resolve({ - ok: true, - url: "https://example.com/atom.xml", - text: async () => feed2Content, - } as Response); + return Promise.resolve( + createFeedResponse( + feed2Content, + "https://example.com/atom.xml" + ) as Response + ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve( createMockHtmlResponse([ "https://example.com/atom", @@ -561,20 +563,22 @@ describe("Feed Discovery - Deduplication", () => { (global.fetch as any).mockImplementation((url: string) => { if (url === "https://example.com/atom") { - return Promise.resolve({ - ok: true, - url: "https://example.com/atom", - text: async () => feedContent, - } as Response); + return Promise.resolve( + createFeedResponse( + feedContent, + "https://example.com/atom" + ) as Response + ); } if (url === "https://example.com/atom.xml") { - return Promise.resolve({ - ok: true, - url: "https://example.com/atom.xml", - text: async () => feedContent, - } as Response); + return Promise.resolve( + createFeedResponse( + feedContent, + "https://example.com/atom.xml" + ) as Response + ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve(createMockHtmlResponse([])); } return Promise.resolve({ ok: false }); @@ -690,7 +694,7 @@ describe("Feed Discovery - Deduplication", () => { ); } // HTML fetch - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve(createMockHtmlResponse([])); } return Promise.resolve({ ok: false }); @@ -716,7 +720,7 @@ describe("Feed Discovery - Deduplication", () => { ) ); } - if (url === "https://example.com") { + if (url === "https://example.com/") { return Promise.resolve(createMockHtmlResponse([])); } return Promise.resolve({ ok: false }); diff --git a/packages/api/src/routers/__tests__/subscriptions-immediate-fetch.test.ts b/packages/api/src/routers/__tests__/subscriptions-immediate-fetch.test.ts index 83cd5347..257a0a66 100644 --- a/packages/api/src/routers/__tests__/subscriptions-immediate-fetch.test.ts +++ b/packages/api/src/routers/__tests__/subscriptions-immediate-fetch.test.ts @@ -5,9 +5,9 @@ */ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; -import { createTestDb, cleanupTestDb, seedTestUser } from "@/test/setup"; +import { createTestDb, cleanupTestDb, seedTestUser } from "@api/test/setup"; import { subscriptionsRouter } from "../subscriptions"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; describe("Subscription Creation - Immediate Article Fetching", () => { @@ -36,17 +36,13 @@ describe("Subscription Creation - Immediate Article Fetching", () => { xmlContent: string, status: number = 200 ): Response { - return { - ok: status >= 200 && status < 300, + const response = new Response(xmlContent, { status, statusText: status === 200 ? "OK" : "Error", - url, - headers: { - get: (key: string) => - key.toLowerCase() === "content-type" ? "application/xml" : null, - } as any, - text: async () => xmlContent, - } as Response; + headers: { "content-type": "application/xml" }, + }); + Object.defineProperty(response, "url", { value: url }); + return response; } /** @@ -97,7 +93,7 @@ describe("Subscription Creation - Immediate Article Fetching", () => { const feedXml = createRssWithArticles("Test Feed", 3); // Mock all fetch calls to return the feed with articles - (global.fetch as any).mockResolvedValue( + vi.mocked(global.fetch).mockImplementation(async () => createMockResponse(feedUrl, feedXml) ); @@ -165,7 +161,7 @@ describe("Subscription Creation - Immediate Article Fetching", () => { const feedXml = createRssWithArticles("Test Feed", 2); // Mock fetch to return feed with articles - (global.fetch as any).mockResolvedValue( + vi.mocked(global.fetch).mockImplementation(async () => createMockResponse(feedUrl, feedXml) ); @@ -199,7 +195,7 @@ describe("Subscription Creation - Immediate Article Fetching", () => { const feedXml = createRssWithArticles("Large Feed", 50); // Mock fetch to return large feed - (global.fetch as any).mockResolvedValue( + vi.mocked(global.fetch).mockImplementation(async () => createMockResponse(feedUrl, feedXml) ); @@ -226,7 +222,7 @@ describe("Subscription Creation - Immediate Article Fetching", () => { const feedXml = createRssWithArticles("Test Feed", 3); // Mock fetch to always return same feed - (global.fetch as any).mockResolvedValue( + vi.mocked(global.fetch).mockImplementation(async () => createMockResponse(feedUrl, feedXml) ); diff --git a/packages/api/src/routers/__tests__/subscriptions-opml-filters.test.ts b/packages/api/src/routers/__tests__/subscriptions-opml-filters.test.ts index fe87b597..945a65e4 100644 --- a/packages/api/src/routers/__tests__/subscriptions-opml-filters.test.ts +++ b/packages/api/src/routers/__tests__/subscriptions-opml-filters.test.ts @@ -1,3 +1,4 @@ +import { createFeedResponse } from "@api/test/mocks"; /** * OPML Filter and Category Export/Import Tests * @@ -12,8 +13,8 @@ import { seedTestSource, seedTestSubscription, seedTestCategory, -} from "@/test/setup"; -import * as schema from "@/db/schema"; +} from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { subscriptionsRouter } from "../subscriptions"; import { parseOpml } from "feedsmith"; import { eq, and } from "drizzle-orm"; @@ -123,34 +124,31 @@ function createRealisticFeedFetcher( if (!feed) { // Default realistic RSS feed if not specified - return { - ok: true, - url: urlStr, - headers: new Headers({ - "content-type": "application/rss+xml; charset=utf-8", + return createFeedResponse( + createRealisticRSSFeed({ + title: "Default Test Feed", + link: urlStr, + description: "A test RSS feed", + items: [ + { title: "Test Article 1", link: `${urlStr}/article-1` }, + { title: "Test Article 2", link: `${urlStr}/article-2` }, + ], }), - text: async () => - createRealisticRSSFeed({ - title: "Default Test Feed", - link: urlStr, - description: "A test RSS feed", - items: [ - { title: "Test Article 1", link: `${urlStr}/article-1` }, - { title: "Test Article 2", link: `${urlStr}/article-2` }, - ], - }), - } as Response; + urlStr, + new Headers({ + "content-type": "application/rss+xml; charset=utf-8", + }) + ) as Response; } - return { - ok: true, - url: urlStr, - headers: new Headers({ + return createFeedResponse( + feed.content, + urlStr, + new Headers({ "content-type": feed.contentType || "application/rss+xml; charset=utf-8", - }), - text: async () => feed.content, - } as Response; + }) + ) as Response; }; } @@ -743,9 +741,8 @@ describe("OPML Filter and Category Export/Import", () => { // Mock fetch for feed validation global.fetch = async () => { - return { - ok: true, - text: async () => ` + return createFeedResponse( + ` New Feed @@ -755,7 +752,8 @@ describe("OPML Filter and Category Export/Import", () => { `, - } as Response; + undefined + ) as Response; }; const result = await caller.import({ @@ -1141,9 +1139,8 @@ describe("OPML Filter and Category Export/Import", () => { // Mock fetch for feed validation global.fetch = async () => { - return { - ok: true, - text: async () => ` + return createFeedResponse( + ` New Feed @@ -1153,7 +1150,8 @@ describe("OPML Filter and Category Export/Import", () => { `, - } as Response; + undefined + ) as Response; }; const result = await caller.import({ @@ -1291,9 +1289,8 @@ describe("OPML Filter and Category Export/Import", () => { // Mock fetch for feed validation global.fetch = async () => { - return { - ok: true, - text: async () => ` + return createFeedResponse( + ` New Feed @@ -1303,7 +1300,8 @@ describe("OPML Filter and Category Export/Import", () => { `, - } as Response; + undefined + ) as Response; }; const result = await caller.import({ @@ -1398,9 +1396,8 @@ describe("OPML Filter and Category Export/Import", () => { // Mock fetch for feed validation global.fetch = async () => { - return { - ok: true, - text: async () => ` + return createFeedResponse( + ` New Feed @@ -1410,7 +1407,8 @@ describe("OPML Filter and Category Export/Import", () => { `, - } as Response; + undefined + ) as Response; }; const result = await caller.import({ @@ -1765,15 +1763,15 @@ describe("OPML Filter and Category Export/Import", () => { // Mock fetch global.fetch = async () => { - return { - ok: true, - text: async () => ` + return createFeedResponse( + ` Test Feed `, - } as Response; + undefined + ) as Response; }; // Import only selected URLs @@ -2439,12 +2437,10 @@ describe("OPML Filter and Category Export/Import", () => { opmlContent: opmlXml, }); - // Verify RSS and Atom feeds were imported successfully - // Note: JSON Feed format is not currently supported by feedsmith parser - expect(result.successCount).toBe(2); - expect(result.errorCount).toBe(1); - expect(result.errors[0]?.url).toBe("https://json.example.com/feed.json"); - expect(result.errors[0]?.error).toContain("Unrecognized feed format"); + // RSS, Atom, and JSON Feed are all supported by feedsmith. + expect(result.successCount).toBe(3); + expect(result.errorCount).toBe(0); + expect(result.errors).toEqual([]); // Verify all successfully imported feeds const importedSubs = await db @@ -2456,8 +2452,8 @@ describe("OPML Filter and Category Export/Import", () => { ) .where(eq(schema.subscriptions.userId, testUser.id)); - // Should have RSS and Atom feeds (plus testSubscription from beforeEach) - expect(importedSubs.length).toBeGreaterThanOrEqual(2); + // Includes the existing fixture subscription and three imported feeds. + expect(importedSubs).toHaveLength(4); // CRITICAL: Verify metadata was extracted correctly for each supported format // This ensures schema changes and parsing logic changes would break the test @@ -2478,11 +2474,13 @@ describe("OPML Filter and Category Export/Import", () => { // Atom feeds use "subtitle" which maps to description expect(atomSource?.sources.description).toBe("Atom format feed"); - // Verify JSON Feed was NOT imported (unsupported format) + // Verify JSON Feed metadata is preserved. const jsonSource = importedSubs.find((s) => s.sources.url.includes("json.example.com") ); - expect(jsonSource).toBeUndefined(); + expect(jsonSource?.sources.title).toBe("JSON Feed"); + expect(jsonSource?.sources.siteUrl).toBe("https://json.example.com"); + expect(jsonSource?.sources.description).toBe("JSON Feed format"); }); it("should verify exported data matches database schema exactly", async () => { diff --git a/packages/api/src/routers/__tests__/userSettings.test.ts b/packages/api/src/routers/__tests__/userSettings.test.ts index dc4c498e..3dba2920 100644 --- a/packages/api/src/routers/__tests__/userSettings.test.ts +++ b/packages/api/src/routers/__tests__/userSettings.test.ts @@ -10,9 +10,9 @@ import { cleanupTestDb, seedTestUser, seedTestCategory, -} from "@/test/setup"; +} from "@api/test/setup"; import { userSettingsRouter } from "../userSettings"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; describe("User Settings Router", () => { diff --git a/packages/api/src/routers/admin.ts b/packages/api/src/routers/admin.ts index d1933c51..75281a22 100644 --- a/packages/api/src/routers/admin.ts +++ b/packages/api/src/routers/admin.ts @@ -19,33 +19,33 @@ import { like, type SQL, } from "drizzle-orm"; -import { router, adminProcedure } from "@/trpc/init"; -import * as schema from "@/db/schema"; +import { router, adminProcedure } from "@api/trpc/init"; +import * as schema from "@api/db/schema"; import { getUserLimits, getUserUsage, recalculateUsage, -} from "@/services/limits"; +} from "@api/services/limits"; import { createPaginatedSchema, withUndefinedAsEmpty, paginationInputSchema, createPaginatedResponse, -} from "@/types/pagination"; -import { validatePlanExists, getAllPlans } from "@/services/plans"; +} from "@api/types/pagination"; +import { validatePlanExists, getAllPlans } from "@api/services/plans"; import { titleValidator, descriptionValidator, domainValidator, -} from "@/types/validators"; -import { normalizeDomain } from "@/utils/domain-checker"; -import { chunkArray, D1_MAX_PARAMETERS } from "@/db/utils"; -import { withQueryMetrics } from "@/utils/db-metrics"; -import { aggregateByDay, calculateStartDate } from "@/utils/admin-metrics"; -import { createAuth } from "@/auth/better-auth"; -import { getGlobalSettings } from "@/services/global-settings"; -import { logSecurityEvent } from "@/auth/security"; -import * as Sentry from "@/utils/sentry"; +} from "@api/types/validators"; +import { normalizeDomain } from "@api/utils/domain-checker"; +import { chunkArray, D1_MAX_PARAMETERS } from "@api/db/utils"; +import { withQueryMetrics } from "@api/utils/db-metrics"; +import { aggregateByDay, calculateStartDate } from "@api/utils/admin-metrics"; +import { createAuth } from "@api/auth/better-auth"; +import { getGlobalSettings } from "@api/services/global-settings"; +import { logSecurityEvent } from "@api/auth/security"; +import * as Sentry from "@api/utils/sentry"; // ============================================================================ // SHARED SCHEMAS AND CONSTANTS @@ -2285,9 +2285,9 @@ export const adminRouter = router({ const { fetchAllFeeds } = await import("../services/rss-fetcher"); // Import Sentry (optional - gracefully handle if unavailable) - let Sentry: typeof import("@/utils/sentry") | null = null; + let Sentry: typeof import("@api/utils/sentry") | null = null; try { - Sentry = await import("@/utils/sentry"); + Sentry = await import("@api/utils/sentry"); } catch (error) { console.warn( "Sentry unavailable, continuing without monitoring:", diff --git a/packages/api/src/routers/articles-helpers.ts b/packages/api/src/routers/articles-helpers.ts index 9831120b..87301cc5 100644 --- a/packages/api/src/routers/articles-helpers.ts +++ b/packages/api/src/routers/articles-helpers.ts @@ -1,12 +1,13 @@ +import type { ArticleCursor } from "@api/types/pagination"; /** * Articles Router Helper Functions * * Extracted helpers to reduce duplication and improve maintainability */ -import { eq, and, or, isNull, type SQL } from "drizzle-orm"; -import * as schema from "@/db/schema"; -import type { Database } from "@/db/client"; +import { eq, and, or, isNull, lt, type SQL } from "drizzle-orm"; +import * as schema from "@api/db/schema"; +import type { Database } from "@api/db/client"; /** * Build base query for articles with all necessary joins @@ -103,3 +104,21 @@ export function buildArticlesWhereConditions(input: { return conditions; } + +/** Match rows strictly after a descending publication-date/id cursor. */ +export function afterArticleCursor(cursor: ArticleCursor): SQL { + if (cursor.publishedAt === null) { + return and( + isNull(schema.articles.publishedAt), + lt(schema.articles.id, cursor.id) + )!; + } + return or( + lt(schema.articles.publishedAt, cursor.publishedAt), + and( + eq(schema.articles.publishedAt, cursor.publishedAt), + lt(schema.articles.id, cursor.id) + ), + isNull(schema.articles.publishedAt) + )!; +} diff --git a/packages/api/src/routers/articles.ts b/packages/api/src/routers/articles.ts index a9e4702e..a4e804cc 100644 --- a/packages/api/src/routers/articles.ts +++ b/packages/api/src/routers/articles.ts @@ -6,24 +6,29 @@ import { z } from "zod"; import { TRPCError } from "@trpc/server"; -import { eq, and, desc, inArray, lt } from "drizzle-orm"; -import { router, rateLimitedProcedure } from "@/trpc/init"; -import { articleWithSourceSchema } from "@/db/schemas.zod"; +import { eq, and, desc, sql } from "drizzle-orm"; +import { router, rateLimitedProcedure } from "@api/trpc/init"; +import { articleWithSourceSchema } from "@api/db/schemas.zod"; import { createPaginatedSchema, + articleCursorSchema, + type ArticleCursor, paginationInputSchema, withUndefinedAsEmpty, -} from "@/types/pagination"; +} from "@api/types/pagination"; import { buildArticlesBaseQuery, + afterArticleCursor, applyCategoryFilter, buildArticlesWhereConditions, } from "./articles-helpers"; -import * as schema from "@/db/schema"; -import { D1_MAX_PARAMETERS, chunkArray, executeBatch } from "@/db/utils"; -import { upsertArticleState } from "@/db/helpers"; -import { withQueryMetrics } from "@/utils/db-metrics"; -import * as Sentry from "@/utils/sentry"; +import * as schema from "@api/db/schema"; +import { executeBatch } from "@api/db/utils"; +import { upsertArticleState } from "@api/db/helpers"; +import { matchesSubscriptionFilters } from "@api/services/article-filters"; +import { fetchSubscriptionFilters } from "@api/db/transformers"; +import { withQueryMetrics } from "@api/utils/db-metrics"; +import * as Sentry from "@api/utils/sentry"; /** * Helper function to transform database row to article output @@ -88,94 +93,6 @@ function transformArticleRow(row: { */ type ArticleWithSubscription = ReturnType; -/** - * Check if an article matches a single filter - */ -function matchesFilter( - article: ArticleWithSubscription, - filter: typeof schema.subscriptionFilters.$inferSelect -): boolean { - const fieldValue = (() => { - switch (filter.field) { - case "title": - return article.title ?? ""; - case "description": - return article.description ?? ""; - case "content": - return article.content ?? ""; - case "author": - return article.author ?? ""; - case "any": - return [ - article.title ?? "", - article.description ?? "", - article.content ?? "", - article.author ?? "", - ].join(" "); - default: - return ""; - } - })(); - - // If field value is empty/null and pattern is not empty, no match - if (!fieldValue && filter.pattern) { - return false; - } - - const searchText = filter.caseSensitive - ? fieldValue - : fieldValue.toLowerCase(); - const pattern = filter.caseSensitive - ? filter.pattern - : filter.pattern.toLowerCase(); - - switch (filter.matchType) { - case "contains": - return searchText.includes(pattern); - case "exact": - return searchText === pattern; - case "regex": { - try { - const regex = new RegExp( - filter.pattern, - filter.caseSensitive ? "" : "i" - ); - return regex.test(fieldValue); - } catch { - // Invalid regex - skip this filter - return false; - } - } - default: - return false; - } -} - -/** - * Check if an article matches subscription filters - */ -function matchesSubscriptionFilters( - article: ArticleWithSubscription, - filters: (typeof schema.subscriptionFilters.$inferSelect)[], - filterMode: "include" | "exclude" -): boolean { - // If no filters exist but filtering is enabled, exclude the article - // (This matches the Go implementation behavior) - if (filters.length === 0) { - return false; - } - - const hasMatch = filters.some((filter) => matchesFilter(article, filter)); - - if (filterMode === "include") { - // Include mode: article must match at least one filter - return hasMatch; - } else { - // Exclude mode: article must not match any filter - return !hasMatch; - } -} - export const articlesRouter = router({ /** * List articles from user's subscriptions with filters @@ -183,7 +100,8 @@ export const articlesRouter = router({ list: rateLimitedProcedure .input( withUndefinedAsEmpty( - paginationInputSchema.extend({ + paginationInputSchema.omit({ cursor: true }).extend({ + cursor: articleCursorSchema.optional(), categoryId: z.number().optional(), subscriptionId: z.number().optional(), read: z.boolean().optional(), @@ -191,7 +109,11 @@ export const articlesRouter = router({ }) ) ) - .output(createPaginatedSchema(articleWithSourceSchema)) + .output( + createPaginatedSchema(articleWithSourceSchema).extend({ + nextCursor: articleCursorSchema.nullable(), + }) + ) .query(async ({ ctx, input }) => { const { userId } = ctx.user; @@ -247,13 +169,15 @@ export const articlesRouter = router({ if (!hasSubscriptionFilters) { // EFFICIENT PATH: No subscription filters, use direct database pagination // Always order by publishedAt for chronological feed - let paginationQuery = queryBuilder.orderBy( - desc(schema.articles.publishedAt) - ); + let paginationQuery = queryBuilder + .where( + and(...conditions, cursor ? afterArticleCursor(cursor) : undefined) + ) + .orderBy(desc(schema.articles.publishedAt), desc(schema.articles.id)); - // Use cursor OR offset (cursor takes precedence for infinite scroll) - // Frontend sends cursor as cumulative item count (50, 100, 150...) - const effectiveOffset = cursor ?? offset; + // Explicit offsets serve numbered pages; infinite scrolling uses a + // stable ordering key so changes to earlier rows cannot shift pages. + const effectiveOffset = cursor ? 0 : offset; if (effectiveOffset > 0) { paginationQuery = paginationQuery.offset(effectiveOffset); @@ -290,45 +214,14 @@ export const articlesRouter = router({ // Calculate total count (accurate since no subscription filtering) // Build COUNT query with same JOINs and WHERE as main query - let countQuery = ctx.db - .select() - .from(schema.articles) - .innerJoin( - schema.sources, - eq(schema.articles.sourceId, schema.sources.id) - ) - .innerJoin( - schema.subscriptions, - and( - eq(schema.articles.sourceId, schema.subscriptions.sourceId), - eq(schema.subscriptions.userId, userId) - ) - ) - .leftJoin( - schema.userArticleStates, - and( - eq(schema.userArticleStates.articleId, schema.articles.id), - eq(schema.userArticleStates.userId, userId) - ) - ) - .$dynamic(); + let countQuery = buildArticlesBaseQuery(ctx.db, userId); // Apply category filter if needed if (input.categoryId) { - countQuery = countQuery.innerJoin( - schema.subscriptionCategories, - and( - eq( - schema.subscriptionCategories.subscriptionId, - schema.subscriptions.id - ), - eq(schema.subscriptionCategories.categoryId, input.categoryId) - ) - ); + countQuery = applyCategoryFilter(countQuery, input.categoryId); } // Apply same WHERE conditions - const conditions = buildArticlesWhereConditions(input); if (conditions.length > 0) { countQuery = countQuery.where(and(...conditions)); } @@ -336,77 +229,47 @@ export const articlesRouter = router({ // Execute count query and count unique article IDs const countResults = await withQueryMetrics( "articles.list.count", - async () => await countQuery, + async () => + await ctx.db.all<{ total: number }>( + sql`SELECT COUNT(DISTINCT id) AS total FROM (${countQuery})` + ), { "db.table": "articles", "db.operation": "count", } ); - // Count unique article IDs (needed because JOINs can create duplicates) - const uniqueArticleIds = new Set( - countResults.map((r) => r.articles.id) - ); - total = uniqueArticleIds.size; + total = countResults[0]?.total ?? 0; } else { // FILTERED PATH: Has subscription filters, must scan in bounded // database chunks and apply the cursor after in-memory filtering. // Aggressive filters can reject most rows, so a one-shot fetch limit // can falsely produce an empty later page even when matches exist. - const filteredOffset = cursor ?? offset; + const filteredOffset = cursor ? 0 : offset; const targetVisibleCount = filteredOffset + limit + 1; const chunkSize = Math.max(limit * 3, 100); const filteredResults: ArticleWithSubscription[] = []; let scannedRowCount = 0; + let scanCursor: ArticleCursor | undefined = cursor; // Always order by publishedAt for chronological feed const paginationQuery = queryBuilder.orderBy( - desc(schema.articles.publishedAt) + desc(schema.articles.publishedAt), + desc(schema.articles.id) ); - // Batch load all filters for the user's filtered subscriptions once. - const filtersBySubscription = new Map< - number, - (typeof schema.subscriptionFilters.$inferSelect)[] - >(); - const subscriptionIdsWithFilters = subscriptionsWithFilters.map( - (subscription) => subscription.id + const filtersBySubscription = await fetchSubscriptionFilters( + ctx.db, + subscriptionsWithFilters.map((subscription) => subscription.id) ); - if (subscriptionIdsWithFilters.length > 0) { - const filters = await withQueryMetrics( - "articles.list.loadFilters", - async () => - ctx.db - .select() - .from(schema.subscriptionFilters) - .where( - inArray( - schema.subscriptionFilters.subscriptionId, - subscriptionIdsWithFilters - ) - ), - { - "db.table": "subscription_filters", - "db.operation": "select", - "db.subscription_count": subscriptionIdsWithFilters.length, - } - ); - - // Group filters by subscription ID - filters.forEach((filter) => { - const existing = - filtersBySubscription.get(filter.subscriptionId) || []; - existing.push(filter); - filtersBySubscription.set(filter.subscriptionId, existing); - }); - } - while (filteredResults.length < targetVisibleCount) { - let chunkQuery = paginationQuery; - if (scannedRowCount > 0) { - chunkQuery = chunkQuery.offset(scannedRowCount); - } + const chunkQuery = paginationQuery.where( + and( + ...conditions, + scanCursor ? afterArticleCursor(scanCursor) : undefined + ) + ); const results = await withQueryMetrics( "articles.list.filteredChunk", @@ -449,6 +312,12 @@ export const articlesRouter = router({ filteredResults.push(...matchingResults); scannedRowCount += results.length; + const lastScanned = results.at(-1)?.articles; + if (lastScanned) + scanCursor = { + publishedAt: lastScanned.publishedAt, + id: lastScanned.id, + }; if (results.length < chunkSize) { break; @@ -472,10 +341,15 @@ export const articlesRouter = router({ total = filteredOffset + visibleResults.length; } + const lastArticle = paginatedResults.at(-1); return { items: paginatedResults, total, hasMore, + nextCursor: + hasMore && lastArticle + ? { publishedAt: lastArticle.publishedAt, id: lastArticle.id } + : null, }; }), @@ -779,45 +653,16 @@ export const articlesRouter = router({ return { updated: 0 }; } - // Get existing states to preserve 'saved' flags - // Batch the query to avoid exceeding D1's 100-parameter limit - // Note: WHERE clause has userId (1 param) + inArray (batch.length params) - // So chunk size must be D1_MAX_PARAMETERS - 1 to stay within limit - const existingStates: (typeof schema.userArticleStates.$inferSelect)[] = - []; - - const batches: number[][] = chunkArray( - input.articleIds, - D1_MAX_PARAMETERS - 1 - ); - - for (const batch of batches) { - const batchStates = await ctx.db - .select() - .from(schema.userArticleStates) - .where( - and( - eq(schema.userArticleStates.userId, userId), - inArray(schema.userArticleStates.articleId, batch) - ) - ); - existingStates.push(...batchStates); - } - - // Create a map for quick lookup - const stateMap = new Map( - existingStates.map((s) => [s.articleId, s.saved]) - ); - - // Batch operations: D1 supports batch(), better-sqlite3 requires sequential - const statements = input.articleIds.map((articleId) => + const articleIds = [...new Set(input.articleIds)]; + // Conflicts update only read; SQLite retains saved and audio fields. + const statements = articleIds.map((articleId) => ctx.db .insert(schema.userArticleStates) .values({ userId, articleId, read: input.read, - saved: stateMap.get(articleId) ?? false, + saved: false, }) .onConflictDoUpdate({ target: [ @@ -864,12 +709,11 @@ export const articlesRouter = router({ } ); - return { updated: input.articleIds.length }; + return { updated: articleIds.length }; }), /** * Mark all articles as read (optionally filter by age) - * Limited to 1000 articles per operation to prevent performance issues */ markAllRead: rateLimitedProcedure .input( @@ -881,124 +725,21 @@ export const articlesRouter = router({ .mutation(async ({ ctx, input }) => { const { userId } = ctx.user; - // Build query to get all article IDs from user's subscriptions - let queryBuilder = ctx.db - .select() - .from(schema.articles) - .innerJoin( - schema.subscriptions, - and( - eq(schema.articles.sourceId, schema.subscriptions.sourceId), - eq(schema.subscriptions.userId, userId) - ) - ) - .$dynamic(); - - // Filter by age if provided - if (input.olderThanDays) { - const cutoffDate = new Date(); - cutoffDate.setDate(cutoffDate.getDate() - input.olderThanDays); - queryBuilder = queryBuilder.where( - lt(schema.articles.publishedAt, cutoffDate) - ); - } - - // Limit to 1000 articles to prevent performance issues - const MAX_BULK_UPDATE = 1000; - const articles = await queryBuilder.limit(MAX_BULK_UPDATE); - const articleIds = articles.map((a) => a.articles.id); - - if (articleIds.length === 0) { - return { updated: 0 }; - } - - // Get existing states to preserve 'saved' flags - // Batch the query to avoid exceeding D1's 100-parameter limit - // Note: WHERE clause has userId (1 param) + inArray (batch.length params) - // So chunk size must be D1_MAX_PARAMETERS - 1 to stay within limit - const existingStates: (typeof schema.userArticleStates.$inferSelect)[] = - []; - - const batches: number[][] = chunkArray( - articleIds, - D1_MAX_PARAMETERS - 1 - ); - - for (const batch of batches) { - const batchStates = await ctx.db - .select() - .from(schema.userArticleStates) - .where( - and( - eq(schema.userArticleStates.userId, userId), - inArray(schema.userArticleStates.articleId, batch) - ) - ); - existingStates.push(...batchStates); - } - - // Create a map for quick lookup - const stateMap = new Map( - existingStates.map((s) => [s.articleId, s.saved]) - ); - - // Batch operations: D1 supports batch(), better-sqlite3 requires sequential - const statements = articleIds.map((articleId) => - ctx.db - .insert(schema.userArticleStates) - .values({ - userId, - articleId, - read: true, - saved: stateMap.get(articleId) ?? false, - }) - .onConflictDoUpdate({ - target: [ - schema.userArticleStates.userId, - schema.userArticleStates.articleId, - ], - set: { - read: true, - updatedAt: new Date(), - }, - }) - ); - - // Wrap batch execution in Sentry span for monitoring - await Sentry.startSpan( - { - op: "db.batch", - name: "Mark All Articles Read", - attributes: { - "db.batch_size": statements.length, - "db.operation": "mark_all_read", - "db.user_id": userId, - "filter.older_than_days": input.olderThanDays ?? "none", - }, - }, - async (span) => { - try { - await executeBatch(ctx.db, statements); - span.setStatus({ code: 1, message: "ok" }); - } catch (error) { - span.setStatus({ code: 2, message: "batch failed" }); - Sentry.captureException(error, { - tags: { - operation: "mark_all_read", - batch_size: statements.length.toString(), - }, - extra: { - userId, - articleCount: articleIds.length, - olderThanDays: input.olderThanDays, - }, - }); - throw error; - } - } - ); - - return { updated: articleIds.length }; + const cutoff = + input.olderThanDays !== undefined + ? sql`AND a.published_at < ${Math.floor((Date.now() - input.olderThanDays * 86_400_000) / 1000)}` + : sql``; + const result = await ctx.db.all<{ articleId: number }>(sql` + INSERT INTO user_article_states (user_id, article_id, read, updated_at) + SELECT DISTINCT ${userId}, a.id, 1, ${Math.floor(Date.now() / 1000)} + FROM articles a JOIN subscriptions s ON s.source_id = a.source_id + WHERE s.user_id = ${userId} ${cutoff} + AND NOT EXISTS (SELECT 1 FROM user_article_states state + WHERE state.user_id = ${userId} AND state.article_id = a.id AND state.read = 1) + ON CONFLICT (user_id, article_id) DO UPDATE SET read = 1, updated_at = excluded.updated_at + RETURNING article_id AS articleId + `); + return { updated: result.length }; }), /** @@ -1018,62 +759,80 @@ export const articlesRouter = router({ .query(async ({ ctx, input }) => { const userId = ctx.user.userId; - // Helper to execute count query efficiently - const executeCount = async (additionalFilters?: { - read?: boolean; - saved?: boolean; - }) => { - // Use buildArticlesBaseQuery - same JOINs as main query - let baseQuery = buildArticlesBaseQuery(ctx.db, userId); - - // Apply category filter if provided - if (input.categoryId) { - baseQuery = applyCategoryFilter(baseQuery, input.categoryId); - } - - // Build WHERE conditions - const conditions = buildArticlesWhereConditions({ - subscriptionId: input.subscriptionId, - ...additionalFilters, - }); - - if (conditions.length > 0) { - baseQuery = baseQuery.where(and(...conditions)); - } - - // Execute and count unique article IDs - const results = await baseQuery; - return new Set(results.map((r) => r.articles.id)).size; - }; + const subscriptionsWithFilters = await ctx.db + .select() + .from(schema.subscriptions) + .where( + and( + eq(schema.subscriptions.userId, userId), + eq(schema.subscriptions.filterEnabled, true), + input.subscriptionId === undefined + ? undefined + : eq(schema.subscriptions.id, input.subscriptionId) + ) + ); - // Execute all counts in parallel - const [allCount, unreadCount, readCount, savedCount] = await Promise.all([ - withQueryMetrics("articles.counts.all", () => executeCount(), { - "db.operation": "count", - "db.user_id": userId, - }), - withQueryMetrics( - "articles.counts.unread", - () => executeCount({ read: false }), - { "db.operation": "count", "db.user_id": userId } - ), - withQueryMetrics( - "articles.counts.read", - () => executeCount({ read: true }), - { "db.operation": "count", "db.user_id": userId } - ), - withQueryMetrics( - "articles.counts.saved", - () => executeCount({ saved: true }), + let query = buildArticlesBaseQuery(ctx.db, userId); + if (input.categoryId) + query = applyCategoryFilter(query, input.categoryId); + const conditions = buildArticlesWhereConditions(input); + if (conditions.length > 0) query = query.where(and(...conditions)); + + if (subscriptionsWithFilters.length === 0) { + // Aggregate inside SQLite/D1 rather than transferring article bodies. + const [counts] = await withQueryMetrics( + "articles.counts", + async () => + ctx.db.all<{ + all: number; + unread: number; + read: number; + saved: number; + }>(sql` + SELECT COUNT(DISTINCT id) AS "all", + COUNT(DISTINCT CASE WHEN COALESCE(read, 0) = 0 THEN id END) AS unread, + COUNT(DISTINCT CASE WHEN read = 1 THEN id END) AS read, + COUNT(DISTINCT CASE WHEN saved = 1 THEN id END) AS saved + FROM (${query}) + `), { "db.operation": "count", "db.user_id": userId } - ), - ]); + ); + return counts ?? { all: 0, unread: 0, read: 0, saved: 0 }; + } - return { - all: allCount, - unread: unreadCount, - read: readCount, - saved: savedCount, - }; + // Regex/content filters must use the same matcher as the article list. + // Scan once in bounded chunks instead of loading the feed four times. + const filters = await fetchSubscriptionFilters( + ctx.db, + subscriptionsWithFilters.map(({ id }) => id) + ); + const counts = { all: 0, unread: 0, read: 0, saved: 0 }; + const seen = new Set(); + const chunkSize = 200; + for (let offset = 0; ; offset += chunkSize) { + const rows = await query + .orderBy(desc(schema.articles.id)) + .limit(chunkSize) + .offset(offset); + for (const row of rows) { + if (seen.has(row.articles.id)) continue; + if ( + row.subscriptions.filterEnabled && + !matchesSubscriptionFilters( + row.articles, + filters.get(row.subscriptions.id) ?? [], + row.subscriptions.filterMode + ) + ) + continue; + seen.add(row.articles.id); + counts.all++; + if (row.user_article_states?.read) counts.read++; + else counts.unread++; + if (row.user_article_states?.saved) counts.saved++; + } + if (rows.length < chunkSize) break; + } + return counts; }), }); diff --git a/packages/api/src/routers/auth.ts b/packages/api/src/routers/auth.ts index b6be4755..db4e0db6 100644 --- a/packages/api/src/routers/auth.ts +++ b/packages/api/src/routers/auth.ts @@ -1,3 +1,4 @@ +import type { Context } from "@api/trpc/context"; /** * Auth Router * @@ -15,35 +16,39 @@ import { publicProcedure, protectedProcedure, protectedProcedureWithoutVerification, -} from "@/trpc/init"; -import { createAuth } from "@/auth/better-auth"; +} from "@api/trpc/init"; +import { createAuth } from "@api/auth/better-auth"; import { fromNodeHeaders } from "better-auth/node"; -import { hasAdminUser } from "@/services/admin-init"; -import { getGlobalSettings } from "@/services/global-settings"; -import { initializeNewUser } from "@/services/user-init"; -import * as schema from "@/db/schema"; +import { getGlobalSettings } from "@api/services/global-settings"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; -import { DEFAULT_USER_PLAN, ADMIN_PLAN } from "@/config/plans"; +import { DEFAULT_USER_PLAN } from "@api/config/plans"; import { usernameValidator, emailValidator, passwordValidator, -} from "@/types/validators"; -import { getBaseUrl } from "@/utils/base-url"; -import * as Sentry from "@/utils/sentry"; -import { emitCounter, emitMetrics } from "@/utils/metrics"; +} from "@api/types/validators"; +import { getBaseUrl } from "@api/utils/base-url"; +import * as Sentry from "@api/utils/sentry"; +import { emitCounter, emitMetrics } from "@api/utils/metrics"; import { logSecurityEvent, getClientIp, getUserAgent, getRequestMetadata, -} from "@/auth/security"; +} from "@api/auth/security"; import type { BetterAuthUser, - SignUpEmailResult, SignInUsernameResult, SignInEmailResult, -} from "@/types/better-auth"; +} from "@api/types/better-auth"; + +function forwardAuthCookies(ctx: Context, headers: Headers): void { + // Split only at a new cookie name, preserving commas inside Expires dates. + const cookies = headers.get("set-cookie")?.split(/,(?=\s*[^;,\s]+=)/) ?? []; + for (const cookie of cookies) + ctx.responseHeaders?.append("set-cookie", cookie.trim()); +} export const authRouter = router({ /** @@ -130,7 +135,8 @@ export const authRouter = router({ }, async (span) => { try { - const result: SignUpEmailResult = await auth.api.signUpEmail({ + const authResult = await auth.api.signUpEmail({ + returnHeaders: true, body: { email: input.email, password: input.password, @@ -140,6 +146,8 @@ export const authRouter = router({ headers: authHeaders, }); + forwardAuthCookies(ctx, authResult.headers); + const result = authResult.response; span?.setAttributes({ "auth.user_created": !!result.user, }); @@ -212,190 +220,11 @@ export const authRouter = router({ }); } - // Ensure username is set (fallback for Better Auth compatibility) - // The username plugin should set this automatically, but ensure it's populated - if (!dbUser.username) { - await ctx.db - .update(schema.user) - .set({ username: input.username }) - .where(eq(schema.user.id, userId)); - } - - // STEP 2: Determine Role and Plan - const roleData = await Sentry.startSpan( - { - name: "auth.signup.determine_role", - op: "db.query", - }, - async (span) => { - let role: "user" | "admin" = - (dbUser.role as "user" | "admin") || "user"; - let plan: string = dbUser.plan || DEFAULT_USER_PLAN; - - const allowFirstUserAdmin = - ctx.env.ALLOW_FIRST_USER_ADMIN !== "false"; - if (allowFirstUserAdmin) { - const hasAdmin = await hasAdminUser(ctx.db); - if (!hasAdmin) { - role = "admin"; - plan = ADMIN_PLAN; - isFirstUser = true; - - // Emit metric for first user admin assignment - emitCounter("signup.first_user_admin", 1, { - user_id: userId!.toString(), - }); - - Sentry.addBreadcrumb({ - category: "auth", - message: "First user assigned admin role", - level: "info", - data: { - user_id: userId!, - }, - }); - } - } - - span?.setAttributes({ - "auth.is_first_user": isFirstUser, - "auth.role_assigned": role, - "auth.plan": plan, - }); - - return { role, plan }; - } - ); - - // STEP 3: Atomic User Initialization (role + settings + usage stats) - // Uses D1 batch for atomic operations - all succeed or all fail - await Sentry.startSpan( - { - name: "auth.signup.init_user", - op: "db.batch", - }, - async (span) => { - try { - await initializeNewUser(ctx.db, userId!, { - role: roleData.role, - plan: roleData.plan, - }); - - span?.setAttributes({ - "auth.user_initialized": true, - "auth.role": roleData.role, - "auth.plan": roleData.plan, - }); - - // Emit funnel progress: user initialized - emitCounter("signup.funnel", 1, { - stage: "initialized", - user_id: userId!.toString(), - }); - - emitCounter("signup.user_initialized", 1, { - role: roleData.role, - plan: roleData.plan, - is_first_user: isFirstUser ? "true" : "false", - }); - } catch (initError) { - const initErrorMessage = - initError instanceof Error - ? initError.message - : String(initError); - const initErrorType = - initError instanceof Error - ? initError.name - : "UnknownError"; - - // Capture error with full context for debugging - span?.setAttributes({ - "auth.init_error": true, - "auth.error_message": initErrorMessage, - }); - - // Emit initialization failure metric - emitCounter("signup.init_failed", 1, { - error_type: initErrorType, - user_id: userId!.toString(), - }); - - console.error( - "User initialization failed, rolling back user creation:", - initError - ); - - Sentry.captureException(initError, { - tags: { - flow: "signup", - step: "init_rollback", - }, - extra: { - userId: userId!, - email: input.email, - role: roleData.role, - plan: roleData.plan, - }, - }); - - // Rollback: Delete the incomplete user - // Emit metrics AFTER successful deletion to ensure accuracy - try { - await ctx.db - .delete(schema.user) - .where(eq(schema.user.id, userId!)); - - // Rollback successful - emit success metrics - emitCounter("signup.rollback_executed", 1, { - reason: "init_failed", - user_id: userId!.toString(), - }); - - emitCounter("signup.user_deleted", 1, { - reason: "rollback", - user_id: userId!.toString(), - }); - } catch (rollbackError) { - // Rollback failed - emit failure metric for observability - // This indicates orphaned user data that may need manual cleanup - emitCounter("signup.rollback_failed", 1, { - reason: "delete_failed", - user_id: userId!.toString(), - error_type: - rollbackError instanceof Error - ? rollbackError.name - : "UnknownError", - }); - - Sentry.captureException(rollbackError, { - level: "error", - tags: { - flow: "signup", - step: "rollback_delete", - severity: "critical", - }, - extra: { - userId: userId!, - email: input.email, - originalError: initErrorMessage, - }, - }); - - console.error( - "CRITICAL: Failed to rollback user creation - orphaned user data:", - rollbackError - ); - } - - throw new TRPCError({ - code: "INTERNAL_SERVER_ERROR", - message: - "Failed to complete registration. Please try again.", - cause: initError, - }); - } - } - ); + const roleData = { + role: dbUser.role ?? "user", + plan: dbUser.plan ?? DEFAULT_USER_PLAN, + }; + isFirstUser = roleData.role === "admin"; // STEP 4: Security Audit Logging await Sentry.startSpan( @@ -608,22 +437,28 @@ export const authRouter = router({ if (isEmail) { // Use email signin - result = await auth.api.signInEmail({ + const authResult = await auth.api.signInEmail({ + returnHeaders: true, body: { email: input.username, password: input.password, }, headers: authHeaders, }); + forwardAuthCookies(ctx, authResult.headers); + result = authResult.response; } else { // Use username signin - result = await auth.api.signInUsername({ + const authResult = await auth.api.signInUsername({ + returnHeaders: true, body: { username: input.username, password: input.password, }, headers: authHeaders, }); + forwardAuthCookies(ctx, authResult.headers); + result = authResult.response; } // Update span attribute to show detected method @@ -860,9 +695,11 @@ export const authRouter = router({ try { // Call Better Auth signOut API - await auth.api.signOut({ + const result = await auth.api.signOut({ headers: authHeaders, + returnHeaders: true, }); + forwardAuthCookies(ctx, result.headers); // Log successful logout to security audit (best effort) if (userId) { @@ -1022,7 +859,7 @@ export const authRouter = router({ }) ) .mutation(async ({ ctx }) => { - const { checkRateLimit } = await import("@/services/rate-limiter"); + const { checkRateLimit } = await import("@api/services/rate-limiter"); // Check if email verification is required const settings = await getGlobalSettings(ctx.db); diff --git a/packages/api/src/routers/categories.ts b/packages/api/src/routers/categories.ts index 30b862d9..521d8118 100644 --- a/packages/api/src/routers/categories.ts +++ b/packages/api/src/routers/categories.ts @@ -7,18 +7,18 @@ import { z } from "zod"; import { TRPCError } from "@trpc/server"; import { eq, and, sql } from "drizzle-orm"; -import { router, rateLimitedProcedure } from "@/trpc/init"; -import { hexColorValidator } from "@/types"; -import { selectCategorySchema } from "@/db/schemas.zod"; -import * as schema from "@/db/schema"; -import { generateColorFromString } from "@/utils/color-generator"; -import { requireOwnership, categoryNameExists } from "@/db/helpers"; +import { router, rateLimitedProcedure } from "@api/trpc/init"; +import { hexColorValidator } from "@api/types"; +import { selectCategorySchema } from "@api/db/schemas.zod"; +import * as schema from "@api/db/schema"; +import { generateColorFromString } from "@api/utils/color-generator"; +import { requireOwnership, categoryNameExists } from "@api/db/helpers"; import { checkCategoryLimit, incrementCategoryCount, decrementCategoryCount, -} from "@/services/limits"; -import { withUndefinedAsEmpty } from "@/types/pagination"; +} from "@api/services/limits"; +import { withUndefinedAsEmpty } from "@api/types/pagination"; export const categoriesRouter = router({ /** diff --git a/packages/api/src/routers/feeds.ts b/packages/api/src/routers/feeds.ts index 0da800a9..01b4f289 100644 --- a/packages/api/src/routers/feeds.ts +++ b/packages/api/src/routers/feeds.ts @@ -1,3 +1,6 @@ +import { chunkArray, D1_MAX_PARAMETERS } from "@api/db/utils"; +import type { Database } from "@api/db/client"; +import { generatePublicFeed } from "@api/services/public-feed"; /** * Feeds Router * @@ -6,26 +9,53 @@ import { z } from "zod"; import { TRPCError } from "@trpc/server"; -import { eq, and, inArray, desc, sql } from "drizzle-orm"; -import { router, publicProcedure, rateLimitedProcedure } from "@/trpc/init"; -import { slugValidator } from "@/types"; -import { selectFeedSchema } from "@/db/schemas.zod"; +import { eq, and, inArray } from "drizzle-orm"; +import { router, publicProcedure, rateLimitedProcedure } from "@api/trpc/init"; +import { slugValidator } from "@api/types"; +import { selectFeedSchema } from "@api/db/schemas.zod"; import { checkPublicFeedLimit, incrementPublicFeedCount, decrementPublicFeedCount, -} from "@/services/limits"; +} from "@api/services/limits"; import { createPaginatedSchema, paginationInputSchema, createPaginatedResponse, -} from "@/types/pagination"; -import * as schema from "@/db/schema"; -import { requireOwnership, slugExists, updateManyToMany } from "@/db/helpers"; -import { fetchFeedCategories } from "@/db/transformers"; -import { generateRSS } from "@/services/xml-generator"; -import { emitCounter, withTiming } from "@/utils/metrics"; -import { withQueryMetrics } from "@/utils/db-metrics"; +} from "@api/types/pagination"; +import * as schema from "@api/db/schema"; +import { + requireOwnership, + slugExists, + updateManyToMany, +} from "@api/db/helpers"; +import { fetchFeedCategories } from "@api/db/transformers"; + +async function validateCategoryOwnership( + db: Database, + userId: number, + categoryIds: number[] +): Promise { + for (const ids of chunkArray( + [...new Set(categoryIds)], + D1_MAX_PARAMETERS - 1 + )) { + const categories = await db + .select() + .from(schema.categories) + .where( + and( + eq(schema.categories.userId, userId), + inArray(schema.categories.id, ids) + ) + ); + if (categories.length !== ids.length) + throw new TRPCError({ + code: "NOT_FOUND", + message: "Category not found or not accessible", + }); + } +} // Feed list response schema (includes extra fields not in database) const feedListItemSchema = z.object({ @@ -198,13 +228,18 @@ export const feedsRouter = router({ slug: slugValidator, description: z.string().optional(), public: z.boolean().default(true), - categoryIds: z.array(z.number()).optional(), + categoryIds: z + .array(z.number().int().positive()) + .transform((ids) => [...new Set(ids)]) + .optional(), }) ) .output(selectFeedSchema) .mutation(async ({ ctx, input }) => { const { userId } = ctx.user; + await validateCategoryOwnership(ctx.db, userId, input.categoryIds ?? []); + // Check if slug already exists for this user const exists = await slugExists(ctx.db, schema.feeds, userId, input.slug); @@ -286,13 +321,18 @@ export const feedsRouter = router({ slug: slugValidator.optional(), description: z.string().optional(), public: z.boolean().optional(), - categoryIds: z.array(z.number()).optional(), + categoryIds: z + .array(z.number().int().positive()) + .transform((ids) => [...new Set(ids)]) + .optional(), }) ) .output(selectFeedSchema) .mutation(async ({ ctx, input }) => { const { userId } = ctx.user; + await validateCategoryOwnership(ctx.db, userId, input.categoryIds ?? []); + // Verify feed exists and belongs to user const existingFeed = await requireOwnership< typeof schema.feeds.$inferSelect @@ -443,282 +483,5 @@ export const feedsRouter = router({ }) ) .output(z.string()) // RSS 2.0 XML - .query(async ({ ctx, input }) => { - return await withTiming( - "public_feed.generation_duration", - async () => { - // Step 1: Find user by username - const users = await withQueryMetrics( - "public_feed.getUser", - async () => - ctx.db - .select() - .from(schema.user) - .where( - sql`COALESCE(${schema.user.username}, ${schema.user.name}) = ${input.username}` - ) - .limit(1), - { - "db.table": "user", - "db.operation": "select", - "db.username": input.username, - } - ); - - if (!users.length) { - emitCounter("public_feed.generated", 1, { - status: "user_not_found", - username: input.username, - }); - throw new TRPCError({ - code: "NOT_FOUND", - message: "User not found", - }); - } - - const user = users[0]; - - if (!user) { - throw new TRPCError({ - code: "NOT_FOUND", - message: "User not found", - }); - } - - // Step 2: Find feed by user ID and slug - const feeds = await withQueryMetrics( - "public_feed.getFeed", - async () => - ctx.db - .select() - .from(schema.feeds) - .where( - and( - eq(schema.feeds.userId, user.id), - eq(schema.feeds.slug, input.slug) - ) - ) - .limit(1), - { - "db.table": "feeds", - "db.operation": "select", - "db.user_id": user.id, - "db.slug": input.slug, - } - ); - - if (!feeds.length) { - emitCounter("public_feed.generated", 1, { - status: "feed_not_found", - username: input.username, - slug: input.slug, - }); - throw new TRPCError({ - code: "NOT_FOUND", - message: "Feed not found", - }); - } - - const feed = feeds[0]!; - - // Step 3: Verify feed is public - if (!feed.public) { - emitCounter("public_feed.generated", 1, { - status: "feed_private", - username: input.username, - slug: input.slug, - }); - throw new TRPCError({ - code: "NOT_FOUND", - message: "Feed not found", - }); - } - - // Step 4: Get category IDs for this feed - const categoryLinks = await withQueryMetrics( - "public_feed.getCategories", - async () => - ctx.db - .select() - .from(schema.feedCategories) - .where(eq(schema.feedCategories.feedId, feed.id)), - { - "db.table": "feedCategories", - "db.operation": "select", - "db.feed_id": feed.id, - } - ); - - const categoryIds = categoryLinks.map((link) => link.categoryId); - - // Step 5: Get articles from these categories - let articles: Array<{ - title: string; - link: string | null; - description: string | null; - author: string | null; - publishedAt: Date | null; - guid: string; - }> = []; - - if (categoryIds.length > 0) { - // Get subscription IDs that match these categories - const subscriptionLinks = await withQueryMetrics( - "public_feed.getSubscriptionLinks", - async () => - ctx.db - .select() - .from(schema.subscriptionCategories) - .where( - inArray( - schema.subscriptionCategories.categoryId, - categoryIds - ) - ), - { - "db.table": "subscriptionCategories", - "db.operation": "select", - "db.category_count": categoryIds.length, - } - ); - - const subscriptionIds = subscriptionLinks.map( - (link) => link.subscriptionId - ); - - if (subscriptionIds.length > 0) { - // Get subscriptions for this user - const subscriptions = await withQueryMetrics( - "public_feed.getSubscriptions", - async () => - ctx.db - .select() - .from(schema.subscriptions) - .where( - and( - eq(schema.subscriptions.userId, user.id), - inArray(schema.subscriptions.id, subscriptionIds) - ) - ), - { - "db.table": "subscriptions", - "db.operation": "select", - "db.user_id": user.id, - "db.subscription_count": subscriptionIds.length, - } - ); - - const sourceIds = subscriptions.map((sub) => sub.sourceId); - - if (sourceIds.length > 0) { - // Get articles from these sources - const articlesResult = await withQueryMetrics( - "public_feed.getArticles", - async () => - ctx.db - .select() - .from(schema.articles) - .where(inArray(schema.articles.sourceId, sourceIds)) - .orderBy(desc(schema.articles.publishedAt)) - .limit(50), - { - "db.table": "articles", - "db.operation": "select", - "db.source_count": sourceIds.length, - "db.has_category_filter": true, - } - ); - - articles = articlesResult.map((article) => ({ - title: article.title, - link: article.link, - description: article.description, - author: article.author, - publishedAt: article.publishedAt, - guid: article.guid, - })); - } - } - } else { - // No category filter - get all articles from user's subscriptions - const subscriptions = await withQueryMetrics( - "public_feed.getSubscriptions", - async () => - ctx.db - .select() - .from(schema.subscriptions) - .where(eq(schema.subscriptions.userId, user.id)), - { - "db.table": "subscriptions", - "db.operation": "select", - "db.user_id": user.id, - } - ); - - const sourceIds = subscriptions.map((sub) => sub.sourceId); - - if (sourceIds.length > 0) { - const articlesResult = await withQueryMetrics( - "public_feed.getArticles", - async () => - ctx.db - .select() - .from(schema.articles) - .where(inArray(schema.articles.sourceId, sourceIds)) - .orderBy(desc(schema.articles.publishedAt)) - .limit(50), - { - "db.table": "articles", - "db.operation": "select", - "db.source_count": sourceIds.length, - "db.has_category_filter": false, - } - ); - - articles = articlesResult.map((article) => ({ - title: article.title, - link: article.link, - description: article.description, - author: article.author, - publishedAt: article.publishedAt, - guid: article.guid, - })); - } - } - - // Step 6: Generate RSS 2.0 XML - const feedUrl = `${ctx.env.BASE_URL || "http://localhost:3000"}/public/${input.username}/${input.slug}`; - - const xml = generateRSS({ - title: feed.title, - link: feedUrl, - description: feed.description || feed.title, - items: articles.map((article) => ({ - title: article.title, - link: article.link || feedUrl, - description: article.description, - author: article.author, - pubDate: article.publishedAt, - guid: article.guid, - })), - }); - - // Emit success metric - emitCounter("public_feed.generated", 1, { - status: "success", - username: input.username, - slug: input.slug, - article_count: articles.length.toString(), - category_count: categoryIds.length.toString(), - }); - - return xml; - }, - { - operation: "public_feed_generation", - username: input.username, - slug: input.slug, - } - ); - }), + .query(({ ctx, input }) => generatePublicFeed(ctx, input)), }); diff --git a/packages/api/src/routers/plans.ts b/packages/api/src/routers/plans.ts index 4d0fb2f1..6011867f 100644 --- a/packages/api/src/routers/plans.ts +++ b/packages/api/src/routers/plans.ts @@ -8,10 +8,10 @@ import { z } from "zod"; import { TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; -import { router, publicProcedure, adminProcedure } from "@/trpc/init"; -import { getAllPlans, getPlanById } from "@/services/plans"; -import * as schema from "@/db/schema"; -import { withUndefinedAsEmpty } from "@/types/pagination"; +import { router, publicProcedure, adminProcedure } from "@api/trpc/init"; +import { getAllPlans, getPlanById } from "@api/services/plans"; +import * as schema from "@api/db/schema"; +import { withUndefinedAsEmpty } from "@api/types/pagination"; export const plansRouter = router({ /** diff --git a/packages/api/src/routers/subscriptions.ts b/packages/api/src/routers/subscriptions.ts index 29079023..1fdf0f90 100644 --- a/packages/api/src/routers/subscriptions.ts +++ b/packages/api/src/routers/subscriptions.ts @@ -1,10 +1,12 @@ +import { readFeedResponse } from "@tuvixrss/tricorder"; +import { safeFetch } from "@api/utils/safe-fetch"; /** * Subscriptions Router * * Handles RSS feed subscriptions, OPML import/export, filters, and discovery. */ -import * as Sentry from "@/utils/sentry"; +import * as Sentry from "@api/utils/sentry"; // Retry configuration for transient HTTP failures const MAX_RETRIES = 2; @@ -13,58 +15,63 @@ const TRANSIENT_STATUS_CODES = [502, 503, 504, 429]; import { z } from "zod"; import { TRPCError } from "@trpc/server"; import { eq, and } from "drizzle-orm"; -import { router, rateLimitedProcedure } from "@/trpc/init"; -import { withQueryMetrics } from "@/utils/db-metrics"; -import type { Opml } from "@/types/feed"; +import { router, rateLimitedProcedure } from "@api/trpc/init"; +import { withQueryMetrics } from "@api/utils/db-metrics"; +import type { Opml, ParsedFeed } from "@api/types/feed"; import { urlValidator, customTitleValidator, categoryNamesArrayValidator, idArrayValidator, STRING_LIMITS, -} from "@/types/validators"; +} from "@api/types/validators"; import { extractDomain, isDomainBlocked, getBlockedDomainReason, getBlockedDomains, -} from "@/utils/domain-checker"; +} from "@api/utils/domain-checker"; import { checkSourceLimit, incrementSourceCount, decrementSourceCount, recalculateUsage, -} from "@/services/limits"; -import { CategorySuggestionSchema, ImportJobSchema } from "@/types"; +} from "@api/services/limits"; +import { CategorySuggestionSchema, ImportJobSchema } from "@api/types"; import { subscriptionResponseSchema, selectSubscriptionFilterSchema, -} from "@/db/schemas.zod"; +} from "@api/db/schemas.zod"; import { createPaginatedSchema, paginationInputSchema, createPaginatedResponse, withUndefinedAsEmpty, -} from "@/types/pagination"; -import * as schema from "@/db/schema"; -import { generateColorFromString } from "@/utils/color-generator"; -import { requireOwnership, findOrCreateCategory } from "@/db/helpers"; +} from "@api/types/pagination"; +import * as schema from "@api/db/schema"; +import { generateColorFromString } from "@api/utils/color-generator"; +import { requireOwnership, findOrCreateCategory } from "@api/db/helpers"; import { transformSubscriptionFilter, fetchSubscriptionCategories, fetchSubscriptionFilters, buildSubscriptionResponse, -} from "@/db/transformers"; -import { fetchAndDiscoverCategories } from "@/services/category-discovery"; -import { stripHtml } from "@/utils/text-sanitizer"; -import { discoverFavicon } from "@/services/favicon-fetcher"; +} from "@api/db/transformers"; +import { fetchAndDiscoverCategories } from "@api/services/category-discovery"; +import { discoverFavicon } from "@api/services/favicon-fetcher"; import { parseFiltersJson, parseCategoriesJson, parseBoolean, type FilterData, -} from "@/utils/opml-parser"; -import { extractItunesImage } from "@/utils/feed-utils"; +} from "@api/utils/opml-parser"; +import { + extractItunesImage, + extractFeedItems, + extractCategoryNames, + countFeedCategories, +} from "@api/utils/feed-utils"; +import { extractFeedMetadata, feedText } from "@tuvixrss/tricorder"; /** * Normalize Reddit feed URLs to use old.reddit.com for consistency. @@ -79,7 +86,8 @@ function normalizeRedditUrl(url: string): string { const parsedUrl = new URL(url); // Check if this is a Reddit domain with an RSS feed if ( - parsedUrl.hostname.includes("reddit.com") && + (parsedUrl.hostname === "reddit.com" || + parsedUrl.hostname.endsWith(".reddit.com")) && parsedUrl.pathname.endsWith(".rss") ) { // Normalize to old.reddit.com (matches RedditDiscoveryService) @@ -114,6 +122,7 @@ export const subscriptionsRouter = router({ eq(schema.subscriptions.sourceId, schema.sources.id) ) .where(eq(schema.subscriptions.userId, userId)) + .orderBy(schema.subscriptions.id) .limit(input.limit + 1) .offset(input.offset), { @@ -305,7 +314,7 @@ export const subscriptionsRouter = router({ const { parseFeed } = await import("feedsmith"); let feedUrl = input.url; - let feedData; + let feedData: ParsedFeed | undefined; let feedContent: string | undefined; let lastError: Error | undefined; let lastStatusCode: number | undefined; @@ -334,7 +343,7 @@ export const subscriptionsRouter = router({ }); } - const response = await fetch(feedUrl, { + const response = await safeFetch(feedUrl, { headers: { "User-Agent": "TuvixRSS/1.0", Accept: @@ -360,7 +369,7 @@ export const subscriptionsRouter = router({ throw new Error(errorMessage); } - feedContent = await response.text(); + feedContent = await readFeedResponse(response); // Parse feed - parsing errors should NOT be retried try { @@ -489,24 +498,11 @@ export const subscriptionsRouter = router({ } // Step 3: Extract metadata from feed - const feedTitle = - "title" in feedData && feedData.title - ? feedData.title - : "Untitled Feed"; - const feedDescription = - "description" in feedData && feedData.description - ? stripHtml(feedData.description) - : "subtitle" in feedData && feedData.subtitle - ? stripHtml(feedData.subtitle) - : undefined; - const siteUrl = - "link" in feedData && feedData.link - ? feedData.link - : "links" in feedData && - Array.isArray(feedData.links) && - feedData.links[0]?.href - ? feedData.links[0].href - : undefined; + const { + title: feedTitle = "Untitled Feed", + description: feedDescription, + siteUrl, + } = extractFeedMetadata(feedData); // Step 3.5: Extract icon URL from feed let feedIconUrl: string | undefined; @@ -514,7 +510,8 @@ export const subscriptionsRouter = router({ // First, try platform-specific discovery for the original input URL // This handles Apple Podcasts, Reddit, etc. with high-quality icons if (!input.iconUrl && (!input.iconType || input.iconType === "auto")) { - const { discoverFeeds } = await import("@/services/feed-discovery"); + const { discoverFeeds } = + await import("@api/services/feed-discovery"); try { const discoveredFeeds = await discoverFeeds(input.url); // Use iconUrl from discovery if available (platform-specific high-quality icons) @@ -598,7 +595,6 @@ export const subscriptionsRouter = router({ ...((!input.iconType || input.iconType === "auto") && feedIconUrl ? { iconUrl: input.iconUrl || feedIconUrl } : {}), - lastFetched: new Date(), }) .where(eq(schema.sources.id, sourceId)); } else { @@ -612,7 +608,6 @@ export const subscriptionsRouter = router({ siteUrl, iconUrl: input.iconUrl || feedIconUrl || null, iconType: input.iconType || "auto", - lastFetched: new Date(), }) .returning(); @@ -683,7 +678,7 @@ export const subscriptionsRouter = router({ // Step 7.5: Immediately fetch articles for the new subscription // This provides instant feedback to the user instead of waiting for batch processing try { - const { fetchSingleFeed } = await import("@/services/rss-fetcher"); + const { fetchSingleFeed } = await import("@api/services/rss-fetcher"); await fetchSingleFeed(sourceId, normalizedFeedUrl, ctx.db); Sentry.addBreadcrumb({ @@ -975,13 +970,14 @@ export const subscriptionsRouter = router({ FeedDiscoveryError, } = await import("@tuvixrss/tricorder"); const { sentryTelemetryAdapter } = - await import("@/adapters/sentry-telemetry"); + await import("@api/adapters/sentry-telemetry"); // Use the extensible discovery system with Sentry telemetry let discoveredFeeds; try { discoveredFeeds = await discoverFeeds(input.url, { telemetry: sentryTelemetryAdapter, + fetch: safeFetch, }); } catch (error) { // Convert tricorder errors to TRPC errors @@ -1061,7 +1057,7 @@ export const subscriptionsRouter = router({ }); // Step 1: Fetch and parse the feed - let feedData; + let feedData: ParsedFeed | undefined; let feedUrl = input.url; let feedContent: string | undefined; let lastError: Error | undefined; @@ -1085,7 +1081,7 @@ export const subscriptionsRouter = router({ }); } - const response = await fetch(feedUrl, { + const response = await safeFetch(feedUrl, { headers: { "User-Agent": "TuvixRSS/1.0", Accept: @@ -1111,7 +1107,7 @@ export const subscriptionsRouter = router({ throw new Error(errorMessage); } - feedContent = await response.text(); + feedContent = await readFeedResponse(response); // Parse feed - parsing errors should NOT be retried try { @@ -1238,31 +1234,17 @@ export const subscriptionsRouter = router({ }); } - // Step 2: Extract metadata - const title = - "title" in feedData && feedData.title - ? feedData.title - : "Untitled Feed"; - const description = - "description" in feedData && feedData.description - ? stripHtml(feedData.description) - : "subtitle" in feedData && feedData.subtitle - ? stripHtml(feedData.subtitle) - : undefined; - const siteUrl = - "link" in feedData && feedData.link - ? feedData.link - : "links" in feedData && - Array.isArray(feedData.links) && - feedData.links[0]?.href - ? feedData.links[0].href - : undefined; + const { + title = "Untitled Feed", + description, + siteUrl, + } = extractFeedMetadata(feedData); // Step 3: Try to get favicon URL let iconUrl: string | undefined; try { // First, try platform-specific discovery (Apple Podcasts, Reddit, etc.) - const { discoverFeeds } = await import("@/services/feed-discovery"); + const { discoverFeeds } = await import("@api/services/feed-discovery"); try { const discoveredFeeds = await discoverFeeds(input.url); // Use iconUrl from discovery if available (platform-specific high-quality icons) @@ -1339,46 +1321,7 @@ export const subscriptionsRouter = router({ count: number; color: string; }[] = []; - const categoryMap = new Map(); - - // Helper to extract category name from various formats - const extractCategoryName = (cat: unknown): string | null => { - if (typeof cat === "string") return cat; - if (typeof cat === "object" && cat !== null) { - const obj = cat as Record; - return ( - (obj.term as string) || - (obj.label as string) || - (obj.name as string) || - null - ); - } - return null; - }; - - // Extract categories from feed metadata - if ("categories" in feedData && Array.isArray(feedData.categories)) { - for (const cat of feedData.categories) { - const catName = extractCategoryName(cat); - if (catName) { - categoryMap.set(catName, (categoryMap.get(catName) || 0) + 1); - } - } - } - - // Extract categories from first few entries - if ("entries" in feedData && Array.isArray(feedData.entries)) { - for (const entry of feedData.entries.slice(0, 10)) { - if (entry.categories && Array.isArray(entry.categories)) { - for (const cat of entry.categories) { - const catName = extractCategoryName(cat); - if (catName) { - categoryMap.set(catName, (categoryMap.get(catName) || 0) + 1); - } - } - } - } - } + const categoryMap = countFeedCategories(feedData); // Convert to array and sort by count for (const [name, count] of categoryMap.entries()) { @@ -1390,6 +1333,7 @@ export const subscriptionsRouter = router({ } suggestedCategories.sort((a, b) => b.count - a.count); + const previewItems = extractFeedItems(feedData).slice(0, 10); return { title, @@ -1400,11 +1344,12 @@ export const subscriptionsRouter = router({ aiSuggestions: await Sentry.startSpan( { name: "ai.getSuggestions", op: "ai.categorize" }, async () => { - const { checkAiFeatureAccess } = await import("@/services/limits"); + const { checkAiFeatureAccess } = + await import("@api/services/limits"); const { suggestCategories } = - await import("@/services/ai-category-suggester"); + await import("@api/services/ai-category-suggester"); - const env = ctx.env as { OPENAI_API_KEY?: string }; + const env = ctx.env; const access = await checkAiFeatureAccess(ctx.db, userId, env); if (!access.allowed) { @@ -1422,24 +1367,9 @@ export const subscriptionsRouter = router({ const entryCategories: string[] = []; const entryTitles: string[] = []; - // Cast feedData to access items/entries safely (handles RSS, Atom, RDF) - const feedWithItems = feedData as { - entries?: Array<{ title?: string; categories?: unknown[] }>; - items?: Array<{ title?: string; categories?: unknown[] }>; - }; - - const items = feedWithItems.entries || feedWithItems.items || []; - - if (Array.isArray(items)) { - for (const item of items.slice(0, 10)) { - entryTitles.push(item.title || ""); - if (item.categories && Array.isArray(item.categories)) { - for (const cat of item.categories) { - const catName = extractCategoryName(cat); - if (catName) entryCategories.push(catName); - } - } - } + for (const item of previewItems) { + entryTitles.push(feedText(item.title) ?? ""); + entryCategories.push(...extractCategoryNames(item)); } if (!env.OPENAI_API_KEY) { @@ -2007,7 +1937,7 @@ export const subscriptionsRouter = router({ async (feedSpan) => { try { // Fetch and validate feed - const response = await fetch(feedInfo.url, { + const response = await safeFetch(feedInfo.url, { headers: { "User-Agent": "TuvixRSS/1.0", Accept: @@ -2020,29 +1950,15 @@ export const subscriptionsRouter = router({ throw new Error(`HTTP ${response.status}`); } - const feedContent = await response.text(); + const feedContent = await readFeedResponse(response); const feedResult = parseFeed(feedContent); const feedData = feedResult.feed; - // Extract metadata - const feedTitle = - "title" in feedData && feedData.title - ? feedData.title - : feedInfo.title; - const feedDescription = - "description" in feedData && feedData.description - ? stripHtml(feedData.description) - : "subtitle" in feedData && feedData.subtitle - ? stripHtml(feedData.subtitle) - : undefined; - const siteUrl = - "link" in feedData && feedData.link - ? feedData.link - : "links" in feedData && - Array.isArray(feedData.links) && - feedData.links[0]?.href - ? feedData.links[0].href - : undefined; + const { + title: feedTitle = feedInfo.title, + description: feedDescription, + siteUrl, + } = extractFeedMetadata(feedData); // Check if source exists // Normalize Reddit URLs to prevent duplicates across different domains @@ -2064,7 +1980,6 @@ export const subscriptionsRouter = router({ title: feedTitle, description: feedDescription, siteUrl, - lastFetched: new Date(), }) .where(eq(schema.sources.id, sourceId)); } else { @@ -2076,7 +1991,6 @@ export const subscriptionsRouter = router({ description: feedDescription, siteUrl, iconType: "auto", - lastFetched: new Date(), }) .returning(); const source = newSource[0]; @@ -2231,7 +2145,7 @@ export const subscriptionsRouter = router({ // This matches single subscription behavior and provides instant feedback try { const { fetchSingleFeed } = - await import("@/services/rss-fetcher"); + await import("@api/services/rss-fetcher"); await fetchSingleFeed(sourceId, normalizedFeedUrl, ctx.db); Sentry.addBreadcrumb({ diff --git a/packages/api/src/routers/userSettings.ts b/packages/api/src/routers/userSettings.ts index fd92f95d..344b587c 100644 --- a/packages/api/src/routers/userSettings.ts +++ b/packages/api/src/routers/userSettings.ts @@ -6,15 +6,15 @@ import { eq } from "drizzle-orm"; import { z } from "zod"; -import { router, rateLimitedProcedure } from "@/trpc/init"; -import * as schema from "@/db/schema"; +import { router, rateLimitedProcedure } from "@api/trpc/init"; +import * as schema from "@api/db/schema"; import { selectUserSettingsSchema, updateUserSettingsSchema, -} from "@/db/schemas.zod"; -import { getUserUsage, getUserLimits } from "@/services/limits"; -import type { Database } from "@/db/client"; -import { withUndefinedAsEmpty } from "@/types/pagination"; +} from "@api/db/schemas.zod"; +import { getUserUsage, getUserLimits } from "@api/services/limits"; +import type { Database } from "@api/db/client"; +import { withUndefinedAsEmpty } from "@api/types/pagination"; // ============================================================================ // HELPERS diff --git a/packages/api/src/services/__tests__/email.test.ts b/packages/api/src/services/__tests__/email.test.ts index a04039c4..7a3183de 100644 --- a/packages/api/src/services/__tests__/email.test.ts +++ b/packages/api/src/services/__tests__/email.test.ts @@ -6,7 +6,7 @@ import { describe, it, expect, beforeEach, vi } from "vitest"; import { sendPasswordResetEmail, sendWelcomeEmail } from "../email"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; // Mock Resend - use hoisted to create shared mock function const { mockSend } = vi.hoisted(() => { @@ -27,7 +27,8 @@ vi.mock("resend", () => { }); // Mock react-email render -vi.mock("react-email", () => ({ +vi.mock("react-email", async (importOriginal) => ({ + ...(await importOriginal()), render: vi.fn().mockResolvedValue("test"), })); diff --git a/packages/api/src/services/__tests__/feed-description-cleanup.test.ts b/packages/api/src/services/__tests__/feed-description-cleanup.test.ts index fe84a4f7..7a3b2f3c 100644 --- a/packages/api/src/services/__tests__/feed-description-cleanup.test.ts +++ b/packages/api/src/services/__tests__/feed-description-cleanup.test.ts @@ -1,3 +1,4 @@ +import { createFeedResponse } from "@api/test/mocks"; /** * Feed Description Cleanup Tests * @@ -6,8 +7,8 @@ */ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; -import { createTestDb, cleanupTestDb, seedTestSource } from "@/test/setup"; -import * as schema from "@/db/schema"; +import { createTestDb, cleanupTestDb, seedTestSource } from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { fetchSingleFeed } from "../rss-fetcher"; // Mock fetch globally @@ -59,12 +60,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -88,12 +90,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -120,12 +123,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -154,12 +158,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -191,12 +196,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -223,12 +229,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -255,12 +262,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -286,12 +294,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -320,12 +329,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -349,12 +359,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -380,12 +391,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -412,12 +424,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); @@ -459,12 +472,13 @@ describe("Feed Description Cleanup", () => { `; - mockFetch.mockResolvedValueOnce({ - ok: true, - status: 200, - headers: new Headers({ "content-type": "application/rss+xml" }), - text: async () => feedXml, - } as Response); + mockFetch.mockResolvedValueOnce( + createFeedResponse( + feedXml, + undefined, + new Headers({ "content-type": "application/rss+xml" }) + ) as Response + ); await fetchSingleFeed(testSourceId, "https://test.example.com/feed", db); diff --git a/packages/api/src/services/__tests__/feed-reliability.test.ts b/packages/api/src/services/__tests__/feed-reliability.test.ts new file mode 100644 index 00000000..bd35ac6c --- /dev/null +++ b/packages/api/src/services/__tests__/feed-reliability.test.ts @@ -0,0 +1,149 @@ +import { beforeEach, afterEach, describe, expect, it, vi } from "vitest"; +import { eq } from "drizzle-orm"; +import { createTestDb, cleanupTestDb } from "@api/test/setup"; +import * as schema from "@api/db/schema"; +import * as Sentry from "@api/utils/sentry"; +import { fetchSingleFeed } from "../rss-fetcher"; +import { recordFeedBatchHealth } from "../feed-health"; + +const feed = (count = 2) => + `Newshttps://example.comNews${Array.from({ length: count }, (_, i) => `item-${i}Story ${i}`).join("")}`; +const response = (count = 2) => + new Response(feed(count), { + headers: { "content-type": "application/rss+xml" }, + }); + +describe("feed reliability", () => { + let db: ReturnType; + beforeEach(() => { + db = createTestDb(); + }); + afterEach(() => { + cleanupTestDb(db); + vi.restoreAllMocks(); + vi.unstubAllGlobals(); + }); + async function source() { + const [row] = await db + .insert(schema.sources) + .values({ url: "https://example.com/rss", title: "News" }) + .returning(); + if (!row) throw new Error("Missing fixture"); + return row; + } + + it("allows only one owner when manual refreshes overlap", async () => { + const row = await source(); + let release: (value: Response) => void = () => { + throw new Error("Not started"); + }; + const pending = new Promise((resolve) => { + release = resolve; + }); + const fetch = vi.fn(() => pending); + vi.stubGlobal("fetch", fetch); + const first = fetchSingleFeed(row.id, row.url, db); + await vi.waitFor(() => expect(fetch).toHaveBeenCalledTimes(1)); + const second = await fetchSingleFeed(row.id, row.url, db); + expect(second.outcome).toBe("leased"); + release(response()); + expect((await first).articlesAdded).toBe(2); + expect(fetch).toHaveBeenCalledTimes(1); + expect(await db.select().from(schema.articles)).toHaveLength(2); + const [finished] = await db.select().from(schema.sources); + expect(finished?.fetchLeaseToken).toBeNull(); + }); + + it("does not store data or clear the new owner's lease after losing ownership", async () => { + const row = await source(); + vi.stubGlobal( + "fetch", + vi.fn(async () => { + await db + .update(schema.sources) + .set({ + fetchLeaseToken: "new-owner", + fetchLeaseUntil: new Date(Date.now() + 60_000), + }) + .where(eq(schema.sources.id, row.id)); + return response(); + }) + ); + await expect(fetchSingleFeed(row.id, row.url, db)).rejects.toThrow( + "ownership changed" + ); + expect(await db.select().from(schema.articles)).toHaveLength(0); + const [current] = await db.select().from(schema.sources); + expect(current?.fetchLeaseToken).toBe("new-owner"); + expect(current?.lastFetched).toBeNull(); + expect(current?.lastFetchError).toBeNull(); + }); + + it("recovers an abandoned lease and inserts duplicates harmlessly", async () => { + const row = await source(); + await db + .update(schema.sources) + .set({ fetchLeaseToken: "abandoned", fetchLeaseUntil: new Date(0) }) + .where(eq(schema.sources.id, row.id)); + vi.stubGlobal( + "fetch", + vi.fn(async () => response()) + ); + expect((await fetchSingleFeed(row.id, row.url, db)).articlesAdded).toBe(2); + expect((await fetchSingleFeed(row.id, row.url, db)).articlesAdded).toBe(0); + expect(await db.select().from(schema.articles)).toHaveLength(2); + }); + + it("records partial storage failures and safely retries completed chunks", async () => { + const row = await source(); + db.$client.exec( + "CREATE TRIGGER reject_article BEFORE INSERT ON articles WHEN NEW.guid = 'item-7' BEGIN SELECT RAISE(ABORT, 'storage failure'); END" + ); + vi.stubGlobal( + "fetch", + vi.fn(async () => response(9)) + ); + await expect(fetchSingleFeed(row.id, row.url, db)).rejects.toThrow(); + const [failed] = await db.select().from(schema.sources); + expect(failed?.lastFetched).toBeNull(); + expect(failed?.consecutiveFetchFailures).toBe(1); + expect(failed?.lastFetchError).toContain("could not all be stored"); + expect(failed?.lastFetchError).not.toContain("INSERT"); + expect(failed?.nextFetchAt).toBeInstanceOf(Date); + expect(failed?.fetchLeaseToken).toBeNull(); + expect(await db.select().from(schema.articles)).toHaveLength(7); + db.$client.exec("DROP TRIGGER reject_article"); + expect((await fetchSingleFeed(row.id, row.url, db)).articlesAdded).toBe(2); + const [recovered] = await db.select().from(schema.sources); + expect(recovered?.lastFetched).toBeInstanceOf(Date); + expect(recovered?.lastFetchError).toBeNull(); + expect(recovered?.consecutiveFetchFailures).toBe(0); + }); + + it("alerts on sustained failures, throttles repeats, and resets on recovery", async () => { + const alert = vi.spyOn(Sentry, "captureMessage"); + const failed = { backlog: 50, errors: 20, added: 0, processed: 20 }; + await recordFeedBatchHealth(db, failed); + await recordFeedBatchHealth(db, failed); + expect(alert).not.toHaveBeenCalled(); + await recordFeedBatchHealth(db, failed); + await recordFeedBatchHealth(db, failed); + expect(alert).toHaveBeenCalledTimes(1); + await recordFeedBatchHealth(db, { ...failed, errors: 0, added: 2 }); + const [health] = await db.select().from(schema.feedFetchHealth); + expect(health?.failingBatches).toBe(0); + }); + + it("alerts when backlog grows across successive productive batches", async () => { + const alert = vi.spyOn(Sentry, "captureMessage"); + for (const backlog of [10, 20, 30, 40]) { + await recordFeedBatchHealth(db, { + backlog, + errors: 0, + added: 1, + processed: 20, + }); + } + expect(alert).toHaveBeenCalledTimes(1); + }); +}); diff --git a/packages/api/src/services/__tests__/global-settings.test.ts b/packages/api/src/services/__tests__/global-settings.test.ts index ecf29216..f9ad2590 100644 --- a/packages/api/src/services/__tests__/global-settings.test.ts +++ b/packages/api/src/services/__tests__/global-settings.test.ts @@ -5,9 +5,9 @@ */ import { describe, it, expect, beforeEach, afterEach } from "vitest"; -import { createTestDb, cleanupTestDb, seedTestUser } from "@/test/setup"; +import { createTestDb, cleanupTestDb, seedTestUser } from "@api/test/setup"; import { getGlobalSettings } from "../global-settings"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; describe("Global Settings Service", () => { diff --git a/packages/api/src/services/__tests__/limits.test.ts b/packages/api/src/services/__tests__/limits.test.ts index 9c0facee..67d847cf 100644 --- a/packages/api/src/services/__tests__/limits.test.ts +++ b/packages/api/src/services/__tests__/limits.test.ts @@ -26,8 +26,8 @@ import { seedTestSource, seedTestSubscription, seedTestCategory, -} from "@/test/setup"; -import * as schema from "@/db/schema"; +} from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; describe("User Limits Service", () => { diff --git a/packages/api/src/services/__tests__/rate-limiter.test.ts b/packages/api/src/services/__tests__/rate-limiter.test.ts index 6b6b1bdc..fc8cad87 100644 --- a/packages/api/src/services/__tests__/rate-limiter.test.ts +++ b/packages/api/src/services/__tests__/rate-limiter.test.ts @@ -16,7 +16,7 @@ import { checkApiRateLimit, checkPublicFeedRateLimit, } from "../rate-limiter"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; describe("Rate Limiter Service", () => { let env: Env; diff --git a/packages/api/src/services/__tests__/rss-fetcher-hn.test.ts b/packages/api/src/services/__tests__/rss-fetcher-hn.test.ts index 19ae527d..6e0ff459 100644 --- a/packages/api/src/services/__tests__/rss-fetcher-hn.test.ts +++ b/packages/api/src/services/__tests__/rss-fetcher-hn.test.ts @@ -7,9 +7,9 @@ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { parseFeed } from "feedsmith"; -import { sanitizeHtml } from "@/utils/text-sanitizer"; -import { createTestDb, cleanupTestDb, seedTestUser } from "@/test/setup"; -import * as schema from "@/db/schema"; +import { sanitizeHtml } from "@api/utils/text-sanitizer"; +import { createTestDb, cleanupTestDb, seedTestUser } from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; import { fetchSingleFeed } from "../rss-fetcher"; diff --git a/packages/api/src/services/__tests__/rss-fetcher-itunes.test.ts b/packages/api/src/services/__tests__/rss-fetcher-itunes.test.ts index 549b3d07..15462355 100644 --- a/packages/api/src/services/__tests__/rss-fetcher-itunes.test.ts +++ b/packages/api/src/services/__tests__/rss-fetcher-itunes.test.ts @@ -1,3 +1,4 @@ +import { createFeedResponse } from "@api/test/mocks"; /** * RSS Fetcher Test - iTunes Podcast Image Extraction * @@ -7,8 +8,8 @@ import { describe, it, expect, beforeEach, afterEach } from "vitest"; import { parseFeed } from "feedsmith"; -import { createTestDb, cleanupTestDb, seedTestUser } from "@/test/setup"; -import * as schema from "@/db/schema"; +import { createTestDb, cleanupTestDb, seedTestUser } from "@api/test/setup"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; import { fetchSingleFeed } from "../rss-fetcher"; @@ -188,14 +189,13 @@ describe("RSS Fetcher - iTunes Podcast Images", () => { `; globalThis.fetch = async () => { - return { - ok: true, - status: 200, - headers: new Headers({ + return createFeedResponse( + mockFeed, + undefined, + new Headers({ "content-type": "application/rss+xml", - }), - text: async () => mockFeed, - } as Response; + }) + ) as Response; }; // Fetch the feed diff --git a/packages/api/src/services/__tests__/rss-fetcher.test.ts b/packages/api/src/services/__tests__/rss-fetcher.test.ts index 2469bcde..b3e23cb9 100644 --- a/packages/api/src/services/__tests__/rss-fetcher.test.ts +++ b/packages/api/src/services/__tests__/rss-fetcher.test.ts @@ -4,15 +4,15 @@ import { describe, it, expect, beforeEach, afterEach, vi } from "vitest"; import { fetchAllFeeds, fetchSingleFeed } from "../rss-fetcher"; -import { createTestDb, cleanupTestDb, seedTestSource } from "@/test/setup"; +import { createTestDb, cleanupTestDb, seedTestSource } from "@api/test/setup"; import { MOCK_RSS_FEED, mockFetchRssFeed, mockFetchAtomFeed, mockFetch404, mockFetchError, -} from "@/test/mocks"; -import * as schema from "@/db/schema"; +} from "@api/test/mocks"; +import * as schema from "@api/db/schema"; import { eq } from "drizzle-orm"; describe("RSS Fetcher Service", () => { @@ -58,6 +58,24 @@ describe("RSS Fetcher Service", () => { expect(result.articlesAdded).toBeGreaterThan(0); }); + it("stores Atom structured text and chooses the publisher link", async () => { + const source = await seedTestSource(db); + const xml = `Atom Newsatom-1Readable title<b>Readable summary</b>2026-09-01T12:00:00Z`; + global.fetch = vi.fn( + async () => + new Response(xml, { + headers: { "content-type": "application/atom+xml" }, + }) + ); + await fetchSingleFeed(source.id, source.url, db); + const [article] = await db.select().from(schema.articles); + expect(article).toMatchObject({ + title: "Readable title", + link: "https://example.com/story", + description: "Readable summary", + }); + }); + it("should store articles in database", async () => { const source = await seedTestSource(db); @@ -242,6 +260,82 @@ describe("RSS Fetcher Service", () => { }); describe("fetchAllFeeds", () => { + it.each(["http", "parse", "network"] as const)( + "advances past a %s failure and retries it only after the cooldown", + async (failure) => { + const failing = await seedTestSource(db, { + url: "https://example.com/failing.xml", + }); + const healthy = await seedTestSource(db, { + url: "https://example.com/healthy.xml", + }); + global.fetch = + failure === "http" + ? mockFetch404() + : failure === "network" + ? mockFetchError() + : mockFetchRssFeed("Not a feed"); + + const first = await fetchAllFeeds(db, { maxFeedsPerBatch: 1 }); + expect(first.errorCount).toBe(1); + expect(first.errors[0]?.sourceId).toBe(failing.id); + const [failedSource] = await db + .select() + .from(schema.sources) + .where(eq(schema.sources.id, failing.id)); + expect(failedSource?.lastFetched).toBeNull(); + expect(failedSource?.lastFetchAttemptAt).toBeInstanceOf(Date); + + global.fetch = mockFetchRssFeed(); + const second = await fetchAllFeeds(db, { maxFeedsPerBatch: 1 }); + expect(second.successCount).toBe(1); + const articles = await db + .select() + .from(schema.articles) + .where(eq(schema.articles.sourceId, healthy.id)); + expect(articles.length).toBeGreaterThan(0); + expect( + (await fetchAllFeeds(db, { maxFeedsPerBatch: 1 })).processedCount + ).toBe(0); + + await db + .update(schema.sources) + .set({ + lastFetchAttemptAt: new Date(Date.now() - 31 * 60 * 1000), + nextFetchAt: new Date(0), + }) + .where(eq(schema.sources.id, failing.id)); + expect( + (await fetchAllFeeds(db, { maxFeedsPerBatch: 1 })).successCount + ).toBe(1); + } + ); + + it("orders retries by attempt time instead of pinning never-successful feeds first", async () => { + const failing = await seedTestSource(db, { + url: "https://example.com/failing.xml", + }); + const healthy = await seedTestSource(db, { + url: "https://example.com/healthy.xml", + }); + const old = new Date(Date.now() - 90 * 60 * 1000); + await db + .update(schema.sources) + .set({ lastFetched: old, lastFetchAttemptAt: old }) + .where(eq(schema.sources.id, healthy.id)); + await db + .update(schema.sources) + .set({ lastFetchAttemptAt: new Date(Date.now() - 31 * 60 * 1000) }) + .where(eq(schema.sources.id, failing.id)); + global.fetch = mockFetchRssFeed(); + + expect( + (await fetchAllFeeds(db, { maxFeedsPerBatch: 1 })).successCount + ).toBe(1); + const [article] = await db.select().from(schema.articles).limit(1); + expect(article?.sourceId).toBe(healthy.id); + }); + it("should fetch all sources in database", async () => { await seedTestSource(db, { url: "https://example.com/feed1.xml", @@ -585,7 +679,7 @@ describe("RSS Fetcher Service", () => { }); // Create blocked domain entry - const { user } = await import("@/test/setup").then((m) => + const { user } = await import("@api/test/setup").then((m) => m.seedTestUser(db, { role: "admin" }) ); await db.insert(schema.blockedDomains).values({ @@ -603,6 +697,17 @@ describe("RSS Fetcher Service", () => { expect(result.articlesSkipped).toBe(0); expect(result.sourceUpdated).toBe(false); + expect(global.fetch).not.toHaveBeenCalled(); + const [blockedSource] = await db + .select() + .from(schema.sources) + .where(eq(schema.sources.id, source.id)); + expect(blockedSource?.lastFetched).toBeNull(); + expect(blockedSource?.lastFetchAttemptAt).toBeInstanceOf(Date); + expect( + (await fetchAllFeeds(db, { maxFeedsPerBatch: 1 })).processedCount + ).toBe(0); + // Verify no articles were stored const articles = await db .select() @@ -642,7 +747,7 @@ describe("RSS Fetcher Service", () => { }); // Create blocked domain in DB (not in cache) - const { user } = await import("@/test/setup").then((m) => + const { user } = await import("@api/test/setup").then((m) => m.seedTestUser(db, { role: "admin" }) ); await db.insert(schema.blockedDomains).values({ diff --git a/packages/api/src/services/admin-init.ts b/packages/api/src/services/admin-init.ts index 1d13f883..91008c30 100644 --- a/packages/api/src/services/admin-init.ts +++ b/packages/api/src/services/admin-init.ts @@ -8,12 +8,11 @@ */ import { eq } from "drizzle-orm"; -import * as schema from "@/db/schema"; -import type { Database } from "@/db/client"; -import type { Env } from "@/types"; -import { ADMIN_PLAN } from "@/config/plans"; -import { createAuth } from "@/auth/better-auth"; -import { initializeNewUser } from "@/services/user-init"; +import * as schema from "@api/db/schema"; +import type { Database } from "@api/db/client"; +import type { Env } from "@api/types"; +import { ADMIN_PLAN } from "@api/config/plans"; +import { createAuth } from "@api/auth/better-auth"; /** * Initialize admin user from environment variables @@ -51,42 +50,17 @@ export async function initializeAdmin( }; } - // Create admin user using Better Auth's API - // This ensures password is hashed correctly (Better Auth uses scrypt) - // We need to create a minimal env object for createAuth - const minimalEnv: Env = { - RUNTIME: "nodejs", - BETTER_AUTH_SECRET: env.BETTER_AUTH_SECRET || "", - DATABASE_PATH: env.DATABASE_PATH, - PORT: env.PORT, - CORS_ORIGIN: env.CORS_ORIGIN, - NODE_ENV: env.NODE_ENV, - BASE_URL: env.BASE_URL, - BETTER_AUTH_URL: env.BETTER_AUTH_URL, - RESEND_API_KEY: env.RESEND_API_KEY, - EMAIL_FROM: env.EMAIL_FROM, - }; - - // Create auth instance - it will use the same database connection - // We pass undefined so createAuth creates its own connection, but we'll use the same db for queries - const auth = createAuth(minimalEnv); - - // Use Better Auth's signUp API to create the user (handles password hashing correctly) - // We'll create a fake request context for this - const fakeHeaders = new Headers(); - fakeHeaders.set("content-type", "application/json"); + const auth = createAuth(env, db); try { - // Use Better Auth's signUpEmail with username field - // According to Better Auth docs, username can be passed in signUpEmail body - const signUpResult = await auth.api.signUpEmail({ + const signUpResult = await auth.api.createUser({ body: { email: adminEmail, password: adminPassword, name: adminUsername, - username: adminUsername, // Pass username directly to signUpEmail + role: "admin", + data: { username: adminUsername, displayUsername: adminUsername }, }, - headers: fakeHeaders, }); if (!signUpResult?.user) { @@ -102,11 +76,6 @@ export async function initializeAdmin( // Atomic initialization: role + settings + usage stats // Uses D1 batch for atomic operations - all succeed or all fail try { - await initializeNewUser(db, adminUserId, { - role: "admin", - plan: ADMIN_PLAN, - }); - // Log the creation (separate - not part of atomic init) await db.insert(schema.securityAuditLog).values({ userId: adminUserId, diff --git a/packages/api/src/services/ai-category-suggester.ts b/packages/api/src/services/ai-category-suggester.ts index db9e203a..3411ae3a 100644 --- a/packages/api/src/services/ai-category-suggester.ts +++ b/packages/api/src/services/ai-category-suggester.ts @@ -7,8 +7,8 @@ import { generateObject } from "ai"; import { z } from "zod"; -import * as Sentry from "@/utils/sentry"; -import { withTiming } from "@/utils/metrics"; +import * as Sentry from "@api/utils/sentry"; +import { withTiming } from "@api/utils/metrics"; interface FeedContext { title: string; diff --git a/packages/api/src/services/article-filters.ts b/packages/api/src/services/article-filters.ts new file mode 100644 index 00000000..0a6ab809 --- /dev/null +++ b/packages/api/src/services/article-filters.ts @@ -0,0 +1,94 @@ +import type * as schema from "@api/db/schema"; + +type FilterableArticle = Pick< + typeof schema.articles.$inferSelect, + "title" | "description" | "content" | "author" +>; + +/** + * Check if an article matches a single filter + */ +function matchesFilter( + article: FilterableArticle, + filter: typeof schema.subscriptionFilters.$inferSelect +): boolean { + const fieldValue = (() => { + switch (filter.field) { + case "title": + return article.title ?? ""; + case "description": + return article.description ?? ""; + case "content": + return article.content ?? ""; + case "author": + return article.author ?? ""; + case "any": + return [ + article.title ?? "", + article.description ?? "", + article.content ?? "", + article.author ?? "", + ].join(" "); + default: + return ""; + } + })(); + + // If field value is empty/null and pattern is not empty, no match + if (!fieldValue && filter.pattern) { + return false; + } + + const searchText = filter.caseSensitive + ? fieldValue + : fieldValue.toLowerCase(); + const pattern = filter.caseSensitive + ? filter.pattern + : filter.pattern.toLowerCase(); + + switch (filter.matchType) { + case "contains": + return searchText.includes(pattern); + case "exact": + return searchText === pattern; + case "regex": { + try { + const regex = new RegExp( + filter.pattern, + filter.caseSensitive ? "" : "i" + ); + return regex.test(fieldValue); + } catch { + // Invalid regex - skip this filter + return false; + } + } + default: + return false; + } +} + +/** + * Check if an article matches subscription filters + */ +export function matchesSubscriptionFilters( + article: FilterableArticle, + filters: (typeof schema.subscriptionFilters.$inferSelect)[], + filterMode: "include" | "exclude" +): boolean { + // If no filters exist but filtering is enabled, exclude the article + // (This matches the Go implementation behavior) + if (filters.length === 0) { + return false; + } + + const hasMatch = filters.some((filter) => matchesFilter(article, filter)); + + if (filterMode === "include") { + // Include mode: article must match at least one filter + return hasMatch; + } else { + // Exclude mode: article must not match any filter + return !hasMatch; + } +} diff --git a/packages/api/src/services/category-discovery.ts b/packages/api/src/services/category-discovery.ts index 08c5a0f9..da1202c4 100644 --- a/packages/api/src/services/category-discovery.ts +++ b/packages/api/src/services/category-discovery.ts @@ -1,3 +1,4 @@ +import { countFeedCategories } from "@api/utils/feed-utils"; /** * Category Discovery Service * @@ -5,51 +6,14 @@ * Analyzes feed metadata and entry tags to suggest relevant categories. */ -import { fetchAndParseFeed } from "@/services/rss-fetcher"; -import type { Rss, Atom, Rdf, Json } from "@/types/feed"; - -// Union type for feeds (feedsmith returns dates as strings) -type AnyFeed = - | Rss.Feed - | Atom.Feed - | Rdf.Feed - | Json.Feed; +import { fetchAndParseFeed } from "@api/services/rss-fetcher"; +import type { ParsedFeed } from "@api/types/feed"; export interface CategorySuggestion { name: string; confidence: number; } -/** - * Extract category name from various feed category formats - * - * Handles different feed formats: - * - String: "Technology" - * - Object with term: { term: "Technology" } - * - Object with label: { label: "Technology" } - * - Object with name: { name: "Technology" } - * - * @param cat Category in unknown format - * @returns Category name string or null if unable to extract - */ -function extractCategoryName(cat: unknown): string | null { - if (typeof cat === "string") { - return cat; - } - - if (typeof cat === "object" && cat !== null) { - const obj = cat as Record; - return ( - (obj.term as string) || - (obj.label as string) || - (obj.name as string) || - null - ); - } - - return null; -} - /** * Discover categories from parsed feed data * @@ -61,39 +25,10 @@ function extractCategoryName(cat: unknown): string | null { * @returns Array of category suggestions sorted by confidence */ export function discoverCategoriesFromFeed( - feedData: AnyFeed, + feedData: ParsedFeed, maxEntries: number = 10 ): CategorySuggestion[] { - const categoryMap = new Map(); - - // Extract feed-level categories - if ("categories" in feedData && Array.isArray(feedData.categories)) { - for (const cat of feedData.categories) { - const catName = extractCategoryName(cat); - if (catName) { - categoryMap.set(catName, (categoryMap.get(catName) || 0) + 1); - } - } - } - - // Extract entry-level categories - if ("items" in feedData && Array.isArray(feedData.items)) { - const entries = feedData.items.slice(0, maxEntries); - for (const entry of entries) { - if ( - "categories" in entry && - entry.categories && - Array.isArray(entry.categories) - ) { - for (const cat of entry.categories) { - const catName = extractCategoryName(cat); - if (catName) { - categoryMap.set(catName, (categoryMap.get(catName) || 0) + 1); - } - } - } - } - } + const categoryMap = countFeedCategories(feedData, maxEntries); // Convert to suggestions with confidence scores const totalMentions = Array.from(categoryMap.values()).reduce( diff --git a/packages/api/src/services/comment-link-extraction/atom-link-extractor.test.ts b/packages/api/src/services/comment-link-extraction/atom-link-extractor.test.ts index f9e63089..95421dca 100644 --- a/packages/api/src/services/comment-link-extraction/atom-link-extractor.test.ts +++ b/packages/api/src/services/comment-link-extraction/atom-link-extractor.test.ts @@ -7,7 +7,7 @@ import { describe, it, expect } from "vitest"; import { AtomLinkExtractor } from "./atom-link-extractor"; -import type { FeedItem } from "./types"; +import type { ParsedFeedItem } from "./types"; describe("AtomLinkExtractor", () => { const extractor = new AtomLinkExtractor(); @@ -20,41 +20,43 @@ describe("AtomLinkExtractor", () => { describe("canHandle", () => { it("should return true when item has links array", () => { - const item: Partial = { + const item: Partial = { links: [ { href: "https://example.com/article", rel: "alternate" }, { href: "https://example.com/comments", rel: "replies" }, ], }; - expect(extractor.canHandle(item as FeedItem)).toBe(true); + expect(extractor.canHandle(item as ParsedFeedItem)).toBe(true); }); it("should return false when item has no links field", () => { - const item: Partial = { + const item: Partial = { title: "Test Article", link: "https://example.com/article", }; - expect(extractor.canHandle(item as FeedItem)).toBe(false); + expect(extractor.canHandle(item as ParsedFeedItem)).toBe(false); }); it("should return false when links is not an array", () => { const item = { links: "not-an-array", }; - expect(extractor.canHandle(item as unknown as FeedItem)).toBe(false); + expect(extractor.canHandle(item as unknown as ParsedFeedItem)).toBe( + false + ); }); it("should return false when links array is empty", () => { - const item: Partial = { + const item: Partial = { links: [], }; - expect(extractor.canHandle(item as FeedItem)).toBe(false); + expect(extractor.canHandle(item as ParsedFeedItem)).toBe(false); }); }); describe("extract", () => { it("should extract comment URL from link with rel='replies'", () => { - const item: Partial = { + const item: Partial = { title: "Atom Feed Article", links: [ { href: "https://example.com/article", rel: "alternate" }, @@ -62,7 +64,7 @@ describe("AtomLinkExtractor", () => { ], }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/article/comments", @@ -71,7 +73,7 @@ describe("AtomLinkExtractor", () => { }); it("should extract comment URL from link with rel='comments'", () => { - const item: Partial = { + const item: Partial = { title: "Atom Feed Article", links: [ { href: "https://example.com/article", rel: "alternate" }, @@ -79,7 +81,7 @@ describe("AtomLinkExtractor", () => { ], }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/comments", @@ -88,7 +90,7 @@ describe("AtomLinkExtractor", () => { }); it("should extract comment URL from link with rel='discussion'", () => { - const item: Partial = { + const item: Partial = { title: "Atom Feed Article", links: [ { href: "https://example.com/article", rel: "alternate" }, @@ -96,7 +98,7 @@ describe("AtomLinkExtractor", () => { ], }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/discussion", @@ -105,7 +107,7 @@ describe("AtomLinkExtractor", () => { }); it("should return first matching link when multiple comment links exist", () => { - const item: Partial = { + const item: Partial = { title: "Article with multiple comment links", links: [ { href: "https://example.com/article", rel: "alternate" }, @@ -114,7 +116,7 @@ describe("AtomLinkExtractor", () => { ], }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/replies", @@ -123,7 +125,7 @@ describe("AtomLinkExtractor", () => { }); it("should return null when no comment-related links exist", () => { - const item: Partial = { + const item: Partial = { title: "Article without comment links", links: [ { href: "https://example.com/article", rel: "alternate" }, @@ -131,45 +133,45 @@ describe("AtomLinkExtractor", () => { ], }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toBeNull(); }); it("should return null when links array is empty", () => { - const item: Partial = { + const item: Partial = { title: "Article with empty links", links: [], }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toBeNull(); }); it("should return null when no links field exists", () => { - const item: Partial = { + const item: Partial = { title: "Article without links field", }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toBeNull(); }); it("should handle links without href field", () => { - const item: Partial = { + const item: Partial = { title: "Article with malformed links", links: [{ rel: "replies" } as { href: string; rel: string }], }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toBeNull(); }); it("should handle links without rel field", () => { - const item: Partial = { + const item: Partial = { title: "Article with links missing rel", links: [ { href: "https://example.com/something" } as { @@ -179,13 +181,13 @@ describe("AtomLinkExtractor", () => { ], }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toBeNull(); }); it("should be case-insensitive for rel values", () => { - const item: Partial = { + const item: Partial = { title: "Article with uppercase rel", links: [ { href: "https://example.com/article", rel: "ALTERNATE" }, @@ -193,7 +195,7 @@ describe("AtomLinkExtractor", () => { ], }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/comments", diff --git a/packages/api/src/services/comment-link-extraction/atom-link-extractor.ts b/packages/api/src/services/comment-link-extraction/atom-link-extractor.ts index 9a7c1079..cee0e2b1 100644 --- a/packages/api/src/services/comment-link-extraction/atom-link-extractor.ts +++ b/packages/api/src/services/comment-link-extraction/atom-link-extractor.ts @@ -8,7 +8,7 @@ import type { CommentLinkExtractor, ExtractedCommentLink, - FeedItem, + ParsedFeedItem, } from "./types"; /** @@ -19,13 +19,13 @@ import type { export class AtomLinkExtractor implements CommentLinkExtractor { readonly priority = 20; // Second priority - standard format - canHandle(item: FeedItem): boolean { + canHandle(item: ParsedFeedItem): boolean { return ( "links" in item && Array.isArray(item.links) && item.links.length > 0 ); } - extract(item: FeedItem): ExtractedCommentLink | null { + extract(item: ParsedFeedItem): ExtractedCommentLink | null { if ("links" in item && Array.isArray(item.links)) { const commentLink = item.links.find((link) => { const rel = link.rel?.toLowerCase(); diff --git a/packages/api/src/services/comment-link-extraction/html-pattern-extractor.test.ts b/packages/api/src/services/comment-link-extraction/html-pattern-extractor.test.ts index 83518a8e..9fbb78e5 100644 --- a/packages/api/src/services/comment-link-extraction/html-pattern-extractor.test.ts +++ b/packages/api/src/services/comment-link-extraction/html-pattern-extractor.test.ts @@ -7,7 +7,7 @@ import { describe, it, expect } from "vitest"; import { HtmlPatternExtractor } from "./html-pattern-extractor"; -import type { FeedItem } from "./types"; +import type { ParsedFeedItem } from "./types"; describe("HtmlPatternExtractor", () => { const extractor = new HtmlPatternExtractor(); @@ -20,42 +20,42 @@ describe("HtmlPatternExtractor", () => { describe("canHandle", () => { it("should return true when item has description field", () => { - const item: Partial = { + const item: Partial = { description: "

Some content with [comments]

", }; - expect(extractor.canHandle(item as FeedItem)).toBe(true); + expect(extractor.canHandle(item as ParsedFeedItem)).toBe(true); }); it("should return true when item has content field", () => { - const item: Partial = { + const item: Partial = { content: "

Article content

", }; - expect(extractor.canHandle(item as FeedItem)).toBe(true); + expect(extractor.canHandle(item as ParsedFeedItem)).toBe(true); }); it("should return true when item has summary field", () => { - const item: Partial = { + const item: Partial = { summary: "

Article summary

", }; - expect(extractor.canHandle(item as FeedItem)).toBe(true); + expect(extractor.canHandle(item as ParsedFeedItem)).toBe(true); }); it("should return false when item has no HTML fields", () => { - const item: Partial = { + const item: Partial = { title: "Test Article", link: "https://example.com/article", }; - expect(extractor.canHandle(item as FeedItem)).toBe(false); + expect(extractor.canHandle(item as ParsedFeedItem)).toBe(false); }); it("should return false when all HTML fields are empty", () => { - const item: Partial = { + const item: Partial = { description: "", content: "", summary: "", }; - expect(extractor.canHandle(item as FeedItem)).toBe(false); + expect(extractor.canHandle(item as ParsedFeedItem)).toBe(false); }); }); @@ -63,13 +63,13 @@ describe("HtmlPatternExtractor", () => { describe("Reddit [comments] pattern", () => { it("should extract comment URL from Reddit style [comments] link", () => { // Based on actual Reddit RSS feed schema - const item: Partial = { + const item: Partial = { title: "TIL something interesting", description: '
[comments]
', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://www.reddit.com/r/todayilearned/comments/abc123/til_something/", @@ -78,12 +78,12 @@ describe("HtmlPatternExtractor", () => { }); it("should handle [comments] with extra whitespace", () => { - const item: Partial = { + const item: Partial = { description: ' [ comments ] ', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://reddit.com/comments/123", @@ -92,11 +92,11 @@ describe("HtmlPatternExtractor", () => { }); it("should handle comments without brackets", () => { - const item: Partial = { + const item: Partial = { description: 'comments', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://reddit.com/comments/123", @@ -107,12 +107,12 @@ describe("HtmlPatternExtractor", () => { describe("Plain text patterns", () => { it("should extract from 'Comments' link text", () => { - const item: Partial = { + const item: Partial = { description: '

Article text Comments

', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/article/comments", @@ -121,12 +121,12 @@ describe("HtmlPatternExtractor", () => { }); it("should extract from 'Discussion' link text", () => { - const item: Partial = { + const item: Partial = { description: '

See the Discussion

', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://forum.example.com/discussion/123", @@ -135,11 +135,11 @@ describe("HtmlPatternExtractor", () => { }); it("should extract from 'Discuss' link text", () => { - const item: Partial = { + const item: Partial = { description: 'Discuss', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/discuss", @@ -150,11 +150,11 @@ describe("HtmlPatternExtractor", () => { describe("Icon patterns", () => { it("should extract from emoji icon + text", () => { - const item: Partial = { + const item: Partial = { description: '💬 Comments', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/comments", @@ -163,12 +163,12 @@ describe("HtmlPatternExtractor", () => { }); it("should extract from comment text in link", () => { - const item: Partial = { + const item: Partial = { description: 'Leave a comment', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/article#comments", @@ -179,26 +179,26 @@ describe("HtmlPatternExtractor", () => { describe("Content field priority", () => { it("should check description first", () => { - const item: Partial = { + const item: Partial = { description: '[comments]', content: '[comments]', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result?.url).toBe("https://example.com/desc-comments"); }); it("should fall back to content if description has no match", () => { - const item: Partial = { + const item: Partial = { description: "

No comment links here

", content: '[comments]', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/content-comments", @@ -207,14 +207,14 @@ describe("HtmlPatternExtractor", () => { }); it("should fall back to summary if description and content have no match", () => { - const item: Partial = { + const item: Partial = { description: "

No links

", content: "

Still no links

", summary: 'Comments', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/summary-comments", @@ -225,33 +225,33 @@ describe("HtmlPatternExtractor", () => { describe("Edge cases", () => { it("should return null when no comment patterns found", () => { - const item: Partial = { + const item: Partial = { description: '

Article content with regular links

', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toBeNull(); }); it("should handle malformed HTML gracefully", () => { // HTML without proper href attribute structure - const item: Partial = { + const item: Partial = { description: "[comments]", }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toBeNull(); }); it("should handle links with single quotes", () => { - const item: Partial = { + const item: Partial = { description: "[comments]", }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/comments", @@ -260,12 +260,12 @@ describe("HtmlPatternExtractor", () => { }); it("should handle links with additional attributes", () => { - const item: Partial = { + const item: Partial = { description: 'Comments', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/comments", @@ -274,11 +274,11 @@ describe("HtmlPatternExtractor", () => { }); it("should be case-insensitive for link text", () => { - const item: Partial = { + const item: Partial = { description: 'COMMENTS', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/comments", @@ -287,12 +287,12 @@ describe("HtmlPatternExtractor", () => { }); it("should handle nested HTML in description", () => { - const item: Partial = { + const item: Partial = { description: '

Article content

', }; - const result = extractor.extract(item as FeedItem); + const result = extractor.extract(item as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/comments", diff --git a/packages/api/src/services/comment-link-extraction/html-pattern-extractor.ts b/packages/api/src/services/comment-link-extraction/html-pattern-extractor.ts index 4be555be..cf992e9a 100644 --- a/packages/api/src/services/comment-link-extraction/html-pattern-extractor.ts +++ b/packages/api/src/services/comment-link-extraction/html-pattern-extractor.ts @@ -23,7 +23,7 @@ import type { CommentLinkExtractor, ExtractedCommentLink, - FeedItem, + ParsedFeedItem, } from "./types"; /** @@ -34,14 +34,14 @@ import type { export class HtmlPatternExtractor implements CommentLinkExtractor { readonly priority = 30; // Third priority - pattern matching - canHandle(item: FeedItem): boolean { + canHandle(item: ParsedFeedItem): boolean { const hasDescription = "description" in item && item.description; const hasContent = "content" in item && item.content; const hasSummary = "summary" in item && item.summary; return !!(hasDescription || hasContent || hasSummary); } - extract(item: FeedItem): ExtractedCommentLink | null { + extract(item: ParsedFeedItem): ExtractedCommentLink | null { // Try each field in priority order: description -> content -> summary const htmlFields = [ "description" in item ? item.description : "", diff --git a/packages/api/src/services/comment-link-extraction/index.ts b/packages/api/src/services/comment-link-extraction/index.ts index a400e07d..dbd25df7 100644 --- a/packages/api/src/services/comment-link-extraction/index.ts +++ b/packages/api/src/services/comment-link-extraction/index.ts @@ -8,7 +8,7 @@ import { CommentLinkRegistry } from "./registry"; import { RssElementExtractor } from "./rss-element-extractor"; import { AtomLinkExtractor } from "./atom-link-extractor"; import { HtmlPatternExtractor } from "./html-pattern-extractor"; -import type { FeedItem } from "./types"; +import type { ParsedFeedItem } from "./types"; // Create singleton registry with default extractors const registry = new CommentLinkRegistry(); @@ -27,7 +27,7 @@ registry.register(new HtmlPatternExtractor()); * @param item - Feed item to extract comment link from * @returns Comment link URL or null if none found */ -export function extractCommentLink(item: FeedItem): string | null { +export function extractCommentLink(item: ParsedFeedItem): string | null { return registry.extract(item); } diff --git a/packages/api/src/services/comment-link-extraction/integration.test.ts b/packages/api/src/services/comment-link-extraction/integration.test.ts index 9a378bb7..4cafb791 100644 --- a/packages/api/src/services/comment-link-extraction/integration.test.ts +++ b/packages/api/src/services/comment-link-extraction/integration.test.ts @@ -7,13 +7,13 @@ import { describe, it, expect } from "vitest"; import { extractCommentLink } from "./index"; -import type { FeedItem } from "./types"; +import type { ParsedFeedItem } from "./types"; describe("Comment Link Extraction Integration", () => { describe("Hacker News RSS feeds", () => { it("should extract comment link from typical HN item", () => { // Based on actual HN RSS structure from https://news.ycombinator.com/rss - const item: Partial = { + const item: Partial = { title: "Show HN: I built a new CLI tool", link: "https://github.com/user/project", comments: "https://news.ycombinator.com/item?id=38471822", @@ -22,13 +22,13 @@ describe("Comment Link Extraction Integration", () => { pubDate: "Mon, 04 Dec 2023 15:30:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe("https://news.ycombinator.com/item?id=38471822"); }); it("should extract comment link from HN Ask item", () => { - const item: Partial = { + const item: Partial = { title: "Ask HN: What are you working on?", link: "https://news.ycombinator.com/item?id=38471900", comments: "https://news.ycombinator.com/item?id=38471900", @@ -36,20 +36,20 @@ describe("Comment Link Extraction Integration", () => { pubDate: "Mon, 04 Dec 2023 16:00:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe("https://news.ycombinator.com/item?id=38471900"); }); it("should extract from HN item without description", () => { - const item: Partial = { + const item: Partial = { title: "Minimalist News Article", link: "https://example.com/article", comments: "https://news.ycombinator.com/item?id=38472000", pubDate: "Mon, 04 Dec 2023 17:00:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe("https://news.ycombinator.com/item?id=38472000"); }); @@ -58,7 +58,7 @@ describe("Comment Link Extraction Integration", () => { describe("Reddit RSS feeds", () => { it("should extract comment link from typical Reddit post", () => { // Based on actual Reddit RSS structure from https://www.reddit.com/r/news/.rss - const item: Partial = { + const item: Partial = { title: "Breaking: Major Tech Company Announces New Product", link: "https://www.reddit.com/r/news/comments/18b9xyz/breaking_major_tech_company/", description: ` @@ -81,7 +81,7 @@ describe("Comment Link Extraction Integration", () => { pubDate: "Mon, 04 Dec 2023 18:00:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe( "https://www.reddit.com/r/news/comments/18b9xyz/breaking_major_tech_company/" @@ -89,7 +89,7 @@ describe("Comment Link Extraction Integration", () => { }); it("should extract from Reddit self-post", () => { - const item: Partial = { + const item: Partial = { title: "AMA: I'm a software developer", link: "https://www.reddit.com/r/IAmA/comments/18c5abc/ama_im_a_software_developer/", description: ` @@ -108,7 +108,7 @@ describe("Comment Link Extraction Integration", () => { pubDate: "Mon, 04 Dec 2023 19:00:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe( "https://www.reddit.com/r/IAmA/comments/18c5abc/ama_im_a_software_developer/" @@ -116,7 +116,7 @@ describe("Comment Link Extraction Integration", () => { }); it("should extract from Reddit post with image", () => { - const item: Partial = { + const item: Partial = { title: "Check out this cool photo", link: "https://www.reddit.com/r/pics/comments/18d7def/check_out_this_cool_photo/", description: ` @@ -138,7 +138,7 @@ describe("Comment Link Extraction Integration", () => { pubDate: "Mon, 04 Dec 2023 20:00:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe( "https://www.reddit.com/r/pics/comments/18d7def/check_out_this_cool_photo/" @@ -148,7 +148,7 @@ describe("Comment Link Extraction Integration", () => { describe("Atom feeds with comment links", () => { it("should extract from Atom feed with replies link", () => { - const item: Partial = { + const item: Partial = { title: "Blog Post About Web Development", links: [ { @@ -164,7 +164,7 @@ describe("Comment Link Extraction Integration", () => { published: "2023-12-04T21:00:00Z", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe( "https://blog.example.com/posts/web-dev-2023#comments" @@ -172,7 +172,7 @@ describe("Comment Link Extraction Integration", () => { }); it("should extract from Atom feed with comments link", () => { - const item: Partial = { + const item: Partial = { title: "Technical Article", links: [ { href: "https://tech.example.com/article", rel: "alternate" }, @@ -182,7 +182,7 @@ describe("Comment Link Extraction Integration", () => { published: "2023-12-04T22:00:00Z", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe("https://tech.example.com/article/discuss"); }); @@ -190,7 +190,7 @@ describe("Comment Link Extraction Integration", () => { describe("WordPress RSS feeds", () => { it("should extract from WordPress post with comments element", () => { - const item: Partial = { + const item: Partial = { title: "WordPress Blog Post", link: "https://myblog.com/2023/12/04/new-post/", comments: "https://myblog.com/2023/12/04/new-post/#comments", @@ -198,13 +198,13 @@ describe("Comment Link Extraction Integration", () => { pubDate: "Mon, 04 Dec 2023 23:00:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe("https://myblog.com/2023/12/04/new-post/#comments"); }); it("should extract from WordPress with comment count in description", () => { - const item: Partial = { + const item: Partial = { title: "Popular Blog Post", link: "https://blog.example.com/popular-post/", comments: "https://blog.example.com/popular-post/#respond", @@ -213,7 +213,7 @@ describe("Comment Link Extraction Integration", () => { pubDate: "Tue, 05 Dec 2023 00:00:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); // Should use RSS comments element (priority 10) not HTML pattern (priority 30) expect(result).toBe("https://blog.example.com/popular-post/#respond"); @@ -222,7 +222,7 @@ describe("Comment Link Extraction Integration", () => { describe("Priority order", () => { it("should prefer RSS comments element over Atom links", () => { - const item: Partial = { + const item: Partial = { title: "Item with multiple comment indicators", comments: "https://example.com/rss-comments", links: [ @@ -231,28 +231,28 @@ describe("Comment Link Extraction Integration", () => { ], }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); // RSS element (priority 10) beats Atom link (priority 20) expect(result).toBe("https://example.com/rss-comments"); }); it("should prefer RSS comments element over HTML patterns", () => { - const item: Partial = { + const item: Partial = { title: "Item with RSS and HTML comment links", comments: "https://example.com/rss-comments", description: '

Check out [comments]

', }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); // RSS element (priority 10) beats HTML pattern (priority 30) expect(result).toBe("https://example.com/rss-comments"); }); it("should prefer Atom links over HTML patterns", () => { - const item: Partial = { + const item: Partial = { title: "Item with Atom and HTML comment links", links: [ { href: "https://example.com/article", rel: "alternate" }, @@ -262,14 +262,14 @@ describe("Comment Link Extraction Integration", () => { '

Discussion at Comments

', }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); // Atom link (priority 20) beats HTML pattern (priority 30) expect(result).toBe("https://example.com/atom-comments"); }); it("should fall back to Atom when RSS comments is empty", () => { - const item: Partial = { + const item: Partial = { title: "Fallback test", comments: "", // Empty RSS comments links: [ @@ -278,19 +278,19 @@ describe("Comment Link Extraction Integration", () => { ], }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe("https://example.com/atom-fallback"); }); it("should fall back to HTML pattern when structured data unavailable", () => { - const item: Partial = { + const item: Partial = { title: "HTML pattern fallback", description: '

Read the discussion

', }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe("https://example.com/html-only"); }); @@ -298,41 +298,41 @@ describe("Comment Link Extraction Integration", () => { describe("Edge cases", () => { it("should return null for item with no comment indicators", () => { - const item: Partial = { + const item: Partial = { title: "Regular Article", link: "https://example.com/article", description: "

Just a regular article with no comments.

", pubDate: "Tue, 05 Dec 2023 01:00:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBeNull(); }); it("should handle minimal feed item", () => { - const item: Partial = { + const item: Partial = { title: "Minimal Item", link: "https://example.com/minimal", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBeNull(); }); it("should handle feed item with only title", () => { - const item: Partial = { + const item: Partial = { title: "Title Only", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBeNull(); }); it("should handle empty object", () => { - const item = {} as any as FeedItem; + const item = {} as any as ParsedFeedItem; const result = extractCommentLink(item); @@ -341,7 +341,7 @@ describe("Comment Link Extraction Integration", () => { it("should handle complex Reddit post with multiple patterns", () => { // Real-world scenario with nested HTML and multiple potential matches - const item: Partial = { + const item: Partial = { title: "TIL: Interesting Fact", link: "https://www.reddit.com/r/todayilearned/comments/abc123/", description: ` @@ -365,7 +365,7 @@ describe("Comment Link Extraction Integration", () => { pubDate: "Tue, 05 Dec 2023 02:00:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe( "https://www.reddit.com/r/todayilearned/comments/abc123/" @@ -373,7 +373,7 @@ describe("Comment Link Extraction Integration", () => { }); it("should handle HN item with HTML entities in description", () => { - const item: Partial = { + const item: Partial = { title: "Article About C++ & Rust", link: "https://example.com/cpp-rust", comments: "https://news.ycombinator.com/item?id=99999", @@ -382,7 +382,7 @@ describe("Comment Link Extraction Integration", () => { pubDate: "Tue, 05 Dec 2023 03:00:00 GMT", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe("https://news.ycombinator.com/item?id=99999"); }); @@ -391,7 +391,7 @@ describe("Comment Link Extraction Integration", () => { describe("Real-world mixed scenarios", () => { it("should handle hybrid feed with mixed standards", () => { // Some feeds mix RSS and Atom elements - const item: Partial = { + const item: Partial = { title: "Hybrid Feed Item", link: "https://hybrid.example.com/post", comments: "https://hybrid.example.com/post#comments", // RSS style @@ -403,14 +403,14 @@ describe("Comment Link Extraction Integration", () => { 'Discuss', // HTML pattern }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); // RSS element should win expect(result).toBe("https://hybrid.example.com/post#comments"); }); it("should handle feed with multiple comment link formats in description", () => { - const item: Partial = { + const item: Partial = { title: "Multiple Comment Links", description: `
@@ -421,32 +421,32 @@ describe("Comment Link Extraction Integration", () => { `, }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); // Should find first matching pattern ([comments]) expect(result).toBe("https://example.com/comments"); }); it("should handle international URLs", () => { - const item: Partial = { + const item: Partial = { title: "International Article", comments: "https://新闻.example.com/评论/123", description: "Article with international domain.", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe("https://新闻.example.com/评论/123"); }); it("should handle fragment identifiers and query parameters", () => { - const item: Partial = { + const item: Partial = { title: "Complex URL", comments: "https://example.com/article?id=123&sort=new#comment-section", description: "Article with complex comment URL.", }; - const result = extractCommentLink(item as any as FeedItem); + const result = extractCommentLink(item as any as ParsedFeedItem); expect(result).toBe( "https://example.com/article?id=123&sort=new#comment-section" diff --git a/packages/api/src/services/comment-link-extraction/registry.test.ts b/packages/api/src/services/comment-link-extraction/registry.test.ts index 49dbff65..fd6d5998 100644 --- a/packages/api/src/services/comment-link-extraction/registry.test.ts +++ b/packages/api/src/services/comment-link-extraction/registry.test.ts @@ -9,18 +9,18 @@ import { CommentLinkRegistry } from "./registry"; import type { CommentLinkExtractor, ExtractedCommentLink, - FeedItem, + ParsedFeedItem, } from "./types"; // Mock extractors for testing class HighPriorityExtractor implements CommentLinkExtractor { readonly priority = 10; - canHandle(_item: FeedItem): boolean { + canHandle(_item: ParsedFeedItem): boolean { return "highPriority" in _item; } - extract(_item: FeedItem): ExtractedCommentLink | null { + extract(_item: ParsedFeedItem): ExtractedCommentLink | null { if ("highPriority" in _item) { return { url: "https://high-priority.com/comments", @@ -34,11 +34,11 @@ class HighPriorityExtractor implements CommentLinkExtractor { class MediumPriorityExtractor implements CommentLinkExtractor { readonly priority = 20; - canHandle(_item: FeedItem): boolean { + canHandle(_item: ParsedFeedItem): boolean { return "mediumPriority" in _item; } - extract(_item: FeedItem): ExtractedCommentLink | null { + extract(_item: ParsedFeedItem): ExtractedCommentLink | null { if ("mediumPriority" in _item) { return { url: "https://medium-priority.com/comments", @@ -52,11 +52,11 @@ class MediumPriorityExtractor implements CommentLinkExtractor { class LowPriorityExtractor implements CommentLinkExtractor { readonly priority = 30; - canHandle(_item: FeedItem): boolean { + canHandle(_item: ParsedFeedItem): boolean { return "lowPriority" in _item; } - extract(_item: FeedItem): ExtractedCommentLink | null { + extract(_item: ParsedFeedItem): ExtractedCommentLink | null { if ("lowPriority" in _item) { return { url: "https://low-priority.com/comments", @@ -70,11 +70,11 @@ class LowPriorityExtractor implements CommentLinkExtractor { class AlwaysMatchExtractor implements CommentLinkExtractor { readonly priority = 40; - canHandle(_item: FeedItem): boolean { + canHandle(_item: ParsedFeedItem): boolean { return true; } - extract(_item: FeedItem): ExtractedCommentLink | null { + extract(_item: ParsedFeedItem): ExtractedCommentLink | null { return { url: "https://always-match.com/comments", source: "url-pattern", @@ -94,7 +94,7 @@ describe("CommentLinkRegistry", () => { const extractor = new HighPriorityExtractor(); registry.register(extractor); - const item = { highPriority: true } as unknown as FeedItem; + const item = { highPriority: true } as unknown as ParsedFeedItem; const result = registry.extract(item); expect(result).toBe("https://high-priority.com/comments"); @@ -105,7 +105,7 @@ describe("CommentLinkRegistry", () => { registry.register(new MediumPriorityExtractor()); registry.register(new LowPriorityExtractor()); - const item = { lowPriority: true } as unknown as FeedItem; + const item = { lowPriority: true } as unknown as ParsedFeedItem; const result = registry.extract(item); expect(result).toBe("https://low-priority.com/comments"); @@ -122,7 +122,7 @@ describe("CommentLinkRegistry", () => { highPriority: true, mediumPriority: true, lowPriority: true, - } as unknown as FeedItem; + } as unknown as ParsedFeedItem; const result = registry.extract(item); @@ -142,7 +142,7 @@ describe("CommentLinkRegistry", () => { const item = { mediumPriority: true, lowPriority: true, - } as unknown as FeedItem; + } as unknown as ParsedFeedItem; const result = registry.extract(item); @@ -151,28 +151,28 @@ describe("CommentLinkRegistry", () => { }); it("should return first match found", () => { - const item = { highPriority: true } as unknown as FeedItem; + const item = { highPriority: true } as unknown as ParsedFeedItem; const result = registry.extract(item); expect(result).toBe("https://high-priority.com/comments"); }); it("should skip extractors that cannot handle item", () => { - const item = { lowPriority: true } as unknown as FeedItem; + const item = { lowPriority: true } as unknown as ParsedFeedItem; const result = registry.extract(item); expect(result).toBe("https://low-priority.com/comments"); }); it("should return null when no extractors can handle item", () => { - const item = { unknown: true } as unknown as FeedItem; + const item = { unknown: true } as unknown as ParsedFeedItem; const result = registry.extract(item); expect(result).toBeNull(); }); it("should return null when extractor returns null", () => { - const item = { title: "Test" } as FeedItem; + const item = { title: "Test" } as ParsedFeedItem; const result = registry.extract(item); expect(result).toBeNull(); @@ -185,7 +185,7 @@ describe("CommentLinkRegistry", () => { const item = { highPriority: true, mediumPriority: true, - } as unknown as FeedItem; + } as unknown as ParsedFeedItem; const result = registry.extract(item); @@ -210,7 +210,7 @@ describe("CommentLinkRegistry", () => { highPriority: true, mediumPriority: true, lowPriority: true, - } as unknown as FeedItem; + } as unknown as ParsedFeedItem; const result = registry.extract(item); @@ -221,20 +221,20 @@ describe("CommentLinkRegistry", () => { it("should handle extractors with same priority (stable sort)", () => { class FirstExtractor implements CommentLinkExtractor { readonly priority = 10; - canHandle(_item: FeedItem): boolean { + canHandle(_item: ParsedFeedItem): boolean { return true; } - extract(_item: FeedItem): ExtractedCommentLink | null { + extract(_item: ParsedFeedItem): ExtractedCommentLink | null { return { url: "https://first.com", source: "rss-comments-element" }; } } class SecondExtractor implements CommentLinkExtractor { readonly priority = 10; - canHandle(_item: FeedItem): boolean { + canHandle(_item: ParsedFeedItem): boolean { return true; } - extract(_item: FeedItem): ExtractedCommentLink | null { + extract(_item: ParsedFeedItem): ExtractedCommentLink | null { return { url: "https://second.com", source: "atom-link" }; } } @@ -242,7 +242,7 @@ describe("CommentLinkRegistry", () => { registry.register(new FirstExtractor()); registry.register(new SecondExtractor()); - const item = { title: "Test" } as FeedItem; + const item = { title: "Test" } as ParsedFeedItem; const result = registry.extract(item); // Should use first registered extractor when priorities are equal @@ -252,7 +252,7 @@ describe("CommentLinkRegistry", () => { describe("edge cases", () => { it("should handle empty registry", () => { - const item = { title: "Test" } as FeedItem; + const item = { title: "Test" } as ParsedFeedItem; const result = registry.extract(item); expect(result).toBeNull(); @@ -261,10 +261,10 @@ describe("CommentLinkRegistry", () => { it("should handle extractor throwing error gracefully", () => { class ErrorExtractor implements CommentLinkExtractor { readonly priority = 10; - canHandle(_item: FeedItem): boolean { + canHandle(_item: ParsedFeedItem): boolean { return true; } - extract(_item: FeedItem): ExtractedCommentLink | null { + extract(_item: ParsedFeedItem): ExtractedCommentLink | null { throw new Error("Extractor error"); } } @@ -272,7 +272,7 @@ describe("CommentLinkRegistry", () => { registry.register(new ErrorExtractor()); registry.register(new AlwaysMatchExtractor()); - const item = { title: "Test" } as FeedItem; + const item = { title: "Test" } as ParsedFeedItem; // Should catch error and continue to next extractor const result = registry.extract(item); @@ -284,17 +284,17 @@ describe("CommentLinkRegistry", () => { it("should handle canHandle returning false for all extractors", () => { class NeverMatchExtractor implements CommentLinkExtractor { readonly priority = 10; - canHandle(_item: FeedItem): boolean { + canHandle(_item: ParsedFeedItem): boolean { return false; } - extract(_item: FeedItem): ExtractedCommentLink | null { + extract(_item: ParsedFeedItem): ExtractedCommentLink | null { return { url: "https://never.com", source: "html-pattern" }; } } registry.register(new NeverMatchExtractor()); - const item = { title: "Test" } as FeedItem; + const item = { title: "Test" } as ParsedFeedItem; const result = registry.extract(item); expect(result).toBeNull(); diff --git a/packages/api/src/services/comment-link-extraction/registry.ts b/packages/api/src/services/comment-link-extraction/registry.ts index 045e755d..a1fa3de1 100644 --- a/packages/api/src/services/comment-link-extraction/registry.ts +++ b/packages/api/src/services/comment-link-extraction/registry.ts @@ -5,8 +5,8 @@ * Extractors are executed in priority order (lower priority = higher priority). */ -import * as Sentry from "@/utils/sentry"; -import type { CommentLinkExtractor, FeedItem } from "./types"; +import * as Sentry from "@api/utils/sentry"; +import type { CommentLinkExtractor, ParsedFeedItem } from "./types"; /** * Comment Link Extraction Registry @@ -37,7 +37,7 @@ export class CommentLinkRegistry { * @param item - Feed item to extract from * @returns Extracted comment link URL, or null if none found */ - extract(item: FeedItem): string | null { + extract(item: ParsedFeedItem): string | null { const itemTitle = "title" in item ? (item.title as string) : "Unknown"; // Try each extractor in priority order diff --git a/packages/api/src/services/comment-link-extraction/rss-element-extractor.test.ts b/packages/api/src/services/comment-link-extraction/rss-element-extractor.test.ts index bdcfe761..53b20b47 100644 --- a/packages/api/src/services/comment-link-extraction/rss-element-extractor.test.ts +++ b/packages/api/src/services/comment-link-extraction/rss-element-extractor.test.ts @@ -7,7 +7,7 @@ import { describe, it, expect } from "vitest"; import { RssElementExtractor } from "./rss-element-extractor"; -import type { FeedItem } from "./types"; +import type { ParsedFeedItem } from "./types"; describe("RssElementExtractor", () => { const extractor = new RssElementExtractor(); @@ -20,48 +20,48 @@ describe("RssElementExtractor", () => { describe("canHandle", () => { it("should return true when item has comments field", () => { - const item: Partial = { + const item: Partial = { comments: "https://news.ycombinator.com/item?id=12345", }; - expect(extractor.canHandle(item as any as FeedItem)).toBe(true); + expect(extractor.canHandle(item as any as ParsedFeedItem)).toBe(true); }); it("should return false when item has no comments field", () => { - const item: Partial = { + const item: Partial = { title: "Test Article", link: "https://example.com/article", }; - expect(extractor.canHandle(item as any as FeedItem)).toBe(false); + expect(extractor.canHandle(item as any as ParsedFeedItem)).toBe(false); }); it("should return false when comments field is empty", () => { - const item: Partial = { + const item: Partial = { comments: "", }; - expect(extractor.canHandle(item as any as FeedItem)).toBe(false); + expect(extractor.canHandle(item as any as ParsedFeedItem)).toBe(false); }); it("should return false when comments field is not a string", () => { const item = { comments: 12345, }; - expect(extractor.canHandle(item as unknown as any as FeedItem)).toBe( - false - ); + expect( + extractor.canHandle(item as unknown as any as ParsedFeedItem) + ).toBe(false); }); }); describe("extract", () => { it("should extract comment URL from Hacker News style feed item", () => { // Based on actual HN RSS feed schema - const item: Partial = { + const item: Partial = { title: "Show HN: My new project", link: "https://example.com/project", comments: "https://news.ycombinator.com/item?id=12345", description: "Check out this cool project I built", }; - const result = extractor.extract(item as any as FeedItem); + const result = extractor.extract(item as any as ParsedFeedItem); expect(result).toEqual({ url: "https://news.ycombinator.com/item?id=12345", @@ -70,14 +70,14 @@ describe("RssElementExtractor", () => { }); it("should extract comment URL from WordPress style feed item", () => { - const item: Partial = { + const item: Partial = { title: "Blog Post Title", link: "https://blog.example.com/post", comments: "https://blog.example.com/post#comments", description: "Post content here", }; - const result = extractor.extract(item as any as FeedItem); + const result = extractor.extract(item as any as ParsedFeedItem); expect(result).toEqual({ url: "https://blog.example.com/post#comments", @@ -86,30 +86,30 @@ describe("RssElementExtractor", () => { }); it("should return null when no comments field exists", () => { - const item: Partial = { + const item: Partial = { title: "Article without comments", link: "https://example.com/article", }; - const result = extractor.extract(item as any as FeedItem); + const result = extractor.extract(item as any as ParsedFeedItem); expect(result).toBeNull(); }); it("should return null when comments field is empty", () => { - const item: Partial = { + const item: Partial = { title: "Article with empty comments", link: "https://example.com/article", comments: "", }; - const result = extractor.extract(item as any as FeedItem); + const result = extractor.extract(item as any as ParsedFeedItem); expect(result).toBeNull(); }); it("should handle feed items with various additional fields", () => { - const item: Partial = { + const item: Partial = { title: "Complex Feed Item", link: "https://example.com/article", comments: "https://example.com/comments", @@ -117,7 +117,7 @@ describe("RssElementExtractor", () => { description: "

Article content

", }; - const result = extractor.extract(item as any as FeedItem); + const result = extractor.extract(item as any as ParsedFeedItem); expect(result).toEqual({ url: "https://example.com/comments", diff --git a/packages/api/src/services/comment-link-extraction/rss-element-extractor.ts b/packages/api/src/services/comment-link-extraction/rss-element-extractor.ts index 901fb592..b3810b63 100644 --- a/packages/api/src/services/comment-link-extraction/rss-element-extractor.ts +++ b/packages/api/src/services/comment-link-extraction/rss-element-extractor.ts @@ -8,7 +8,7 @@ import type { CommentLinkExtractor, ExtractedCommentLink, - FeedItem, + ParsedFeedItem, } from "./types"; /** @@ -19,7 +19,7 @@ import type { export class RssElementExtractor implements CommentLinkExtractor { readonly priority = 10; // Highest priority - explicit element - canHandle(item: FeedItem): boolean { + canHandle(item: ParsedFeedItem): boolean { return ( "comments" in item && typeof item.comments === "string" && @@ -27,7 +27,7 @@ export class RssElementExtractor implements CommentLinkExtractor { ); } - extract(item: FeedItem): ExtractedCommentLink | null { + extract(item: ParsedFeedItem): ExtractedCommentLink | null { if ("comments" in item && item.comments) { return { url: item.comments, diff --git a/packages/api/src/services/comment-link-extraction/types.ts b/packages/api/src/services/comment-link-extraction/types.ts index e7ab746f..f9b0dfed 100644 --- a/packages/api/src/services/comment-link-extraction/types.ts +++ b/packages/api/src/services/comment-link-extraction/types.ts @@ -4,16 +4,8 @@ * Types and interfaces for the extensible comment link extraction system. */ -import type { Rss, Atom, Rdf, Json } from "feedsmith/types"; - -/** - * Union type representing any feed item from supported feed formats - */ -export type FeedItem = - | Rss.Item - | Atom.Entry - | Rdf.Item - | Json.Item; +import type { ParsedFeedItem } from "@api/types/feed"; +export type { ParsedFeedItem } from "@api/types/feed"; /** * Extracted comment link result @@ -38,7 +30,7 @@ export interface CommentLinkExtractor { * @param item - The feed item to check * @returns True if this extractor can handle the item */ - canHandle(item: FeedItem): boolean; + canHandle(item: ParsedFeedItem): boolean; /** * Extract comment link from the given feed item. @@ -46,7 +38,7 @@ export interface CommentLinkExtractor { * @param item - The feed item to extract from * @returns Extracted comment link, or null if none found */ - extract(item: FeedItem): ExtractedCommentLink | null; + extract(item: ParsedFeedItem): ExtractedCommentLink | null; /** * Execution priority (lower = higher priority). diff --git a/packages/api/src/services/email-templates/layout.tsx b/packages/api/src/services/email-templates/layout.tsx index 25417c8e..3b4cf706 100644 --- a/packages/api/src/services/email-templates/layout.tsx +++ b/packages/api/src/services/email-templates/layout.tsx @@ -10,7 +10,7 @@ import { Section, Tailwind, Text, -} from "@react-email/components"; +} from "react-email"; import * as React from "react"; interface EmailLayoutProps { diff --git a/packages/api/src/services/email-templates/password-reset.tsx b/packages/api/src/services/email-templates/password-reset.tsx index a8fbb489..b5c490f7 100644 --- a/packages/api/src/services/email-templates/password-reset.tsx +++ b/packages/api/src/services/email-templates/password-reset.tsx @@ -1,4 +1,4 @@ -import { Button, Heading, Section, Text } from "@react-email/components"; +import { Button, Heading, Section, Text } from "react-email"; import * as React from "react"; import { EmailLayout } from "./layout"; diff --git a/packages/api/src/services/email-templates/verification.tsx b/packages/api/src/services/email-templates/verification.tsx index 7ab1e26c..c37a615e 100644 --- a/packages/api/src/services/email-templates/verification.tsx +++ b/packages/api/src/services/email-templates/verification.tsx @@ -1,4 +1,4 @@ -import { Button, Heading, Section, Text } from "@react-email/components"; +import { Button, Heading, Section, Text } from "react-email"; import * as React from "react"; import { EmailLayout } from "./layout"; diff --git a/packages/api/src/services/email-templates/welcome.tsx b/packages/api/src/services/email-templates/welcome.tsx index d3dd7cb7..a78c2172 100644 --- a/packages/api/src/services/email-templates/welcome.tsx +++ b/packages/api/src/services/email-templates/welcome.tsx @@ -1,4 +1,4 @@ -import { Button, Heading, Link, Section, Text } from "@react-email/components"; +import { Button, Heading, Link, Section, Text } from "react-email"; import * as React from "react"; import { EmailLayout } from "./layout"; diff --git a/packages/api/src/services/email.ts b/packages/api/src/services/email.ts index 7582ac42..21bc2bce 100644 --- a/packages/api/src/services/email.ts +++ b/packages/api/src/services/email.ts @@ -13,15 +13,15 @@ */ import { Resend } from "resend"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; import { PasswordResetEmail, WelcomeEmail, VerificationEmail, } from "./email-templates"; import type React from "react"; -import * as Sentry from "@/utils/sentry"; -import { emitCounter, withTiming } from "@/utils/metrics"; +import * as Sentry from "@api/utils/sentry"; +import { emitCounter, withTiming } from "@api/utils/metrics"; // ============================================================================ // TYPES diff --git a/packages/api/src/services/favicon-fetcher.ts b/packages/api/src/services/favicon-fetcher.ts index a6067576..e9dc7dcc 100644 --- a/packages/api/src/services/favicon-fetcher.ts +++ b/packages/api/src/services/favicon-fetcher.ts @@ -1,11 +1,12 @@ +import { safeFetch } from "@api/utils/safe-fetch"; /** * Favicon Fetcher Service * * Discovers and fetches favicons from multiple sources with fallback strategies. */ -import { emitCounter, withTiming } from "@/utils/metrics"; -import { extractDomain } from "@/utils/domain-checker"; +import { emitCounter, withTiming } from "@api/utils/metrics"; +import { extractDomain } from "@api/utils/domain-checker"; // Maximum icon size: 2MB const MAX_ICON_SIZE = 2 * 1024 * 1024; @@ -133,7 +134,7 @@ async function isValidIcon(iconUrl: string): Promise { const timeout = setTimeout(() => controller.abort(), FETCH_TIMEOUT); try { - const response = await fetch(iconUrl, { + const response = await safeFetch(iconUrl, { method: "HEAD", signal: controller.signal, headers: { diff --git a/packages/api/src/services/feed-discovery/apple-discovery.ts b/packages/api/src/services/feed-discovery/apple-discovery.ts index 07b83d8f..06074ca7 100644 --- a/packages/api/src/services/feed-discovery/apple-discovery.ts +++ b/packages/api/src/services/feed-discovery/apple-discovery.ts @@ -1,3 +1,4 @@ +import { safeFetch } from "@api/utils/safe-fetch"; /** * Apple Podcast Discovery Service * @@ -5,8 +6,8 @@ * to look up podcast metadata and extract the RSS feed URL. */ -import * as Sentry from "@/utils/sentry"; -import { isSubdomainOf } from "@/utils/domain-matcher"; +import * as Sentry from "@api/utils/sentry"; +import { isSubdomainOf } from "@api/utils/domain-matcher"; import type { DiscoveryContext, DiscoveryService, @@ -118,7 +119,7 @@ export class AppleDiscoveryService implements DiscoveryService { // Call iTunes Search API const apiUrl = `https://itunes.apple.com/lookup?id=${podcastId}&entity=podcast`; - const response = await fetch(apiUrl, { + const response = await safeFetch(apiUrl, { headers: { "User-Agent": "TuvixRSS/1.0", }, diff --git a/packages/api/src/services/feed-discovery/feed-validator.ts b/packages/api/src/services/feed-discovery/feed-validator.ts index 7a7a1f6c..1ac9724e 100644 --- a/packages/api/src/services/feed-discovery/feed-validator.ts +++ b/packages/api/src/services/feed-discovery/feed-validator.ts @@ -1,3 +1,5 @@ +import { readFeedResponse } from "@tuvixrss/tricorder"; +import { safeFetch } from "@api/utils/safe-fetch"; /** * Feed Validator Utility * @@ -6,8 +8,8 @@ */ import { parseFeed } from "feedsmith"; -import { normalizeFeedUrl } from "@/utils/url-normalize"; -import { stripHtml } from "@/utils/text-sanitizer"; +import { normalizeFeedUrl } from "@api/utils/url-normalize"; +import { extractFeedMetadata } from "@tuvixrss/tricorder"; import type { DiscoveredFeed } from "./types"; /** @@ -23,7 +25,7 @@ export function createFeedValidator( ): (feedUrl: string) => Promise { return async (feedUrl: string): Promise => { try { - const response = await fetch(feedUrl, { + const response = await safeFetch(feedUrl, { headers: { "User-Agent": "TuvixRSS/1.0", Accept: @@ -44,7 +46,7 @@ export function createFeedValidator( // Mark URL as seen immediately to prevent race conditions with parallel checks seenUrls.add(normalizedUrl); - const feedContent = await response.text(); + const feedContent = await readFeedResponse(response); const result = parseFeed(feedContent); const feed = result.feed; @@ -77,14 +79,9 @@ export function createFeedValidator( ? "json" : "rss"; - const title = - "title" in feed && feed.title ? String(feed.title) : "Untitled Feed"; - const description = - "description" in feed && feed.description - ? stripHtml(String(feed.description)) - : "subtitle" in feed && feed.subtitle - ? stripHtml(String(feed.subtitle)) - : undefined; + const metadata = extractFeedMetadata(feed); + const title = metadata.title || "Untitled Feed"; + const description = metadata.description; // Return discovered feed (use original feedUrl, not final redirected URL) return { diff --git a/packages/api/src/services/feed-discovery/registry.ts b/packages/api/src/services/feed-discovery/registry.ts index c239d3ed..c9ff15d3 100644 --- a/packages/api/src/services/feed-discovery/registry.ts +++ b/packages/api/src/services/feed-discovery/registry.ts @@ -5,7 +5,7 @@ * Services are executed in priority order (lower priority = higher priority). */ -import * as Sentry from "@/utils/sentry"; +import * as Sentry from "@api/utils/sentry"; import { TRPCError } from "@trpc/server"; import { createFeedValidator } from "./feed-validator"; import type { diff --git a/packages/api/src/services/feed-discovery/standard-discovery.ts b/packages/api/src/services/feed-discovery/standard-discovery.ts index 206debca..c5770ea1 100644 --- a/packages/api/src/services/feed-discovery/standard-discovery.ts +++ b/packages/api/src/services/feed-discovery/standard-discovery.ts @@ -1,3 +1,5 @@ +import { readFeedResponse } from "@tuvixrss/tricorder"; +import { safeFetch } from "@api/utils/safe-fetch"; /** * Standard URL-Based Discovery Service * @@ -7,7 +9,7 @@ * - HTML link tag parsing */ -import * as Sentry from "@/utils/sentry"; +import * as Sentry from "@api/utils/sentry"; import type { DiscoveryContext, DiscoveryService, @@ -150,7 +152,7 @@ export class StandardDiscoveryService implements DiscoveryService { // Step 2: Fetch HTML and parse for feed links try { - const response = await fetch(url, { + const response = await safeFetch(url, { headers: { "User-Agent": "TuvixRSS/1.0", Accept: "text/html,application/xhtml+xml", @@ -161,7 +163,7 @@ export class StandardDiscoveryService implements DiscoveryService { span.setAttribute("html_fetch_status", response.status); if (response.ok) { - const html = await response.text(); + const html = await readFeedResponse(response); span.setAttribute("html_size", html.length); // Parse for RSS/Atom link tags using regex diff --git a/packages/api/src/services/feed-discovery/types.ts b/packages/api/src/services/feed-discovery/types.ts index 69089e7f..f0697c50 100644 --- a/packages/api/src/services/feed-discovery/types.ts +++ b/packages/api/src/services/feed-discovery/types.ts @@ -4,7 +4,7 @@ * Types and interfaces for the extensible feed discovery system. */ -import type { DiscoveredFeed } from "@/types/feed"; +import type { DiscoveredFeed } from "@api/types/feed"; /** * Context shared across discovery services during a single discovery request. @@ -50,4 +50,4 @@ export interface DiscoveryService { priority: number; } -export type { DiscoveredFeed } from "@/types/feed"; +export type { DiscoveredFeed } from "@api/types/feed"; diff --git a/packages/api/src/services/feed-health.ts b/packages/api/src/services/feed-health.ts new file mode 100644 index 00000000..0ff4033b --- /dev/null +++ b/packages/api/src/services/feed-health.ts @@ -0,0 +1,62 @@ +import { and, eq, isNull, lt, or, sql } from "drizzle-orm"; +import type { Database } from "@api/db/client"; +import { feedFetchHealth } from "@api/db/schema"; +import * as Sentry from "@api/utils/sentry"; + +/** Alert on sustained ingestion failures/growing backlog; throttle across workers. */ +export async function recordFeedBatchHealth( + db: Database, + batch: { + backlog: number; + errors: number; + added: number; + processed: number; + } +): Promise { + if (batch.processed === 0) return; + const stalled = batch.errors > 0 && batch.added === 0; + const [health] = await db + .insert(feedFetchHealth) + .values({ + id: 1, + backlog: batch.backlog, + failingBatches: stalled ? 1 : 0, + }) + .onConflictDoUpdate({ + target: feedFetchHealth.id, + set: { + backlog: batch.backlog, + failingBatches: stalled + ? sql`${feedFetchHealth.failingBatches} + 1` + : 0, + growingBatches: sql`CASE WHEN ${batch.backlog} > ${feedFetchHealth.backlog} THEN ${feedFetchHealth.growingBatches} + 1 ELSE 0 END`, + }, + }) + .returning(); + if (!health || (health.failingBatches < 3 && health.growingBatches < 3)) + return; + const now = new Date(); + const claimed = await db + .update(feedFetchHealth) + .set({ lastAlertAt: now }) + .where( + and( + eq(feedFetchHealth.id, 1), + or( + isNull(feedFetchHealth.lastAlertAt), + lt(feedFetchHealth.lastAlertAt, new Date(now.getTime() - 30 * 60_000)) + ) + ) + ) + .returning(); + if (!claimed.length) return; + Sentry.captureMessage("RSS ingestion is stalled or falling behind", { + level: "error", + tags: { operation: "rss_ingestion_health" }, + extra: { + ...batch, + failing_batches: health.failingBatches, + growing_batches: health.growingBatches, + }, + }); +} diff --git a/packages/api/src/services/global-settings.ts b/packages/api/src/services/global-settings.ts index 074a6998..24fa51cd 100644 --- a/packages/api/src/services/global-settings.ts +++ b/packages/api/src/services/global-settings.ts @@ -8,12 +8,11 @@ import type { DrizzleD1Database } from "drizzle-orm/d1"; import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; import { eq } from "drizzle-orm"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; // Generic database type that works with both D1 and better-sqlite3 type Database = - | DrizzleD1Database - | BetterSQLite3Database; + DrizzleD1Database | BetterSQLite3Database; /** * Global settings type diff --git a/packages/api/src/services/limits.ts b/packages/api/src/services/limits.ts index 610d7edd..91d9f299 100644 --- a/packages/api/src/services/limits.ts +++ b/packages/api/src/services/limits.ts @@ -11,12 +11,11 @@ import type { DrizzleD1Database } from "drizzle-orm/d1"; import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; import { eq, and, inArray } from "drizzle-orm"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; // Generic database type that works with both D1 and better-sqlite3 type Database = - | DrizzleD1Database - | BetterSQLite3Database; + DrizzleD1Database | BetterSQLite3Database; // ============================================================================ // TYPES @@ -476,7 +475,7 @@ export async function checkAiFeatureAccess( env: { OPENAI_API_KEY?: string } ): Promise<{ allowed: boolean; reason?: string }> { // 1. Check global setting - const { getGlobalSettings } = await import("@/services/global-settings"); + const { getGlobalSettings } = await import("@api/services/global-settings"); const globalSettings = await getGlobalSettings(db); if (!globalSettings.aiEnabled) { diff --git a/packages/api/src/services/plans.ts b/packages/api/src/services/plans.ts index c89c6cf2..c4f99eec 100644 --- a/packages/api/src/services/plans.ts +++ b/packages/api/src/services/plans.ts @@ -1,5 +1,5 @@ -import type { Database } from "@/db/client"; -import * as schema from "@/db/schema"; +import type { Database } from "@api/db/client"; +import * as schema from "@api/db/schema"; import { eq, asc } from "drizzle-orm"; /** diff --git a/packages/api/src/services/public-feed.ts b/packages/api/src/services/public-feed.ts new file mode 100644 index 00000000..7f2994e6 --- /dev/null +++ b/packages/api/src/services/public-feed.ts @@ -0,0 +1,133 @@ +import { TRPCError } from "@trpc/server"; +import { and, desc, eq, sql } from "drizzle-orm"; +import * as schema from "@api/db/schema"; +import type { Context } from "@api/trpc/context"; +import { fetchSubscriptionFilters } from "@api/db/transformers"; +import { matchesSubscriptionFilters } from "./article-filters"; +import { getUserLimits } from "./limits"; +import { checkPublicFeedRateLimit } from "./rate-limiter"; +import { generateRSS } from "./xml-generator"; + +/** Both HTTP and tRPC use this path, including limits, filters and access logs. */ +export async function generatePublicFeed( + ctx: Context, + input: { username: string; slug: string } +): Promise { + const [user] = await ctx.db + .select() + .from(schema.user) + .where(eq(schema.user.username, input.username)) + .limit(1); + if (!user) + throw new TRPCError({ code: "NOT_FOUND", message: "User not found" }); + const [feed] = await ctx.db + .select() + .from(schema.feeds) + .where( + and( + eq(schema.feeds.userId, user.id), + eq(schema.feeds.slug, input.slug), + eq(schema.feeds.public, true) + ) + ) + .limit(1); + if (!feed) + throw new TRPCError({ code: "NOT_FOUND", message: "Feed not found" }); + + const limits = await getUserLimits(ctx.db, user.id); + const limit = await checkPublicFeedRateLimit( + ctx.env, + user.id, + user.plan ?? "free", + limits.publicFeedRateLimitPerMinute + ); + if (!limit.allowed) + throw new TRPCError({ + code: "TOO_MANY_REQUESTS", + message: "Rate limit exceeded", + }); + + const categoryCondition = sql`(NOT EXISTS (SELECT 1 FROM feed_categories WHERE feed_id = ${feed.id}) + OR EXISTS (SELECT 1 FROM subscription_categories sc + JOIN feed_categories fc ON fc.category_id = sc.category_id + WHERE fc.feed_id = ${feed.id} AND sc.subscription_id = ${schema.subscriptions.id}))`; + const subscriptions = await ctx.db + .select() + .from(schema.subscriptions) + .where(and(eq(schema.subscriptions.userId, user.id), categoryCondition)); + const bySource = new Map( + subscriptions.map((subscription) => [subscription.sourceId, subscription]) + ); + const filters = await fetchSubscriptionFilters( + ctx.db, + subscriptions.filter((s) => s.filterEnabled).map((s) => s.id) + ); + const articles: (typeof schema.articles.$inferSelect)[] = []; + let offset = 0; + while (subscriptions.length > 0 && articles.length < 50) { + const rows = await ctx.db + .select() + .from(schema.articles) + .innerJoin( + schema.subscriptions, + and( + eq(schema.subscriptions.sourceId, schema.articles.sourceId), + eq(schema.subscriptions.userId, user.id) + ) + ) + .where(categoryCondition) + .orderBy(desc(schema.articles.publishedAt), desc(schema.articles.id)) + .limit(200) + .offset(offset); + for (const { articles: article } of rows) { + const subscription = bySource.get(article.sourceId); + if ( + subscription && + (!subscription.filterEnabled || + matchesSubscriptionFilters( + article, + filters.get(subscription.id) ?? [], + subscription.filterMode + )) + ) { + articles.push(article); + if (articles.length === 50) break; + } + } + if (rows.length < 200) break; + offset += rows.length; + } + const baseUrl = ( + ctx.env.API_URL || + ctx.env.BETTER_AUTH_URL || + "http://localhost:3001" + ).replace(/\/$/, ""); + const feedUrl = `${baseUrl}/public/${encodeURIComponent(input.username)}/${encodeURIComponent(input.slug)}`; + const xml = generateRSS({ + title: feed.title, + link: feedUrl, + description: feed.description || feed.title, + items: articles.map((article) => ({ + title: article.title, + link: article.link || feedUrl, + description: article.description, + author: article.author, + pubDate: article.publishedAt, + guid: article.guid, + })), + }); + try { + await ctx.db.insert(schema.publicFeedAccessLog).values({ + feedId: feed.id, + ipAddress: + ctx.headers["cf-connecting-ip"] || + ctx.headers["x-forwarded-for"]?.split(",")[0] || + "unknown", + userAgent: ctx.headers["user-agent"] || null, + accessedAt: new Date(), + }); + } catch (error) { + console.error("Failed to log feed access:", error); + } + return xml; +} diff --git a/packages/api/src/services/rate-limiter.ts b/packages/api/src/services/rate-limiter.ts index 5468f9c2..86b8450a 100644 --- a/packages/api/src/services/rate-limiter.ts +++ b/packages/api/src/services/rate-limiter.ts @@ -7,7 +7,7 @@ * Rate limiting is disabled for Docker Compose deployments. */ -import type { Env } from "@/types"; +import type { Env } from "@api/types"; // ============================================================================ // TYPES diff --git a/packages/api/src/services/rss-fetcher.ts b/packages/api/src/services/rss-fetcher.ts index 95aedd81..e35f52a1 100644 --- a/packages/api/src/services/rss-fetcher.ts +++ b/packages/api/src/services/rss-fetcher.ts @@ -1,3 +1,7 @@ +import { recordFeedBatchHealth } from "./feed-health"; +import { readFeedResponse } from "@tuvixrss/tricorder"; +import type { ParsedFeed, ParsedFeedItem } from "@api/types/feed"; +import { safeFetch } from "@api/utils/safe-fetch"; /** * RSS Fetcher Service * @@ -5,27 +9,27 @@ * Supports automatic format detection and handles multiple feed formats. */ -import * as Sentry from "@/utils/sentry"; +import * as Sentry from "@api/utils/sentry"; import { parseFeed } from "feedsmith"; -import type { Rss, Atom, Rdf, Json } from "@/types/feed"; -import type { Database } from "@/db/client"; -import * as schema from "@/db/schema"; -import { and, eq, inArray, or, isNull, lt } from "drizzle-orm"; -import { extractOgImage } from "@/utils/og-image-fetcher"; +import type { Database } from "@api/db/client"; +import * as schema from "@api/db/schema"; +import { and, eq, inArray, or, isNull, lt, lte, gt } from "drizzle-orm"; +import { extractOgImage } from "@api/utils/og-image-fetcher"; import { sanitizeHtml, stripHtml, truncateText, truncateHtml, -} from "@/utils/text-sanitizer"; +} from "@api/utils/text-sanitizer"; import { extractDomain, isDomainBlocked, getBlockedDomains, -} from "@/utils/domain-checker"; -import { chunkArray, D1_MAX_PARAMETERS, supportsBatch } from "@/db/utils"; -import { emitCounter, emitGauge, withTiming } from "@/utils/metrics"; -import { extractItunesImage } from "@/utils/feed-utils"; +} from "@api/utils/domain-checker"; +import { chunkArray, D1_MAX_PARAMETERS } from "@api/db/utils"; +import { emitCounter, emitGauge, withTiming } from "@api/utils/metrics"; +import { extractItunesImage, extractFeedItems } from "@api/utils/feed-utils"; +import { extractFeedMetadata, feedText } from "@tuvixrss/tricorder"; import { extractCommentLink } from "./comment-link-extraction"; // ============================================================================= @@ -48,7 +52,7 @@ const PROCESSING_DELAYS = { /** Limits for content processing and batching */ const LIMITS = { - batchInsertChunkSize: 50, // Articles per batch insert + batchInsertChunkSize: 7, // 13 bound columns per row; stay below D1's 100 parameters contentMaxBytes: 500000, // 500KB max for article content descriptionMaxChars: 5000, // Max chars for article description } as const; @@ -81,6 +85,7 @@ export interface FetchResult { * Result from fetchSingleFeed operation */ export interface FetchSingleResult { + outcome: "fetched" | "leased" | "blocked"; /** Number of new articles added to database */ articlesAdded: number; /** Number of articles skipped (already exist or invalid) */ @@ -89,18 +94,6 @@ export interface FetchSingleResult { sourceUpdated: boolean; } -// Union types for feeds and items (feedsmith returns dates as strings, not Date objects) -type AnyFeed = - | Rss.Feed - | Atom.Feed - | Rdf.Feed - | Json.Feed; -type AnyItem = - | Rss.Item - | Atom.Entry - | Rdf.Item - | Json.Item; - // ============================================================================= // Query Helpers // ============================================================================= @@ -109,9 +102,24 @@ type AnyItem = * Build WHERE clause for staleness filtering */ function buildStalenessWhereClause(staleThreshold: Date) { - return or( - isNull(schema.sources.lastFetched), // Never fetched - lt(schema.sources.lastFetched, staleThreshold) // Older than threshold + const now = new Date(); + return and( + or( + isNull(schema.sources.fetchLeaseUntil), + lte(schema.sources.fetchLeaseUntil, now) + ), + or( + isNull(schema.sources.nextFetchAt), + lte(schema.sources.nextFetchAt, now) + ), + or( + isNull(schema.sources.lastFetched), + lt(schema.sources.lastFetched, staleThreshold) + ), + or( + isNull(schema.sources.lastFetchAttemptAt), + lt(schema.sources.lastFetchAttemptAt, staleThreshold) + ) ); } @@ -127,7 +135,7 @@ async function getStaleSources( .select() .from(schema.sources) .where(buildStalenessWhereClause(staleThreshold)) - .orderBy(schema.sources.lastFetched) + .orderBy(schema.sources.lastFetchAttemptAt, schema.sources.id) .limit(limit); } @@ -193,7 +201,7 @@ export async function fetchAllFeeds( const [sources, totalSources, totalStaleFeeds, blockedDomainsList] = await Promise.all([ // Get sources that are "stale" (not fetched recently) - // Ordered by lastFetched (oldest first, null first) + // Ordered by last attempt (oldest first, null first) // This ensures we rotate through all feeds over time // IMPORTANT: Use .limit() server-side to avoid loading all feeds into memory getStaleSources(db, staleThreshold, maxFeedsPerBatch), @@ -206,6 +214,8 @@ export async function fetchAllFeeds( ]); let successCount = 0; + let articlesAdded = 0; + let skippedLeases = 0; let errorCount = 0; const errors: Array<{ sourceId: number; url: string; error: string }> = []; @@ -225,8 +235,23 @@ export async function fetchAllFeeds( source.id, source.url, db, - blockedDomainsList + blockedDomainsList, + { staleThreshold, intervalMinutes: stalenessThresholdMinutes } ); + if (result.outcome === "leased") { + skippedLeases++; + continue; + } + if (result.outcome === "blocked") { + errorCount++; + errors.push({ + sourceId: source.id, + url: source.url, + error: "Domain blocked", + }); + continue; + } + articlesAdded += result.articlesAdded; console.log( `✓ Fetched ${source.url}: ${result.articlesAdded} new, ${result.articlesSkipped} skipped` ); @@ -263,6 +288,12 @@ export async function fetchAllFeeds( `Fetch complete: ${successCount} succeeded, ${errorCount} failed out of ${sources.length} (batch ${sources.length}/${totalSources})` ); + await recordFeedBatchHealth(db, { + backlog: totalStaleFeeds, + errors: errorCount, + added: articlesAdded, + processed: sources.length - skippedLeases, + }); // Emit aggregate metrics emitCounter("rss.batch_completed", 1, { success_count: successCount.toString(), @@ -274,7 +305,7 @@ export async function fetchAllFeeds( return { successCount, errorCount, - processedCount: sources.length, + processedCount: sources.length - skippedLeases, errors, }; }, @@ -291,7 +322,8 @@ export async function fetchSingleFeed( sourceId: number, feedUrl: string, db: Database, - blockedDomainsList?: Awaited> + blockedDomainsList?: Awaited>, + scheduling?: { staleThreshold: Date; intervalMinutes: number } ): Promise { return await Sentry.startSpan( { @@ -304,6 +336,60 @@ export async function fetchSingleFeed( }, }, async (span) => { + const token = crypto.randomUUID(); + const now = new Date(); + const intervalMs = + (scheduling?.intervalMinutes ?? STALENESS_DEFAULTS.thresholdMinutes) * + 60_000; + const [claimed] = await db + .update(schema.sources) + .set({ + fetchLeaseToken: token, + fetchLeaseUntil: new Date(now.getTime() + 2 * 60_000), + lastFetchAttemptAt: now, + nextFetchAt: new Date(now.getTime() + intervalMs), + }) + .where( + and( + eq(schema.sources.id, sourceId), + or( + isNull(schema.sources.fetchLeaseUntil), + lte(schema.sources.fetchLeaseUntil, now) + ), + scheduling + ? buildStalenessWhereClause(scheduling.staleThreshold) + : undefined + ) + ) + .returning(); + if (!claimed) + return { + outcome: "leased", + articlesAdded: 0, + articlesSkipped: 0, + sourceUpdated: false, + }; + let failureReason = "Feed could not be downloaded."; + const ownedSource = and( + eq(schema.sources.id, sourceId), + eq(schema.sources.fetchLeaseToken, token) + ); + let renewAt = Date.now() + 30_000; + const renewLease = async (force = false) => { + if (!force && Date.now() < renewAt) return; + const renewed = await db + .update(schema.sources) + .set({ + fetchLeaseUntil: new Date(Date.now() + 2 * 60_000), + }) + .where( + and(ownedSource, gt(schema.sources.fetchLeaseUntil, new Date())) + ) + .returning(); + if (!renewed.length) + throw new Error("Feed fetch lease expired or ownership changed"); + renewAt = Date.now() + 30_000; + }; try { // 0. Check if domain is blocked (before fetching) // Note: This check happens at fetch-time to avoid wasting HTTP requests @@ -320,7 +406,15 @@ export async function fetchSingleFeed( console.log(`Skipping blocked domain: ${domain}`); span.setAttribute("domain_blocked", true); span.setStatus({ code: 1, message: "Domain blocked" }); + await db + .update(schema.sources) + .set({ + lastFetchError: "Domain blocked", + consecutiveFetchFailures: claimed.consecutiveFetchFailures + 1, + }) + .where(ownedSource); return { + outcome: "blocked", articlesAdded: 0, articlesSkipped: 0, sourceUpdated: false, @@ -336,7 +430,7 @@ export async function fetchSingleFeed( }); // 1. Fetch feed with timeout - const response = await fetch(feedUrl, { + const response = await safeFetch(feedUrl, { headers: { "User-Agent": FETCH_CONFIG.userAgent, Accept: FETCH_CONFIG.accept, @@ -351,6 +445,7 @@ export async function fetchSingleFeed( ); if (!response.ok) { + failureReason = `Publisher returned HTTP ${response.status}.`; span.setStatus({ code: 2, message: `HTTP ${response.status}` }); const error = new Error( `HTTP ${response.status}: ${response.statusText}` @@ -384,15 +479,18 @@ export async function fetchSingleFeed( span.setAttribute("unexpected_content_type", true); } - const feedContent = await response.text(); + failureReason = + "Feed response could not be read or exceeds the size limit."; + const feedContent = await readFeedResponse(response); + failureReason = "Feed content could not be parsed."; span.setAttribute("feed_content_size", feedContent.length); // 2. Parse feed using feedsmith (auto-detects format) - let feed: AnyFeed; + let feed: ParsedFeed; let feedFormat: string; try { const result = parseFeed(feedContent); - feed = result.feed as AnyFeed; + feed = result.feed; feedFormat = result.format; span.setAttribute("feed_format", feedFormat); console.log(`Parsed ${feedUrl} as ${feedFormat}`); @@ -424,17 +522,30 @@ export async function fetchSingleFeed( throw parseError; } - // 3. Update source metadata - const sourceUpdated = await updateSourceMetadata(sourceId, feed, db); - span.setAttribute("source_updated", sourceUpdated); - - // 4. Extract and store articles + failureReason = + "Articles could not all be stored. A retry is scheduled."; + // 3. Extract and store articles + await renewLease(true); const { articlesAdded, articlesSkipped } = await storeArticles( sourceId, feed, - db + db, + renewLease ); + // Only report a successful refresh after article processing completes. + await renewLease(true); + const sourceUpdated = await updateSourceMetadata( + sourceId, + feed, + db, + token + ); + await db + .update(schema.sources) + .set({ lastFetchError: null, consecutiveFetchFailures: 0 }) + .where(ownedSource); + span.setAttribute("source_updated", sourceUpdated); span.setAttribute("articles_added", articlesAdded); span.setAttribute("articles_skipped", articlesSkipped); span.setStatus({ code: 1, message: "ok" }); @@ -456,6 +567,7 @@ export async function fetchSingleFeed( } return { + outcome: "fetched", articlesAdded, articlesSkipped, sourceUpdated, @@ -469,8 +581,27 @@ export async function fetchSingleFeed( domain: extractDomain(feedUrl) || "unknown", }); - // Error already captured in specific places, re-throw + await db + .update(schema.sources) + .set({ + lastFetchError: failureReason, + consecutiveFetchFailures: claimed.consecutiveFetchFailures + 1, + nextFetchAt: new Date( + Date.now() + + Math.min( + 24 * 60 * 60_000, + intervalMs * + 2 ** Math.min(claimed.consecutiveFetchFailures, 10) + ) + ), + }) + .where(ownedSource); throw error; + } finally { + await db + .update(schema.sources) + .set({ fetchLeaseToken: null, fetchLeaseUntil: null }) + .where(ownedSource); } } ); @@ -485,35 +616,15 @@ export async function fetchSingleFeed( */ async function updateSourceMetadata( sourceId: number, - feed: AnyFeed, - db: Database + feed: ParsedFeed, + db: Database, + leaseToken: string ): Promise { const updates: Partial = { lastFetched: new Date(), }; - // Extract metadata (handle different feed formats) - if ("title" in feed && feed.title) { - updates.title = feed.title; - } - - if ("description" in feed && feed.description) { - updates.description = stripHtml(feed.description); - } else if ("subtitle" in feed && feed.subtitle) { - // Atom uses subtitle instead of description - updates.description = stripHtml(feed.subtitle); - } - - if ("link" in feed && feed.link) { - updates.siteUrl = feed.link; - } else if ( - "links" in feed && - Array.isArray(feed.links) && - feed.links[0]?.href - ) { - // Atom uses links array - updates.siteUrl = feed.links[0].href; - } + Object.assign(updates, extractFeedMetadata(feed)); // Extract icon URL from feed (for podcasts with iTunes image) // Priority: itunes:image > image.url > icon @@ -534,7 +645,12 @@ async function updateSourceMetadata( const currentSource = await db .select() .from(schema.sources) - .where(eq(schema.sources.id, sourceId)) + .where( + and( + eq(schema.sources.id, sourceId), + eq(schema.sources.fetchLeaseToken, leaseToken) + ) + ) .limit(1) .then((rows) => rows[0]); @@ -552,21 +668,21 @@ async function updateSourceMetadata( updates.iconUpdatedAt = new Date(); } - // Only update if we have something to update (beyond lastFetched) - if (Object.keys(updates).length > 1) { - await db - .update(schema.sources) - .set(updates) - .where(eq(schema.sources.id, sourceId)); - return true; - } - - // Just update lastFetched - await db + const metadataChanged = Object.keys(updates).length > 1; + const updated = await db .update(schema.sources) - .set({ lastFetched: new Date() }) - .where(eq(schema.sources.id, sourceId)); - return false; + .set(updates) + .where( + and( + eq(schema.sources.id, sourceId), + eq(schema.sources.fetchLeaseToken, leaseToken), + gt(schema.sources.fetchLeaseUntil, new Date()) + ) + ) + .returning(); + if (!updated.length) + throw new Error("Feed fetch lease expired before completion"); + return metadataChanged; } /** @@ -574,8 +690,9 @@ async function updateSourceMetadata( */ async function storeArticles( sourceId: number, - feed: AnyFeed, - db: Database + feed: ParsedFeed, + db: Database, + renewLease: () => Promise ): Promise<{ articlesAdded: number; articlesSkipped: number }> { return await Sentry.startSpan( { @@ -599,20 +716,30 @@ async function storeArticles( span.setAttribute("items_found", items.length); let articlesSkipped = 0; + let extractionFailures = 0; + const seenGuids = new Set(); const guidSamplesForLogging: string[] = []; // Step 1: Extract GUIDs from all items - const validItems: Array<{ item: AnyItem; guid: string }> = []; + const validItems: Array<{ item: ParsedFeedItem; guid: string }> = []; for (const item of items) { const guid = extractGuid(item, sourceId); if (!guid) { - console.warn("Skipping item without guid:", item.title || "Untitled"); - articlesSkipped++; + console.warn( + "Item has no usable identity:", + item.title || "Untitled" + ); + extractionFailures++; continue; } + if (seenGuids.has(guid)) { + articlesSkipped++; + continue; + } + seenGuids.add(guid); // Log first 5 GUIDs as breadcrumbs if (guidSamplesForLogging.length < 5) { guidSamplesForLogging.push(guid); @@ -621,6 +748,9 @@ async function storeArticles( validItems.push({ item, guid }); } + if (validItems.length === 0 && extractionFailures > 0) { + throw new Error("Feed articles have no usable identity"); + } if (validItems.length === 0) { span.setAttribute("articles_added", 0); span.setAttribute("articles_skipped", articlesSkipped); @@ -635,6 +765,7 @@ async function storeArticles( const existingGuids = new Set(); for (const chunk of guidChunks) { + await renewLease(); const existingArticles = await db .select() .from(schema.articles) @@ -680,68 +811,33 @@ async function storeArticles( item_title: "title" in item ? item.title : "Unknown", }, }); - articlesSkipped++; - // Continue with next article + extractionFailures++; + // Keep valid articles, but do not report this refresh as successful. } } - // Step 4: Batch insert all new articles + // Conflict handling is specific to feed identity. Other database errors + // propagate; partial earlier chunks are safe to retry on the next attempt. let articlesAdded = 0; - - if (newArticles.length > 0) { - // Split into chunks for batch insert (D1 batch API supports multiple statements) - const insertChunks = chunkArray( - newArticles, - LIMITS.batchInsertChunkSize + for (const chunk of chunkArray( + newArticles, + LIMITS.batchInsertChunkSize + )) { + await renewLease(); + const inserted = await db + .insert(schema.articles) + .values(chunk) + .onConflictDoNothing({ + target: [schema.articles.sourceId, schema.articles.guid], + }) + .returning(); + articlesAdded += inserted.length; + articlesSkipped += chunk.length - inserted.length; + } + if (extractionFailures > 0) { + throw new Error( + `Failed to process ${extractionFailures} feed articles (${articlesAdded} stored successfully)` ); - - for (const chunk of insertChunks) { - try { - // Use batch API if available (Cloudflare D1), otherwise insert sequentially - if (supportsBatch(db)) { - const statements = chunk.map((data) => - db.insert(schema.articles).values(data) - ); - // Type assertion needed: Drizzle's insert() returns PgInsertBase which doesn't match DatabaseWithBatch's expected type - // This is safe because D1's batch() accepts Drizzle insert statements - await db.batch( - statements as Array<{ execute: () => Promise }> - ); - articlesAdded += chunk.length; - } else { - // Fallback for better-sqlite3 (local dev) - for (const data of chunk) { - await db.insert(schema.articles).values(data); - articlesAdded++; - } - } - } catch (error) { - console.error("Failed to batch insert articles:", error); - Sentry.captureException(error, { - level: "warning", - tags: { - operation: "batch_insert_articles", - source_id: sourceId.toString(), - }, - extra: { - chunk_size: chunk.length, - }, - }); - // Try inserting one by one as fallback - for (const data of chunk) { - try { - await db.insert(schema.articles).values(data); - articlesAdded++; - } catch (insertError) { - console.error( - "Failed to insert individual article:", - insertError - ); - articlesSkipped++; - } - } - } - } } if (guidSamplesForLogging.length > 0) { @@ -767,27 +863,10 @@ async function storeArticles( ); } -/** - * Extract items/entries from feed (handles different formats) - */ -function extractFeedItems(feed: AnyFeed): AnyItem[] { - // RSS/RDF use 'items' - if ("items" in feed && Array.isArray(feed.items)) { - return feed.items; - } - - // Atom uses 'entries' - if ("entries" in feed && Array.isArray(feed.entries)) { - return feed.entries; - } - - return []; -} - /** * Extract GUID from feed item */ -function extractGuid(item: AnyItem, sourceId: number): string | null { +function extractGuid(item: ParsedFeedItem, sourceId: number): string | null { // RSS guid if ("guid" in item && item.guid) { return typeof item.guid === "string" ? item.guid : item.guid.value || null; @@ -812,10 +891,10 @@ function extractGuid(item: AnyItem, sourceId: number): string | null { if ("title" in item && item.title) { const pubDate = extractPublishedDate(item); if (pubDate) { - return `${sourceId}-${item.title}-${pubDate.getTime()}`; + return `${sourceId}-${feedText(item.title)}-${pubDate.getTime()}`; } // Without date, use title alone (not ideal but better than nothing) - return `${sourceId}-${item.title}`; + return `${sourceId}-${feedText(item.title)}`; } return null; @@ -824,7 +903,7 @@ function extractGuid(item: AnyItem, sourceId: number): string | null { /** * Extract article content from feed item */ -function extractArticleContent(item: AnyItem): string { +function extractArticleContent(item: ParsedFeedItem): string { let rawContent = ""; // JSON Feed @@ -866,14 +945,14 @@ function extractArticleContent(item: AnyItem): string { * @param processedContent - Already-processed content (stripped and truncated) */ function extractArticleDescription( - item: AnyItem, + item: ParsedFeedItem, processedContent: string ): string { let rawDescription = ""; if ("description" in item && typeof item.description === "string") { rawDescription = item.description; - } else if ("summary" in item && typeof item.summary === "string") { - rawDescription = item.summary; + } else if ("summary" in item && item.summary) { + rawDescription = feedText(item.summary) ?? ""; } else if ("contentSnippet" in item) { const snippet = (item as Record).contentSnippet; if (typeof snippet === "string") { @@ -949,13 +1028,14 @@ function extractArticleDescription( /** * Extract article author from feed item */ -function extractArticleAuthor(item: AnyItem): string | undefined { +function extractArticleAuthor(item: ParsedFeedItem): string | undefined { // RSS string author or Atom/JSON Feed author object if ("authors" in item && Array.isArray(item.authors) && item.authors[0]) { const firstAuthor = item.authors[0]; return typeof firstAuthor === "string" ? firstAuthor - : firstAuthor.name || undefined; + : firstAuthor.name || + ("email" in firstAuthor ? firstAuthor.email : undefined); } else if ("author" in item) { const itemAuthor = (item as Record).author; return typeof itemAuthor === "string" @@ -969,12 +1049,7 @@ function extractArticleAuthor(item: AnyItem): string | undefined { } // Dublin Core creator else if ("dc" in item) { - const dc = (item as Record).dc as - | { creator?: string | string[] } - | undefined; - if (dc?.creator) { - return Array.isArray(dc.creator) ? dc.creator[0] : dc.creator; - } + return item.dc?.creators?.[0]; } return undefined; @@ -984,7 +1059,7 @@ function extractArticleAuthor(item: AnyItem): string | undefined { * Extract article image URL from feed item */ async function extractArticleImage( - item: AnyItem, + item: ParsedFeedItem, link: string, skipOgImageFetch: boolean ): Promise { @@ -1085,7 +1160,7 @@ async function extractArticleImage( /** * Extract audio URL from feed item (for podcasts) */ -function extractArticleAudio(item: AnyItem): string | undefined { +function extractArticleAudio(item: ParsedFeedItem): string | undefined { if ("enclosures" in item && Array.isArray(item.enclosures)) { const audioEnclosure = item.enclosures.find((enc) => enc.type?.startsWith("audio/") @@ -1101,7 +1176,7 @@ function extractArticleAudio(item: AnyItem): string | undefined { * Extract published date from feed item * Note: feedsmith returns dates as strings, not Date objects */ -function extractPublishedDate(item: AnyItem): Date | null { +function extractPublishedDate(item: ParsedFeedItem): Date | null { // Try different date fields (all are strings from feedsmith parser) const dateFields = [ "pubDate", @@ -1136,13 +1211,13 @@ function extractPublishedDate(item: AnyItem): Date | null { * Orchestrates extraction of all article fields by delegating to focused helper functions. */ async function extractArticleData( - item: AnyItem, + item: ParsedFeedItem, sourceId: number, guid: string, skipOgImageFetch = false ): Promise { // Title - const title = ("title" in item && item.title) || "Untitled"; + const title = feedText(item.title) || "Untitled"; // Link - handle both RSS/JSON Feed (string) and Atom (links array) let link = ""; @@ -1157,7 +1232,9 @@ async function extractArticleData( item.links[0]?.href ) { // Atom uses links array - link = item.links[0].href; + link = + item.links.find((entry) => !entry.rel || entry.rel === "alternate") + ?.href ?? ""; } // Extract article fields using focused helpers @@ -1187,8 +1264,8 @@ async function extractArticleData( /** * Fetch and parse a feed without storing (for preview/discovery) */ -export async function fetchAndParseFeed(feedUrl: string): Promise { - const response = await fetch(feedUrl, { +export async function fetchAndParseFeed(feedUrl: string): Promise { + const response = await safeFetch(feedUrl, { headers: { "User-Agent": FETCH_CONFIG.userAgent, Accept: FETCH_CONFIG.accept, @@ -1200,8 +1277,8 @@ export async function fetchAndParseFeed(feedUrl: string): Promise { throw new Error(`HTTP ${response.status}: ${response.statusText}`); } - const feedContent = await response.text(); + const feedContent = await readFeedResponse(response); const { feed } = parseFeed(feedContent); - return feed as AnyFeed; + return feed as ParsedFeed; } diff --git a/packages/api/src/services/user-init.ts b/packages/api/src/services/user-init.ts index af8bbe11..2af0aea1 100644 --- a/packages/api/src/services/user-init.ts +++ b/packages/api/src/services/user-init.ts @@ -1,67 +1,39 @@ -/** - * User Initialization Service - * - * Handles atomic user initialization after Better Auth creates the user: - * - Set user role and plan - * - Create default user settings - * - Initialize usage stats - * - * Uses D1 batch for atomic operations when available. - */ +/** Shared initialization for every Better Auth user creation path. */ +import { eq, sql } from "drizzle-orm"; +import * as schema from "@api/db/schema"; +import { executeBatch } from "@api/db/utils"; +import { ADMIN_PLAN, DEFAULT_USER_PLAN } from "@api/config/plans"; +import type { Database } from "@api/db/client"; -import { eq } from "drizzle-orm"; -import * as schema from "@/db/schema"; -import { executeBatch } from "@/db/utils"; -import type { Database } from "@/db/client"; - -// ============================================================================ -// TYPES -// ============================================================================ - -export interface InitializeUserOptions { - role: "user" | "admin"; - plan: string; -} - -// ============================================================================ -// INITIALIZE NEW USER -// ============================================================================ - -/** - * Initialize a new user with role, settings, and usage stats. - * - * Uses D1 batch for atomic operations - all succeed or all fail together. - * On better-sqlite3 (tests/Docker), executes sequentially. - * - * @param db Database connection - * @param userId User ID (from Better Auth) - * @param options Role and plan to assign - * @throws Error if any initialization step fails - */ export async function initializeNewUser( db: Database, userId: number, - options: InitializeUserOptions + allowFirstUserAdmin: boolean ): Promise { - // Build all initialization statements - const roleUpdate = db - .update(schema.user) - .set({ role: options.role, plan: options.plan }) - .where(eq(schema.user.id, userId)); - - const settingsInsert = db.insert(schema.userSettings).values({ userId }); - - const usageInsert = db.insert(schema.usageStats).values({ - userId, - sourceCount: 0, - publicFeedCount: 0, - categoryCount: 0, - articleCount: 0, - lastUpdated: new Date(), - }); - - // Execute atomically via executeBatch - // D1: Uses db.batch() - all succeed or all roll back - // better-sqlite3: Executes sequentially - await executeBatch(db, [roleUpdate, settingsInsert, usageInsert]); + // The lowest database ID wins even when signups run concurrently. Existing + // accounts prevent a later signup from claiming a missing administrator role. + const isAdmin = sql`(${schema.user.role} = 'admin' OR (${Number(allowFirstUserAdmin)} AND ${schema.user.id} = (SELECT min(id) FROM user)))`; + try { + await executeBatch(db, [ + db + .update(schema.user) + .set({ + role: sql`CASE WHEN ${isAdmin} THEN 'admin' ELSE 'user' END`, + plan: sql`CASE WHEN ${isAdmin} THEN ${ADMIN_PLAN} ELSE ${DEFAULT_USER_PLAN} END`, + }) + .where(eq(schema.user.id, userId)), + db.insert(schema.userSettings).values({ userId }), + db.insert(schema.usageStats).values({ + userId, + sourceCount: 0, + publicFeedCount: 0, + categoryCount: 0, + articleCount: 0, + lastUpdated: new Date(), + }), + ]); + } catch (error) { + await db.delete(schema.user).where(eq(schema.user.id, userId)); + throw error; + } } diff --git a/packages/api/src/services/xml-generator.ts b/packages/api/src/services/xml-generator.ts index 10a71b4e..cb94c6c6 100644 --- a/packages/api/src/services/xml-generator.ts +++ b/packages/api/src/services/xml-generator.ts @@ -2,7 +2,7 @@ * RSS 2.0 XML Generator * * Uses feedsmith's native RSS generation. - * For full type safety, import Rss types from "@/types/feed" and use generateRssFeed directly. + * For full type safety, import Rss types from "@api/types/feed" and use generateRssFeed directly. * https://feedsmith.dev/generating/ */ @@ -82,7 +82,7 @@ export function generateRSS(input: RSSGeneratorInput): string { value: item.guid, isPermaLink: false, }, - authors: item.author ? [item.author] : undefined, + authors: item.author ? [{ name: item.author }] : undefined, })), }; diff --git a/packages/api/src/test/README.md b/packages/api/src/test/README.md index 9ab54da2..34546323 100644 --- a/packages/api/src/test/README.md +++ b/packages/api/src/test/README.md @@ -57,7 +57,7 @@ src/ ```typescript import { describe, it, expect, beforeEach, afterEach } from "vitest"; -import { createTestDb, cleanupTestDb, seedTestUser } from "@/test/setup"; +import { createTestDb, cleanupTestDb, seedTestUser } from "@api/test/setup"; import { someFunction } from "./your-module"; describe("someFunction", () => { @@ -95,7 +95,7 @@ import { cleanupTestDb, seedTestUser, seedTestPlan, -} from "@/test/setup"; +} from "@api/test/setup"; // Create in-memory test database const db = createTestDb(); @@ -114,7 +114,7 @@ cleanupTestDb(db); #### Helpers ```typescript -import { generateTestEmail, expectError, mockConsole } from "@/test/helpers"; +import { generateTestEmail, expectError, mockConsole } from "@api/test/helpers"; // Generate unique test data const email = generateTestEmail("mytest"); @@ -137,7 +137,7 @@ import { mockFetchRssFeed, MOCK_RSS_FEED, MOCK_BETTER_AUTH_SECRET, -} from "@/test/mocks"; +} from "@api/test/mocks"; // Mock fetch for RSS feeds global.fetch = mockFetchRssFeed(); diff --git a/packages/api/src/test/helpers.test.ts b/packages/api/src/test/helpers.test.ts new file mode 100644 index 00000000..71873685 --- /dev/null +++ b/packages/api/src/test/helpers.test.ts @@ -0,0 +1,21 @@ +import { expect, it } from "vitest"; +import { expectError } from "./helpers"; + +it("fails when the operation resolves instead of throwing", async () => { + await expect(expectError(async () => 42)).rejects.toThrow("but it did not"); +}); +it("returns the original matching error", async () => { + const error = new Error("expected failure"); + expect( + await expectError(async () => { + throw error; + }, /expected/) + ).toBe(error); +}); +it("rejects a mismatched error", async () => { + await expect( + expectError(async () => { + throw new Error("actual"); + }, "expected") + ).rejects.toThrow("Expected error message"); +}); diff --git a/packages/api/src/test/helpers.ts b/packages/api/src/test/helpers.ts index 550912b5..917f03ae 100644 --- a/packages/api/src/test/helpers.ts +++ b/packages/api/src/test/helpers.ts @@ -32,13 +32,12 @@ export function wait(ms: number): Promise { /** * Assert that an error was thrown */ -export async function expectError( - fn: () => Promise, +export async function expectError( + fn: () => Promise, expectedMessage?: string | RegExp ): Promise { try { await fn(); - throw new Error("Expected function to throw an error, but it did not"); } catch (error) { if (error instanceof Error) { if (expectedMessage) { @@ -60,6 +59,7 @@ export async function expectError( } throw new Error(`Expected Error instance, got ${typeof error}`); } + throw new Error("Expected function to throw an error, but it did not"); } /** @@ -80,7 +80,7 @@ export function createMockResponse( }); } -import type { Database } from "@/db/client"; +import type { Database } from "@api/db/client"; /** * Get count of records in a table diff --git a/packages/api/src/test/mocks.ts b/packages/api/src/test/mocks.ts index a1ea8c82..2288574a 100644 --- a/packages/api/src/test/mocks.ts +++ b/packages/api/src/test/mocks.ts @@ -201,3 +201,14 @@ export const MOCK_ADMIN = { role: "admin" as const, plan: "free", }; + +/** Real streamed response for feed/discovery tests, including a redirect URL. */ +export function createFeedResponse( + body: string, + url?: string, + headers: HeadersInit = { "content-type": "application/xml" } +): Response { + const response = new Response(body, { headers }); + if (url) Object.defineProperty(response, "url", { value: url }); + return response; +} diff --git a/packages/api/src/test/setup.ts b/packages/api/src/test/setup.ts index 27c9f05e..bc387bf1 100644 --- a/packages/api/src/test/setup.ts +++ b/packages/api/src/test/setup.ts @@ -9,11 +9,11 @@ import { drizzle } from "drizzle-orm/better-sqlite3"; import { migrate } from "drizzle-orm/better-sqlite3/migrator"; import { eq } from "drizzle-orm"; import type { BetterSQLite3Database } from "drizzle-orm/better-sqlite3"; -import * as schema from "@/db/schema"; +import * as schema from "@api/db/schema"; import bcrypt from "bcrypt"; import path from "path"; import { fileURLToPath } from "url"; -import type { Database as AppDatabase } from "@/db/client"; +import type { Database as AppDatabase } from "@api/db/client"; const __filename = fileURLToPath(import.meta.url); const __dirname = path.dirname(__filename); diff --git a/packages/api/src/trpc/__tests__/init.test.ts b/packages/api/src/trpc/__tests__/init.test.ts index a8d2b1a9..f377d100 100644 --- a/packages/api/src/trpc/__tests__/init.test.ts +++ b/packages/api/src/trpc/__tests__/init.test.ts @@ -16,13 +16,13 @@ import { } from "vitest"; import { router, publicProcedure, rateLimitedProcedure } from "../init"; import { TRPCError } from "@trpc/server"; -import { createTestDb, seedTestUser, cleanupTestDb } from "@/test/setup"; +import { createTestDb, seedTestUser, cleanupTestDb } from "@api/test/setup"; import { createContext } from "../context"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; // Mock Better Auth // Set up default mock that returns empty auth (no session) -vi.mock("@/auth/better-auth", () => { +vi.mock("@api/auth/better-auth", () => { const mockCreateAuth = vi.fn(() => ({ api: { getSession: vi.fn().mockResolvedValue({ data: null }), @@ -34,7 +34,7 @@ vi.mock("@/auth/better-auth", () => { }); // Mock database client -vi.mock("@/db/client", () => ({ +vi.mock("@api/db/client", () => ({ createDatabase: vi.fn(), })); @@ -51,7 +51,7 @@ afterAll(() => { beforeEach(async () => { // Set default mock return value for all tests - const { createDatabase } = await import("@/db/client"); + const { createDatabase } = await import("@api/db/client"); vi.mocked(createDatabase).mockReturnValue(globalTestDb as any); }); @@ -115,7 +115,7 @@ describe("rateLimitedProcedure", () => { } as Env; // Mock createDatabase to return our test db - const { createDatabase } = await import("@/db/client"); + const { createDatabase } = await import("@api/db/client"); vi.mocked(createDatabase).mockReturnValue(db as any); }); @@ -155,7 +155,7 @@ describe("rateLimitedProcedure", () => { }; // Override the default mock to return our test user session - const authModule = await import("@/auth/better-auth"); + const authModule = await import("@api/auth/better-auth"); const createAuthMock = vi.mocked(authModule.createAuth); // Better Auth's getSession returns the session object directly (with user property) diff --git a/packages/api/src/trpc/context.ts b/packages/api/src/trpc/context.ts index c62b6ded..e4803816 100644 --- a/packages/api/src/trpc/context.ts +++ b/packages/api/src/trpc/context.ts @@ -8,13 +8,13 @@ import type { Context as HonoContext } from "hono"; import { fromNodeHeaders } from "better-auth/node"; -import { createDatabase } from "@/db/client"; -import { createAuth } from "@/auth/better-auth"; -import type { AuthUser } from "@/types"; -import type { BetterAuthUser } from "@/types/better-auth"; -import type { UserLimits } from "@/services/limits"; -import type * as schema from "@/db/schema"; -import type { Variables } from "@/hono/app"; +import { createDatabase } from "@api/db/client"; +import { createAuth } from "@api/auth/better-auth"; +import type { AuthUser } from "@api/types"; +import type { BetterAuthUser } from "@api/types/better-auth"; +import type { UserLimits } from "@api/services/limits"; +import type * as schema from "@api/db/schema"; +import type { Variables } from "@api/hono/app"; /** * Request-scoped cache to prevent N+1 queries @@ -35,7 +35,8 @@ export interface RequestCache { * - Request metadata from Hono context */ export const createContext = async ( - c: HonoContext<{ Variables: Variables }> + c: HonoContext<{ Variables: Variables }>, + responseHeaders?: Headers ) => { const env = c.get("env"); const req = c.req.raw; @@ -44,7 +45,7 @@ export const createContext = async ( const db = createDatabase(env); // Get Better Auth instance - const auth = createAuth(env); + const auth = createAuth(env, db); // Extract and verify Better Auth session (if present) let user: AuthUser | null = null; @@ -113,7 +114,11 @@ export const createContext = async ( headers, req, cache, + responseHeaders, }; }; -export type Context = Awaited>; +export type Context = Omit< + Awaited>, + "responseHeaders" +> & { responseHeaders?: Headers }; diff --git a/packages/api/src/trpc/init.ts b/packages/api/src/trpc/init.ts index f19a0a90..fdbfe5a8 100644 --- a/packages/api/src/trpc/init.ts +++ b/packages/api/src/trpc/init.ts @@ -7,11 +7,11 @@ import { initTRPC, TRPCError } from "@trpc/server"; import { eq } from "drizzle-orm"; import superjson from "superjson"; -import * as schema from "@/db/schema"; -import { checkLimit, getUserLimits } from "@/services/limits"; -import { checkApiRateLimit } from "@/services/rate-limiter"; -import { getGlobalSettings } from "@/services/global-settings"; -import * as Sentry from "@/utils/sentry"; +import * as schema from "@api/db/schema"; +import { checkLimit, getUserLimits } from "@api/services/limits"; +import { checkApiRateLimit } from "@api/services/rate-limiter"; +import { getGlobalSettings } from "@api/services/global-settings"; +import * as Sentry from "@api/utils/sentry"; import type { Context } from "./context"; // Initialize tRPC with context and SuperJSON transformer @@ -60,7 +60,7 @@ export const router = t.router; * Creates spans and improves error capturing for tRPC handlers * See: https://docs.sentry.io/platforms/javascript/guides/cloudflare/configuration/integrations/trpc * - * Uses build-time aliased @/utils/sentry which resolves to: + * Uses build-time aliased @api/utils/sentry which resolves to: * - @sentry/cloudflare in Workers * - @sentry/node in Node.js * - noop in tests @@ -70,7 +70,7 @@ const baseProcedure = (() => { if (typeof Sentry.trpcMiddleware === "function") { const sentryMiddleware = t.middleware( Sentry.trpcMiddleware({ - attachRpcInput: true, // Include RPC input in spans and error context + attachRpcInput: false, // Include RPC input in spans and error context }) ); return t.procedure.use(sentryMiddleware); @@ -160,16 +160,19 @@ const isAuthed = t.middleware(async ({ ctx, next }) => { }); } - // Check email verification requirement (admin users bypass this check) - if (ctx.user.role !== "admin") { - const settings = await getGlobalSettings(ctx.db); - if (settings.requireEmailVerification && !userRecord.emailVerified) { - throw new TRPCError({ - code: "FORBIDDEN", - message: - "Email verification required. Please check your email for a verification link.", - }); - } + const settings = await getGlobalSettings(ctx.db); + const verificationBypass = + userRecord.role === "admin" && settings.adminBypassEmailVerification; + if ( + settings.requireEmailVerification && + !userRecord.emailVerified && + !verificationBypass + ) { + throw new TRPCError({ + code: "FORBIDDEN", + message: + "Email verification required. Please check your email for a verification link.", + }); } // Update lastSeenAt (throttled to once every 5 minutes) @@ -328,7 +331,7 @@ const isAdmin = t.middleware(async ({ ctx, next }) => { } // Check admin role from Better Auth session - if (ctx.user.role !== "admin") { + if (userRecord.role !== "admin") { throw new TRPCError({ code: "FORBIDDEN", message: "Admin access required", diff --git a/packages/api/src/trpc/router.ts b/packages/api/src/trpc/router.ts index edcb7949..41f79fdb 100644 --- a/packages/api/src/trpc/router.ts +++ b/packages/api/src/trpc/router.ts @@ -6,14 +6,14 @@ */ import { router } from "./init"; -import { authRouter } from "@/routers/auth"; -import { articlesRouter } from "@/routers/articles"; -import { subscriptionsRouter } from "@/routers/subscriptions"; -import { categoriesRouter } from "@/routers/categories"; -import { feedsRouter } from "@/routers/feeds"; -import { userSettingsRouter } from "@/routers/userSettings"; -import { adminRouter } from "@/routers/admin"; -import { plansRouter } from "@/routers/plans"; +import { authRouter } from "@api/routers/auth"; +import { articlesRouter } from "@api/routers/articles"; +import { subscriptionsRouter } from "@api/routers/subscriptions"; +import { categoriesRouter } from "@api/routers/categories"; +import { feedsRouter } from "@api/routers/feeds"; +import { userSettingsRouter } from "@api/routers/userSettings"; +import { adminRouter } from "@api/routers/admin"; +import { plansRouter } from "@api/routers/plans"; export const appRouter = router({ auth: authRouter, diff --git a/packages/api/src/types/better-auth.ts b/packages/api/src/types/better-auth.ts index be7407a8..d38740df 100644 --- a/packages/api/src/types/better-auth.ts +++ b/packages/api/src/types/better-auth.ts @@ -5,10 +5,10 @@ * Plugins (username, admin, customSession) automatically extend these types. * * These types are extracted from the Auth type returned by createAuth(). - * Import Auth from @/auth/better-auth and use these helper types. + * Import Auth from @api/auth/better-auth and use these helper types. */ -import type { Auth } from "@/auth/better-auth"; +import type { Auth } from "@api/auth/better-auth"; /** * Helper type to extract $Infer types from Auth instance diff --git a/packages/api/src/types/feed.ts b/packages/api/src/types/feed.ts index 0adef1c7..992811f1 100644 --- a/packages/api/src/types/feed.ts +++ b/packages/api/src/types/feed.ts @@ -1,3 +1,5 @@ +import type { AnyFeed } from "feedsmith"; + /** * Feed Type Definitions for TuvixRSS * @@ -5,7 +7,7 @@ * Use the modern namespace types for full type safety and access to all feed components. */ -export type { Rss, Atom, Rdf, Json, Opml } from "feedsmith/types"; +export type { RssFeed, AtomFeed, RdfFeed, JsonFeed, Opml } from "feedsmith"; /** * Feed discovered from a website URL during autodiscovery @@ -18,3 +20,9 @@ export interface DiscoveredFeed { /** Platform-specific high-quality icon URL (e.g., iTunes artwork, Reddit community icon) */ iconUrl?: string; } + +export type ParsedFeed = AnyFeed["feed"]; + +export type ParsedFeedItem = + | NonNullable["items"]>[number] + | NonNullable["entries"]>[number]; diff --git a/packages/api/src/types/index.ts b/packages/api/src/types/index.ts index 8fd2b27d..ccbe6435 100644 --- a/packages/api/src/types/index.ts +++ b/packages/api/src/types/index.ts @@ -6,7 +6,7 @@ * * @example * ```ts - * import { selectUserSchema, insertUserSchema } from '@/types'; + * import { selectUserSchema, insertUserSchema } from '@api/types'; * * // Use schemas for validation * const user = selectUserSchema.parse(data); @@ -16,8 +16,9 @@ * ``` */ +import type { D1Database } from "@cloudflare/workers-types"; import { z } from "zod"; -import * as dbSchemas from "@/db/schemas.zod"; +import * as dbSchemas from "@api/db/schemas.zod"; // ============================================================================ // DATABASE SCHEMAS - Auto-generated from Drizzle @@ -62,7 +63,7 @@ export { selectFeedSchema, insertFeedSchema, updateFeedSchema, -} from "@/db/schemas.zod"; +} from "@api/db/schemas.zod"; // ============================================================================ // CUSTOM VALIDATORS & APPLICATION TYPES @@ -114,6 +115,8 @@ export interface Env { RATE_LIMIT_DEBUG?: string; // "true" or "false" - enable debug logging for rate limits // Optional Services + OPENAI_API_KEY?: string; + TRUST_PROXY_HEADERS?: string; RESEND_API_KEY?: string; EMAIL_FROM?: string; BASE_URL?: string; // Frontend URL for redirects after verification (e.g., https://feed.tuvix.app) diff --git a/packages/api/src/types/pagination.ts b/packages/api/src/types/pagination.ts index c5665678..28028b9e 100644 --- a/packages/api/src/types/pagination.ts +++ b/packages/api/src/types/pagination.ts @@ -49,7 +49,7 @@ export const paginationInputSchema = z.object({ limit: z.number().int().min(1).max(100).default(50), offset: z.number().int().min(0).default(0), // Cursor-based pagination: cumulative count of items fetched (used as offset for infinite scroll) - cursor: z.number().int().optional(), + cursor: z.number().int().min(0).optional(), }); /** @@ -63,7 +63,11 @@ export const paginationInputSchema = z.object({ * ``` */ export const withUndefinedAsEmpty = (schema: T) => - z.preprocess((val) => (val === undefined ? {} : val), schema); + schema + .optional() + .transform((value): z.output => + value === undefined ? schema.parse({}) : value + ); /** * Infer TypeScript type from pagination input @@ -155,3 +159,10 @@ export function calculatePaginationMeta( itemsPerPage: limit, }; } + +/** Stable article ordering, including feeds with no publication date. */ +export const articleCursorSchema = z.object({ + publishedAt: z.date().nullable(), + id: z.number().int().positive(), +}); +export type ArticleCursor = z.infer; diff --git a/packages/api/src/utils/__tests__/base-url.test.ts b/packages/api/src/utils/__tests__/base-url.test.ts index bef5ca45..7f002710 100644 --- a/packages/api/src/utils/__tests__/base-url.test.ts +++ b/packages/api/src/utils/__tests__/base-url.test.ts @@ -6,7 +6,7 @@ import { describe, it, expect } from "vitest"; import { getBaseUrl } from "../base-url"; -import type { Env } from "@/types"; +import type { Env } from "@api/types"; describe("getBaseUrl", () => { it("should use BASE_URL from environment if set", () => { diff --git a/packages/api/src/utils/__tests__/domain-checker.test.ts b/packages/api/src/utils/__tests__/domain-checker.test.ts index 87a8a77d..f4ff4b44 100644 --- a/packages/api/src/utils/__tests__/domain-checker.test.ts +++ b/packages/api/src/utils/__tests__/domain-checker.test.ts @@ -12,8 +12,8 @@ import { getBlockedDomainReason, getBlockedDomains, } from "../domain-checker"; -import { createTestDb, cleanupTestDb, seedTestUser } from "@/test/setup"; -import * as schema from "@/db/schema"; +import { createTestDb, cleanupTestDb, seedTestUser } from "@api/test/setup"; +import * as schema from "@api/db/schema"; describe("extractDomain", () => { it("should extract domain from HTTP URL", () => { diff --git a/packages/api/src/utils/__tests__/feed-utils.test.ts b/packages/api/src/utils/__tests__/feed-utils.test.ts new file mode 100644 index 00000000..3ae18ceb --- /dev/null +++ b/packages/api/src/utils/__tests__/feed-utils.test.ts @@ -0,0 +1,64 @@ +import { expect, it } from "vitest"; +import { parseFeed } from "feedsmith"; +import { extractFeedMetadata } from "@tuvixrss/tricorder"; + +it("preserves the JSON Feed home page and sanitizes its description", () => { + const { feed } = parseFeed( + JSON.stringify({ + version: "https://jsonfeed.org/version/1.1", + title: "News", + home_page_url: "https://example.com", + description: "Latest news", + items: [], + }) + ); + expect(extractFeedMetadata(feed)).toEqual({ + title: "News", + siteUrl: "https://example.com", + description: "Latest news", + }); +}); + +it("uses an Atom alternate link instead of its self link", () => { + const { feed } = parseFeed( + 'News' + ); + expect(extractFeedMetadata(feed).siteUrl).toBe("https://example.com"); +}); + +it("extracts Atom text constructs without stringifying objects", () => { + const { feed } = parseFeed( + 'Atom News<b>Latest</b> stories' + ); + expect(extractFeedMetadata(feed)).toMatchObject({ + title: "Atom News", + description: "Latest stories", + }); +}); + +it.each([ + [ + 'NewsTechStoryTech', + 2, + ], + [ + 'NewsStory', + 2, + ], + [ + JSON.stringify({ + version: "https://jsonfeed.org/version/1.1", + title: "News", + items: [{ id: "1", tags: ["Tech"], content_text: "Story" }], + }), + 1, + ], +])( + "counts feed and entry categories across feed formats", + async (content, count) => { + const { countFeedCategories } = await import("../feed-utils"); + expect(countFeedCategories(parseFeed(content).feed)).toEqual( + new Map([["Tech", count]]) + ); + } +); diff --git a/packages/api/src/utils/__tests__/http-transport.node.test.ts b/packages/api/src/utils/__tests__/http-transport.node.test.ts new file mode 100644 index 00000000..ced29c28 --- /dev/null +++ b/packages/api/src/utils/__tests__/http-transport.node.test.ts @@ -0,0 +1,26 @@ +import { expect, it, vi } from "vitest"; +import type { LookupAddress } from "node:dns"; + +vi.mock("node:dns", () => ({ + lookup: vi.fn( + ( + _hostname: string, + _options: object, + callback: (error: Error | null, addresses: LookupAddress[]) => void + ) => { + callback(null, [{ address: "127.0.0.1", family: 4 }]); + } + ), +})); + +it("rejects a private DNS answer in the connection lookup", async () => { + const { fetchPublicUrl } = await import("../http-transport.node"); + await expect( + fetchPublicUrl("http://rebind.example/feed", {}) + ).rejects.toMatchObject({ + cause: { + message: + "Requests to private or reserved network addresses are not allowed", + }, + }); +}); diff --git a/packages/api/src/utils/__tests__/http-transport.response.test.ts b/packages/api/src/utils/__tests__/http-transport.response.test.ts new file mode 100644 index 00000000..b5e9c28a --- /dev/null +++ b/packages/api/src/utils/__tests__/http-transport.response.test.ts @@ -0,0 +1,36 @@ +import { expect, it, vi } from "vitest"; +import { Response as UndiciResponse } from "undici"; +import { fetchPublicUrl } from "../http-transport.node"; + +const { mockFetch } = vi.hoisted(() => ({ + mockFetch: vi.fn(), +})); + +vi.mock("undici", async (importOriginal) => ({ + ...(await importOriginal()), + fetch: mockFetch, +})); + +it("returns a native streaming response with the URL needed by discovery", async () => { + const upstream = new UndiciResponse("feed", { + headers: { "content-type": "application/rss+xml" }, + }); + Object.defineProperty(upstream, "url", { value: "https://example.com/feed" }); + mockFetch.mockResolvedValue(upstream); + + const response = await fetchPublicUrl("https://example.com/feed", { + headers: { "user-agent": "TuvixRSS" }, + }); + + expect(response).toBeInstanceOf(Response); + expect(response.url).toBe("https://example.com/feed"); + expect(response.headers.get("content-type")).toBe("application/rss+xml"); + expect(await response.text()).toBe("feed"); + expect(mockFetch).toHaveBeenCalledWith( + "https://example.com/feed", + expect.objectContaining({ + redirect: "manual", + headers: expect.arrayContaining([["user-agent", "TuvixRSS"]]), + }) + ); +}); diff --git a/packages/api/src/utils/__tests__/safe-fetch.test.ts b/packages/api/src/utils/__tests__/safe-fetch.test.ts new file mode 100644 index 00000000..fbb7be31 --- /dev/null +++ b/packages/api/src/utils/__tests__/safe-fetch.test.ts @@ -0,0 +1,95 @@ +import { afterEach, describe, expect, it, vi } from "vitest"; +import { safeFetch } from "../safe-fetch"; +import { assertPublicAddress } from "../public-url"; + +afterEach(() => vi.unstubAllGlobals()); + +describe("server-side URL validation", () => { + it.each([ + "http://127.0.0.1/private", + "http://2130706433/", + "http://0x7f000001/", + "http://10.0.0.1/", + "http://169.254.169.254/", + "http://[::1]/", + "http://[::ffff:127.0.0.1]/", + "http://[fc00::1]/", + "http://localhost./", + "http://server.internal/", + "http://server/", + "file:///etc/passwd", + "https://user:password@example.com/", + ])("rejects %s before opening a connection", async (url) => { + const fetch = vi.fn(); + vi.stubGlobal("fetch", fetch); + await expect(safeFetch(url)).rejects.toThrow(); + expect(fetch).not.toHaveBeenCalled(); + }); + + it("rejects redirects to private addresses", async () => { + const fetch = vi.fn( + async () => + new Response(null, { + status: 302, + headers: { location: "http://127.0.0.1/admin" }, + }) + ); + vi.stubGlobal("fetch", fetch); + await expect(safeFetch("https://example.com/feed")).rejects.toThrow( + /private|reserved/ + ); + expect(fetch).toHaveBeenCalledTimes(1); + }); + + it("follows public redirects manually and removes credentials", async () => { + const fetch = vi + .fn() + .mockResolvedValueOnce( + new Response(null, { status: 301, headers: { location: "/rss" } }) + ) + .mockResolvedValueOnce(new Response("feed")); + vi.stubGlobal("fetch", fetch); + expect( + await ( + await safeFetch("https://example.com/feed", { + headers: { authorization: "secret", cookie: "session=secret" }, + }) + ).text() + ).toBe("feed"); + expect(fetch.mock.lastCall?.[0]).toBe("https://example.com/rss"); + const options: RequestInit = fetch.mock.lastCall![1]; + expect(options.redirect).toBe("manual"); + expect(new Headers(options.headers).has("authorization")).toBe(false); + expect(new Headers(options.headers).has("cookie")).toBe(false); + }); + + it("shares one timeout budget across every redirect", async () => { + const signals: (AbortSignal | null | undefined)[] = []; + vi.stubGlobal( + "fetch", + vi.fn(async (_url: string, init: RequestInit) => { + signals.push(init.signal); + return signals.length === 1 + ? new Response(null, { status: 302, headers: { location: "/feed" } }) + : new Response("feed"); + }) + ); + await safeFetch("https://example.com"); + expect(signals).toHaveLength(2); + expect(signals[0]).toBeInstanceOf(AbortSignal); + expect(signals[1]).toBe(signals[0]); + }); + + it("rejects non-public DNS results, including IPv4 mapped IPv6", () => { + for (const address of [ + "127.0.0.1", + "192.168.1.1", + "::ffff:10.0.0.1", + "100.64.0.1", + "fe80::1", + ]) + expect(() => assertPublicAddress(address)).toThrow(); + expect(() => assertPublicAddress("93.184.216.34")).not.toThrow(); + expect(() => assertPublicAddress("2606:4700:4700::1111")).not.toThrow(); + }); +}); diff --git a/packages/api/src/utils/base-url.ts b/packages/api/src/utils/base-url.ts index f498b16b..6eccda87 100644 --- a/packages/api/src/utils/base-url.ts +++ b/packages/api/src/utils/base-url.ts @@ -5,7 +5,7 @@ * Works in both Node.js and Cloudflare Workers environments. */ -import type { Env } from "@/types"; +import type { Env } from "@api/types"; /** * Get the base URL for the application diff --git a/packages/api/src/utils/db-metrics.ts b/packages/api/src/utils/db-metrics.ts index d187dcc4..1d67c024 100644 --- a/packages/api/src/utils/db-metrics.ts +++ b/packages/api/src/utils/db-metrics.ts @@ -8,7 +8,7 @@ * Emits both Span Metrics (for detailed tracing) and Sentry Metrics (for dashboards). */ -import * as Sentry from "@/utils/sentry"; +import * as Sentry from "@api/utils/sentry"; import { emitCounter, emitDistribution } from "./metrics.js"; /** diff --git a/packages/api/src/utils/domain-checker.ts b/packages/api/src/utils/domain-checker.ts index bab3dd7a..bed00368 100644 --- a/packages/api/src/utils/domain-checker.ts +++ b/packages/api/src/utils/domain-checker.ts @@ -23,8 +23,8 @@ * while allowing enterprise users to opt-in to blocked domains if needed. */ -import type { Database } from "@/db/client"; -import * as schema from "@/db/schema"; +import type { Database } from "@api/db/client"; +import * as schema from "@api/db/schema"; /** * Extract domain from URL diff --git a/packages/api/src/utils/feed-utils.ts b/packages/api/src/utils/feed-utils.ts index 29638de4..9cc0cdd6 100644 --- a/packages/api/src/utils/feed-utils.ts +++ b/packages/api/src/utils/feed-utils.ts @@ -1,3 +1,44 @@ +import type { ParsedFeed, ParsedFeedItem } from "@api/types/feed"; + +/** RSS/RDF/JSON use items; Atom uses entries. */ +export function extractFeedItems(feed: ParsedFeed): ParsedFeedItem[] { + if ("items" in feed) return feed.items ?? []; + if ("entries" in feed) return feed.entries ?? []; + return []; +} + +/** Read publisher categories consistently across every supported format. */ +export function extractCategoryNames( + value: ParsedFeed | ParsedFeedItem +): string[] { + if ("tags" in value) return value.tags ?? []; + if (!("categories" in value)) return []; + return (value.categories ?? []).flatMap((category) => { + const name = + typeof category === "string" + ? category + : "term" in category + ? category.term || category.label + : "name" in category + ? category.name + : undefined; + const trimmed = name?.trim(); + return trimmed ? [trimmed] : []; + }); +} + +export function countFeedCategories( + feed: ParsedFeed, + maxEntries = 10 +): Map { + const counts = new Map(); + for (const value of [feed, ...extractFeedItems(feed).slice(0, maxEntries)]) { + for (const name of extractCategoryNames(value)) + counts.set(name, (counts.get(name) ?? 0) + 1); + } + return counts; +} + /** * Utility functions for RSS/Atom/JSON feed processing */ diff --git a/packages/api/src/utils/http-transport.cloudflare.ts b/packages/api/src/utils/http-transport.cloudflare.ts new file mode 100644 index 00000000..3b7a55f5 --- /dev/null +++ b/packages/api/src/utils/http-transport.cloudflare.ts @@ -0,0 +1,7 @@ +/** Workers fetch uses the public network; private VPC bindings are not used. */ +export function fetchPublicUrl( + url: string, + init: RequestInit +): Promise { + return fetch(url, init); +} diff --git a/packages/api/src/utils/http-transport.node.ts b/packages/api/src/utils/http-transport.node.ts new file mode 100644 index 00000000..f7341299 --- /dev/null +++ b/packages/api/src/utils/http-transport.node.ts @@ -0,0 +1,54 @@ +import { lookup } from "node:dns"; +import { Agent, fetch } from "undici"; +import { assertPublicAddress } from "./public-url"; + +// Validate the addresses supplied to the connection itself, preventing DNS +// rebinding between an earlier validation lookup and the actual connection. +const dispatcher = new Agent({ + connect: { + lookup(hostname, options, callback) { + lookup(hostname, { all: true, verbatim: true }, (error, addresses) => { + if (error) return callback(error, "", 4); + try { + if (!addresses.length) throw new Error("Hostname has no addresses"); + for (const { address } of addresses) assertPublicAddress(address); + const first = addresses[0]!; + if (options.all) callback(null, addresses); + else callback(null, first.address, first.family); + } catch (cause) { + callback( + cause instanceof Error + ? cause + : new Error("Invalid network address"), + "", + 4 + ); + } + }); + }, + }, +}); + +export async function fetchPublicUrl( + url: string, + init: RequestInit +): Promise { + const request = new Request(url, init); + const response = await fetch(url, { + method: request.method, + headers: Array.from(request.headers), + signal: request.signal, + redirect: "manual", + body: request.body ? await request.arrayBuffer() : undefined, + dispatcher, + }); + const result = new Response(response.body, { + status: response.status, + statusText: response.statusText, + headers: Array.from(response.headers), + }); + // Preserve the final URL used by feed discovery while returning the runtime's + // native Response and streaming the body without buffering it. + Object.defineProperty(result, "url", { value: response.url }); + return result; +} diff --git a/packages/api/src/utils/metrics.ts b/packages/api/src/utils/metrics.ts index 022bc014..d6fa94ca 100644 --- a/packages/api/src/utils/metrics.ts +++ b/packages/api/src/utils/metrics.ts @@ -8,7 +8,7 @@ * Works in both Node.js and Cloudflare Workers runtimes. */ -import * as Sentry from "@/utils/sentry"; +import * as Sentry from "@api/utils/sentry"; /** * Emit a counter metric diff --git a/packages/api/src/utils/og-image-fetcher.ts b/packages/api/src/utils/og-image-fetcher.ts index 5968a62d..4eda4324 100644 --- a/packages/api/src/utils/og-image-fetcher.ts +++ b/packages/api/src/utils/og-image-fetcher.ts @@ -1,3 +1,4 @@ +import { safeFetch } from "@api/utils/safe-fetch"; /** * OpenGraph Image Fetcher * @@ -36,7 +37,7 @@ export async function extractOgImage( const domain = extractDomain(url) || "unknown"; try { - const response = await fetch(url, { + const response = await safeFetch(url, { signal: controller.signal, headers: { "User-Agent": userAgent }, }); diff --git a/packages/api/src/utils/public-url.ts b/packages/api/src/utils/public-url.ts new file mode 100644 index 00000000..7ec6d152 --- /dev/null +++ b/packages/api/src/utils/public-url.ts @@ -0,0 +1,38 @@ +import ipaddr from "ipaddr.js"; + +export function assertPublicAddress(address: string): void { + if ( + !ipaddr.isValid(address) || + ipaddr.process(address).range() !== "unicast" + ) { + throw new Error( + "Requests to private or reserved network addresses are not allowed" + ); + } +} + +export function validatePublicUrl(input: string | URL): URL { + const url = new URL(input); + if ( + !["http:", "https:"].includes(url.protocol) || + url.username || + url.password + ) { + throw new Error( + "Only HTTP(S) URLs without embedded credentials are allowed" + ); + } + const host = url.hostname + .replace(/^\[|\]$/g, "") + .replace(/\.$/, "") + .toLowerCase(); + if (ipaddr.isValid(host)) { + assertPublicAddress(host); + } else if ( + !host.includes(".") || + /\.(localhost|local|internal|lan|home|test|invalid)$/.test(host) + ) { + throw new Error("Requests to local hostnames are not allowed"); + } + return url; +} diff --git a/packages/api/src/utils/safe-fetch.ts b/packages/api/src/utils/safe-fetch.ts new file mode 100644 index 00000000..bc11d060 --- /dev/null +++ b/packages/api/src/utils/safe-fetch.ts @@ -0,0 +1,32 @@ +import { fetchPublicUrl } from "@api/utils/http-transport"; +import { validatePublicUrl } from "./public-url"; + +/** Validate every redirect, never forwarding credentials to another origin. */ +export async function safeFetch( + input: string | URL | Request, + init: RequestInit = {} +): Promise { + if (input instanceof Request) throw new Error("Pass a URL to safeFetch"); + if (init.method && init.method !== "GET" && init.method !== "HEAD") { + throw new Error("Feed requests must use GET or HEAD"); + } + let url = validatePublicUrl(input); + const headers = new Headers(init.headers); + headers.delete("cookie"); + headers.delete("authorization"); + const signal = init.signal ?? AbortSignal.timeout(15_000); + for (let redirects = 0; redirects <= 5; redirects++) { + const response = await fetchPublicUrl(url.href, { + ...init, + headers, + redirect: "manual", + signal, + }); + if (![301, 302, 303, 307, 308].includes(response.status)) return response; + const location = response.headers.get("location"); + await response.body?.cancel(); + if (!location) throw new Error("Redirect response has no location"); + url = validatePublicUrl(new URL(location, url)); + } + throw new Error("Too many redirects"); +} diff --git a/packages/api/src/utils/sentry.cloudflare.ts b/packages/api/src/utils/sentry.cloudflare.ts index 22d52124..aa366c18 100644 --- a/packages/api/src/utils/sentry.cloudflare.ts +++ b/packages/api/src/utils/sentry.cloudflare.ts @@ -4,7 +4,7 @@ * This file re-exports all Sentry functionality from @sentry/cloudflare. * It's used in production Cloudflare Workers builds. * - * Build-time aliasing in tsup.config.ts routes imports of "@/utils/sentry" + * Build-time aliasing in tsup.config.ts routes imports of "@api/utils/sentry" * to either this file (Cloudflare) or sentry.noop.ts (Node.js/tests). */ diff --git a/packages/api/src/utils/sentry.node.ts b/packages/api/src/utils/sentry.node.ts index b9d81401..2c97c72a 100644 --- a/packages/api/src/utils/sentry.node.ts +++ b/packages/api/src/utils/sentry.node.ts @@ -4,7 +4,7 @@ * This file re-exports all Sentry functionality from @sentry/node. * It's used in local Docker development builds. * - * Build-time aliasing in tsup.config.ts routes imports of "@/utils/sentry" + * Build-time aliasing in tsup.config.ts routes imports of "@api/utils/sentry" * to this file for Node.js builds. * * Note: Sentry must be initialized in the entry point (entries/node.ts) diff --git a/packages/api/src/utils/sentry.noop.ts b/packages/api/src/utils/sentry.noop.ts index 2a12f323..1c0272d0 100644 --- a/packages/api/src/utils/sentry.noop.ts +++ b/packages/api/src/utils/sentry.noop.ts @@ -5,7 +5,7 @@ * Used in Node.js builds and tests where Sentry is not needed. * * Build-time aliasing in tsup.config.ts and vitest.config.ts routes - * imports of "@/utils/sentry" to this file for Node.js/test builds. + * imports of "@api/utils/sentry" to this file for Node.js/test builds. * * All functions match the @sentry/cloudflare API signatures exactly. */ @@ -61,13 +61,7 @@ export function captureException( export function captureMessage( _message: string, _levelOrContext?: - | "fatal" - | "error" - | "warning" - | "log" - | "info" - | "debug" - | CaptureContext + "fatal" | "error" | "warning" | "log" | "info" | "debug" | CaptureContext ): string | undefined { return undefined; } diff --git a/packages/api/tsconfig.json b/packages/api/tsconfig.json index 44354270..7c286fa0 100644 --- a/packages/api/tsconfig.json +++ b/packages/api/tsconfig.json @@ -32,28 +32,11 @@ "noImplicitOverride": true, "skipLibCheck": true, "types": ["node", "@cloudflare/workers-types"], - "baseUrl": "./src", "paths": { - // Sentry path for IDE/type checking. Uses @sentry/cloudflare as canonical API. - // Build-time aliasing routes to actual impl: sentry.node.ts, sentry.noop.ts, or this. - "@/utils/sentry": ["utils/sentry.cloudflare.ts"], - "@/utils/*": ["utils/*"], - "@/db": ["db"], - "@/db/*": ["db/*"], - "@/services/*": ["services/*"], - "@/routers/*": ["routers/*"], - "@/trpc/*": ["trpc/*"], - "@/adapters/*": ["adapters/*"], - "@/storage/*": ["storage/*"], - "@/auth/*": ["auth/*"], - "@/cron/*": ["cron/*"], - "@/config/*": ["config/*"], - "@/hono/*": ["hono/*"], - "@/entries/*": ["entries/*"], - "@/cli/*": ["cli/*"], - "@/types": ["types"], - "@/types/*": ["types/*"], - "@/test/*": ["test/*"] + // Canonical Worker paths; Node and tests select their own transports. + "@api/utils/http-transport": ["./src/utils/http-transport.cloudflare.ts"], + "@api/utils/sentry": ["./src/utils/sentry.cloudflare.ts"], + "@api/*": ["./src/*"] } }, "include": ["src/**/*"], diff --git a/packages/api/tsconfig.node.json b/packages/api/tsconfig.node.json new file mode 100644 index 00000000..0850c21e --- /dev/null +++ b/packages/api/tsconfig.node.json @@ -0,0 +1,10 @@ +{ + "extends": "./tsconfig.json", + "compilerOptions": { + "paths": { + "@api/utils/sentry": ["./src/utils/sentry.node.ts"], + "@api/utils/http-transport": ["./src/utils/http-transport.node.ts"], + "@api/*": ["./src/*"] + } + } +} diff --git a/packages/api/tsup.config.ts b/packages/api/tsup.config.ts index c74a64a5..65623c15 100644 --- a/packages/api/tsup.config.ts +++ b/packages/api/tsup.config.ts @@ -7,7 +7,7 @@ export default defineConfig({ "db/migrate-local": "src/db/migrate-local.ts", }, format: ["esm"], - target: "node20", + target: "node24", platform: "node", outDir: "dist", clean: true, @@ -25,7 +25,7 @@ export default defineConfig({ ], splitting: false, treeshake: true, - // BUILD-TIME ALIAS: Route @/utils/sentry to sentry.node.ts (which wraps @sentry/node) + // BUILD-TIME ALIAS: Route @api/utils/sentry to sentry.node.ts (which wraps @sentry/node) // This replaces runtime detection with build-time SDK selection. // - Node.js builds: sentry.node.ts → @sentry/node (via this config) // - Cloudflare Workers: sentry.cloudflare.ts → @sentry/cloudflare (via wrangler) @@ -33,7 +33,14 @@ export default defineConfig({ esbuildOptions(options) { options.alias = { ...options.alias, - "@/utils/sentry": path.resolve(__dirname, "./src/utils/sentry.node.ts"), + "@api/utils/http-transport": path.resolve( + import.meta.dirname, + "./src/utils/http-transport.node.ts" + ), + "@api/utils/sentry": path.resolve( + import.meta.dirname, + "./src/utils/sentry.node.ts" + ), }; }, }); diff --git a/packages/api/vitest.config.ts b/packages/api/vitest.config.ts index d78046f5..85a219a6 100644 --- a/packages/api/vitest.config.ts +++ b/packages/api/vitest.config.ts @@ -55,20 +55,27 @@ export default defineConfig({ // Path resolution - match tsconfig.json resolve: { alias: { - // IMPORTANT: Sentry no-op alias must come BEFORE the general @/utils alias - // to ensure @/utils/sentry resolves to the no-op implementation in tests - "@/utils/sentry": path.resolve(__dirname, "./src/utils/sentry.noop.ts"), - "@/utils": path.resolve(__dirname, "./src/utils"), - "@/db": path.resolve(__dirname, "./src/db"), - "@/services": path.resolve(__dirname, "./src/services"), - "@/routers": path.resolve(__dirname, "./src/routers"), - "@/trpc": path.resolve(__dirname, "./src/trpc"), - "@/adapters": path.resolve(__dirname, "./src/adapters"), - "@/auth": path.resolve(__dirname, "./src/auth"), - "@/cron": path.resolve(__dirname, "./src/cron"), - "@/config": path.resolve(__dirname, "./src/config"), - "@/types": path.resolve(__dirname, "./src/types"), - "@": path.resolve(__dirname, "./src"), + // IMPORTANT: Sentry no-op alias must come BEFORE the general @api/utils alias + // to ensure @api/utils/sentry resolves to the no-op implementation in tests + "@api/utils/http-transport": path.resolve( + import.meta.dirname, + "./src/utils/http-transport.cloudflare.ts" + ), + "@api/utils/sentry": path.resolve( + import.meta.dirname, + "./src/utils/sentry.noop.ts" + ), + "@api/utils": path.resolve(import.meta.dirname, "./src/utils"), + "@api/db": path.resolve(import.meta.dirname, "./src/db"), + "@api/services": path.resolve(import.meta.dirname, "./src/services"), + "@api/routers": path.resolve(import.meta.dirname, "./src/routers"), + "@api/trpc": path.resolve(import.meta.dirname, "./src/trpc"), + "@api/adapters": path.resolve(import.meta.dirname, "./src/adapters"), + "@api/auth": path.resolve(import.meta.dirname, "./src/auth"), + "@api/cron": path.resolve(import.meta.dirname, "./src/cron"), + "@api/config": path.resolve(import.meta.dirname, "./src/config"), + "@api/types": path.resolve(import.meta.dirname, "./src/types"), + "@api": path.resolve(import.meta.dirname, "./src"), }, }, }); diff --git a/packages/app/Dockerfile b/packages/app/Dockerfile index ab5d1c53..1267818c 100644 --- a/packages/app/Dockerfile +++ b/packages/app/Dockerfile @@ -1,4 +1,4 @@ -FROM node:20-alpine AS builder +FROM node:24-alpine AS builder WORKDIR /app @@ -7,7 +7,7 @@ WORKDIR /app RUN apk add --no-cache python3 make g++ # Install pnpm -RUN npm install -g pnpm@10.19.0 +RUN npm install -g pnpm@12.4.2 # Copy workspace files COPY package.json pnpm-lock.yaml pnpm-workspace.yaml ./ @@ -32,6 +32,9 @@ ARG VITE_APP_VERSION ENV VITE_API_URL=${VITE_API_URL} ENV VITE_APP_VERSION=${VITE_APP_VERSION} +# Compile workspace types before checking the application +RUN pnpm --filter @tuvixrss/tricorder build + # Build the application RUN pnpm --filter @tuvixrss/app build diff --git a/packages/app/README.md b/packages/app/README.md index fc32fc98..0e7db928 100644 --- a/packages/app/README.md +++ b/packages/app/README.md @@ -4,7 +4,7 @@ This template provides a minimal setup to get React working in Vite with HMR and Currently, two official plugins are available: -- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Babel](https://babeljs.io/) (or [oxc](https://oxc.rs) when used in [rolldown-vite](https://vite.dev/guide/rolldown)) for Fast Refresh +- [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react) uses [Oxc](https://oxc.rs) with Vite 8 for Fast Refresh - [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/blob/main/packages/plugin-react-swc) uses [SWC](https://swc.rs/) for Fast Refresh ## React Compiler diff --git a/packages/app/eslint.config.js b/packages/app/eslint.config.js index 775430e7..801522c1 100644 --- a/packages/app/eslint.config.js +++ b/packages/app/eslint.config.js @@ -3,7 +3,6 @@ import globals from "globals"; import reactHooks from "eslint-plugin-react-hooks"; import reactRefresh from "eslint-plugin-react-refresh"; import tseslint from "typescript-eslint"; -import noRelativeImportPaths from "eslint-plugin-no-relative-import-paths"; import { defineConfig, globalIgnores } from "eslint/config"; export default defineConfig([ @@ -16,6 +15,7 @@ export default defineConfig([ "coverage/**", "**/coverage/**", "**/*.gen.*", + "src/lib/api/generated/**", "**/__tests__/**", "**/*.test.ts", "**/*.test.tsx", @@ -28,7 +28,6 @@ export default defineConfig([ plugins: { "react-hooks": reactHooks, "react-refresh": reactRefresh, - "no-relative-import-paths": noRelativeImportPaths, }, languageOptions: { ecmaVersion: 2020, @@ -38,7 +37,10 @@ export default defineConfig([ ...reactHooks.configs.recommended.rules, "react-refresh/only-export-components": [ "warn", - { allowConstantExport: true }, + { + allowConstantExport: true, + extraHOCs: ["createFileRoute", "createRootRouteWithContext"], + }, ], // Detect explicit any types "@typescript-eslint/no-explicit-any": "error", @@ -49,9 +51,17 @@ export default defineConfig([ "@typescript-eslint/no-unsafe-return": "off", "@typescript-eslint/no-unsafe-argument": "off", // Enforce tsconfig path aliases, disallow ../ imports but allow same folder ./ - "no-relative-import-paths/no-relative-import-paths": [ + "no-restricted-imports": [ "error", - { allowSameFolder: true, rootDir: "src", prefix: "@" }, + { + patterns: [ + { + group: ["../**"], + message: + "Use the configured source path alias for parent imports.", + }, + ], + }, ], }, }, diff --git a/packages/app/package.json b/packages/app/package.json index f2d459d1..4b6c2746 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -5,12 +5,12 @@ "type": "module", "scripts": { "dev": "vite", - "build": "tsc --noEmit && vite build", + "build": "pnpm run type-check && vite build", "lint": "eslint .", "preview": "vite preview", "generate:routes": "tsr generate", "generate:icons": "node scripts/generate-icons.mjs", - "type-check": "tsc --noEmit", + "type-check": "tsc --noEmit -p tsconfig.app.json && tsc --noEmit -p tsconfig.node.json", "knip": "knip", "format": "prettier --write .", "format:check": "prettier --check .", @@ -22,75 +22,74 @@ "deploy": "pnpm predeploy && bash scripts/deploy.sh" }, "dependencies": { - "@floating-ui/react": "^0.27.16", - "@hookform/resolvers": "^5.2.2", - "@radix-ui/react-avatar": "^1.1.11", - "@radix-ui/react-checkbox": "^1.3.3", - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-label": "^2.1.8", - "@radix-ui/react-popover": "^1.1.15", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-select": "^2.2.6", - "@radix-ui/react-separator": "^1.1.8", - "@radix-ui/react-slot": "^1.2.4", - "@radix-ui/react-tooltip": "^1.2.8", - "@sentry/react": "^10.26.0", - "@tailwindcss/typography": "^0.5.19", - "@tailwindcss/vite": "^4.1.17", - "@tanstack/react-query": "^5.90.10", - "@tanstack/react-router": "^1.139.3", - "@tanstack/react-table": "^8.21.3", - "@trpc/client": "^11.7.2", - "@trpc/react-query": "^11.7.2", - "@trpc/server": "^11.7.2", + "@floating-ui/react": "^0.27.20", + "@hookform/resolvers": "^5.9.1", + "@radix-ui/react-avatar": "^1.2.6", + "@radix-ui/react-checkbox": "^1.3.11", + "@radix-ui/react-dialog": "^1.1.23", + "@radix-ui/react-label": "^2.1.15", + "@radix-ui/react-popover": "^1.1.23", + "@radix-ui/react-scroll-area": "^1.2.18", + "@radix-ui/react-select": "^2.3.7", + "@radix-ui/react-separator": "^1.1.15", + "@radix-ui/react-slot": "^1.3.3", + "@radix-ui/react-tooltip": "^1.2.16", + "@sentry/react": "^10.75.0", + "@tailwindcss/typography": "^0.5.20", + "@tailwindcss/vite": "^4.3.3", + "@tanstack/react-query": "^5.103.1", + "@tanstack/react-router": "^1.170.38", + "@tanstack/react-table": "^9.2.4", + "@trpc/client": "^11.19.0", + "@trpc/react-query": "^11.19.0", + "@trpc/server": "^11.19.0", "@tuvixrss/api": "workspace:*", - "better-auth": "^1.4.1", + "better-auth": "^1.7.5", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "cmdk": "^1.1.1", - "lucide-react": "^0.554.0", - "motion": "^12.23.24", - "radix-ui": "^1.4.3", - "react": "^19.2.0", - "react-dom": "^19.2.0", - "react-hook-form": "^7.66.1", - "react-intersection-observer": "^10.0.0", - "recharts": "3.5.0", - "sonner": "^2.0.7", + "lucide-react": "^1.47.0", + "motion": "^13.4.0", + "radix-ui": "^1.6.7", + "react": "^19.3.0", + "react-dom": "^19.3.0", + "react-hook-form": "^7.88.0", + "react-intersection-observer": "^11.0.1", + "recharts": "3.10.1", + "sonner": "^2.0.8", "superjson": "^2.2.6", - "tailwind-merge": "^3.4.0", - "tailwindcss": "^4.1.17", + "tailwind-merge": "^3.7.0", + "tailwindcss": "^4.3.3", "vaul": "^1.1.2", - "zod": "^4.1.12" + "zod": "^4.6.5" }, "devDependencies": { - "@eslint/js": "^9.39.1", - "@tanstack/router-cli": "^1.139.3", - "@tanstack/router-plugin": "^1.139.3", - "@testing-library/jest-dom": "^6.9.1", - "@testing-library/react": "^16.3.0", - "@testing-library/user-event": "^14.6.1", - "@types/node": "^24.10.1", - "@types/react": "^19.2.6", - "@types/react-dom": "^19.2.3", - "@vitejs/plugin-react": "^5.1.1", - "@vitest/coverage-v8": "^4.0.13", - "@vitest/ui": "^4.0.13", - "eslint": "^9.39.1", - "eslint-plugin-react-hooks": "^7.0.1", - "eslint-plugin-react-refresh": "^0.4.24", - "globals": "^16.5.0", - "jsdom": "^27.2.0", - "knip": "^5.70.1", - "prettier": "^3.6.2", - "sharp": "^0.34.5", + "@eslint/js": "^10.0.1", + "@tanstack/router-cli": "^1.167.38", + "@tanstack/router-plugin": "^1.168.40", + "@testing-library/jest-dom": "^7.0.1", + "@testing-library/react": "^16.3.3", + "@testing-library/user-event": "^14.6.7", + "@types/node": "^24.13.5", + "@types/react": "^19.3.0", + "@types/react-dom": "^19.3.0", + "@vitejs/plugin-react": "^6.1.1", + "@vitest/coverage-v8": "^5.0.1", + "@vitest/ui": "^5.0.1", + "eslint": "^10.10.0", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-react-refresh": "^0.5.7", + "globals": "^17.12.0", + "jsdom": "^30.1.0", + "knip": "^6.37.0", + "prettier": "^3.9.8", + "sharp": "^0.35.4", "tw-animate-css": "^1.4.0", - "typescript": "~5.9.3", - "typescript-eslint": "^8.47.0", - "vite": "npm:rolldown-vite@7.2.7", - "vite-plugin-pwa": "^1.1.0", - "vitest": "^4.0.13", - "workbox-window": "^7.4.0" - }, - "packageManager": "pnpm@10.19.0+sha512.c9fc7236e92adf5c8af42fd5bf1612df99c2ceb62f27047032f4720b33f8eacdde311865e91c411f2774f618d82f320808ecb51718bfa82c060c4ba7c76a32b8" + "typescript": "~6.0.3", + "typescript-eslint": "^8.70.0", + "vite": "^8.3.0", + "vite-plugin-pwa": "^1.3.0", + "vitest": "^5.0.1", + "workbox-window": "^7.4.1" + } } diff --git a/packages/app/src/__tests__/routes/debug-sentry.test.tsx b/packages/app/src/__tests__/routes/debug-sentry.test.tsx index 71773279..4edf70b7 100644 --- a/packages/app/src/__tests__/routes/debug-sentry.test.tsx +++ b/packages/app/src/__tests__/routes/debug-sentry.test.tsx @@ -19,7 +19,7 @@ const mockEnv = { const { mockCaptureException, mockStartSpan } = vi.hoisted(() => { return { mockCaptureException: vi.fn().mockResolvedValue("test-event-id"), - mockStartSpan: vi.fn().mockImplementation(async (options, callback) => { + mockStartSpan: vi.fn().mockImplementation(async (_options, callback) => { return await callback(); }), }; @@ -46,7 +46,7 @@ describe("DebugSentryPage", () => { vi.clearAllMocks(); // Reset mock implementations mockCaptureException.mockResolvedValue("test-event-id"); - mockStartSpan.mockImplementation(async (options, callback) => { + mockStartSpan.mockImplementation(async (_options, callback) => { return await callback(); }); @@ -328,7 +328,7 @@ describe("DebugSentryPage - Error Messages", () => { vi.clearAllMocks(); // Reset mock implementations mockCaptureException.mockResolvedValue("test-event-id"); - mockStartSpan.mockImplementation(async (options, callback) => { + mockStartSpan.mockImplementation(async (_options, callback) => { return await callback(); }); diff --git a/packages/app/src/components/__tests__/offline-indicator.test.tsx b/packages/app/src/components/__tests__/offline-indicator.test.tsx index 49bf788f..0b109321 100644 --- a/packages/app/src/components/__tests__/offline-indicator.test.tsx +++ b/packages/app/src/components/__tests__/offline-indicator.test.tsx @@ -80,7 +80,7 @@ describe("OfflineIndicator", () => { render(); const callArgs = vi.mocked(toast.error).mock.calls[0]; - expect(callArgs[1]?.duration).toBe(Infinity); + expect(callArgs![1]?.duration).toBe(Infinity); }); it("should include WifiOff icon in offline toast", () => { @@ -91,7 +91,7 @@ describe("OfflineIndicator", () => { render(); const callArgs = vi.mocked(toast.error).mock.calls[0]; - expect(callArgs[1]?.icon).toBeDefined(); + expect(callArgs![1]?.icon).toBeDefined(); }); }); @@ -140,7 +140,7 @@ describe("OfflineIndicator", () => { rerender(); const callArgs = vi.mocked(toast.success).mock.calls[0]; - expect(callArgs[1]?.duration).toBe(3000); + expect(callArgs![1]?.duration).toBe(3000); }); it("should not show success toast if never went offline", () => { @@ -172,7 +172,7 @@ describe("OfflineIndicator", () => { rerender(); const callArgs = vi.mocked(toast.success).mock.calls[0]; - expect(callArgs[1]?.icon).toBeDefined(); + expect(callArgs![1]?.icon).toBeDefined(); }); }); diff --git a/packages/app/src/components/admin/users/columns.tsx b/packages/app/src/components/admin/users/columns.tsx index e9c8df97..af858ebb 100644 --- a/packages/app/src/components/admin/users/columns.tsx +++ b/packages/app/src/components/admin/users/columns.tsx @@ -1,3 +1,4 @@ +import type { DataTableFeatures } from "./table-features"; import { ColumnDef } from "@tanstack/react-table"; import { Badge } from "@/components/ui/badge"; import { Button } from "@/components/ui/button"; @@ -70,7 +71,7 @@ type ColumnActions = { export const createColumns = ( actions: ColumnActions -): ColumnDef[] => [ +): ColumnDef[] => [ { accessorKey: "username", header: ({ column }) => ( @@ -85,7 +86,7 @@ export const createColumns = (
); }, - filterFn: (row, id, value) => { + filterFn: (row, _id, value) => { const user = row.original; const searchValue = String(value).toLowerCase(); return ( @@ -219,7 +220,7 @@ export const createColumns = ( return
{relativeTime}
; }, enableSorting: true, - sortingFn: (rowA, rowB) => { + sortFn: (rowA, rowB) => { const a = rowA.getValue("lastSeenAt") as Date | null; const b = rowB.getValue("lastSeenAt") as Date | null; // Sort nulls last diff --git a/packages/app/src/components/admin/users/data-table-column-header.tsx b/packages/app/src/components/admin/users/data-table-column-header.tsx index 78c80756..17706995 100644 --- a/packages/app/src/components/admin/users/data-table-column-header.tsx +++ b/packages/app/src/components/admin/users/data-table-column-header.tsx @@ -1,3 +1,4 @@ +import type { DataTableFeatures } from "./table-features"; import { Column } from "@tanstack/react-table"; import { ArrowUpDown, ArrowUp, ArrowDown } from "lucide-react"; @@ -5,14 +6,14 @@ import { cn } from "@/lib/utils"; import { Button } from "@/components/ui/button"; interface DataTableColumnHeaderProps< - TData, + TData extends object, TValue, > extends React.HTMLAttributes { - column: Column; + column: Column; title: string; } -export function DataTableColumnHeader({ +export function DataTableColumnHeader({ column, title, className, diff --git a/packages/app/src/components/admin/users/data-table-faceted-filter.tsx b/packages/app/src/components/admin/users/data-table-faceted-filter.tsx index 0f74f06e..27e9ec01 100644 --- a/packages/app/src/components/admin/users/data-table-faceted-filter.tsx +++ b/packages/app/src/components/admin/users/data-table-faceted-filter.tsx @@ -1,3 +1,4 @@ +import type { DataTableFeatures } from "./table-features"; import * as React from "react"; import { Column } from "@tanstack/react-table"; import { Check, PlusCircle } from "lucide-react"; @@ -21,8 +22,8 @@ import { } from "@/components/ui/popover"; import { Separator } from "@/components/ui/separator"; -interface DataTableFacetedFilterProps { - column?: Column; +interface DataTableFacetedFilterProps { + column?: Column; title?: string; options: { label: string; @@ -31,7 +32,7 @@ interface DataTableFacetedFilterProps { }[]; } -export function DataTableFacetedFilter({ +export function DataTableFacetedFilter({ column, title, options, diff --git a/packages/app/src/components/admin/users/data-table-pagination.tsx b/packages/app/src/components/admin/users/data-table-pagination.tsx index c99d2c88..661b0da8 100644 --- a/packages/app/src/components/admin/users/data-table-pagination.tsx +++ b/packages/app/src/components/admin/users/data-table-pagination.tsx @@ -1,4 +1,5 @@ -import { Table } from "@tanstack/react-table"; +import type { DataTableFeatures } from "./table-features"; +import { ReactTable } from "@tanstack/react-table"; import { ChevronLeft, ChevronRight, @@ -15,12 +16,12 @@ import { SelectValue, } from "@/components/ui/select"; -interface DataTablePaginationProps { - table: Table; +interface DataTablePaginationProps { + table: ReactTable; totalCount?: number; } -export function DataTablePagination({ +export function DataTablePagination({ table, totalCount, }: DataTablePaginationProps) { @@ -36,13 +37,13 @@ export function DataTablePagination({

Rows per page

- Page {table.getState().pagination.pageIndex + 1} of{" "} - {table.getPageCount()} + Page {table.state.pagination.pageIndex + 1} of {table.getPageCount()}
)} {/* Only show "add subscriptions" empty state if there are NO articles across ALL filters */} - {!isLoading && !isError && allCount === 0 && ( + {!isLoading && !isError && counts?.all === 0 && articles.length === 0 && ( @@ -380,234 +372,170 @@ function ArticlesPage() { - - - + )} {/* Show tabs if there are ANY articles (even if current filter is empty) */} - {!isLoading && !isError && allCount > 0 && ( - - {/* Filter Tabs */} -
-
- - - All - {allCount > 0 && ( - - {allCount} - - )} - - - Unread - {unreadCount > 0 && ( - - {unreadCount} - - )} - - - Read - {readCount > 0 && ( - - {readCount} - - )} - - - Saved - {savedCount > 0 && ( - - {savedCount} - - )} - - -
- - {/* Bulk Actions */} - {unreadCount > 0 && ( -
- - -
- )} -
- - - - {articles.length === 0 ? ( - - - - - - No articles - - - ) : ( - - {/* Infinite scroll trigger */} -
- {isFetchingNextPage && ( -
- - - Loading more articles... - -
- )} - {!hasNextPage && articles.length > 0 && ( - - No more articles - + {!isLoading && + (!isError || !!data) && + (counts?.all !== 0 || articles.length > 0) && ( + + {/* Filter Tabs */} +
+
+ + + All + {allCount > 0 && ( + + {allCount} + )} -
- - )} - - - - {articles.length === 0 ? ( - - - - - - No unread articles - You're all caught up! - - - ) : ( - - {/* Infinite scroll trigger */} -
- {isFetchingNextPage && ( -
- - - Loading more articles... - -
- )} - {!hasNextPage && articles.length > 0 && ( - - No more articles - + + + Unread + {unreadCount > 0 && ( + + {unreadCount} + )} -
-
- )} -
- - - {articles.length === 0 ? ( - - - - - - No read articles - - Articles you've read will appear here - - - - ) : ( - - {/* Infinite scroll trigger */} -
- {isFetchingNextPage && ( -
- - - Loading more articles... - -
+ + + Read + {readCount > 0 && ( + + {readCount} + )} - {!hasNextPage && articles.length > 0 && ( - - No more articles - + + + Saved + {savedCount > 0 && ( + + {savedCount} + )} -
-
- )} -
- - - {articles.length === 0 ? ( - - - - - - No saved articles - - Save articles to read them later - - - - ) : ( - - {/* Infinite scroll trigger */} -
- {isFetchingNextPage && ( -
- - - Loading more articles... - -
- )} - {!hasNextPage && articles.length > 0 && ( - - No more articles - - )} -
-
+ + +
+ + {/* Bulk Actions */} + {unreadCount > 0 && ( +
+ + +
)} - - -
- )} +
+ + + {[ + { + value: "all", + title: "No articles", + description: null, + }, + { + value: "unread", + title: "No unread articles", + description: "You're all caught up!", + }, + { + value: "read", + title: "No read articles", + description: "Articles you've read will appear here", + }, + { + value: "saved", + title: "No saved articles", + description: "Save articles to read them later", + }, + ].map((tab) => ( + + {activeFilter === tab.value && + (articles.length === 0 ? ( + + + + + + {tab.title} + {tab.description && ( + + {tab.description} + + )} + + + ) : ( + +
+ {hasNextPage && !isFetchingNextPage && ( + + )} + {isFetchingNextPage && ( +
+ + + Loading more articles... + +
+ )} + {!hasNextPage && ( + + No more articles + + )} +
+
+ ))} +
+ ))} +
+
+ )} {/* Mark All Read Confirmation Dialog */} void; }) { const { data: feed, isLoading } = useFeedByCategoryId(category.id); - const { data: user } = useCurrentUser(); + const { data: session } = useCurrentUser(); + const user = session?.user; if (isLoading) { return Loading...; diff --git a/packages/app/src/routes/app/index.tsx b/packages/app/src/routes/app/index.tsx index 9c267b73..0928291d 100644 --- a/packages/app/src/routes/app/index.tsx +++ b/packages/app/src/routes/app/index.tsx @@ -1,13 +1,13 @@ import { createFileRoute, redirect } from "@tanstack/react-router"; -// @ts-expect-error - Route type generation issue export const Route = createFileRoute("/app/")({ beforeLoad: () => { throw redirect({ to: "/app/articles", search: { category_id: undefined, - } satisfies { category_id?: number }, + subscription_id: undefined, + }, }); }, }); diff --git a/packages/app/src/routes/app/route.tsx b/packages/app/src/routes/app/route.tsx index 0852aff4..ff8f9f60 100644 --- a/packages/app/src/routes/app/route.tsx +++ b/packages/app/src/routes/app/route.tsx @@ -1,3 +1,6 @@ +import { createTRPCClient, httpBatchLink } from "@trpc/client"; +import { transformer } from "@/lib/api/transformer"; +import { createFetchWithCredentials } from "@/lib/api/query-options"; import { createFileRoute, Link, @@ -42,8 +45,6 @@ export const Route = createFileRoute("/app")({ try { // Create a tRPC caller for server-side check // Note: In beforeLoad, we need to use the tRPC client directly - const { createTRPCClient, httpBatchLink } = await import("@trpc/client"); - const { transformer } = await import("@/lib/api/transformer"); const apiUrl = import.meta.env.VITE_API_URL || "/trpc"; const client = createTRPCClient({ @@ -51,16 +52,7 @@ export const Route = createFileRoute("/app")({ httpBatchLink({ url: apiUrl, transformer, - // Include cookies for authentication - fetch: (url, options) => { - return fetch(url, { - ...options, - credentials: "include", - headers: { - ...options?.headers, // Preserve Sentry trace headers - }, - }); - }, + fetch: createFetchWithCredentials, }), ], }); diff --git a/packages/app/src/routes/app/subscriptions.tsx b/packages/app/src/routes/app/subscriptions.tsx index 27fe934b..eeacf573 100644 --- a/packages/app/src/routes/app/subscriptions.tsx +++ b/packages/app/src/routes/app/subscriptions.tsx @@ -1,3 +1,4 @@ +import { FeedHealthStatus } from "@/components/app/feed-health-status"; import { createFileRoute, Link } from "@tanstack/react-router"; import { useSubscriptions, @@ -62,16 +63,26 @@ export const Route = createFileRoute("/app/subscriptions")({ }); type InitialFilterField = - | "title" - | "content" - | "description" - | "author" - | "any"; + "title" | "content" | "description" | "author" | "any"; type InitialFilterMatchType = "contains" | "exact" | "regex"; +function parseSubscribeUrl(value: string | undefined): string | null { + if (!value) return null; + try { + const url = new URL(value); + return url.protocol === "http:" || url.protocol === "https:" + ? url.href + : null; + } catch { + return null; + } +} + function SubscriptionsPage() { const search = Route.useSearch(); const navigate = Route.useNavigate(); + const subscribeUrl = parseSubscribeUrl(search.subscribe); + const [handledSubscribe, setHandledSubscribe] = useState(search.subscribe); const { data: subscriptionsData, isLoading, isError } = useSubscriptions(); const subscriptions = subscriptionsData?.items || []; const createSubscription = useCreateSubscriptionWithRefetch(); @@ -87,10 +98,13 @@ function SubscriptionsPage() { const [editValue, setEditValue] = useState(""); const [editCategoryIds, setEditCategoryIds] = useState([]); const [editNewCategories, setEditNewCategories] = useState([]); - const [showAddForm, setShowAddForm] = useState(false); - const [newSubUrl, setNewSubUrl] = useState(""); + const [showAddForm, setShowAddForm] = useState(!!subscribeUrl); + const [newSubUrl, setNewSubUrl] = useState(subscribeUrl ?? ""); const [newSubTitle, setNewSubTitle] = useState(""); - const [discoveredFeeds, setDiscoveredFeeds] = useState([]); + const [discoveryResult, setDiscoveryResult] = useState<{ + url: string; + feeds: DiscoveredFeed[]; + } | null>(null); const [deleteDialogOpen, setDeleteDialogOpen] = useState(false); const [subscriptionToDelete, setSubscriptionToDelete] = useState< number | null @@ -141,118 +155,96 @@ function SubscriptionsPage() { // Use query-based preview (auto-fetches when URL is valid) const feedPreview = useFeedPreview(looksLikeFeedUrl ? debouncedUrl : null); - // Auto-discover feeds when URL looks like a website (not direct feed) + const { mutate: discoverFeeds } = feedDiscovery; + const discoveredFeeds = + !looksLikeFeedUrl && + newSubUrl === debouncedUrl && + discoveryResult?.url === debouncedUrl + ? discoveryResult.feeds + : []; + useEffect(() => { - if (debouncedUrl && debouncedUrl.startsWith("http") && !looksLikeFeedUrl) { - // Website URL - attempt discovery - feedDiscovery.mutate( + let active = true; + if ( + debouncedUrl === newSubUrl && + debouncedUrl.startsWith("http") && + !looksLikeFeedUrl + ) { + discoverFeeds( { url: debouncedUrl }, { onSuccess: (feeds: DiscoveredFeed[]) => { - setDiscoveredFeeds(feeds); - - // If only one feed found, auto-select it + if (!active) return; + setDiscoveryResult({ url: debouncedUrl, feeds }); const [feed] = feeds; if (feed && feeds.length === 1) setNewSubUrl(feed.url); }, onError: () => { - setDiscoveredFeeds([]); + if (active) setDiscoveryResult(null); }, } ); - } else { - // Clear discovered feeds when URL is empty, invalid, or looks like a feed - setDiscoveredFeeds([]); } - // Only depend on the actual values that should trigger discovery, not the mutation objects - // eslint-disable-next-line react-hooks/exhaustive-deps - }, [debouncedUrl, looksLikeFeedUrl]); - - // Track which feed URL we've already auto-categorized to avoid infinite loops or re-toasting - const autoCategorizedUrl = useRef(null); + return () => { + active = false; + }; + }, [debouncedUrl, newSubUrl, looksLikeFeedUrl, discoverFeeds]); + + const [autoCategorization, setAutoCategorization] = useState<{ + url: string; + count: number; + } | null>(null); + + // Adjust local form state only when a new, current preview arrives. + if (!newSubUrl && autoCategorization) { + setAutoCategorization(null); + } else if ( + feedPreview.isSuccess && + feedPreview.data?.aiSuggestions && + newSubUrl && + newSubUrl === debouncedUrl && + autoCategorization?.url !== newSubUrl + ) { + const newIds = feedPreview.data.aiSuggestions.matchedCategoryIds.filter( + (id) => !selectedCategoryIds.includes(id) + ); + setAutoCategorization({ url: newSubUrl, count: newIds.length }); + if (newIds.length) + setSelectedCategoryIds([...new Set([...selectedCategoryIds, ...newIds])]); + } - // Auto-apply AI suggested categories useEffect(() => { - if ( - feedPreview.isSuccess && - feedPreview.data?.aiSuggestions && - newSubUrl && - autoCategorizedUrl.current !== newSubUrl - ) { - const { matchedCategoryIds } = feedPreview.data.aiSuggestions; - - if (matchedCategoryIds.length > 0) { - setSelectedCategoryIds((prev) => { - // Filter out already selected ones to see if we're actually adding anything - const newToSelect = matchedCategoryIds.filter( - (id: number) => !prev.includes(id) - ); - - if (newToSelect.length === 0) return prev; - - toast.success( - `✨ AI auto-applied ${newToSelect.length} ${ - newToSelect.length === 1 ? "category" : "categories" - }`, - { - duration: 3000, - } - ); - - const next = [...prev]; - newToSelect.forEach((id: number) => { - if (!next.includes(id)) next.push(id); - }); - return next; - }); - } - autoCategorizedUrl.current = newSubUrl; + if (autoCategorization?.count) { + const count = autoCategorization.count; + toast.success( + `✨ AI auto-applied ${count} ${count === 1 ? "category" : "categories"}`, + { + duration: 3000, + id: `auto-categories:${autoCategorization.url}`, + } + ); } - }, [feedPreview.isSuccess, feedPreview.data, newSubUrl]); + }, [autoCategorization]); - // Reset auto-categorization tracker if URL clears - useEffect(() => { - if (!newSubUrl) { - autoCategorizedUrl.current = null; + if (search.subscribe !== handledSubscribe) { + setHandledSubscribe(search.subscribe); + if (subscribeUrl) { + setShowAddForm(true); + setNewSubUrl(subscribeUrl); } - }, [newSubUrl]); + } - // Handle subscribe URL parameter useEffect(() => { - if (search.subscribe) { - try { - // Decode the URL - const url = decodeURIComponent(search.subscribe); - - // Validate it's a proper URL - new URL(url); - - // Pre-populate the form - setShowAddForm(true); - setNewSubUrl(url); - - // Clear the parameter from URL (don't keep it in browser history) - navigate({ - to: "/app/subscriptions", - search: { subscribe: undefined }, - replace: true, - }); - - // Show helpful message - toast.info("Feed URL loaded - review and confirm subscription"); - } catch { - // Invalid URL provided - toast.error("Invalid feed URL provided"); - - // Still clear the parameter - navigate({ - to: "/app/subscriptions", - search: { subscribe: undefined }, - replace: true, - }); - } - } - }, [search.subscribe, navigate]); + if (!search.subscribe) return; + if (subscribeUrl) + toast.info("Feed URL loaded - review and confirm subscription"); + else toast.error("Invalid feed URL provided"); + void navigate({ + to: "/app/subscriptions", + search: { subscribe: undefined }, + replace: true, + }); + }, [search.subscribe, subscribeUrl, navigate]); // Handle OPML files opened via File Handling API useEffect(() => { @@ -373,7 +365,7 @@ function SubscriptionsPage() { setNewSubUrl(""); setNewSubTitle(""); setShowAddForm(false); - setDiscoveredFeeds([]); + setDiscoveryResult(null); setSelectedCategoryIds([]); setNewCategoryNames([]); setFilterEnabled(false); @@ -420,7 +412,7 @@ function SubscriptionsPage() { const handleSelectFeed = useCallback((feed: DiscoveredFeed) => { setNewSubUrl(feed.url); // Clear discovery results to show preview - setDiscoveredFeeds([]); + setDiscoveryResult(null); }, []); const handleEdit = useCallback( @@ -482,7 +474,7 @@ function SubscriptionsPage() { setShowAddForm(false); setNewSubUrl(""); setNewSubTitle(""); - setDiscoveredFeeds([]); + setDiscoveryResult(null); setSelectedCategoryIds([]); setNewCategoryNames([]); setFilterEnabled(false); @@ -491,11 +483,6 @@ function SubscriptionsPage() { feedDiscovery.reset(); }, [feedDiscovery]); - const formatDate = useCallback((dateString?: string) => { - if (!dateString) return "Never"; - return new Date(dateString).toLocaleDateString(); - }, []); - // Import handlers const handleFileChange = useCallback( async (e: React.ChangeEvent) => { @@ -1305,15 +1292,14 @@ function SubscriptionsPage() { )}
+
+ +
{/* Metadata row - Spans full width at bottom */}
{sub.source?.url} - • - - Updated: {formatDate(sub.source?.lastFetched)} -
)} diff --git a/packages/app/src/routes/register.tsx b/packages/app/src/routes/register.tsx index 4ba16d05..569fb82f 100644 --- a/packages/app/src/routes/register.tsx +++ b/packages/app/src/routes/register.tsx @@ -16,7 +16,10 @@ function RegisterPage() { // Redirect to app if user is already logged in useEffect(() => { if (!isPending && user) { - navigate({ to: "/app/articles", search: { category_id: undefined } }); + navigate({ + to: "/app/articles", + search: { category_id: undefined, subscription_id: undefined }, + }); } }, [isPending, user, navigate]); diff --git a/packages/app/src/test/fixtures.ts b/packages/app/src/test/fixtures.ts new file mode 100644 index 00000000..3e1c94b1 --- /dev/null +++ b/packages/app/src/test/fixtures.ts @@ -0,0 +1,120 @@ +import { QueryClient, QueryObserver } from "@tanstack/react-query"; +import { vi } from "vitest"; +import type { RouterOutputs } from "@/lib/api/trpc"; +import type { useCurrentUser } from "@/lib/hooks/useAuth"; + +type Article = RouterOutputs["articles"]["list"]["items"][number]; +type Subscription = RouterOutputs["subscriptions"]["list"]["items"][number]; +const date = new Date("2026-01-01T00:00:00Z"); +const source: Article["source"] = { + id: 1, + title: "Test Source", + url: "https://example.com/feed", + description: null, + siteUrl: null, + iconUrl: null, + iconType: "auto", + iconUpdatedAt: null, + lastFetched: null, + createdAt: date, + updatedAt: date, +}; + +export function createArticle( + overrides: Omit, "source"> & { + source?: Partial; + } = {} +): Article { + return { + id: 1, + sourceId: 1, + guid: "test-guid", + title: "Test Article", + link: "https://example.com/article", + description: null, + content: null, + author: null, + imageUrl: null, + audioUrl: null, + commentLink: null, + publishedAt: date, + createdAt: date, + read: false, + saved: false, + audioProgress: null, + ...overrides, + source: { ...source, ...overrides.source }, + }; +} + +export function createSubscriptionsResult( + items: (Omit, "source"> & { + source?: Partial; + })[] +) { + const data: RouterOutputs["subscriptions"]["list"] = { + items: items.map((item) => ({ + id: 1, + userId: 1, + sourceId: 1, + customTitle: null, + filterEnabled: false, + filterMode: "include", + createdAt: date, + updatedAt: date, + categories: [], + filters: [], + ...item, + source: { + ...source, + fetchHealth: { + lastFetchAttemptAt: null, + nextFetchAt: null, + lastFetchError: null, + consecutiveFetchFailures: 0, + }, + ...item.source, + }, + })), + total: items.length, + hasMore: false, + }; + return new QueryObserver(new QueryClient(), { + queryKey: ["fixture"], + initialData: data, + }).getCurrentResult(); +} + +type SessionResult = ReturnType; +type SessionUser = NonNullable["user"]; +export function createSessionResult(user: Partial): SessionResult { + return { + data: { + user: { + id: "1", + name: "Test User", + username: "testuser", + email: "test@example.com", + emailVerified: true, + role: "user", + plan: "free", + banned: false, + createdAt: date, + updatedAt: date, + ...user, + }, + session: { + id: "1", + userId: "1", + token: "test-session", + expiresAt: date, + createdAt: date, + updatedAt: date, + }, + }, + isPending: false, + isRefetching: false, + error: null, + refetch: vi.fn(async () => {}), + }; +} diff --git a/packages/app/src/test/setup.ts b/packages/app/src/test/setup.ts index 5fbde25d..d95aace2 100644 --- a/packages/app/src/test/setup.ts +++ b/packages/app/src/test/setup.ts @@ -1,4 +1,4 @@ -import { cleanup } from "@testing-library/react"; +import { act, cleanup } from "@testing-library/react"; import { afterEach } from "vitest"; import * as matchers from "@testing-library/jest-dom/matchers"; import { expect } from "vitest"; @@ -8,6 +8,13 @@ expect.extend(matchers); // Cleanup after each test case (e.g., clearing jsdom) afterEach(() => { + // Release focus before removing its node. Otherwise jsdom can retain the + // detached focus target and emit a window blur when the next test focuses a + // menu, which Radix correctly interprets as leaving the browser window. + act(() => { + if (document.activeElement instanceof HTMLElement) + document.activeElement.blur(); + }); cleanup(); }); diff --git a/packages/app/tsconfig.app.json b/packages/app/tsconfig.app.json index 379988b7..c3510c0a 100644 --- a/packages/app/tsconfig.app.json +++ b/packages/app/tsconfig.app.json @@ -5,7 +5,7 @@ "useDefineForClassFields": true, "lib": ["ES2022", "DOM", "DOM.Iterable"], "module": "ESNext", - "types": ["vite/client"], + "types": ["vite/client", "vite-plugin-pwa/client", "node"], "skipLibCheck": true, /* Bundler mode */ @@ -30,9 +30,13 @@ "noImplicitOverride": true, /* Path Mapping */ - "baseUrl": ".", "paths": { "@/*": ["./src/*"], + "@api/utils/http-transport": [ + "../api/src/utils/http-transport.cloudflare.ts" + ], + "@api/utils/sentry": ["../api/src/utils/sentry.cloudflare.ts"], + "@api/*": ["../api/src/*"], "@tuvixrss/api": ["../api/src/index.ts"] } }, diff --git a/packages/app/tsconfig.json b/packages/app/tsconfig.json index fec8c8e5..c36d52af 100644 --- a/packages/app/tsconfig.json +++ b/packages/app/tsconfig.json @@ -5,7 +5,6 @@ { "path": "./tsconfig.node.json" } ], "compilerOptions": { - "baseUrl": ".", "paths": { "@/*": ["./src/*"] } diff --git a/packages/app/vite.config.ts b/packages/app/vite.config.ts index ee337de8..8b1c5bb1 100644 --- a/packages/app/vite.config.ts +++ b/packages/app/vite.config.ts @@ -11,7 +11,8 @@ export default defineConfig(({ mode }) => { plugins: [ tanstackRouter({ target: "react", - autoCodeSplitting: true, + routeFileIgnorePattern: "(?:__tests__|\\.(?:test|spec)\\.)", + autoCodeSplitting: mode !== "test", }), react(), tailwindcss(), @@ -52,21 +53,6 @@ export default defineConfig(({ mode }) => { }, }, }, - { - urlPattern: /\/api\/.*/i, - handler: "NetworkFirst", - options: { - cacheName: "api-cache", - expiration: { - maxEntries: 100, - maxAgeSeconds: 60 * 5, // 5 minutes - }, - networkTimeoutSeconds: 10, - cacheableResponse: { - statuses: [0, 200], - }, - }, - }, { urlPattern: /\.(png|jpg|jpeg|svg|gif|webp)$/i, handler: "CacheFirst", @@ -115,8 +101,11 @@ export default defineConfig(({ mode }) => { ], resolve: { alias: { - "@": path.resolve(__dirname, "./src"), - "@tuvixrss/api": path.resolve(__dirname, "../api/src/index.ts"), + "@": path.resolve(import.meta.dirname, "./src"), + "@tuvixrss/api": path.resolve( + import.meta.dirname, + "../api/src/index.ts" + ), }, }, server: { @@ -128,6 +117,26 @@ export default defineConfig(({ mode }) => { }, }, }, + build: { + rolldownOptions: { + output: { + codeSplitting: { + groups: [ + { + name: "react", + test: /\/node_modules\/(?:react|react-dom|scheduler)\//, + priority: 20, + }, + { + name: "sentry", + test: /\/node_modules\/@sentry\//, + priority: 10, + }, + ], + }, + }, + }, + }, optimizeDeps: { exclude: ["class-variance-authority"], }, diff --git a/packages/tricorder/package.json b/packages/tricorder/package.json index 34d65b22..eb98beda 100644 --- a/packages/tricorder/package.json +++ b/packages/tricorder/package.json @@ -56,18 +56,18 @@ "registry": "https://registry.npmjs.org/" }, "dependencies": { - "feedsmith": "^2.6.0", - "sanitize-html": "^2.17.0" + "feedsmith": "^3.0.0", + "sanitize-html": "^2.17.7" }, "devDependencies": { - "@types/sanitize-html": "^2.16.0", - "@typescript-eslint/eslint-plugin": "^8.47.0", - "@typescript-eslint/parser": "^8.47.0", - "@vitest/coverage-v8": "^4.0.13", - "eslint": "^9.39.1", - "prettier": "^3.6.2", - "typescript": "^5.9.3", - "vitest": "^4.0.13" + "@types/sanitize-html": "^2.16.1", + "@typescript-eslint/eslint-plugin": "^8.70.0", + "@typescript-eslint/parser": "^8.70.0", + "@vitest/coverage-v8": "^5.0.1", + "eslint": "^10.10.0", + "prettier": "^3.9.8", + "typescript": "~6.0.3", + "vitest": "^5.0.1" }, "engines": { "node": ">=20.0.0" diff --git a/packages/tricorder/src/browser.ts b/packages/tricorder/src/browser.ts index 151d7462..7ec9ab20 100644 --- a/packages/tricorder/src/browser.ts +++ b/packages/tricorder/src/browser.ts @@ -5,4 +5,4 @@ * Re-exports everything from main index. */ -export * from "./index"; +export * from "./index.js"; diff --git a/packages/tricorder/src/core/registry.ts b/packages/tricorder/src/core/registry.ts index f29831cd..1250b0b9 100644 --- a/packages/tricorder/src/core/registry.ts +++ b/packages/tricorder/src/core/registry.ts @@ -5,14 +5,14 @@ * Services are executed in priority order (lower priority = higher priority). */ -import { createFeedValidator } from "../validators/feed-validator"; -import { NoFeedsFoundError } from "./errors"; +import { createFeedValidator } from "../validators/feed-validator.js"; +import { NoFeedsFoundError } from "./errors.js"; import type { DiscoveryContext, DiscoveryService, DiscoveredFeed, TelemetryAdapter, -} from "./types"; +} from "./types.js"; /** * Discovery Registry - Main orchestrator for feed discovery. @@ -74,7 +74,10 @@ import type { export class DiscoveryRegistry { private services: DiscoveryService[] = []; - constructor(private telemetry?: TelemetryAdapter) {} + constructor( + private telemetry?: TelemetryAdapter, + private fetch: typeof globalThis.fetch = globalThis.fetch + ) {} /** * Register a discovery service. @@ -201,9 +204,10 @@ export class DiscoveryRegistry { const seenFeedIds = new Set(); // Create feed validator function - const validateFeed = createFeedValidator(seenUrls, seenFeedIds); + const validateFeed = createFeedValidator(seenUrls, seenFeedIds, this.fetch); const context: DiscoveryContext = { + fetch: this.fetch, seenUrls, seenFeedIds, validateFeed, diff --git a/packages/tricorder/src/core/types.ts b/packages/tricorder/src/core/types.ts index 7768621a..2198d587 100644 --- a/packages/tricorder/src/core/types.ts +++ b/packages/tricorder/src/core/types.ts @@ -56,6 +56,7 @@ export interface DiscoveryService { * Used for deduplication and feed validation. */ export interface DiscoveryContext { + fetch: typeof globalThis.fetch; /** Normalized URLs already discovered (for deduplication) */ seenUrls: Set; /** Atom feed IDs already discovered (for content-based deduplication) */ diff --git a/packages/tricorder/src/index.ts b/packages/tricorder/src/index.ts index ba6e97f7..bc74c64a 100644 --- a/packages/tricorder/src/index.ts +++ b/packages/tricorder/src/index.ts @@ -5,38 +5,38 @@ */ // Core -export { DiscoveryRegistry } from "./core/registry"; +export { DiscoveryRegistry } from "./core/registry.js"; export type { DiscoveredFeed, DiscoveryService, DiscoveryContext, TelemetryAdapter, -} from "./core/types"; +} from "./core/types.js"; export { FeedDiscoveryError, NoFeedsFoundError, FeedValidationError, -} from "./core/errors"; +} from "./core/errors.js"; // Services -export { StandardDiscoveryService } from "./services/standard-discovery"; -export { AppleDiscoveryService } from "./services/apple-discovery"; -export { RedditDiscoveryService } from "./services/reddit-discovery"; +export { StandardDiscoveryService } from "./services/standard-discovery.js"; +export { AppleDiscoveryService } from "./services/apple-discovery.js"; +export { RedditDiscoveryService } from "./services/reddit-discovery.js"; // Import for use in factory functions -import { DiscoveryRegistry } from "./core/registry"; -import { StandardDiscoveryService } from "./services/standard-discovery"; -import { AppleDiscoveryService } from "./services/apple-discovery"; -import { RedditDiscoveryService } from "./services/reddit-discovery"; -import type { DiscoveredFeed, TelemetryAdapter } from "./core/types"; +import { DiscoveryRegistry } from "./core/registry.js"; +import { StandardDiscoveryService } from "./services/standard-discovery.js"; +import { AppleDiscoveryService } from "./services/apple-discovery.js"; +import { RedditDiscoveryService } from "./services/reddit-discovery.js"; +import type { DiscoveredFeed, TelemetryAdapter } from "./core/types.js"; // Validators -export { createFeedValidator } from "./validators/feed-validator"; +export { createFeedValidator } from "./validators/feed-validator.js"; // Utilities -export { isSubdomainOf } from "./utils/domain-matcher"; -export { normalizeFeedUrl } from "./utils/url-normalize"; -export { stripHtml } from "./utils/text-sanitizer"; +export { isSubdomainOf } from "./utils/domain-matcher.js"; +export { normalizeFeedUrl } from "./utils/url-normalize.js"; +export { stripHtml } from "./utils/text-sanitizer.js"; /** * Create a discovery registry with default services registered. @@ -88,8 +88,9 @@ export { stripHtml } from "./utils/text-sanitizer"; */ export function createDefaultRegistry(options?: { telemetry?: TelemetryAdapter; + fetch?: typeof globalThis.fetch; }): DiscoveryRegistry { - const registry = new DiscoveryRegistry(options?.telemetry); + const registry = new DiscoveryRegistry(options?.telemetry, options?.fetch); registry.register(new AppleDiscoveryService()); registry.register(new RedditDiscoveryService()); registry.register(new StandardDiscoveryService()); @@ -178,8 +179,15 @@ export function createDefaultRegistry(options?: { */ export async function discoverFeeds( url: string, - options?: { telemetry?: TelemetryAdapter } + options?: { telemetry?: TelemetryAdapter; fetch?: typeof globalThis.fetch } ): Promise { const registry = createDefaultRegistry(options); return registry.discover(url); } + +export { feedText, extractFeedMetadata } from "./utils/feed-metadata.js"; + +export { + readFeedResponse, + MAX_FEED_BYTES, +} from "./utils/read-feed-response.js"; diff --git a/packages/tricorder/src/services/apple-discovery.ts b/packages/tricorder/src/services/apple-discovery.ts index 7d26d8bf..6bebffa8 100644 --- a/packages/tricorder/src/services/apple-discovery.ts +++ b/packages/tricorder/src/services/apple-discovery.ts @@ -5,12 +5,12 @@ * to look up podcast metadata and extract the RSS feed URL. */ -import { isSubdomainOf } from "../utils/domain-matcher"; +import { isSubdomainOf } from "../utils/domain-matcher.js"; import type { DiscoveryContext, DiscoveryService, DiscoveredFeed, -} from "../core/types"; +} from "../core/types.js"; /** * iTunes Search API response types @@ -125,7 +125,7 @@ export class AppleDiscoveryService implements DiscoveryService { // Call iTunes Search API const apiUrl = `https://itunes.apple.com/lookup?id=${podcastId}&entity=podcast`; - const response = await fetch(apiUrl, { + const response = await context.fetch(apiUrl, { headers: { "User-Agent": "TuvixRSS/1.0", }, diff --git a/packages/tricorder/src/services/index.ts b/packages/tricorder/src/services/index.ts index 5a05030f..41f1c267 100644 --- a/packages/tricorder/src/services/index.ts +++ b/packages/tricorder/src/services/index.ts @@ -4,6 +4,6 @@ * Exported discovery service implementations. */ -export { StandardDiscoveryService } from "./standard-discovery"; -export { AppleDiscoveryService } from "./apple-discovery"; -export { RedditDiscoveryService } from "./reddit-discovery"; +export { StandardDiscoveryService } from "./standard-discovery.js"; +export { AppleDiscoveryService } from "./apple-discovery.js"; +export { RedditDiscoveryService } from "./reddit-discovery.js"; diff --git a/packages/tricorder/src/services/reddit-discovery.ts b/packages/tricorder/src/services/reddit-discovery.ts index 1ed876d6..b0f497a1 100644 --- a/packages/tricorder/src/services/reddit-discovery.ts +++ b/packages/tricorder/src/services/reddit-discovery.ts @@ -9,7 +9,7 @@ import type { DiscoveryContext, DiscoveryService, DiscoveredFeed, -} from "../core/types"; +} from "../core/types.js"; const FETCH_TIMEOUT = 5000; @@ -168,7 +168,7 @@ export class RedditDiscoveryService implements DiscoveryService { try { const aboutUrl = `https://old.reddit.com/r/${subreddit}/about.json`; - const response = await fetch(aboutUrl, { + const response = await context.fetch(aboutUrl, { signal: controller.signal, headers: { "User-Agent": diff --git a/packages/tricorder/src/services/standard-discovery.ts b/packages/tricorder/src/services/standard-discovery.ts index dc511c12..5eef8c39 100644 --- a/packages/tricorder/src/services/standard-discovery.ts +++ b/packages/tricorder/src/services/standard-discovery.ts @@ -1,3 +1,4 @@ +import { readFeedResponse } from "../utils/read-feed-response.js"; /** * Standard URL-Based Discovery Service * @@ -11,7 +12,7 @@ import type { DiscoveryContext, DiscoveryService, DiscoveredFeed, -} from "../core/types"; +} from "../core/types.js"; /** * Standard Discovery Service @@ -152,7 +153,7 @@ export class StandardDiscoveryService implements DiscoveryService { // Step 2: Fetch HTML and parse for feed links try { - const response = await fetch(url, { + const response = await context.fetch(url, { headers: { "User-Agent": "TuvixRSS/1.0", Accept: "text/html,application/xhtml+xml", @@ -161,7 +162,7 @@ export class StandardDiscoveryService implements DiscoveryService { }); if (response.ok) { - const html = await response.text(); + const html = await readFeedResponse(response); // Parse for RSS/Atom link tags using regex const linkRegex = diff --git a/packages/tricorder/src/utils/__tests__/read-feed-response.test.ts b/packages/tricorder/src/utils/__tests__/read-feed-response.test.ts new file mode 100644 index 00000000..4bd08645 --- /dev/null +++ b/packages/tricorder/src/utils/__tests__/read-feed-response.test.ts @@ -0,0 +1,46 @@ +import { describe, expect, it, vi } from "vitest"; +import { readFeedResponse } from "../read-feed-response.js"; + +describe("bounded feed reader", () => { + it("rejects an oversized declared body before reading it", async () => { + const cancel = vi.fn(); + const body = new ReadableStream({ cancel }); + await expect( + readFeedResponse( + new Response(body, { headers: { "content-length": "100" } }), + 10 + ) + ).rejects.toThrow("maximum response size"); + expect(cancel).toHaveBeenCalledOnce(); + }); + it.each([{}, { "content-length": "1" }])( + "enforces streamed bytes even with missing or dishonest length", + async (headers) => { + const cancel = vi.fn(); + const body = new ReadableStream({ + start(controller) { + controller.enqueue(new Uint8Array(11)); + }, + cancel, + }); + await expect( + readFeedResponse(new Response(body, { headers }), 10) + ).rejects.toThrow("maximum response size"); + expect(cancel).toHaveBeenCalledOnce(); + } + ); + it("decodes multi-byte characters across chunks and allows the exact limit", async () => { + const bytes = new TextEncoder().encode("é😃"); + const body = new ReadableStream({ + start(controller) { + controller.enqueue(bytes.slice(0, 1)); + controller.enqueue(bytes.slice(1, 4)); + controller.enqueue(bytes.slice(4)); + controller.close(); + }, + }); + expect(await readFeedResponse(new Response(body), bytes.length)).toBe( + "é😃" + ); + }); +}); diff --git a/packages/tricorder/src/utils/__tests__/url-normalize.test.ts b/packages/tricorder/src/utils/__tests__/url-normalize.test.ts index b29156a7..4cca4eb3 100644 --- a/packages/tricorder/src/utils/__tests__/url-normalize.test.ts +++ b/packages/tricorder/src/utils/__tests__/url-normalize.test.ts @@ -6,7 +6,7 @@ */ import { describe, it, expect } from "vitest"; -import { normalizeFeedUrl } from "../url-normalize"; +import { normalizeFeedUrl } from "../url-normalize.js"; describe("normalizeFeedUrl", () => { describe("hostname normalization", () => { diff --git a/packages/tricorder/src/utils/feed-metadata.ts b/packages/tricorder/src/utils/feed-metadata.ts new file mode 100644 index 00000000..8aeb6544 --- /dev/null +++ b/packages/tricorder/src/utils/feed-metadata.ts @@ -0,0 +1,33 @@ +import type { AnyFeed, AtomFeed } from "feedsmith"; +import { stripHtml } from "./text-sanitizer.js"; + +/** Normalize Atom text constructs and plain RSS/JSON text. */ +export function feedText( + value: string | AtomFeed.Text | undefined +): string | undefined { + return typeof value === "string" ? value : value?.value; +} + +/** Shared metadata mapping for discovery and subscription storage. */ +export function extractFeedMetadata(feed: AnyFeed["feed"]) { + const description = + "description" in feed + ? feed.description + : "subtitle" in feed + ? feedText(feed.subtitle) + : undefined; + const siteUrl = + "home_page_url" in feed && feed.home_page_url + ? feed.home_page_url + : "link" in feed && feed.link + ? feed.link + : "links" in feed + ? feed.links?.find((link) => !link.rel || link.rel === "alternate") + ?.href + : undefined; + return { + title: feedText(feed.title) || undefined, + description: description ? stripHtml(description) : undefined, + siteUrl, + }; +} diff --git a/packages/tricorder/src/utils/index.ts b/packages/tricorder/src/utils/index.ts index 952e97cc..ea6a1a03 100644 --- a/packages/tricorder/src/utils/index.ts +++ b/packages/tricorder/src/utils/index.ts @@ -4,6 +4,10 @@ * Exported utility functions for feed discovery. */ -export { isSubdomainOf } from "./domain-matcher"; -export { normalizeFeedUrl } from "./url-normalize"; -export { stripHtml } from "./text-sanitizer"; +export { isSubdomainOf } from "./domain-matcher.js"; +export { normalizeFeedUrl } from "./url-normalize.js"; +export { stripHtml } from "./text-sanitizer.js"; + +export { feedText, extractFeedMetadata } from "./feed-metadata.js"; + +export { readFeedResponse, MAX_FEED_BYTES } from "./read-feed-response.js"; diff --git a/packages/tricorder/src/utils/read-feed-response.ts b/packages/tricorder/src/utils/read-feed-response.ts new file mode 100644 index 00000000..3e071098 --- /dev/null +++ b/packages/tricorder/src/utils/read-feed-response.ts @@ -0,0 +1,33 @@ +/** Limit decoded response bytes before allocating/parsing an untrusted feed. */ +export const MAX_FEED_BYTES = 5 * 1024 * 1024; + +export async function readFeedResponse( + response: Response, + maxBytes = MAX_FEED_BYTES +): Promise { + const declaredLength = Number(response.headers.get("content-length")); + if (declaredLength > maxBytes) { + await response.body?.cancel(); + throw new Error("Feed exceeds the maximum response size"); + } + if (!response.body) return ""; + const reader = response.body.getReader(); + const buffer = new Uint8Array(maxBytes); + let bytes = 0; + try { + while (true) { + const { done, value } = await reader.read(); + if (done) break; + if (bytes + value.byteLength > maxBytes) + throw new Error("Feed exceeds the maximum response size"); + buffer.set(value, bytes); + bytes += value.byteLength; + } + return new TextDecoder().decode(buffer.subarray(0, bytes)); + } catch (error) { + await reader.cancel().catch(() => {}); + throw error; + } finally { + reader.releaseLock(); + } +} diff --git a/packages/tricorder/src/validators/__tests__/feed-validator.test.ts b/packages/tricorder/src/validators/__tests__/feed-validator.test.ts index 1eaeef23..e768e814 100644 --- a/packages/tricorder/src/validators/__tests__/feed-validator.test.ts +++ b/packages/tricorder/src/validators/__tests__/feed-validator.test.ts @@ -6,7 +6,15 @@ */ import { describe, it, expect, beforeEach, vi } from "vitest"; -import { createFeedValidator } from "../feed-validator"; +import { createFeedValidator } from "../feed-validator.js"; + +function feedResponse(body: string, url: string): Response { + const response = new Response(body, { + headers: { "content-type": "application/xml" }, + }); + Object.defineProperty(response, "url", { value: url }); + return response; +} describe("createFeedValidator", () => { let seenUrls: Set; @@ -22,10 +30,8 @@ describe("createFeedValidator", () => { * Helper to create a mock RSS feed response */ function createMockRssResponse(url: string, title: string = "Test Feed") { - return { - ok: true, - url: url, // Final URL after redirects - text: async () => ` + return feedResponse( + ` ${title} @@ -33,7 +39,8 @@ describe("createFeedValidator", () => { Test feed description `, - } as Response; + url + ); } /** @@ -44,17 +51,16 @@ describe("createFeedValidator", () => { feedId: string, title: string = "Test Feed" ) { - return { - ok: true, - url: url, - text: async () => ` + return feedResponse( + ` ${feedId} ${title} Test feed description `, - } as Response; + url + ); } describe("basic validation", () => { @@ -410,17 +416,18 @@ describe("createFeedValidator", () => { describe("edge cases", () => { it("should handle feeds without description", async () => { - const fetchMock = vi.fn().mockResolvedValue({ - ok: true, - url: "https://example.com/feed", - text: async () => ` + const fetchMock = vi.fn().mockResolvedValue( + feedResponse( + ` Test Feed https://example.com `, - }); + "https://example.com/feed" + ) + ); global.fetch = fetchMock as any; const validator = createFeedValidator(seenUrls, seenFeedIds); @@ -435,17 +442,18 @@ describe("createFeedValidator", () => { }); it("should handle feeds without title", async () => { - const fetchMock = vi.fn().mockResolvedValue({ - ok: true, - url: "https://example.com/feed", - text: async () => ` + const fetchMock = vi.fn().mockResolvedValue( + feedResponse( + ` https://example.com Test description `, - }); + "https://example.com/feed" + ) + ); global.fetch = fetchMock as any; const validator = createFeedValidator(seenUrls, seenFeedIds); @@ -455,11 +463,11 @@ describe("createFeedValidator", () => { }); it("should handle malformed XML gracefully", async () => { - const fetchMock = vi.fn().mockResolvedValue({ - ok: true, - url: "https://example.com/feed", - text: async () => "not valid xml", - }); + const fetchMock = vi + .fn() + .mockResolvedValue( + feedResponse("not valid xml", "https://example.com/feed") + ); global.fetch = fetchMock as any; const validator = createFeedValidator(seenUrls, seenFeedIds); diff --git a/packages/tricorder/src/validators/feed-validator.ts b/packages/tricorder/src/validators/feed-validator.ts index 10be2d9a..3eba3bfb 100644 --- a/packages/tricorder/src/validators/feed-validator.ts +++ b/packages/tricorder/src/validators/feed-validator.ts @@ -1,3 +1,4 @@ +import { readFeedResponse } from "../utils/read-feed-response.js"; /** * Feed Validator Utility * @@ -6,9 +7,9 @@ */ import { parseFeed } from "feedsmith"; -import { normalizeFeedUrl } from "../utils/url-normalize"; -import { stripHtml } from "../utils/text-sanitizer"; -import type { DiscoveredFeed } from "../core/types"; +import { normalizeFeedUrl } from "../utils/url-normalize.js"; +import { extractFeedMetadata } from "../utils/feed-metadata.js"; +import type { DiscoveredFeed } from "../core/types.js"; /** * Create a feed validator function bound to deduplication sets. @@ -19,7 +20,8 @@ import type { DiscoveredFeed } from "../core/types"; */ export function createFeedValidator( seenUrls: Set, - seenFeedIds: Set + seenFeedIds: Set, + fetch: typeof globalThis.fetch = globalThis.fetch ): (feedUrl: string) => Promise { // Track in-flight requests to prevent concurrent validation of the same URL const inFlightRequests = new Map>(); @@ -75,7 +77,7 @@ export function createFeedValidator( seenUrls.add(normalizedFinalUrl); } - const feedContent = await response.text(); + const feedContent = await readFeedResponse(response); const result = parseFeed(feedContent); const feed = result.feed; @@ -108,16 +110,9 @@ export function createFeedValidator( ? "json" : "rss"; - const title = - "title" in feed && feed.title - ? String(feed.title) - : "Untitled Feed"; - const description = - "description" in feed && feed.description - ? stripHtml(String(feed.description)) - : "subtitle" in feed && feed.subtitle - ? stripHtml(String(feed.subtitle)) - : undefined; + const metadata = extractFeedMetadata(feed); + const title = metadata.title || "Untitled Feed"; + const description = metadata.description; // Return discovered feed (preserve original URL for better UX) // We use the original feedUrl instead of finalUrl so users see clean URLs diff --git a/packages/tricorder/src/validators/index.ts b/packages/tricorder/src/validators/index.ts index b34f3cdd..a659ed10 100644 --- a/packages/tricorder/src/validators/index.ts +++ b/packages/tricorder/src/validators/index.ts @@ -4,4 +4,4 @@ * Exported validator functions. */ -export { createFeedValidator } from "./feed-validator"; +export { createFeedValidator } from "./feed-validator.js"; diff --git a/packages/tricorder/tsconfig.json b/packages/tricorder/tsconfig.json index 0aefd1c2..ed774c49 100644 --- a/packages/tricorder/tsconfig.json +++ b/packages/tricorder/tsconfig.json @@ -1,9 +1,9 @@ { "compilerOptions": { "target": "ES2022", - "module": "ESNext", + "module": "NodeNext", "lib": ["ES2022", "DOM", "DOM.Iterable"], - "moduleResolution": "bundler", + "moduleResolution": "NodeNext", "resolveJsonModule": true, "allowJs": true, "checkJs": false, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index af948c67..635435a7 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,3 +1,161 @@ +--- +lockfileVersion: '9.0' + +importers: + + .: + configDependencies: {} + packageManagerDependencies: + pnpm: + specifier: 12.4.2 + version: 12.4.2 + +packages: + + '@pnpm/exe.android-arm64@12.4.2': + resolution: {integrity: sha512-E255MbcQ0V1577M2BV0ajWuP7KmTPYA0jqZnk3rK6Lq3kTvZWulMMb7iqRmnLsQbyWTkMEB2CfyM70loVDA8xg==} + cpu: [arm64] + os: [android] + + '@pnpm/exe.android-x64@12.4.2': + resolution: {integrity: sha512-J1pSeCUwuKxMG70ZzpWn8JzElxiEa8NN/3N0SlZRtU2xbztChaJCKF3HaBNIj9yPfeofWzJo/lwNvDDjraQuZw==} + cpu: [x64] + os: [android] + + '@pnpm/exe.darwin-arm64@12.4.2': + resolution: {integrity: sha512-A0WDo8iErfZBXgrLseQxw8i8Y9ctUpOEl/Uu+cubnTzpD8tT9ykIB548L8YTM2WD4OS+ZOHSxy8aGZcvKq8PaQ==} + cpu: [arm64] + os: [darwin] + + '@pnpm/exe.darwin-x64@12.4.2': + resolution: {integrity: sha512-MSgJdovBWHcb5DEOvfPH9yNi/T5O1Xa4ess+E1ESGo/5yuty7S4JoiIjami+fsNXfnoQMlwsMUqYU4zAvBcNCw==} + cpu: [x64] + os: [darwin] + + '@pnpm/exe.freebsd-x64@12.4.2': + resolution: {integrity: sha512-h2YumlQSNvgbRPv+RXwABohX65f9bOBZn+jMIt7bFDISZPCzQ+Nvpt6Awbp4ip5PwQgYxbu5iREJ1fHE39Fm8A==} + cpu: [x64] + os: [freebsd] + + '@pnpm/exe.linux-arm64-musl@12.4.2': + resolution: {integrity: sha512-LwSEtSEDTv6S51YLs3YvSkPyun/QmfMic1UGICUkPWFu6ByP43RdMlkKvmVkfGhAYCpnxO057vrmyJqtfZrPCA==} + cpu: [arm64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-arm64@12.4.2': + resolution: {integrity: sha512-2dSiDXyhx+RTHsewxex8f/jVjqQXWJ2oow4kCVHEWdZKeBpgMxvZ6fHkTAUBJXgqhbKIDHvuNlZBP7gJfUWL5A==} + cpu: [arm64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-ppc64@12.4.2': + resolution: {integrity: sha512-8Itc+jQk+MTz04LS9D1RcH+VctAWmzM4l1cJQ+Sx7pAJNo7EKHdRMbC0Tok1jyQ7eEHNJZD5EleYneZqWfZM+g==} + cpu: [ppc64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-riscv64@12.4.2': + resolution: {integrity: sha512-hleOeqhTVpH+z9RVMGnxvU4ZnrkBUClWjCbHD9u6kwyqhGSpevoU1wTGish+CBRhmIgMAy9pAfFpqhbAKOKNfw==} + cpu: [riscv64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-s390x@12.4.2': + resolution: {integrity: sha512-LAsQRRdP9aToENR6dtcIJ9l+e1zMYOX0tQcLGpRyLPVBQcYRLlvAPcmDshsiIHQjp05SDa9FI0czX1ZQ1a7a/A==} + cpu: [s390x] + os: [linux] + libc: [glibc] + + '@pnpm/exe.linux-x64-musl@12.4.2': + resolution: {integrity: sha512-kzfzH2/0BWdTABK14Yj5a1xsdkTEQUp2eXEPNakaD9jKL025lq3hyaKHIz/gIZaPDMe/1bFFK/En4ztFlbBJxw==} + cpu: [x64] + os: [linux] + libc: [musl] + + '@pnpm/exe.linux-x64@12.4.2': + resolution: {integrity: sha512-/pbt0UVTa8NMDhzOWLQRfZ6G9ROKXlJPZtx845BqyWfc7hCrWXhTLBd70yO2y8+E+IWN3oHM1s/JsIQNGk1yvg==} + cpu: [x64] + os: [linux] + libc: [glibc] + + '@pnpm/exe.win32-arm64@12.4.2': + resolution: {integrity: sha512-PsW19e4dAUNpZ0cS9flaxFuAmpt2dKlH/Vvi8TZ4qyJjjQzue/CEsWm+6wKVP4CJ7IT8RdL4qh+soOPWIgF2Zw==} + cpu: [arm64] + os: [win32] + + '@pnpm/exe.win32-x64@12.4.2': + resolution: {integrity: sha512-+xGoeE0g55ztWvl8i5QqdmNfW3nIrTVcoQrNshEOwxthm9Ag48oXton3uxOA3/SANyz5AXexEjj2KO20NnOrEw==} + cpu: [x64] + os: [win32] + + pnpm@12.4.2: + resolution: {integrity: sha512-CK3GYTGAJ1x8ntraOdzwjJxhrU5+rzMKTzRh8QKw+QdCNFTRF/mOctR/7wYWBwZE17/8lzpqV/UJCm18NosHyQ==} + engines: {node: '>=18.*'} + hasBin: true + +snapshots: + + '@pnpm/exe.android-arm64@12.4.2': + optional: true + + '@pnpm/exe.android-x64@12.4.2': + optional: true + + '@pnpm/exe.darwin-arm64@12.4.2': + optional: true + + '@pnpm/exe.darwin-x64@12.4.2': + optional: true + + '@pnpm/exe.freebsd-x64@12.4.2': + optional: true + + '@pnpm/exe.linux-arm64-musl@12.4.2': + optional: true + + '@pnpm/exe.linux-arm64@12.4.2': + optional: true + + '@pnpm/exe.linux-ppc64@12.4.2': + optional: true + + '@pnpm/exe.linux-riscv64@12.4.2': + optional: true + + '@pnpm/exe.linux-s390x@12.4.2': + optional: true + + '@pnpm/exe.linux-x64-musl@12.4.2': + optional: true + + '@pnpm/exe.linux-x64@12.4.2': + optional: true + + '@pnpm/exe.win32-arm64@12.4.2': + optional: true + + '@pnpm/exe.win32-x64@12.4.2': + optional: true + + pnpm@12.4.2: + optionalDependencies: + '@pnpm/exe.android-arm64': 12.4.2 + '@pnpm/exe.android-x64': 12.4.2 + '@pnpm/exe.darwin-arm64': 12.4.2 + '@pnpm/exe.darwin-x64': 12.4.2 + '@pnpm/exe.freebsd-x64': 12.4.2 + '@pnpm/exe.linux-arm64': 12.4.2 + '@pnpm/exe.linux-arm64-musl': 12.4.2 + '@pnpm/exe.linux-ppc64': 12.4.2 + '@pnpm/exe.linux-riscv64': 12.4.2 + '@pnpm/exe.linux-s390x': 12.4.2 + '@pnpm/exe.linux-x64': 12.4.2 + '@pnpm/exe.linux-x64-musl': 12.4.2 + '@pnpm/exe.win32-arm64': 12.4.2 + '@pnpm/exe.win32-x64': 12.4.2 + +--- lockfileVersion: '9.0' settings: @@ -5,236 +163,235 @@ settings: excludeLinksFromLockfile: false overrides: - vite: npm:rolldown-vite@7.2.7 - esbuild: '>=0.25.0' + esbuild: '>=0.28.1' importers: .: devDependencies: concurrently: - specifier: ^9.2.1 - version: 9.2.1 - eslint-plugin-no-relative-import-paths: - specifier: ^1.6.1 - version: 1.6.1 + specifier: ^10.0.5 + version: 10.0.5 + node-gyp: + specifier: ^13.0.2 + version: 13.0.2 nyc: - specifier: ^17.1.0 - version: 17.1.0 + specifier: ^18.0.0 + version: 18.0.0(supports-color@10.2.2) prettier: - specifier: ^3.7.4 - version: 3.7.4 + specifier: ^3.9.8 + version: 3.9.8 shadcn: - specifier: ^3.5.1 - version: 3.5.1(@types/node@24.10.1)(typescript@5.9.3) + specifier: ^4.21.0 + version: 4.21.0(supports-color@10.2.2)(typescript@7.0.2) packages/api: dependencies: '@ai-sdk/openai': - specifier: ^3.0.7 - version: 3.0.7(zod@4.1.12) + specifier: ^4.0.70 + version: 4.0.70(zod@4.6.5) '@hono/node-server': - specifier: ^1.19.6 - version: 1.19.6(hono@4.10.6) + specifier: ^2.1.1 + version: 2.1.1(hono@4.13.8) '@hono/trpc-server': - specifier: ^0.4.1 - version: 0.4.1(@trpc/server@11.7.2(typescript@5.9.3))(hono@4.10.6) - '@react-email/components': - specifier: ^1.0.1 - version: 1.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^0.4.2 + version: 0.4.2(@trpc/server@11.19.0(typescript@6.0.3))(hono@4.13.8) '@sentry/cloudflare': - specifier: ^10.26.0 - version: 10.26.0(@cloudflare/workers-types@4.20251121.0) + specifier: ^10.75.0 + version: 10.75.0(@cloudflare/workers-types@5.20260918.1)(wrangler@4.135.0(@cloudflare/workers-types@5.20260918.1)(@types/node@24.13.5)) '@sentry/node': - specifier: ^10.26.0 - version: 10.26.0 + specifier: ^10.75.0 + version: 10.75.0(@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1))(supports-color@10.2.2) '@trpc/server': - specifier: ^11.7.2 - version: 11.7.2(typescript@5.9.3) + specifier: ^11.19.0 + version: 11.19.0(typescript@6.0.3) '@tuvixrss/tricorder': specifier: workspace:* version: link:../tricorder ai: - specifier: ^6.0.19 - version: 6.0.19(zod@4.1.12) + specifier: ^7.0.106 + version: 7.0.106(zod@4.6.5) bcrypt: specifier: ^6.0.0 version: 6.0.0 better-auth: - specifier: ^1.4.1 - version: 1.4.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.7.5 + version: 1.7.5(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(vitest@5.0.1) better-sqlite3: - specifier: ^12.4.6 - version: 12.4.6 + specifier: ^13.0.3 + version: 13.0.3 drizzle-orm: - specifier: ^0.44.7 - version: 0.44.7(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.15.5)(better-sqlite3@12.4.6)(kysely@0.28.8) + specifier: ^0.45.2 + version: 0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6) drizzle-zod: specifier: ^0.8.3 - version: 0.8.3(drizzle-orm@0.44.7(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.15.5)(better-sqlite3@12.4.6)(kysely@0.28.8))(zod@4.1.12) - eslint-plugin-drizzle: - specifier: ^0.2.3 - version: 0.2.3(eslint@9.39.1(jiti@2.6.1)) + version: 0.8.3(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6))(zod@4.6.5) feedsmith: - specifier: ^2.6.0 - version: 2.6.0 + specifier: ^3.0.0 + version: 3.0.0 hono: - specifier: ^4.10.6 - version: 4.10.6 + specifier: ^4.13.8 + version: 4.13.8 + ipaddr.js: + specifier: 2.5.0 + version: 2.5.0 node-cron: - specifier: ^4.2.1 - version: 4.2.1 + specifier: ^4.6.0 + version: 4.6.0 react-email: - specifier: ^5.0.5 - version: 5.0.5 + specifier: ^6.9.5 + version: 6.9.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(supports-color@10.2.2) resend: - specifier: ^6.5.2 - version: 6.5.2(@react-email/render@2.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)) + specifier: ^6.28.1 + version: 6.28.1(@react-email/render@2.1.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0)) sanitize-html: - specifier: ^2.17.0 - version: 2.17.0 + specifier: ^2.17.7 + version: 2.17.7 superjson: specifier: ^2.2.6 version: 2.2.6 + undici: + specifier: 8.10.2 + version: 8.10.2 zod: - specifier: ^4.1.12 - version: 4.1.12 + specifier: ^4.6.5 + version: 4.6.5 devDependencies: '@cloudflare/workers-types': - specifier: ^4.20251121.0 - version: 4.20251121.0 - '@react-email/preview-server': - specifier: 5.0.5 - version: 5.0.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^5.20260918.1 + version: 5.20260918.1 '@types/bcrypt': specifier: ^6.0.0 version: 6.0.0 '@types/better-sqlite3': - specifier: ^7.6.13 - version: 7.6.13 + specifier: ^9.6.0 + version: 9.6.0 '@types/node': - specifier: ^24.10.1 - version: 24.10.1 + specifier: ^24.13.5 + version: 24.13.5 '@types/node-cron': specifier: ^3.0.11 version: 3.0.11 '@types/react': - specifier: ^19.2.6 - version: 19.2.6 + specifier: ^19.3.0 + version: 19.3.0 '@types/sanitize-html': - specifier: ^2.16.0 - version: 2.16.0 + specifier: ^2.16.1 + version: 2.16.1 '@typescript-eslint/eslint-plugin': - specifier: ^8.47.0 - version: 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.70.0 + version: 8.70.0(@typescript-eslint/parser@8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) '@typescript-eslint/parser': - specifier: ^8.47.0 - version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.70.0 + version: 8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) '@vitest/coverage-v8': - specifier: ^4.0.13 - version: 4.0.13(vitest@4.0.13) + specifier: ^5.0.1 + version: 5.0.1(vitest@5.0.1) drizzle-kit: - specifier: ^0.31.7 - version: 0.31.7 + specifier: ^0.31.10 + version: 0.31.10 eslint: - specifier: ^9.39.1 - version: 9.39.1(jiti@2.6.1) + specifier: ^10.10.0 + version: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) + eslint-plugin-drizzle: + specifier: ^0.2.3 + version: 0.2.3(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2)) knip: - specifier: ^5.70.1 - version: 5.70.1(@types/node@24.10.1)(typescript@5.9.3) + specifier: ^6.37.0 + version: 6.37.0 prettier: - specifier: ^3.6.2 - version: 3.6.2 + specifier: ^3.9.8 + version: 3.9.8 react: - specifier: ^19.2.0 - version: 19.2.0 + specifier: ^19.3.0 + version: 19.3.0 tsup: specifier: ^8.5.1 - version: 8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3) + version: 8.5.1(jiti@2.6.1)(postcss@8.5.28)(supports-color@10.2.2)(tsx@4.23.13)(typescript@6.0.3)(yaml@2.9.1) tsx: - specifier: ^4.20.6 - version: 4.20.6 + specifier: ^4.23.13 + version: 4.23.13 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ~6.0.3 + version: 6.0.3 vitest: - specifier: ^4.0.13 - version: 4.0.13(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/ui@4.0.13)(esbuild@0.27.0)(jiti@2.6.1)(jsdom@27.2.0)(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6) + specifier: ^5.0.1 + version: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@24.13.5)(@vitest/coverage-v8@5.0.1)(@vitest/ui@5.0.1)(jsdom@30.1.0(@noble/hashes@2.4.0))(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) wrangler: - specifier: ^4.50.0 - version: 4.50.0(@cloudflare/workers-types@4.20251121.0) + specifier: ^4.135.0 + version: 4.135.0(@cloudflare/workers-types@5.20260918.1)(@types/node@24.13.5) packages/app: dependencies: '@floating-ui/react': - specifier: ^0.27.16 - version: 0.27.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^0.27.20 + version: 0.27.20(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@hookform/resolvers': - specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.66.1(react@19.2.0)) + specifier: ^5.9.1 + version: 5.9.1(@standard-schema/spec@1.1.0)(ajv-formats@2.1.1(ajv@8.20.0))(ajv@8.20.0)(react-hook-form@7.88.0(react@19.3.0))(zod@4.6.5) '@radix-ui/react-avatar': - specifier: ^1.1.11 - version: 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.2.6 + version: 1.2.6(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@radix-ui/react-checkbox': - specifier: ^1.3.3 - version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.3.11 + version: 1.3.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@radix-ui/react-dialog': - specifier: ^1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.1.23 + version: 1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@radix-ui/react-label': - specifier: ^2.1.8 - version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^2.1.15 + version: 2.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@radix-ui/react-popover': - specifier: ^1.1.15 - version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.1.23 + version: 1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@radix-ui/react-scroll-area': - specifier: ^1.2.10 - version: 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.2.18 + version: 1.2.18(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@radix-ui/react-select': - specifier: ^2.2.6 - version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^2.3.7 + version: 2.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@radix-ui/react-separator': - specifier: ^1.1.8 - version: 1.1.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.1.15 + version: 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@radix-ui/react-slot': - specifier: ^1.2.4 - version: 1.2.4(@types/react@19.2.6)(react@19.2.0) + specifier: ^1.3.3 + version: 1.3.3(@types/react@19.3.0)(react@19.3.0) '@radix-ui/react-tooltip': - specifier: ^1.2.8 - version: 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.2.16 + version: 1.2.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@sentry/react': - specifier: ^10.26.0 - version: 10.26.0(react@19.2.0) + specifier: ^10.75.0 + version: 10.75.0(react@19.3.0) '@tailwindcss/typography': - specifier: ^0.5.19 - version: 0.5.19(tailwindcss@4.1.17) + specifier: ^0.5.20 + version: 0.5.20(tailwindcss@4.3.3) '@tailwindcss/vite': - specifier: ^4.1.17 - version: 4.1.17(rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)) + specifier: ^4.3.3 + version: 4.3.3(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) '@tanstack/react-query': - specifier: ^5.90.10 - version: 5.90.10(react@19.2.0) + specifier: ^5.103.1 + version: 5.103.1(react@19.3.0) '@tanstack/react-router': - specifier: ^1.139.3 - version: 1.139.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.170.38 + version: 1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@tanstack/react-table': - specifier: ^8.21.3 - version: 8.21.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^9.2.4 + version: 9.2.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@trpc/client': - specifier: ^11.7.2 - version: 11.7.2(@trpc/server@11.7.2(typescript@5.9.3))(typescript@5.9.3) + specifier: ^11.19.0 + version: 11.19.0(@trpc/server@11.19.0(typescript@6.0.3))(typescript@6.0.3) '@trpc/react-query': - specifier: ^11.7.2 - version: 11.7.2(@tanstack/react-query@5.90.10(react@19.2.0))(@trpc/client@11.7.2(@trpc/server@11.7.2(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.7.2(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3) + specifier: ^11.19.0 + version: 11.19.0(@tanstack/react-query@5.103.1(react@19.3.0))(@trpc/client@11.19.0(@trpc/server@11.19.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/server@11.19.0(typescript@6.0.3))(react@19.3.0)(typescript@6.0.3) '@trpc/server': - specifier: ^11.7.2 - version: 11.7.2(typescript@5.9.3) + specifier: ^11.19.0 + version: 11.19.0(typescript@6.0.3) '@tuvixrss/api': specifier: workspace:* version: link:../api better-auth: - specifier: ^1.4.1 - version: 1.4.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.7.5 + version: 1.7.5(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(vitest@5.0.1) class-variance-authority: specifier: ^0.7.1 version: 0.7.1 @@ -243,355 +400,352 @@ importers: version: 2.1.1 cmdk: specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 1.1.1(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) lucide-react: - specifier: ^0.554.0 - version: 0.554.0(react@19.2.0) + specifier: ^1.47.0 + version: 1.47.0(react@19.3.0) motion: - specifier: ^12.23.24 - version: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^13.4.0 + version: 13.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) radix-ui: - specifier: ^1.4.3 - version: 1.4.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^1.6.7 + version: 1.6.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) react: - specifier: ^19.2.0 - version: 19.2.0 + specifier: ^19.3.0 + version: 19.3.0 react-dom: - specifier: ^19.2.0 - version: 19.2.0(react@19.2.0) + specifier: ^19.3.0 + version: 19.3.0(react@19.3.0) react-hook-form: - specifier: ^7.66.1 - version: 7.66.1(react@19.2.0) + specifier: ^7.88.0 + version: 7.88.0(react@19.3.0) react-intersection-observer: - specifier: ^10.0.0 - version: 10.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^11.0.1 + version: 11.0.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0) recharts: - specifier: 3.5.0 - version: 3.5.0(@types/react@19.2.6)(eslint@9.39.1(jiti@2.6.1))(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1) + specifier: 3.10.1 + version: 3.10.1(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react-is@19.3.0)(react@19.3.0)(redux@5.0.1) sonner: - specifier: ^2.0.7 - version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^2.0.8 + version: 2.0.8(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) superjson: specifier: ^2.2.6 version: 2.2.6 tailwind-merge: - specifier: ^3.4.0 - version: 3.4.0 + specifier: ^3.7.0 + version: 3.7.0 tailwindcss: - specifier: ^4.1.17 - version: 4.1.17 + specifier: ^4.3.3 + version: 4.3.3 vaul: specifier: ^1.1.2 - version: 1.1.2(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + version: 1.1.2(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) zod: - specifier: ^4.1.12 - version: 4.1.12 + specifier: ^4.6.5 + version: 4.6.5 devDependencies: '@eslint/js': - specifier: ^9.39.1 - version: 9.39.1 + specifier: ^10.0.1 + version: 10.0.1(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2)) '@tanstack/router-cli': - specifier: ^1.139.3 - version: 1.139.3 + specifier: ^1.167.38 + version: 1.167.38(supports-color@10.2.2) '@tanstack/router-plugin': - specifier: ^1.139.3 - version: 1.139.3(@tanstack/react-router@1.139.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)) + specifier: ^1.168.40 + version: 1.168.40(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(esbuild@0.28.2)(rolldown@1.2.9)(rollup@4.63.3)(supports-color@10.2.2)(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) '@testing-library/jest-dom': - specifier: ^6.9.1 - version: 6.9.1 + specifier: ^7.0.1 + version: 7.0.1(@testing-library/dom@10.4.2)(vitest@5.0.1) '@testing-library/react': - specifier: ^16.3.0 - version: 16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + specifier: ^16.3.3 + version: 16.3.3(@testing-library/dom@10.4.2)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) '@testing-library/user-event': - specifier: ^14.6.1 - version: 14.6.1(@testing-library/dom@10.4.1) + specifier: ^14.6.7 + version: 14.6.7(@testing-library/dom@10.4.2) '@types/node': - specifier: ^24.10.1 - version: 24.10.1 + specifier: ^24.13.5 + version: 24.13.5 '@types/react': - specifier: ^19.2.6 - version: 19.2.6 + specifier: ^19.3.0 + version: 19.3.0 '@types/react-dom': - specifier: ^19.2.3 - version: 19.2.3(@types/react@19.2.6) + specifier: ^19.3.0 + version: 19.3.0(@types/react@19.3.0) '@vitejs/plugin-react': - specifier: ^5.1.1 - version: 5.1.1(rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)) + specifier: ^6.1.1 + version: 6.1.1(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) '@vitest/coverage-v8': - specifier: ^4.0.13 - version: 4.0.13(vitest@4.0.13) + specifier: ^5.0.1 + version: 5.0.1(vitest@5.0.1) '@vitest/ui': - specifier: ^4.0.13 - version: 4.0.13(vitest@4.0.13) + specifier: ^5.0.1 + version: 5.0.1(vitest@5.0.1) eslint: - specifier: ^9.39.1 - version: 9.39.1(jiti@2.6.1) + specifier: ^10.10.0 + version: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) eslint-plugin-react-hooks: - specifier: ^7.0.1 - version: 7.0.1(eslint@9.39.1(jiti@2.6.1)) + specifier: ^7.1.1 + version: 7.1.1(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2) eslint-plugin-react-refresh: - specifier: ^0.4.24 - version: 0.4.24(eslint@9.39.1(jiti@2.6.1)) + specifier: ^0.5.7 + version: 0.5.7(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2)) globals: - specifier: ^16.5.0 - version: 16.5.0 + specifier: ^17.12.0 + version: 17.12.0 jsdom: - specifier: ^27.2.0 - version: 27.2.0 + specifier: ^30.1.0 + version: 30.1.0(@noble/hashes@2.4.0) knip: - specifier: ^5.70.1 - version: 5.70.1(@types/node@24.10.1)(typescript@5.9.3) + specifier: ^6.37.0 + version: 6.37.0 prettier: - specifier: ^3.6.2 - version: 3.6.2 + specifier: ^3.9.8 + version: 3.9.8 sharp: - specifier: ^0.34.5 - version: 0.34.5 + specifier: ^0.35.4 + version: 0.35.4(@types/node@24.13.5) tw-animate-css: specifier: ^1.4.0 version: 1.4.0 typescript: - specifier: ~5.9.3 - version: 5.9.3 + specifier: ~6.0.3 + version: 6.0.3 typescript-eslint: - specifier: ^8.47.0 - version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.70.0 + version: 8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) vite: - specifier: npm:rolldown-vite@7.2.7 - version: rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6) + specifier: ^8.3.0 + version: 8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1) vite-plugin-pwa: - specifier: ^1.1.0 - version: 1.1.0(rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.4.0) + specifier: ^1.3.0 + version: 1.3.0(supports-color@10.2.2)(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1))(workbox-build@7.4.1(supports-color@10.2.2))(workbox-window@7.4.1) vitest: - specifier: ^4.0.13 - version: 4.0.13(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/ui@4.0.13)(esbuild@0.27.0)(jiti@2.6.1)(jsdom@27.2.0)(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6) + specifier: ^5.0.1 + version: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@24.13.5)(@vitest/coverage-v8@5.0.1)(@vitest/ui@5.0.1)(jsdom@30.1.0(@noble/hashes@2.4.0))(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) workbox-window: - specifier: ^7.4.0 - version: 7.4.0 + specifier: ^7.4.1 + version: 7.4.1 packages/tricorder: dependencies: feedsmith: - specifier: ^2.6.0 - version: 2.6.0 + specifier: ^3.0.0 + version: 3.0.0 sanitize-html: - specifier: ^2.17.0 - version: 2.17.0 + specifier: ^2.17.7 + version: 2.17.7 devDependencies: '@types/sanitize-html': - specifier: ^2.16.0 - version: 2.16.0 + specifier: ^2.16.1 + version: 2.16.1 '@typescript-eslint/eslint-plugin': - specifier: ^8.47.0 - version: 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.70.0 + version: 8.70.0(@typescript-eslint/parser@8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) '@typescript-eslint/parser': - specifier: ^8.47.0 - version: 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + specifier: ^8.70.0 + version: 8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) '@vitest/coverage-v8': - specifier: ^4.0.13 - version: 4.0.13(vitest@4.0.13) + specifier: ^5.0.1 + version: 5.0.1(vitest@5.0.1) eslint: - specifier: ^9.39.1 - version: 9.39.1(jiti@2.6.1) + specifier: ^10.10.0 + version: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) prettier: - specifier: ^3.6.2 - version: 3.6.2 + specifier: ^3.9.8 + version: 3.9.8 typescript: - specifier: ^5.9.3 - version: 5.9.3 + specifier: ~6.0.3 + version: 6.0.3 vitest: - specifier: ^4.0.13 - version: 4.0.13(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/ui@4.0.13)(esbuild@0.27.0)(jiti@2.6.1)(jsdom@27.2.0)(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6) + specifier: ^5.0.1 + version: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@26.6.1)(@vitest/coverage-v8@5.0.1)(@vitest/ui@5.0.1)(jsdom@30.1.0(@noble/hashes@2.4.0))(vite@8.3.0(@types/node@26.6.1)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) packages: - '@acemir/cssom@0.9.24': - resolution: {integrity: sha512-5YjgMmAiT2rjJZU7XK1SNI7iqTy92DpaYVgG6x63FxkJ11UpYfLndHJATtinWJClAXiOlW9XWaUyAQf8pMrQPg==} - - '@adobe/css-tools@4.4.4': - resolution: {integrity: sha512-Elp+iwUx5rN5+Y8xLt5/GRoG20WGoDCQ/1Fb+1LiGtvwbDavuSk0jhD/eZdckHAuzcDzccnkv+rEjyWfRx18gg==} + '@adobe/css-tools@4.5.0': + resolution: {integrity: sha512-6OzddxPio9UiWTCemp4N8cYLV2ZN1ncRnV1cVGtve7dhPOtRkleRyx32GQCYSwDYgaHU3USMm84tNsvKzRCa1Q==} - '@ai-sdk/gateway@3.0.10': - resolution: {integrity: sha512-sRlPMKd38+fdp2y11USW44c0o8tsIsT6T/pgyY04VXC3URjIRnkxugxd9AkU2ogfpPDMz50cBAGPnMxj+6663Q==} - engines: {node: '>=18'} + '@ai-sdk/gateway@4.0.86': + resolution: {integrity: sha512-sPqb9+Uparn18A7zf6GDXXIx/+tsdA7V43NyL+HaHMBl7wrFaO9fBEf4/FoiKn1D/zv0Cc3PgpJX9JsuG7MKeg==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/openai@3.0.7': - resolution: {integrity: sha512-CBoYn1U59Lop8yBL9KuVjHCKc/B06q9Qo0SasRwHoyMEq+X4I8LQZu3a8Ck1jwwcZTTxfyiExB70LtIRSynBDA==} - engines: {node: '>=18'} + '@ai-sdk/openai@4.0.70': + resolution: {integrity: sha512-D2JjGOPnn67HYqMn/22/xtel0Gdz/0jSwe6Ig7HMa0piGmAekBfg71vAmFwx3GN9PZPKB+JUIpuzTASRLUBVKw==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider-utils@4.0.4': - resolution: {integrity: sha512-VxhX0B/dWGbpNHxrKCWUAJKXIXV015J4e7qYjdIU9lLWeptk0KMLGcqkB4wFxff5Njqur8dt8wRi1MN9lZtDqg==} - engines: {node: '>=18'} + '@ai-sdk/provider-utils@5.0.44': + resolution: {integrity: sha512-TZGr0Al1mMnRh7Wd+3qTnSdWvBDIst2Abl8mglkob8rbXF1TG5xoeVLV19rD/AtB+NL/LUPITdbQ0EFGHRBcSw==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 - '@ai-sdk/provider@3.0.2': - resolution: {integrity: sha512-HrEmNt/BH/hkQ7zpi2o6N3k1ZR1QTb7z85WYhYygiTxOQuaml4CMtHCWRbric5WPU+RNsYI7r1EpyVQMKO1pYw==} - engines: {node: '>=18'} - - '@antfu/ni@25.0.0': - resolution: {integrity: sha512-9q/yCljni37pkMr4sPrI3G4jqdIk074+iukc5aFJl7kmDCCsiJrbZ6zKxnES1Gwg+i9RcDZwvktl23puGslmvA==} - hasBin: true + '@ai-sdk/provider@4.0.17': + resolution: {integrity: sha512-VYMBxIQdcHqbIf1j+YZlI9Ati6LZ4wJe0GGd4z4a5H/KxTggjeOiyaVYTnfF7LHZK5jMQ+rofmzz4QPqf++NUw==} + engines: {node: '>=22'} - '@apideck/better-ajv-errors@0.3.6': - resolution: {integrity: sha512-P+ZygBLZtkp0qqOAJJVX4oX/sFo5JR3eBWwwuqHHhK0GIgQOKWrAfiAaWX0aArHkRWHMuggFEgAZNxVPwPZYaA==} + '@apideck/better-ajv-errors@0.3.7': + resolution: {integrity: sha512-TajUJwGWbDwkCx/CZi7tRE8PVB7simCvKJfHUsSdvps+aTM/PDPP4gkLmKnc+x3CE//y9i/nj74GqdL/hwk7Iw==} engines: {node: '>=10'} peerDependencies: ajv: '>=8' - '@apm-js-collab/code-transformer@0.8.2': - resolution: {integrity: sha512-YRjJjNq5KFSjDUoqu5pFUWrrsvGOxl6c3bu+uMFc9HNNptZ2rNU/TI2nLw4jnhQNtka972Ee2m3uqbvDQtPeCA==} + '@asamuzakjp/css-color@7.0.0': + resolution: {integrity: sha512-IxddtGnnoidVSO6O/aiTueptbTThHvi2qGHu9/AWuD1J7i86Ox+jl+Y5SXcDH1RixzQlP2cjH/PjnlImZiAurQ==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} - '@apm-js-collab/tracing-hooks@0.3.1': - resolution: {integrity: sha512-Vu1CbmPURlN5fTboVuKMoJjbO5qcq9fA5YXpskx3dXe/zTBvjODFoerw+69rVBlRLrJpwPqSDqEuJDEKIrTldw==} + '@asamuzakjp/dom-selector@9.2.0': + resolution: {integrity: sha512-qKvLetaSd/OTWif9JT0eu1SHBg3H7Nvp9SoMwMxqT5tmYyrxea/P1A5pIfGbnIJlOtm3yVeqw+ORxDOkjN1aEw==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} - '@asamuzakjp/css-color@4.1.0': - resolution: {integrity: sha512-9xiBAtLn4aNsa4mDnpovJvBn72tNEIACyvlqaNJ+ADemR+yeMJWnBudOi2qGDviJa7SwcDOU/TRh5dnET7qk0w==} - - '@asamuzakjp/dom-selector@6.7.4': - resolution: {integrity: sha512-buQDjkm+wDPXd6c13534URWZqbz0RP5PAhXZ+LIoa5LgwInT9HVJvGIJivg75vi8I13CxDGdTnz+aY5YUJlIAA==} - - '@asamuzakjp/nwsapi@2.3.9': - resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} - - '@babel/code-frame@7.27.1': - resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} engines: {node: '>=6.9.0'} - '@babel/compat-data@7.28.5': - resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} engines: {node: '>=6.9.0'} - '@babel/core@7.28.5': - resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} engines: {node: '>=6.9.0'} - '@babel/generator@7.28.5': - resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} + '@babel/generator@7.29.8': + resolution: {integrity: sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==} engines: {node: '>=6.9.0'} - '@babel/helper-annotate-as-pure@7.27.3': - resolution: {integrity: sha512-fXSwMQqitTGeHLBC08Eq5yXz2m37E4pJX1qAU1+2cNedz/ifv/bVXft90VeSav5nFO61EcNgwr0aJxbyPaWBPg==} + '@babel/helper-annotate-as-pure@7.29.7': + resolution: {integrity: sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==} engines: {node: '>=6.9.0'} - '@babel/helper-compilation-targets@7.27.2': - resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} engines: {node: '>=6.9.0'} - '@babel/helper-create-class-features-plugin@7.28.5': - resolution: {integrity: sha512-q3WC4JfdODypvxArsJQROfupPBq9+lMwjKq7C33GhbFYJsufD0yd/ziwD+hJucLeWsnFPWZjsU2DNFqBPE7jwQ==} + '@babel/helper-create-class-features-plugin@7.29.7': + resolution: {integrity: sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-create-regexp-features-plugin@7.28.5': - resolution: {integrity: sha512-N1EhvLtHzOvj7QQOUCCS3NrPJP8c5W6ZXCHDn7Yialuy1iu4r5EmIYkXlKNqT99Ciw+W0mDqWoR6HWMZlFP3hw==} + '@babel/helper-create-regexp-features-plugin@7.29.7': + resolution: {integrity: sha512-907Uymvqgg1dwUA+7IGwFAOSYzQOuzPXKNJ1yxzwPffzkYFg2q2eHi1fIOs6sXkG9NbIUMunnUlkYsfRFNvomg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-define-polyfill-provider@0.6.5': - resolution: {integrity: sha512-uJnGFcPsWQK8fvjgGP5LZUZZsYGIoPeRjSF5PGwrelYgq7Q15/Ft9NGFp1zglwgIv//W0uG4BevRuSJRyylZPg==} + '@babel/helper-define-polyfill-provider@0.6.8': + resolution: {integrity: sha512-47UwBLPpQi1NoWzLuHNjRoHlYXMwIJoBf7MFou6viC/sIHWYygpvr0B6IAyh5sBdA2nr2LPIRww8lfaUVQINBA==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - '@babel/helper-globals@7.28.0': - resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} engines: {node: '>=6.9.0'} - '@babel/helper-member-expression-to-functions@7.28.5': - resolution: {integrity: sha512-cwM7SBRZcPCLgl8a7cY0soT1SptSzAlMH39vwiRpOQkJlh53r5hdHwLSCZpQdVLT39sZt+CRpNwYG4Y2v77atg==} + '@babel/helper-member-expression-to-functions@7.29.7': + resolution: {integrity: sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==} engines: {node: '>=6.9.0'} - '@babel/helper-module-imports@7.27.1': - resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} engines: {node: '>=6.9.0'} - '@babel/helper-module-transforms@7.28.3': - resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-optimise-call-expression@7.27.1': - resolution: {integrity: sha512-URMGH08NzYFhubNSGJrpUEphGKQwMQYBySzat5cAByY1/YgIRkULnIy3tAMeszlL/so2HbeilYloUmSpd7GdVw==} + '@babel/helper-optimise-call-expression@7.29.7': + resolution: {integrity: sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==} engines: {node: '>=6.9.0'} - '@babel/helper-plugin-utils@7.27.1': - resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} engines: {node: '>=6.9.0'} - '@babel/helper-remap-async-to-generator@7.27.1': - resolution: {integrity: sha512-7fiA521aVw8lSPeI4ZOD3vRFkoqkJcS+z4hFo82bFSH/2tNd6eJ5qCVMS5OzDmZh/kaHQeBaeyxK6wljcPtveA==} + '@babel/helper-remap-async-to-generator@7.29.7': + resolution: {integrity: sha512-16AMiW26DbXWBbr3B8wNozKM0ydMLB892vaOaJW/fPJdnT8vJk5sdkQcU/isqUxyCE0cEoa8wZOcbgDuC4b6Og==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-replace-supers@7.27.1': - resolution: {integrity: sha512-7EHz6qDZc8RYS5ElPoShMheWvEgERonFCs7IAonWLLUTXW59DP14bCZt89/GKyreYn8g3S83m21FelHKbeDCKA==} + '@babel/helper-replace-supers@7.29.7': + resolution: {integrity: sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': - resolution: {integrity: sha512-Tub4ZKEXqbPjXgWLl2+3JpQAYBJ8+ikpQ2Ocj/q/r0LwE3UhENh7EUabyHjz2kCEsrRY83ew2DQdHluuiDQFzg==} + '@babel/helper-skip-transparent-expression-wrappers@7.29.7': + resolution: {integrity: sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==} engines: {node: '>=6.9.0'} - '@babel/helper-string-parser@7.27.1': - resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-identifier@7.28.5': - resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} engines: {node: '>=6.9.0'} - '@babel/helper-validator-option@7.27.1': - resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} engines: {node: '>=6.9.0'} - '@babel/helper-wrap-function@7.28.3': - resolution: {integrity: sha512-zdf983tNfLZFletc0RRXYrHrucBEg95NIFMkn6K9dbeMYnsgHaSBGcQqdsCSStG2PYwRre0Qc2NNSCXbG+xc6g==} + '@babel/helper-wrap-function@7.29.7': + resolution: {integrity: sha512-iES0Skag9ERIF68aXadpO6dbXa03mNWK3sEqJaMnLNs/eC3l0lkImdfoy6Y09/SfkpawdAB4RjQ7PVA7TcVGdw==} engines: {node: '>=6.9.0'} - '@babel/helpers@7.28.4': - resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} engines: {node: '>=6.9.0'} - '@babel/parser@7.28.5': - resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} + '@babel/parser@7.29.2': + resolution: {integrity: sha512-4GgRzy/+fsBa72/RZVJmGKPmZu9Byn8o4MoLpmNe1m8ZfYnz5emHLQz3U4gLud6Zwl0RZIcgiLD7Uq7ySFuDLA==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/parser@7.29.9': + resolution: {integrity: sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==} engines: {node: '>=6.0.0'} hasBin: true - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5': - resolution: {integrity: sha512-87GDMS3tsmMSi/3bWOte1UblL+YUTFMV8SZPZ2eSEL17s74Cw/l63rR6NmGVKMYW2GYi85nE+/d6Hw5N0bEk2Q==} + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7': + resolution: {integrity: sha512-j8SrR0zLZrRsC09DlszEx8FpMiwukKffYXMK0d5LmOglO7vGG6sz/BR/20yHqWH+Lnn31JTt2PE3hIWNgM2J6w==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7': + resolution: {integrity: sha512-r8j8escF+U2FUHo0KOhPUdMzUO+jp9fInva6+ACVAF3Y97Ev+5iNZwiqTghmzNeWwDkOPlYuTcfb1vDaoZKmAQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1': - resolution: {integrity: sha512-qNeq3bCKnGgLkEXUuFry6dPlGfCdQNZbn7yUAPCInwAJHMU7THJfrBSozkcWq5sNM6RcF3S8XyQL2A52KNR9IA==} + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7': + resolution: {integrity: sha512-GE1TFSiuFeGsCxmYXZl8HwoPrVlwe4rHPFE8weieGKZqnDORK+Ar3vgWMgW+AOxQ6/2TgLSKx9p6W7O4rC6qgQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1': - resolution: {integrity: sha512-g4L7OYun04N1WyqMNjldFwlfPCLVkgB54A/YCXICZYBsvJJE3kByKv9c9+R/nAfmIfjl2rKYLNyMHboYbZaWaA==} + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7': + resolution: {integrity: sha512-oBNVCvnO5tND+xSopWvV8WNGfpTfgP4Zr/YXXSj8zfmcPktp5Ku/aZlsIowgSD4fjmgHn6sGmB9APVsU5zOdhA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1': - resolution: {integrity: sha512-oO02gcONcD5O1iTLi/6frMJBIwWEHceWGSGqrpCmEL8nogiS6J9PBlE48CaK20/Jx1LuRml9aDftLgdjXT8+Cw==} + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7': + resolution: {integrity: sha512-QQt9qKHZ2sg/kivaLr7lnQr8HVrQDdBNSfCsTjiDxRuX/K5ORyKq+Bu8Xr0cDE3Dfkv0cw28Ve0EKyKMvulkOw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.13.0 - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3': - resolution: {integrity: sha512-b6YTX108evsvE4YgWyQ921ZAFFQm3Bn+CA3+ZXlNVnPhx+UfsVURoPjfGAPCjBgrqo30yX/C2nZGX96DxvR9Iw==} + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7': + resolution: {integrity: sha512-pn6QacGLgvCcwc+syUhKE/qSjV2D1IHDB84RNxWYSt1mW3K/SCtjinZ2p0cETJxAWBjPy3K/1lHwG5BjjPxNlw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 @@ -602,26 +756,26 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-assertions@7.27.1': - resolution: {integrity: sha512-UT/Jrhw57xg4ILHLFnzFpPDlMbcdEicaAtjPQpbj9wa8T4r5KVWCimHcL/460g8Ht0DMxDyjsLgiWSkVjnwPFg==} + '@babel/plugin-syntax-import-assertions@7.29.7': + resolution: {integrity: sha512-/An1OCBN93thpBAGyfsK2pcf0jvju1SAtKkL2Ny++B5Sy6sqgzXDQH1cZxWbF96Wuk+bn41MDA9bLd4VVAw6rw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-import-attributes@7.27.1': - resolution: {integrity: sha512-oFT0FrKHgF53f4vOsZGi2Hh3I35PfSmVs4IBFLFj4dnafP+hIWDLg3VyKmUHfLoLHlyxY4C7DGtmHuJgn+IGww==} + '@babel/plugin-syntax-import-attributes@7.29.7': + resolution: {integrity: sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-jsx@7.27.1': - resolution: {integrity: sha512-y8YTNIeKoyhGd9O0Jiyzyyqk8gdjnumGTQPsz0xOZOQ2RmkVJeZ1vmmfIvFEKqucBG6axJGBZDE/7iI5suUI/w==} + '@babel/plugin-syntax-jsx@7.29.7': + resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-syntax-typescript@7.27.1': - resolution: {integrity: sha512-xfYCBMxveHrRMnAWl1ZlPXOZjzkN82THFvLhQhFXFt81Z5HnN+EtUkZhv/zcKpmT3fzmWZB0ywiBrbC3vogbwQ==} + '@babel/plugin-syntax-typescript@7.29.7': + resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -632,332 +786,320 @@ packages: peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-arrow-functions@7.27.1': - resolution: {integrity: sha512-8Z4TGic6xW70FKThA5HYEKKyBpOOsucTOD1DjU3fZxDg+K3zBJcXMFnt/4yQiZnf5+MiOMSXQ9PaEK/Ilh1DeA==} + '@babel/plugin-transform-arrow-functions@7.29.7': + resolution: {integrity: sha512-N7zArUXWzAMzm+/N0uPBeVB3Fam5lMxtUwMmDK5f/IBBS7a7p1qeUoxd/6CckXoxUdgsntq1Dh8xNW06maZbDQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-generator-functions@7.28.0': - resolution: {integrity: sha512-BEOdvX4+M765icNPZeidyADIvQ1m1gmunXufXxvRESy/jNNyfovIqUyE7MVgGBjWktCoJlzvFA1To2O4ymIO3Q==} + '@babel/plugin-transform-async-generator-functions@7.29.7': + resolution: {integrity: sha512-d98gXZkgswvkyohMBABkhm3GeXhYj8psWfwQ2C7gtfrKGTykQa/iOIi+JJhwMjPlZ6Vm2XN+DCf3Es1EoG4ZLA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-async-to-generator@7.27.1': - resolution: {integrity: sha512-NREkZsZVJS4xmTr8qzE5y8AfIPqsdQfRuUiLRTEzb7Qii8iFWCyDKaUV2c0rCuh4ljDZ98ALHP/PetiBV2nddA==} + '@babel/plugin-transform-async-to-generator@7.29.7': + resolution: {integrity: sha512-pcUb2SS+RMo9TWVBwKGI5ShtoG7R+zBsFmCKDa6fe8c+hPr3XJlZgoE5j6i8W7gDjhyvy+85vmYexanvXh3d1w==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoped-functions@7.27.1': - resolution: {integrity: sha512-cnqkuOtZLapWYZUYM5rVIdv1nXYuFVIltZ6ZJ7nIj585QsjKM5dhL2Fu/lICXZ1OyIAFc7Qy+bvDAtTXqGrlhg==} + '@babel/plugin-transform-block-scoped-functions@7.29.7': + resolution: {integrity: sha512-cUSmjh72N+rN4PrkFlN1dJwNCwjVp5d38/CQrEsFggkD10UiFlBFgdH3tv5dNsLuHY+3S8db2xCHjhZcv5WgvA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-block-scoping@7.28.5': - resolution: {integrity: sha512-45DmULpySVvmq9Pj3X9B+62Xe+DJGov27QravQJU1LLcapR6/10i+gYVAucGGJpHBp5mYxIMK4nDAT/QDLr47g==} + '@babel/plugin-transform-block-scoping@7.29.7': + resolution: {integrity: sha512-ONyr4+AZhKh8yKWInVxU9AXA9EbsyeLcL6V0dJy6M2/62vuvpGm29zzuymbTpdc451GEpDIdAyPLP3r+P61yKQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-properties@7.27.1': - resolution: {integrity: sha512-D0VcalChDMtuRvJIu3U/fwWjf8ZMykz5iZsg77Nuj821vCKI3zCyRLwRdWbsuJ/uRwZhZ002QtCqIkwC/ZkvbA==} + '@babel/plugin-transform-class-properties@7.29.7': + resolution: {integrity: sha512-GtcpjFvanPfzNQi3eTitsCqtRRmmqzpy/A+yhTR1HaZo1Ly3EA8ZXxlPyHdR8/IuRMYc3E4wdGBewB2QKQjAaA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-class-static-block@7.28.3': - resolution: {integrity: sha512-LtPXlBbRoc4Njl/oh1CeD/3jC+atytbnf/UqLoqTDcEYGUPj022+rvfkbDYieUrSj3CaV4yHDByPE+T2HwfsJg==} + '@babel/plugin-transform-class-static-block@7.29.7': + resolution: {integrity: sha512-kibJgmEdX2iMwsHY2tSZNDgj8PwIlCQz7FK9KuGKO8zsuoUwSEhoNnNVp/emKWrbY4HeO6kkXfdMqRKKKXBm2A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.12.0 - '@babel/plugin-transform-classes@7.28.4': - resolution: {integrity: sha512-cFOlhIYPBv/iBoc+KS3M6et2XPtbT2HiCRfBXWtfpc9OAyostldxIf9YAYB6ypURBBbx+Qv6nyrLzASfJe+hBA==} + '@babel/plugin-transform-classes@7.29.7': + resolution: {integrity: sha512-qV0OGGBVacduzQHE649JyCneOFI/maT+YKsO+K4Yi3xv2wTPNjM/W2o2gdzMwEAZz7fXNTHAe0NcSg30bIN69g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-computed-properties@7.27.1': - resolution: {integrity: sha512-lj9PGWvMTVksbWiDT2tW68zGS/cyo4AkZ/QTp0sQT0mjPopCmrSkzxeXkznjqBxzDI6TclZhOJbBmbBLjuOZUw==} + '@babel/plugin-transform-computed-properties@7.29.7': + resolution: {integrity: sha512-RK7/IyU5phpuCdBAuig5VkzG/EnbDaui5SQGdU9BFrHdV+mV4cUjLMQ9lJDjLNtWHsqtiefpGZUXQP2BiTYMsA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-destructuring@7.28.5': - resolution: {integrity: sha512-Kl9Bc6D0zTUcFUvkNuQh4eGXPKKNDOJQXVyyM4ZAQPMveniJdxi8XMJwLo+xSoW3MIq81bD33lcUe9kZpl0MCw==} + '@babel/plugin-transform-destructuring@7.29.7': + resolution: {integrity: sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-dotall-regex@7.27.1': - resolution: {integrity: sha512-gEbkDVGRvjj7+T1ivxrfgygpT7GUd4vmODtYpbs0gZATdkX8/iSnOtZSxiZnsgm1YjTgjI6VKBGSJJevkrclzw==} + '@babel/plugin-transform-dotall-regex@7.29.7': + resolution: {integrity: sha512-3qc18hsD2RdZiyJNDNc7HQpv6xbncwh8FYtxNFFzclSyh/trPD9KkVR9BDECUjDLvb7yJVF15GfYUuC+LMkkiQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-keys@7.27.1': - resolution: {integrity: sha512-MTyJk98sHvSs+cvZ4nOauwTTG1JeonDjSGvGGUNHreGQns+Mpt6WX/dVzWBHgg+dYZhkC4X+zTDfkTU+Vy9y7Q==} + '@babel/plugin-transform-duplicate-keys@7.29.7': + resolution: {integrity: sha512-6IvRRriEMqnBwD6chtxdLpMYCHWEzN+oL5cyQtjykya19UgzbmKhxmhZgKC/LHxS2nYr9Q/qYPZ5Lr6jOL9+yQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-hkGcueTEzuhB30B3eJCbCYeCaaEQOmQR0AdvzpD4LoN0GXMWzzGSuRrxR2xTnCrvNbVwK9N6/jQ92GSLfiZWoQ==} + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7': + resolution: {integrity: sha512-2wiIyo2BjtgU7HufSeDnL9L2O7zr8jmhFKuSr65VpRkUiRKRNpb0mdlk56+XPPKoIrfHqzbMuglDvZun0RISsA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-dynamic-import@7.27.1': - resolution: {integrity: sha512-MHzkWQcEmjzzVW9j2q8LGjwGWpG2mjwaaB0BNQwst3FIjqsg8Ct/mIZlvSPJvfi9y2AC8mi/ktxbFVL9pZ1I4A==} + '@babel/plugin-transform-dynamic-import@7.29.7': + resolution: {integrity: sha512-giOlEm/EFjfjr+te9NsdjkUo2v4f8rS/SXPumRVHAtbNcyNlvtREkU1dZzaIDclNpnaVhlCqRdFKhJBjBikzLg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-explicit-resource-management@7.28.0': - resolution: {integrity: sha512-K8nhUcn3f6iB+P3gwCv/no7OdzOZQcKchW6N389V6PD8NUWKZHzndOd9sPDVbMoBsbmjMqlB4L9fm+fEFNVlwQ==} + '@babel/plugin-transform-explicit-resource-management@7.29.7': + resolution: {integrity: sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-exponentiation-operator@7.28.5': - resolution: {integrity: sha512-D4WIMaFtwa2NizOp+dnoFjRez/ClKiC2BqqImwKd1X28nqBtZEyCYJ2ozQrrzlxAFrcrjxo39S6khe9RNDlGzw==} + '@babel/plugin-transform-exponentiation-operator@7.29.7': + resolution: {integrity: sha512-zFpMOTLZBdW5LfObqcSbL6kefg4R4eLdmvS0wbN9M6D5Mym/sKm9toOoWyVOa+xDjvCnuWcHls2YonXwHvH3CQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-export-namespace-from@7.27.1': - resolution: {integrity: sha512-tQvHWSZ3/jH2xuq/vZDy0jNn+ZdXJeM8gHvX4lnJmsc3+50yPlWdZXIc5ay+umX+2/tJIqHqiEqcJvxlmIvRvQ==} + '@babel/plugin-transform-export-namespace-from@7.29.7': + resolution: {integrity: sha512-24B2nOy2TeJSMheqwPD4DDQOV/elLSIlKxjZt4i05H5AgdPdWR3n18HnNrcJ+j76WJd9gbwb9jPjNYUy6RautA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-for-of@7.27.1': - resolution: {integrity: sha512-BfbWFFEJFQzLCQ5N8VocnCtA8J1CLkNTe2Ms2wocj75dd6VpiqS5Z5quTYcUoo4Yq+DN0rtikODccuv7RU81sw==} + '@babel/plugin-transform-for-of@7.29.7': + resolution: {integrity: sha512-zeSIHh0+E1Um1WJRXCFlHQYu2ieJNdivLLjlBEp+dIBu3S51n+SZZmIXjxnItw6pz56Cn+KvK68BIBVsxq2JiQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-function-name@7.27.1': - resolution: {integrity: sha512-1bQeydJF9Nr1eBCMMbC+hdwmRlsv5XYOMu03YSWFwNs0HsAmtSxxF1fyuYPqemVldVyFmlCU7w8UE14LupUSZQ==} + '@babel/plugin-transform-function-name@7.29.7': + resolution: {integrity: sha512-otRWaHXE6fbAGkePvaj/kvs3HsqXfPhlnzwSOlnFgbqCPMd975dW+4wZ00WFBt+/YlBGcJwNrARQTOJOb4ZrIg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-json-strings@7.27.1': - resolution: {integrity: sha512-6WVLVJiTjqcQauBhn1LkICsR2H+zm62I3h9faTDKt1qP4jn2o72tSvqMwtGFKGTpojce0gJs+76eZ2uCHRZh0Q==} + '@babel/plugin-transform-json-strings@7.29.7': + resolution: {integrity: sha512-RRnE2+eon1rJAq8MnoF1b5kTpY1vU88twHcvcKMrsqP/jxIRqDVs9iJB5fqPuqyeFAW0wJo4MlUIPpQCq/aRsg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-literals@7.27.1': - resolution: {integrity: sha512-0HCFSepIpLTkLcsi86GG3mTUzxV5jpmbv97hTETW3yzrAij8aqlD36toB1D0daVFJM8NK6GvKO0gslVQmm+zZA==} + '@babel/plugin-transform-literals@7.29.7': + resolution: {integrity: sha512-DZ/oLP21ZuWx1vKqnoNv6/tvEK48AQOBRai40CX9dTjGluvT/YZCyY3rryDtyUqCEoyNroy5KKPwX2iQCiRvyw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-logical-assignment-operators@7.28.5': - resolution: {integrity: sha512-axUuqnUTBuXyHGcJEVVh9pORaN6wC5bYfE7FGzPiaWa3syib9m7g+/IT/4VgCOe2Upef43PHzeAvcrVek6QuuA==} + '@babel/plugin-transform-logical-assignment-operators@7.29.7': + resolution: {integrity: sha512-A0H91hh6W8MFRkp5TqJmMr39jzGD1A1E1Ysiv2O06Sfbhkapm+XyIzxWCEh5kqwOZ1/8QZ0dY3SeQ7XBqfJd5Q==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-member-expression-literals@7.27.1': - resolution: {integrity: sha512-hqoBX4dcZ1I33jCSWcXrP+1Ku7kdqXf1oeah7ooKOIiAdKQ+uqftgCFNOSzA5AMS2XIHEYeGFg4cKRCdpxzVOQ==} + '@babel/plugin-transform-member-expression-literals@7.29.7': + resolution: {integrity: sha512-hl1kwFZCCiDyfH25Xmco9jTrkPgnS9pmOzSG7W5I4SaGbLeqKv417hcU2RKmaxoPEgsoJh7ZPOrnPGq99bHoUg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-amd@7.27.1': - resolution: {integrity: sha512-iCsytMg/N9/oFq6n+gFTvUYDZQOMK5kEdeYxmxt91fcJGycfxVP9CnrxoliM0oumFERba2i8ZtwRUCMhvP1LnA==} + '@babel/plugin-transform-modules-amd@7.29.7': + resolution: {integrity: sha512-fxtQoH3m5ywUSIfaH0FGCzWu4McsYon5bD3K4XnskC7f+OyQMj7rsOMi4NvvmJ83WwBAg4UCe+ov4VZlqEvyew==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-commonjs@7.27.1': - resolution: {integrity: sha512-OJguuwlTYlN0gBZFRPqwOGNWssZjfIUdS7HMYtN8c1KmwpwHFBwTeFZrg9XZa+DFTitWOW5iTAG7tyCUPsCCyw==} + '@babel/plugin-transform-modules-commonjs@7.29.7': + resolution: {integrity: sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-systemjs@7.28.5': - resolution: {integrity: sha512-vn5Jma98LCOeBy/KpeQhXcV2WZgaRUtjwQmjoBuLNlOmkg0fB5pdvYVeWRYI69wWKwK2cD1QbMiUQnoujWvrew==} + '@babel/plugin-transform-modules-systemjs@7.29.8': + resolution: {integrity: sha512-6iSnEK0zlkLKU4heofK/AdmRD4e2SHVpJMtrwnTCzhnaM98ria4rTrOXBBi45BTTYnJtO8txnPsX4fChYXkmeA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-modules-umd@7.27.1': - resolution: {integrity: sha512-iQBE/xC5BV1OxJbp6WG7jq9IWiD+xxlZhLrdwpPkTX3ydmXdvoCpyfJN7acaIBZaOqTfr76pgzqBJflNbeRK+w==} + '@babel/plugin-transform-modules-umd@7.29.7': + resolution: {integrity: sha512-B4UkaTK3QpgCwJnrxKfMPKdo92CN7OKXAlpAAnM3UPu0Q0lCCk57ylA9AJbRy2v8dDKOPAAWcoR6CMyeoHwRCA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1': - resolution: {integrity: sha512-SstR5JYy8ddZvD6MhV0tM/j16Qds4mIpJTOd1Yu9J9pJjH93bxHECF7pgtc28XvkzTD6Pxcm/0Z73Hvk7kb3Ng==} + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7': + resolution: {integrity: sha512-vuFoLwr4qnv2xbZ16SQd6uPcH5FNrLHhk/Jzo++0XJFcaDsr4gjJVg6j398oMHiC+83k/GiBzviwF5KBJkPUtQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-new-target@7.27.1': - resolution: {integrity: sha512-f6PiYeqXQ05lYq3TIfIDu/MtliKUbNwkGApPUvyo6+tc7uaR4cPjPe7DFPr15Uyycg2lZU6btZ575CuQoYh7MQ==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1': - resolution: {integrity: sha512-aGZh6xMo6q9vq1JGcw58lZ1Z0+i0xB2x0XaauNIUXd6O1xXc3RwoWEBlsTQrY4KQ9Jf0s5rgD6SiNkaUdJegTA==} - engines: {node: '>=6.9.0'} - peerDependencies: - '@babel/core': ^7.0.0-0 - - '@babel/plugin-transform-numeric-separator@7.27.1': - resolution: {integrity: sha512-fdPKAcujuvEChxDBJ5c+0BTaS6revLV7CJL08e4m3de8qJfNIuCc2nc7XJYOjBoTMJeqSmwXJ0ypE14RCjLwaw==} + '@babel/plugin-transform-new-target@7.29.7': + resolution: {integrity: sha512-fEo41GmsOUhOBlw8ioo6zvjX5Xc2Lqkzlyfqbpsk3eB6TReV18uhxZ0esfEokVbY2+PVJAQHNKxER6lGrzNd3A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-rest-spread@7.28.4': - resolution: {integrity: sha512-373KA2HQzKhQCYiRVIRr+3MjpCObqzDlyrM6u4I201wL8Mp2wHf7uB8GhDwis03k2ti8Zr65Zyyqs1xOxUF/Ew==} + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7': + resolution: {integrity: sha512-idmp1dFaekP9GbcMvG24Kvw2BfhFZjHnNJCkV4WuIY4PskJzwI3f1N5OdgYke38T7rftO6ERulFRn2cFeZwRkg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-object-super@7.27.1': - resolution: {integrity: sha512-SFy8S9plRPbIcxlJ8A6mT/CxFdJx/c04JEctz4jf8YZaVS2px34j7NXRrlGlHkN/M2gnpL37ZpGRGVFLd3l8Ng==} + '@babel/plugin-transform-numeric-separator@7.29.7': + resolution: {integrity: sha512-zR7fv/z14OjgHl4AgRtkDBvBMhIzCxqV/qN/2BCRC7LjFwvuzjYe7gDWxC4Wl/SNsLM6SE1IWvRPYMgSJaUvNw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-catch-binding@7.27.1': - resolution: {integrity: sha512-txEAEKzYrHEX4xSZN4kJ+OfKXFVSWKB2ZxM9dpcE3wT7smwkNmXo5ORRlVzMVdJbD+Q8ILTgSD7959uj+3Dm3Q==} + '@babel/plugin-transform-object-rest-spread@7.29.7': + resolution: {integrity: sha512-Ld98jn4c0smUywL57m7SgsHq3OpThOa6LqZJif3G6jYOovPleoFhVrBJ1WegRApSFB2wu4+RelAj9AC9G08Z4A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-optional-chaining@7.28.5': - resolution: {integrity: sha512-N6fut9IZlPnjPwgiQkXNhb+cT8wQKFlJNqcZkWlcTqkcqx6/kU4ynGmLFoa4LViBSirn05YAwk+sQBbPfxtYzQ==} + '@babel/plugin-transform-object-super@7.29.7': + resolution: {integrity: sha512-Ea/diGcw0twB5IlZPO5sgET6fJsLJqPABqTuFWIR+iMPGPZJkATEIWx0wa+aEQ5UY1CBQyP/gkAiLEqn1vBiQA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-parameters@7.27.7': - resolution: {integrity: sha512-qBkYTYCb76RRxUM6CcZA5KRu8K4SM8ajzVeUgVdMVO9NN9uI/GaVmBg/WKJJGnNokV9SY8FxNOVWGXzqzUidBg==} + '@babel/plugin-transform-optional-catch-binding@7.29.7': + resolution: {integrity: sha512-sLsyndxK2VwX6yNUOakMb7Sh553ZTe/vVM1XJ+9Z5aW1ytsc8xOIwmyk05NNjN60vkc5/KqoTH6hB4V41LJhng==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-methods@7.27.1': - resolution: {integrity: sha512-10FVt+X55AjRAYI9BrdISN9/AQWHqldOeZDUoLyif1Kn05a56xVBXb8ZouL8pZ9jem8QpXaOt8TS7RHUIS+GPA==} + '@babel/plugin-transform-optional-chaining@7.29.7': + resolution: {integrity: sha512-6GM1dhvK3gNODkXcEcMCOLEDCLSoZ/sBbro2Ax8HURyasQ4NshagQixkRFdh5niI6E4gmA/jYI/4aT7rRos3ZQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-private-property-in-object@7.27.1': - resolution: {integrity: sha512-5J+IhqTi1XPa0DXF83jYOaARrX+41gOewWbkPyjMNRDqgOCqdffGh8L3f/Ek5utaEBZExjSAzcyjmV9SSAWObQ==} + '@babel/plugin-transform-parameters@7.29.7': + resolution: {integrity: sha512-ZDOBqV/qLYJI0YElr8DcENEyARsFQeESqWXH6gZlghYXuPPjvweuDhP4VyEi4BlUBlLRFZVjxoZDMjxhLW766g==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-property-literals@7.27.1': - resolution: {integrity: sha512-oThy3BCuCha8kDZ8ZkgOg2exvPYUlprMukKQXI1r1pJ47NCvxfkEy8vK+r/hT9nF0Aa4H1WUPZZjHTFtAhGfmQ==} + '@babel/plugin-transform-private-methods@7.29.7': + resolution: {integrity: sha512-/6Rz4DK1ETDEM/bWHsPHcaEe7ZaT1EqSXjtSP/L0DijOYuaUhiRiOKcwpZ8P7zR4xXEHc2ITdiCgBm9Tpyv9ug==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-self@7.27.1': - resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} + '@babel/plugin-transform-private-property-in-object@7.29.7': + resolution: {integrity: sha512-+BNo06dnrzdNNqCm1X6YUaVv0DKk8Q+JYcoZfOkLhYWNCXzlwTSRq8zGWayT1csjcpNXV9CQTBRRbmTLZac5cA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-react-jsx-source@7.27.1': - resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} + '@babel/plugin-transform-property-literals@7.29.7': + resolution: {integrity: sha512-bOMRLQuI0A5ZqHq3OWJ89/rXpJ/NJrbVhXiP4zwPGMs6kpcVsuTUNjwoE30K0Qm3mf48a/TnRYYD6vPNqcg6jA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regenerator@7.28.4': - resolution: {integrity: sha512-+ZEdQlBoRg9m2NnzvEeLgtvBMO4tkFBw5SQIUgLICgTrumLoU7lr+Oghi6km2PFj+dbUt2u1oby2w3BDO9YQnA==} + '@babel/plugin-transform-regenerator@7.29.8': + resolution: {integrity: sha512-0UpIXPtdDtMXfnV2OJAVMLpj3H/92vmkA6lpSRakmycJvj3VUy6Xs1dM8tXRugupykr5WB+LpiVl0J8LMVg2mg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-regexp-modifiers@7.27.1': - resolution: {integrity: sha512-TtEciroaiODtXvLZv4rmfMhkCv8jx3wgKpL68PuiPh2M4fvz5jhsA7697N1gMvkvr/JTF13DrFYyEbY9U7cVPA==} + '@babel/plugin-transform-regexp-modifiers@7.29.7': + resolution: {integrity: sha512-mB5Fs0VWrJ42ZCmc8114v60qetdaUVNkj9PmSZRmanCZM3S9hm0CFRLjRmYIsuXav14l2jvZ+4T8iiCGnhj3nQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/plugin-transform-reserved-words@7.27.1': - resolution: {integrity: sha512-V2ABPHIJX4kC7HegLkYoDpfg9PVmuWy/i6vUM5eGK22bx4YVFD3M5F0QQnWQoDs6AGsUWTVOopBiMFQgHaSkVw==} + '@babel/plugin-transform-reserved-words@7.29.7': + resolution: {integrity: sha512-5+YhdpVgmfSmwZyLMftfaiffLRMHjzIRHFHHLdibcSyJm2pasMrKHrO3Ptrt2DRshjvpgjEJJ1zVW14WPq/6QA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-shorthand-properties@7.27.1': - resolution: {integrity: sha512-N/wH1vcn4oYawbJ13Y/FxcQrWk63jhfNa7jef0ih7PHSIHX2LB7GWE1rkPrOnka9kwMxb6hMl19p7lidA+EHmQ==} + '@babel/plugin-transform-shorthand-properties@7.29.7': + resolution: {integrity: sha512-I+WYbGBAiCn7nA6xBrlgPH+MB7HWb4u8pv5S0Pv7OtwNvIFvCCb24YlttKEeUFVurfBCEaOTnuhlqsb7f0Z5Dg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-spread@7.27.1': - resolution: {integrity: sha512-kpb3HUqaILBJcRFVhFUs6Trdd4mkrzcGXss+6/mxUd273PfbWqSDHRzMT2234gIg2QYfAjvXLSquP1xECSg09Q==} + '@babel/plugin-transform-spread@7.29.8': + resolution: {integrity: sha512-4S9ksMGVWUshvgK0mKfvZky7leuG5/uoFVwMpAomJ8bMoDJiNHRVmc1EglwW/CmGVSqqWpEbXm9FmbRit22qoA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-sticky-regex@7.27.1': - resolution: {integrity: sha512-lhInBO5bi/Kowe2/aLdBAawijx+q1pQzicSgnkB6dUPc1+RC8QmJHKf2OjvU+NZWitguJHEaEmbV6VWEouT58g==} + '@babel/plugin-transform-sticky-regex@7.29.7': + resolution: {integrity: sha512-BCHzNYJGe9l7EpwwDBN/ztlL2NYFFq8hp9ddjtUEM9f2O7S7kKV/lL6Fwo7IF7NSkYhPK2vO+86nIGltA90MsA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-template-literals@7.27.1': - resolution: {integrity: sha512-fBJKiV7F2DxZUkg5EtHKXQdbsbURW3DZKQUWphDum0uRP6eHGGa/He9mc0mypL680pb+e/lDIthRohlv8NCHkg==} + '@babel/plugin-transform-template-literals@7.29.7': + resolution: {integrity: sha512-NCSEJ4sLFU2gqAub45HYh4fus2yQ36rr6ei6vpU7NdoJqCpxvEG8E6eJpscGyXP3VHD2Ny+fSXr04k1hoUrFqA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typeof-symbol@7.27.1': - resolution: {integrity: sha512-RiSILC+nRJM7FY5srIyc4/fGIwUhyDuuBSdWn4y6yT6gm652DpCHZjIipgn6B7MQ1ITOUnAKWixEUjQRIBIcLw==} + '@babel/plugin-transform-typeof-symbol@7.29.7': + resolution: {integrity: sha512-223mNGoTkBiTEWFoK+Q6Go3tueMRclO8vxxxxquNCYuNI4jWOofFKJRRDu6SDrB8Sgo1UEGW9T4GAQ8ZyRso1A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-typescript@7.28.5': - resolution: {integrity: sha512-x2Qa+v/CuEoX7Dr31iAfr0IhInrVOWZU/2vJMJ00FOR/2nM0BcBEclpaf9sWCDc+v5e9dMrhSH8/atq/kX7+bA==} + '@babel/plugin-transform-typescript@7.29.9': + resolution: {integrity: sha512-FFwIwzU+7SCOuxxV4YtJql6T9981ZVTm+FHO5GhVsRqCTdy0WwrEZh3l42ARpXruJUDGOptdduHW6Zr7pNPLNg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-escapes@7.27.1': - resolution: {integrity: sha512-Ysg4v6AmF26k9vpfFuTZg8HRfVWzsh1kVfowA23y9j/Gu6dOuahdUVhkLqpObp3JIv27MLSii6noRnuKN8H0Mg==} + '@babel/plugin-transform-unicode-escapes@7.29.7': + resolution: {integrity: sha512-jCfXxSjf94lf4E0hKE0AByxF6F3/pVFqRdUUNkDJhsY0m1ZKjnN6ZYyMeHNpzflxb/0q5b7t3p+BE+SLF1WOtA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-property-regex@7.27.1': - resolution: {integrity: sha512-uW20S39PnaTImxp39O5qFlHLS9LJEmANjMG7SxIhap8rCHqu0Ik+tLEPX5DKmHn6CsWQ7j3lix2tFOa5YtL12Q==} + '@babel/plugin-transform-unicode-property-regex@7.29.7': + resolution: {integrity: sha512-OgZ+zoAJgZLUCunsTRQ5LAjOywDv5zzZ2/hQ5aMw1pGXyY2rtE8/chXYUmu3AlVHKpm10KEdG9aMwbI/K76ZGw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-regex@7.27.1': - resolution: {integrity: sha512-xvINq24TRojDuyt6JGtHmkVkrfVV3FPT16uytxImLeBZqW3/H52yN+kM1MGuyPkIQxrzKwPHs5U/MP3qKyzkGw==} + '@babel/plugin-transform-unicode-regex@7.29.7': + resolution: {integrity: sha512-7D/x/23/d/3VqZ0QA+LGbZMlGwZjztBygSWWWsfTPoQ1oQ6Q1P6Mr3d0kk42XabyUVw+fha3LqdRsFqeKqvCyA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/plugin-transform-unicode-sets-regex@7.27.1': - resolution: {integrity: sha512-EtkOujbc4cgvb0mlpQefi4NTPBzhSIevblFevACNLUspmrALgmEBdL/XfnyyITfd8fKBZrZys92zOWcik7j9Tw==} + '@babel/plugin-transform-unicode-sets-regex@7.29.7': + resolution: {integrity: sha512-BLOhLht9DOJwIxlmp91wHvkXv1lguuHS3/FwUO8HL1H0u8s4hR1gASVFyilu9iGtcTRYqjTZmlsFFeQletntEg==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - '@babel/preset-env@7.28.5': - resolution: {integrity: sha512-S36mOoi1Sb6Fz98fBfE+UZSpYw5mJm0NUHtIKrOuNcqeFauy1J6dIvXm2KRVKobOSaGq4t/hBXdN4HGU3wL9Wg==} + '@babel/preset-env@7.29.7': + resolution: {integrity: sha512-GYzX36n1nsciIb0uyH0GHwxwtNwPQIcpxSeiVLDtG/B7jB5xXgchnmL1f/jCX5o+pwnaDBtO60ONSJhEBJfxYA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 @@ -967,323 +1109,399 @@ packages: peerDependencies: '@babel/core': ^7.0.0-0 || ^8.0.0-0 <8.0.0 - '@babel/preset-typescript@7.28.5': - resolution: {integrity: sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g==} + '@babel/preset-typescript@7.29.7': + resolution: {integrity: sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - '@babel/runtime@7.28.4': - resolution: {integrity: sha512-Q/N6JNWvIvPnLDvjlE1OUBLPQHH6l3CltCEsHIujp45zQUSSh8K+gHnaEX45yAT1nyngnINhvWtzN+Nb9D8RAQ==} + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} engines: {node: '>=6.9.0'} - '@babel/template@7.27.2': - resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} + '@babel/traverse@7.29.0': + resolution: {integrity: sha512-4HPiQr0X7+waHfyXPZpWPfWL/J7dcN1mx9gL6WdQVMbPnF3+ZhSMs8tCxN7oHddJE9fhNE7+lxdnlyemKfJRuA==} engines: {node: '>=6.9.0'} - '@babel/traverse@7.28.5': - resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} + '@babel/traverse@7.29.8': + resolution: {integrity: sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==} engines: {node: '>=6.9.0'} - '@babel/types@7.28.5': - resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} + '@babel/types@7.29.8': + resolution: {integrity: sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==} engines: {node: '>=6.9.0'} '@bcoe/v8-coverage@1.0.2': resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} engines: {node: '>=18'} - '@better-auth/core@1.4.1': - resolution: {integrity: sha512-N4kyRdA472WGLoCjsJpUeYdZZvpoBDgP65hUeQQxTQYwBTqD9O17Tokax9CdNbkb4g34sTfxaJCfcncE3Hy4SA==} + '@better-auth/core@1.7.5': + resolution: {integrity: sha512-kVlSu4H8OKQfjg4b/Zj5MOaospt83N0JbX38wsDzE58Yw95jzovFkU3pxzB1eUFYc4mkuhUMZD8iT1gpUjNMcQ==} peerDependencies: - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.18 - better-call: 1.1.0 + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@opentelemetry/api': ^1.9.0 + better-call: 1.4.0 jose: ^6.1.0 - kysely: ^0.28.5 + kysely: ^0.28.5 || ^0.29.0 nanostores: ^1.0.1 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true - '@better-auth/telemetry@1.4.1': - resolution: {integrity: sha512-yNeazXYvMbyuCe1AA6tYWsJEKgcS7gF9PmmACmrPVhVBe1ncDhVfWMZ++YCmA2h8hjkR9755ZyofiYRPbj+kXQ==} + '@better-auth/drizzle-adapter@1.7.5': + resolution: {integrity: sha512-9SM7v1735SoaedRDcDbHc5ULgXEd2vUlEJkvRHpMF2Q9qf59TRh1b5A9hryyecyi56bm/0CNUDU3nY0uVWj5/Q==} peerDependencies: - '@better-auth/core': 1.4.1 + '@better-auth/core': ^1.7.5 + '@better-auth/utils': 0.4.2 + drizzle-orm: ^0.45.2 || >=1.0.0-rc.1 <2.0.0 + peerDependenciesMeta: + drizzle-orm: + optional: true + + '@better-auth/kysely-adapter@1.7.5': + resolution: {integrity: sha512-1wE5gvnjW+c1i4GrLtL9HLn3s0Xrq4YneCDan1NO1dpz0mEguLFNlzfnUGykTFrDwvFh2X5rkIbA8ALCj6WzXQ==} + peerDependencies: + '@better-auth/core': ^1.7.5 + '@better-auth/utils': 0.4.2 + kysely: ^0.28.17 || ^0.29.0 + peerDependenciesMeta: + kysely: + optional: true - '@better-auth/utils@0.3.0': - resolution: {integrity: sha512-W+Adw6ZA6mgvnSnhOki270rwJ42t4XzSK6YWGF//BbVXL6SwCLWfyzBc1lN2m/4RM28KubdBKQ4X5VMoLRNPQw==} + '@better-auth/memory-adapter@1.7.5': + resolution: {integrity: sha512-YDmnfR9zOXbn5SNYYwfHBPuc19hg1d1C1vUXb+Hm8Q91pTsstFNX5OTlZbo7f28q06FpogAEfGGCN/2QV39cig==} + peerDependencies: + '@better-auth/core': ^1.7.5 + '@better-auth/utils': 0.4.2 - '@better-fetch/fetch@1.1.18': - resolution: {integrity: sha512-rEFOE1MYIsBmoMJtQbl32PGHHXuG2hDxvEd7rUHE0vCBoFQVSDqaVs9hkZEtHCxRoY+CljXKFCOuJ8uxqw1LcA==} + '@better-auth/mongo-adapter@1.7.5': + resolution: {integrity: sha512-Yq0LfF0VlA9Kfjcjp/v43MSsChv7vKd1ct0Mt15px4zlqaCPIGfPbjw9YNM6jTo0fGpqLR0n15PllSWmLLRp9g==} + peerDependencies: + '@better-auth/core': ^1.7.5 + '@better-auth/utils': 0.4.2 + mongodb: ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + mongodb: + optional: true - '@cloudflare/kv-asset-handler@0.4.0': - resolution: {integrity: sha512-+tv3z+SPp+gqTIcImN9o0hqE9xyfQjI1XD9pL6NuKjua9B1y7mNYv0S9cP+QEbA4ppVgGZEmKOvHX5G5Ei1CVA==} - engines: {node: '>=18.0.0'} + '@better-auth/prisma-adapter@1.7.5': + resolution: {integrity: sha512-QfW6HS9vK0FMcbI/GsQLdplICxOz0EPzYWGONZT4ovL3cSItd4YH/09USbPPVl+VUQCdznAQIk+n+NKvHdmSag==} + peerDependencies: + '@better-auth/core': ^1.7.5 + '@better-auth/utils': 0.4.2 + '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 + prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 + peerDependenciesMeta: + '@prisma/client': + optional: true + prisma: + optional: true + + '@better-auth/telemetry@1.7.5': + resolution: {integrity: sha512-e/REPqMy9Em+gC6G0xWBikiMLRuy532Er7jqdoNkPBa65FbywgWcm1cZbgdW5CnHsrM3OLZsmKn14yeGoDISeg==} + peerDependencies: + '@better-auth/core': ^1.7.5 + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + + '@better-auth/utils@0.4.2': + resolution: {integrity: sha512-AUxrvu+HaaODsUyzDxFgwd/8RZ1yZaYo42LXKSrU2oGgR38pS1ij8nqQKNgtTWoYGpNevNXtCfgTy6loHveW9A==} + + '@better-auth/utils@0.5.0': + resolution: {integrity: sha512-BL8W4EfIZFwlu0r54m3v1ztjDhu6dDe/amLTm0xybmbZaNgYUqhD3SjpAsnq0q8YD6/ki4iwIgxJNLP/N3TxiA==} + + '@better-fetch/fetch@1.3.2': + resolution: {integrity: sha512-Gs7n99b5tqUC6cQAPbV0uED3IraHB6xQbHLQ/C3l7ZFafHScOx9pQ+DYmP5blbLFShVWLqxNUlI9wi4xU/X+ow==} - '@cloudflare/unenv-preset@2.7.11': - resolution: {integrity: sha512-se23f1D4PxKrMKOq+Stz+Yn7AJ9ITHcEecXo2Yjb+UgbUDCEBch1FXQC6hx6uT5fNA3kmX3mfzeZiUmpK1W9IQ==} + '@bramus/specificity@2.4.2': + resolution: {integrity: sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==} + hasBin: true + + '@cacheable/memory@2.2.0': + resolution: {integrity: sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==} + + '@cacheable/utils@2.5.0': + resolution: {integrity: sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==} + + '@cloudflare/kv-asset-handler@0.5.0': + resolution: {integrity: sha512-jxQYkj8dSIzc0cD6cMMNdOc1UVjqSqu8BZdor5s8cGjW2I8BjODt/kWPVdY+u9zj3ms75Q5qaZgnxUad83+eAg==} + engines: {node: '>=22.0.0'} + + '@cloudflare/unenv-preset@2.16.1': + resolution: {integrity: sha512-ECxObrMfyTl5bhQf/lZCXwo5G6xX9IAUo+nDMKK4SZ8m4Jvvxp52vilxyySSWh2YTZz8+HQ07qGH/2rEom1vDw==} peerDependencies: unenv: 2.0.0-rc.24 - workerd: ^1.20251106.1 + workerd: '>1.20260305.0 <2.0.0-0' peerDependenciesMeta: workerd: optional: true - '@cloudflare/workerd-darwin-64@1.20251118.0': - resolution: {integrity: sha512-UmWmYEYS/LkK/4HFKN6xf3Hk8cw70PviR+ftr3hUvs9HYZS92IseZEp16pkL6ZBETrPRpZC7OrzoYF7ky6kHsg==} + '@cloudflare/workerd-darwin-64@1.20260918.1': + resolution: {integrity: sha512-H5Em6Wd0jjxaloYh2rp+WLBl2eWbkk7nSP1svGt6K1RSv/rNVqmKdpjZPJTBSavOmeYGa88qvtOWwS+33OHTqQ==} engines: {node: '>=16'} cpu: [x64] os: [darwin] - '@cloudflare/workerd-darwin-arm64@1.20251118.0': - resolution: {integrity: sha512-RockU7Qzf4rxNfY1lx3j4rvwutNLjTIX7rr2hogbQ4mzLo8Ea40/oZTzXVxl+on75joLBrt0YpenGW8o/r44QA==} + '@cloudflare/workerd-darwin-arm64@1.20260918.1': + resolution: {integrity: sha512-CR9JRZEQo93fNgBVF4Df2H2/VYO4n7rxSseSwCVv3bJQEb0huADUSCj2FK4ipxar8ToOEB4wawyw0vJo5U/rQQ==} engines: {node: '>=16'} cpu: [arm64] os: [darwin] - '@cloudflare/workerd-linux-64@1.20251118.0': - resolution: {integrity: sha512-aT97GnOAbJDuuOG0zPVhgRk0xFtB1dzBMrxMZ09eubDLoU4djH4BuORaqvxNRMmHgKfa4T6drthckT0NjUvBdw==} + '@cloudflare/workerd-linux-64@1.20260918.1': + resolution: {integrity: sha512-UQ2nnY3qpXLzQ80frmWO+8HvtqyWaQILe8QYZwpemdjT+sqwCz4Dz+0/WVkFco0v/04kIIqikVeLTY/7gEhmkw==} engines: {node: '>=16'} cpu: [x64] os: [linux] - '@cloudflare/workerd-linux-arm64@1.20251118.0': - resolution: {integrity: sha512-bXZPJcwlq00MPOXqP7DMWjr+goYj0+Fqyw6zgEC2M3FR1+SWla4yjghnZ4IdpN+H1t7VbUrsi5np2LzMUFs0NA==} + '@cloudflare/workerd-linux-arm64@1.20260918.1': + resolution: {integrity: sha512-4rib51MaLNWweUIUxM/Xj558M5QmyZoBSf0ffv+lYah5VTrvwnez3XGxX72pElnBKHROvAPOi5msQ5Ts8JSI0A==} engines: {node: '>=16'} cpu: [arm64] os: [linux] - '@cloudflare/workerd-windows-64@1.20251118.0': - resolution: {integrity: sha512-2LV99AHSlpr8WcCb/BYbU2QsYkXLUL1izN6YKWkN9Eibv80JKX0RtgmD3dfmajE5sNvClavxZejgzVvHD9N9Ag==} + '@cloudflare/workerd-windows-64@1.20260918.1': + resolution: {integrity: sha512-sATrMx5ShYYgmgUGrcTmvsFSJBFuN95NEkX3xwb1qk8w1A6h5N11sea7yN2IeibwPyPmXKjWNjXOno0hZAM71Q==} engines: {node: '>=16'} cpu: [x64] os: [win32] - '@cloudflare/workers-types@4.20251121.0': - resolution: {integrity: sha512-jzFg7hEGKzpEalxTCanN6lM8IdkvO/brsERp/+OyMms4Zi0nhDPUAg9dUcKU8wDuDUnzbjkplY6YRwle7Cq6gA==} + '@cloudflare/workers-types@5.20260918.1': + resolution: {integrity: sha512-bUGc9gIdooYPi6lAUoB/eBXmy/ev9ok0XvDLzfJZQVCT8WCEQwv9f6smz6XeE83JzpX6ZSVi9CG1aDORnErYRQ==} '@cspotcode/source-map-support@0.8.1': resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} engines: {node: '>=12'} - '@csstools/color-helpers@5.1.0': - resolution: {integrity: sha512-S11EXWJyy0Mz5SYvRmY8nJYTFFd1LCNV+7cXyAgQtOOuzb4EsgfqDufL+9esx72/eLhsRdGZwaldu/h+E4t4BA==} - engines: {node: '>=18'} + '@csstools/color-helpers@6.1.1': + resolution: {integrity: sha512-gLNsunvwf3mCi5u5o46/Z/JcJMnhbHSaZ69rkgPzNM3J4s8hWwpPUQB6/tt0EDFyCiWzxANlx+2LJwpYj4zS1w==} + engines: {node: '>=20.19.0'} - '@csstools/css-calc@2.1.4': - resolution: {integrity: sha512-3N8oaj+0juUw/1H3YwmDDJXCgTB1gKU6Hc/bB502u9zR0q2vd786XJH9QfrKIEgFlZmhZiq6epXl4rHqhzsIgQ==} - engines: {node: '>=18'} + '@csstools/css-calc@3.4.0': + resolution: {integrity: sha512-XQKj5B7QiZcHiegCOCAzcAOJdhGgWOHbbu62h5e5mkHnn8lWcfiJhllkqWmxu5zWR9jucPHuo1iTB56P033hcg==} + engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-color-parser@3.1.0': - resolution: {integrity: sha512-nbtKwh3a6xNVIp/VRuXV64yTKnb1IjTAEEh3irzS+HkKjAOYLTGNb9pmVNntZ8iVBHcWDA2Dof0QtPgFI1BaTA==} - engines: {node: '>=18'} + '@csstools/css-color-parser@4.2.3': + resolution: {integrity: sha512-y4LpL+lmpuyKDiEFq2PnZUVFdAjsoB/qQJod79yLNokXyW7jewi+/WJ69EfItj8A2unWtxXnGjw6LYXgXu5ZjA==} + engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-parser-algorithms': ^3.0.5 - '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-parser-algorithms': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-parser-algorithms@3.0.5': - resolution: {integrity: sha512-DaDeUkXZKjdGhgYaHNJTV9pV7Y9B3b644jCLs9Upc3VeNGg6LWARAT6O+Q+/COo+2gg/bM5rhpMAtf70WqfBdQ==} - engines: {node: '>=18'} + '@csstools/css-parser-algorithms@4.0.0': + resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-tokenizer': ^3.0.4 + '@csstools/css-tokenizer': ^4.0.0 - '@csstools/css-syntax-patches-for-csstree@1.0.17': - resolution: {integrity: sha512-LCC++2h8pLUSPY+EsZmrrJ1EOUu+5iClpEiDhhdw3zRJpPbABML/N5lmRuBHjxtKm9VnRcsUzioyD0sekFMF0A==} - engines: {node: '>=18'} + '@csstools/css-syntax-patches-for-csstree@1.1.14': + resolution: {integrity: sha512-HpbVXyrofRXpHpgkNIjU/3EWR4WJvOkO3emNK/L6X/mTJU7bGUI3AkkpoTNXznQLp0KRjLHELTGeKI5dIkI9JQ==} + peerDependencies: + css-tree: ^3.2.1 + peerDependenciesMeta: + css-tree: + optional: true - '@csstools/css-tokenizer@3.0.4': - resolution: {integrity: sha512-Vd/9EVDiu6PPJt9yAh6roZP6El1xHrdvIVGjyBsHR0RYwNHgL7FJPyIIW4fANJNG6FtyZfvlRPpFI4ZM/lubvw==} - engines: {node: '>=18'} + '@csstools/css-tokenizer@4.0.1': + resolution: {integrity: sha512-bPlN9S9O1A0euCpEWE4qnvB5YDuyYVsUTrxSgmAM1Is0j4tICHoVyOVAXfWMP/kS9ZrjvyIXWV2PmomiAXXqOw==} + engines: {node: '>=20.19.0'} - '@dotenvx/dotenvx@1.51.1': - resolution: {integrity: sha512-fqcQxcxC4LOaUlW8IkyWw8x0yirlLUkbxohz9OnWvVWjf73J5yyw7jxWnkOJaUKXZotcGEScDox9MU6rSkcDgg==} + '@dotenvx/dotenvx@1.75.1': + resolution: {integrity: sha512-/BITOC9dmS/edY2zQwZNicQ059O6RKabtQfyEafV0nGtfYRNHYy1DIPiYVcov40+tob9hfmBnbR963dS+EQ1DQ==} hasBin: true + '@dotenvx/primitives@0.8.0': + resolution: {integrity: sha512-VYJy0uhFm9zTJ1TxBaW/pA8bjbOM/OttaNMwZ1RHG4JKyRG7DhSdiqD1ipQoAyoD22olUtxbP78W9xY3Wd11bg==} + '@drizzle-team/brocli@0.10.2': resolution: {integrity: sha512-z33Il7l5dKjUgGULTqBsQBQwckHh5AbIuxhdsIxDDiZAzBOrZO6q9ogcWC65kU382AfynTfgNumVcNIjuIua6w==} - '@ecies/ciphers@0.2.5': - resolution: {integrity: sha512-GalEZH4JgOMHYYcYmVqnFirFsjZHeoGMDt9IxEnM9F7GRUUyUksJ7Ou53L83WHJq3RWKD3AcBpo0iQh0oMpf8A==} - engines: {bun: '>=1', deno: '>=2', node: '>=16'} - peerDependencies: - '@noble/ciphers': ^1.0.0 + '@emnapi/core@1.11.2': + resolution: {integrity: sha512-TC8MkTuZUtcTSiFeuC0ksCh9QIJ5+F21MvZ4Wn4ORfYaFJ/0dsiudv5tVkejgwZlwQ39jL9WWDe2lz8x0WglOA==} - '@emnapi/core@1.7.1': - resolution: {integrity: sha512-o1uhUASyo921r2XtHYOHy7gdkGLge8ghBEQHMWmyJFoXlpU58kIrhhN3w26lpQb6dspetweapMn2CSNwQ8I4wg==} + '@emnapi/runtime@1.11.2': + resolution: {integrity: sha512-kyOl3X0DuTiT1h2ft8r2fYO8JYtU9a9Xis/zBSiGArNaagCOWx90N1k2wxp18czFDH+OgcWGb5ZP/XMt3dcyPA==} - '@emnapi/runtime@1.7.1': - resolution: {integrity: sha512-PVtJr5CmLwYAU9PZDMITZoR5iAOShYREoR45EyyLrbntV50mdePTgUn4AmOw90Ifcj+x2kRjdzr1HP3RrNiHGA==} + '@emnapi/runtime@1.11.3': + resolution: {integrity: sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==} - '@emnapi/wasi-threads@1.1.0': - resolution: {integrity: sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==} + '@emnapi/wasi-threads@1.2.2': + resolution: {integrity: sha512-c95qOXkHdydNKhscBTebqEC1CVAZpyqOfVfBzQ1qgzyl3gfeldUjIggDbIZgDKsHLgnsM+igH7TJ/eAasaVuMA==} '@esbuild-kit/core-utils@3.3.2': resolution: {integrity: sha512-sPRAnw9CdSsRmEtnsl2WXWdyquogVpB3yZ3dgwJfe8zrOzTsV7cJvmwrKVa+0ma5BoiGJ+BoqkMvawbayKUsqQ==} - deprecated: 'Merged into tsx: https://tsx.is' + deprecated: 'Merged into tsx: https://tsx.hirok.io' '@esbuild-kit/esm-loader@2.6.5': resolution: {integrity: sha512-FxEMIkJKnodyA1OaCUoEvbYRkoZlLZ4d/eXFu9Fh8CbBBgP5EmZxrfTRyN0qpXZ4vOvqnE5YdRdcrmUUXuU+dA==} - deprecated: 'Merged into tsx: https://tsx.is' + deprecated: 'Merged into tsx: https://tsx.hirok.io' - '@esbuild/aix-ppc64@0.27.0': - resolution: {integrity: sha512-KuZrd2hRjz01y5JK9mEBSD3Vj3mbCvemhT466rSuJYeE/hjuBrHfjjcjMdTm/sz7au+++sdbJZJmuBwQLuw68A==} + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.0': - resolution: {integrity: sha512-CC3vt4+1xZrs97/PKDkl0yN7w8edvU2vZvAFGD16n9F0Cvniy5qvzRXjfO1l94efczkkQE6g1x0i73Qf5uthOQ==} + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.0': - resolution: {integrity: sha512-j67aezrPNYWJEOHUNLPj9maeJte7uSMM6gMoxfPC9hOg8N02JuQi/T7ewumf4tNvJadFkvLZMlAq73b9uwdMyQ==} + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.0': - resolution: {integrity: sha512-wurMkF1nmQajBO1+0CJmcN17U4BP6GqNSROP8t0X/Jiw2ltYGLHpEksp9MpoBqkrFR3kv2/te6Sha26k3+yZ9Q==} + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.0': - resolution: {integrity: sha512-uJOQKYCcHhg07DL7i8MzjvS2LaP7W7Pn/7uA0B5S1EnqAirJtbyw4yC5jQ5qcFjHK9l6o/MX9QisBg12kNkdHg==} + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.0': - resolution: {integrity: sha512-8mG6arH3yB/4ZXiEnXof5MK72dE6zM9cDvUcPtxhUZsDjESl9JipZYW60C3JGreKCEP+p8P/72r69m4AZGJd5g==} + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.0': - resolution: {integrity: sha512-9FHtyO988CwNMMOE3YIeci+UV+x5Zy8fI2qHNpsEtSF83YPBmE8UWmfYAQg6Ux7Gsmd4FejZqnEUZCMGaNQHQw==} + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.0': - resolution: {integrity: sha512-zCMeMXI4HS/tXvJz8vWGexpZj2YVtRAihHLk1imZj4efx1BQzN76YFeKqlDr3bUWI26wHwLWPd3rwh6pe4EV7g==} + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.0': - resolution: {integrity: sha512-AS18v0V+vZiLJyi/4LphvBE+OIX682Pu7ZYNsdUHyUKSoRwdnOsMf6FDekwoAFKej14WAkOef3zAORJgAtXnlQ==} + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.0': - resolution: {integrity: sha512-t76XLQDpxgmq2cNXKTVEB7O7YMb42atj2Re2Haf45HkaUpjM2J0UuJZDuaGbPbamzZ7bawyGFUkodL+zcE+jvQ==} + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.0': - resolution: {integrity: sha512-Mz1jxqm/kfgKkc/KLHC5qIujMvnnarD9ra1cEcrs7qshTUSksPihGrWHVG5+osAIQ68577Zpww7SGapmzSt4Nw==} + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.0': - resolution: {integrity: sha512-QbEREjdJeIreIAbdG2hLU1yXm1uu+LTdzoq1KCo4G4pFOLlvIspBm36QrQOar9LFduavoWX2msNFAAAY9j4BDg==} + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.0': - resolution: {integrity: sha512-sJz3zRNe4tO2wxvDpH/HYJilb6+2YJxo/ZNbVdtFiKDufzWq4JmKAiHy9iGoLjAV7r/W32VgaHGkk35cUXlNOg==} + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.0': - resolution: {integrity: sha512-z9N10FBD0DCS2dmSABDBb5TLAyF1/ydVb+N4pi88T45efQ/w4ohr/F/QYCkxDPnkhkp6AIpIcQKQ8F0ANoA2JA==} + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.0': - resolution: {integrity: sha512-pQdyAIZ0BWIC5GyvVFn5awDiO14TkT/19FTmFcPdDec94KJ1uZcmFs21Fo8auMXzD4Tt+diXu1LW1gHus9fhFQ==} + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.0': - resolution: {integrity: sha512-hPlRWR4eIDDEci953RI1BLZitgi5uqcsjKMxwYfmi4LcwyWo2IcRP+lThVnKjNtk90pLS8nKdroXYOqW+QQH+w==} + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.0': - resolution: {integrity: sha512-1hBWx4OUJE2cab++aVZ7pObD6s+DK4mPGpemtnAORBvb5l/g5xFGk0vc0PjSkrDs0XaXj9yyob3d14XqvnQ4gw==} + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.0': - resolution: {integrity: sha512-6m0sfQfxfQfy1qRuecMkJlf1cIzTOgyaeXaiVaaki8/v+WB+U4hc6ik15ZW6TAllRlg/WuQXxWj1jx6C+dfy3w==} + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.0': - resolution: {integrity: sha512-xbbOdfn06FtcJ9d0ShxxvSn2iUsGd/lgPIO2V3VZIPDbEaIj1/3nBBe1AwuEZKXVXkMmpr6LUAgMkLD/4D2PPA==} + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.0': - resolution: {integrity: sha512-fWgqR8uNbCQ/GGv0yhzttj6sU/9Z5/Sv/VGU3F5OuXK6J6SlriONKrQ7tNlwBrJZXRYk5jUhuWvF7GYzGguBZQ==} + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.0': - resolution: {integrity: sha512-aCwlRdSNMNxkGGqQajMUza6uXzR/U0dIl1QmLjPtRbLOx3Gy3otfFu/VjATy4yQzo9yFDGTxYDo1FfAD9oRD2A==} + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.0': - resolution: {integrity: sha512-nyvsBccxNAsNYz2jVFYwEGuRRomqZ149A39SHWk4hV0jWxKM0hjBPm3AmdxcbHiFLbBSwG6SbpIcUbXjgyECfA==} + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.0': - resolution: {integrity: sha512-Q1KY1iJafM+UX6CFEL+F4HRTgygmEW568YMqDA5UV97AuZSm21b7SXIrRJDwXWPzr8MGr75fUZPV67FdtMHlHA==} + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.0': - resolution: {integrity: sha512-W1eyGNi6d+8kOmZIwi/EDjrL9nxQIQ0MiGqe/AWc6+IaHloxHSGoeRgDRKHFISThLmsewZ5nHFvGFWdBYlgKPg==} + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.0': - resolution: {integrity: sha512-30z1aKL9h22kQhilnYkORFYt+3wp7yZsHWus+wSKAJR8JtdfI76LJ4SBdMsCopTR3z/ORqVu5L1vtnHZWVj4cQ==} + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.0': - resolution: {integrity: sha512-aIitBcjQeyOhMTImhLZmtxfdOcuNRpwlPNmlFKPcHQYPhEssw75Cl1TSXJXpMkzaua9FUetx/4OQKq7eJul5Cg==} + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} engines: {node: '>=18'} cpu: [x64] os: [win32] - '@eslint-community/eslint-utils@4.9.0': - resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} + '@eslint-community/eslint-utils@4.10.1': + resolution: {integrity: sha512-cuadcxVFE8sDK6iWJbs8Sn0av2Nrh2QSGQhVlBW9AaAHqHwjWsZHT8LJ4hFGPh7ASBV2deFdM7H/DPjulmh8rg==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 @@ -1292,79 +1510,166 @@ packages: resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - '@eslint/config-array@0.21.1': - resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-array@0.23.5': + resolution: {integrity: sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/config-helpers@0.4.2': - resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/config-helpers@0.7.0': + resolution: {integrity: sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/core@0.17.0': - resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/core@1.2.1': + resolution: {integrity: sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/eslintrc@3.3.1': - resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/js@10.0.1': + resolution: {integrity: sha512-zeR9k5pd4gxjZ0abRoIaxdc7I3nDktoXZk2qOv9gCNWx3mVwEn32VRhyLaRsDiJjTs0xq/T8mfPtyuXu7GWBcA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + peerDependencies: + eslint: ^10.0.0 + peerDependenciesMeta: + eslint: + optional: true - '@eslint/js@9.39.1': - resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@eslint/object-schema@3.0.5': + resolution: {integrity: sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@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.7.3': + resolution: {integrity: sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@eslint/plugin-kit@0.4.1': - resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@exodus/bytes@1.15.1': + resolution: {integrity: sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true - '@floating-ui/core@1.7.3': - resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + '@floating-ui/core@1.8.0': + resolution: {integrity: sha512-0CIZ5itps/8x7BG8dEIhs53BvCUH2PCoogtakwRTut+Arm58sJooJ0AuZhLw2HJYIR5cMLNPBSS728sPho2khQ==} - '@floating-ui/dom@1.7.4': - resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + '@floating-ui/dom@1.8.0': + resolution: {integrity: sha512-yXSrzeHZBTZadLOlfyhCkJHNeLJnHRnRInwdZ40L7ZiaAtrBwoYlsDrX3v5zB1Utk7CLfzcOVnVVWoXEky7Ceg==} - '@floating-ui/react-dom@2.1.6': - resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} + '@floating-ui/react-dom@2.1.9': + resolution: {integrity: sha512-JDjEFGCpImxDCA7JJKviA0M9+RtmJdj0m/NVU5IMgBK+AmZouAQQ7/+2GLH0GXXY0YMw9oXPB8hKdbPYg5QLYg==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - '@floating-ui/react@0.27.16': - resolution: {integrity: sha512-9O8N4SeG2z++TSM8QA/KTeKFBVCNEz/AGS7gWPJf6KFRzmRWixFRnCnkPHRDwSVZW6QPDO6uT0P2SpWNKCc9/g==} + '@floating-ui/react@0.27.20': + resolution: {integrity: sha512-CMqMy7OaXl9W0eq1Uy7L7i2Y/anPvHmFmESd2CEw0t5YvZhcVCeo4MBevAmswRllX7Y2dEidA4ozGPunLSTQpw==} peerDependencies: react: '>=17.0.0' react-dom: '>=17.0.0' - '@floating-ui/utils@0.2.10': - resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@floating-ui/utils@0.2.12': + resolution: {integrity: sha512-HpCo8tmWzLVad5s2d19EhAz5zqrrQ6s69qd6moPMQvkOuSwDT1YgRfWSVuc4ennqrgv3OHppiOGMQ7oC13yIww==} - '@hono/node-server@1.19.6': - resolution: {integrity: sha512-Shz/KjlIeAhfiuE93NDKVdZ7HdBVLQAfdbaXEaoAVO3ic9ibRSLGIQGkcBbFyuLr+7/1D5ZCINM8B+6IvXeMtw==} - engines: {node: '>=18.14.1'} + '@hono/node-server@2.1.1': + resolution: {integrity: sha512-ELuehkj5VCBdgEw9zs+ivkKwyzzUCSQuE96YmiPvn1ECBoZCczbFXJLeEGMTYjphP6gydh4pHMqEYPVMYUVgQg==} + engines: {node: '>=20'} peerDependencies: hono: ^4 - '@hono/trpc-server@0.4.1': - resolution: {integrity: sha512-5D4gA+MpJxUzqCEDgZMlhxz1G8BkoneR+N+bD7Kt28LPJ0jAhXp1GA3ucpV6KxMBBLvFXIAFAfzdBeRmz12Pkw==} + '@hono/trpc-server@0.4.2': + resolution: {integrity: sha512-3TDrc42CZLgcTFkXQba+y7JlRWRiyw1AqhLqztWyNS2IFT+3bHld0lxKdGBttCtGKHYx0505dM67RMazjhdZqw==} engines: {node: '>=16.0.0'} peerDependencies: '@trpc/server': ^10.10.0 || >11.0.0-rc hono: '>=4.0.0' - '@hookform/resolvers@5.2.2': - resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} - peerDependencies: + '@hookform/resolvers@5.9.1': + resolution: {integrity: sha512-7b7vsbraJxKgjVSA1Nur9tLwj539WGJUBLA7QNvXnFoT2pM5Z7G+6rlukk4B2/QrTZy6huRtH6wKeESPKuIr6w==} + peerDependencies: + '@sinclair/typebox': '>=0.25.24' + '@standard-schema/spec': ^1.0.0 + '@typeschema/main': '>=0.13.7' + '@vinejs/vine': ^2.0.0 || ^3.0.0 || ^4.0.0 + ajv: ^8.12.0 + ajv-errors: ^3.0.0 + ajv-formats: ^2.1.1 + arktype: ^2.0.0 + ata-validator: ^1.2.0 + class-transformer: '>=0.4.0' + class-validator: '>=0.12.0' + computed-types: ^1.0.0 + effect: ^3.10.3 + fluentvalidation-ts: ^3.0.0 + fp-ts: ^2.7.0 + io-ts: ^2.0.0 + joi: ^17.0.0 || ^18.0.0 + nope-validator: '>=0.12.0' react-hook-form: ^7.55.0 + superstruct: '>=0.12.0' + typanion: ^3.3.2 + valibot: '>=0.31.0 || ^1.0.0-beta.4 || ^1.0.0-rc' + vest: '>=6.0.0' + yup: ^1.0.0 + zod: ^3.25.0 || ^4.0.0 + peerDependenciesMeta: + '@sinclair/typebox': + optional: true + '@standard-schema/spec': + optional: true + '@typeschema/main': + optional: true + '@vinejs/vine': + optional: true + ajv: + optional: true + ajv-errors: + optional: true + ajv-formats: + optional: true + arktype: + optional: true + ata-validator: + optional: true + class-transformer: + optional: true + class-validator: + optional: true + computed-types: + optional: true + effect: + optional: true + fluentvalidation-ts: + optional: true + fp-ts: + optional: true + io-ts: + optional: true + joi: + optional: true + nope-validator: + optional: true + superstruct: + optional: true + typanion: + optional: true + valibot: + optional: true + vest: + optional: true + yup: + optional: true + zod: + optional: true + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} - '@humanfs/core@0.19.1': - resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} engines: {node: '>=18.18.0'} - '@humanfs/node@0.16.7': - resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} engines: {node: '>=18.18.0'} '@humanwhocodes/module-importer@1.0.1': @@ -1375,301 +1680,182 @@ packages: resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - '@img/colour@1.0.0': - resolution: {integrity: sha512-A5P/LfWGFSl6nsckYtjw9da+19jB8hkJ6ACTGcDfEJ0aE+l2n2El7dsVM7UVHZQ9s2lmYMWlrS21YLy2IR1LUw==} + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} engines: {node: '>=18'} - '@img/sharp-darwin-arm64@0.33.5': - resolution: {integrity: sha512-UT4p+iz/2H4twwAoLCqfA9UH5pI6DggwKEGuaPy7nCVQ8ZsiY5PIcrRvD1DzuY3qYL07NtIQcWnBSY/heikIFQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [darwin] - - '@img/sharp-darwin-arm64@0.34.5': - resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-arm64@0.35.4': + resolution: {integrity: sha512-Uhfl4V4lhP2nbUVF9+hyH1+luj86f1gUFeo8ALYxFoULoU+G87D43BfeMP8XHsk9boxAnCY/bf2EHwhA7MuGsA==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [darwin] - '@img/sharp-darwin-x64@0.33.5': - resolution: {integrity: sha512-fyHac4jIc1ANYGRDxtiqelIbdWkIuQaI84Mv45KvGRRxSAa7o7d1ZKAOBaYbnepLC1WqxfpimdeWfvqqSGwR2Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [darwin] - - '@img/sharp-darwin-x64@0.34.5': - resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-darwin-x64@0.35.4': + resolution: {integrity: sha512-hWniXY3bG5qKpkKrAwPe4y+VTPmf086YQAnkxWh7uA1YrlRouWGa0M0Mxj3ZjnXFkv7/TD1bTy9lGUK26vRvWw==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-arm64@1.0.4': - resolution: {integrity: sha512-XblONe153h0O2zuFfTAbQYAX2JhYmDHeWikp1LM9Hul9gVPjFY427k6dFEcOL72O01QxQsWi761svJ/ev9xEDg==} - cpu: [arm64] - os: [darwin] + '@img/sharp-freebsd-wasm32@0.35.4': + resolution: {integrity: sha512-lIsKw/BU+kjB4eZjxrYrZmwOJYi3Ajrv66iAlBmUPyKc3HpnloevB1g3wxGD9P/5BbQ1brBGl65VRRrCvQDEqA==} + engines: {node: '>=20.9.0'} + os: [freebsd] - '@img/sharp-libvips-darwin-arm64@1.2.4': - resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + '@img/sharp-libvips-darwin-arm64@1.3.3': + resolution: {integrity: sha512-suTBPTDGrI9WodccaDdwZItTSaBYASlBk1NSfElSHrUfzu3szG6lvIF58+WiFvnfzuK8ZBFS5zE00PxqxnRiPg==} cpu: [arm64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.0.4': - resolution: {integrity: sha512-xnGR8YuZYfJGmWPvmlunFaWJsb9T/AO2ykoP3Fz/0X5XV2aoYBPkX6xqCQvUTKKiLddarLaxpzNe+b1hjeWHAQ==} + '@img/sharp-libvips-darwin-x64@1.3.3': + resolution: {integrity: sha512-FVJZ5mITMobmXIz/hPDTw0EintTW5H3WfrxwLqEqjiIihlu+hVRyGrFQ60xl0Lxn7Bt3zdpevPaQi0HEzqz9fw==} cpu: [x64] os: [darwin] - '@img/sharp-libvips-darwin-x64@1.2.4': - resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} - cpu: [x64] - os: [darwin] - - '@img/sharp-libvips-linux-arm64@1.0.4': - resolution: {integrity: sha512-9B+taZ8DlyyqzZQnoeIvDVR/2F4EbMepXMc/NdVbkzsJbzkUjhXv/70GQJ7tdLA4YJgNP25zukcxpX2/SueNrA==} - cpu: [arm64] - os: [linux] - - '@img/sharp-libvips-linux-arm64@1.2.4': - resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + '@img/sharp-libvips-linux-arm64@1.3.3': + resolution: {integrity: sha512-0DaL0A6Xu6sQSQFwe4iVCrKWU2cCTItnRsYsCdxAMm9NF6twAA9BKnoqy4hqz4+azQ0JHuA26qiUKsf1XJ/v5A==} cpu: [arm64] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linux-arm@1.0.5': - resolution: {integrity: sha512-gvcC4ACAOPRNATg/ov8/MnbxFDJqf/pDePbBnuBDcjsI8PssmjoKMAz4LtLaVi+OnSb5FK/yIOamqDwGmXW32g==} - cpu: [arm] - os: [linux] - - '@img/sharp-libvips-linux-arm@1.2.4': - resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + '@img/sharp-libvips-linux-arm@1.3.3': + resolution: {integrity: sha512-3rbU4vqXXc3hY/OiXdl52xZvT0F1yEngWfvqudtPJg/KkyiaQw2DRsFrNzpmLvfavbwOq3qXn36GP8obHRULQA==} cpu: [arm] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linux-ppc64@1.2.4': - resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + '@img/sharp-libvips-linux-ppc64@1.3.3': + resolution: {integrity: sha512-cdn1OvUBwsXhbC0zSzJnNzf5MZ/mTrobawDvNXBTxe8VtqKAm0sRuEY2Evzovb/w9JMk4TvRxqt1mekSuJz64w==} cpu: [ppc64] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linux-riscv64@1.2.4': - resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + '@img/sharp-libvips-linux-riscv64@1.3.3': + resolution: {integrity: sha512-HjPVx7yKz+0lqdhDlTw1tt90wamBoxhiXpvl1XZpJLiHH4RCJ5yDTqH+VlYPv2fwFs89JFw4c1IexYOcQUi4IQ==} cpu: [riscv64] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.0.4': - resolution: {integrity: sha512-u7Wz6ntiSSgGSGcjZ55im6uvTrOxSIS8/dgoVMoiGE9I6JAfU50yH5BoDlYA1tcuGS7g/QNtetJnxA6QEsCVTA==} + '@img/sharp-libvips-linux-s390x@1.3.3': + resolution: {integrity: sha512-neWLh+3yCNThxnfy3c4BbVBeGgt9aftno+XbT56iK28RgeDs3UOFWviLWlUu0bArYVYJaFDK+RRohbicUNCm8Q==} cpu: [s390x] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linux-s390x@1.2.4': - resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} - cpu: [s390x] + '@img/sharp-libvips-linux-x64@1.3.3': + resolution: {integrity: sha512-4vKmvAst9nrowcqquKFAyZJUDolUaIp8uRiN0mWFguJ1IplC9/pitXtlnnlU4aa/eJw3J7i67V+pwUL+wZGdsA==} + cpu: [x64] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linux-x64@1.0.4': - resolution: {integrity: sha512-MmWmQ3iPFZr0Iev+BAgVMb3ZyC4KeFc3jFxnNbEPas60e1cIfevbtuyf9nDGIzOaW9PdnDciJm+wFFaTlj5xYw==} - cpu: [x64] + '@img/sharp-libvips-linuxmusl-arm64@1.3.3': + resolution: {integrity: sha512-Y9kQaLMuNoB0bPYOOdcZMaseNrFpPodIWWMrx+CZyydf2xn68j9WYc6sWWRrDwNkzCQjKYfc68L7jKjGlHMibw==} + cpu: [arm64] os: [linux] + libc: [musl] - '@img/sharp-libvips-linux-x64@1.2.4': - resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + '@img/sharp-libvips-linuxmusl-x64@1.3.3': + resolution: {integrity: sha512-fj8Mv0HHfD1Rr+4I68+3agJynxDWtBFgicTbSOb9Bke6pIwzGcJ+RX/yHjmiEGFMCavY/dxvem7MyNaJF+wDiw==} cpu: [x64] os: [linux] + libc: [musl] - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': - resolution: {integrity: sha512-9Ti+BbTYDcsbp4wfYib8Ctm1ilkugkA/uscUn6UXK1ldpC1JjiXbLfFZtRlBhjPZ5o1NCLiDbg8fhUPKStHoTA==} + '@img/sharp-linux-arm64@0.35.4': + resolution: {integrity: sha512-De4jpEnAU8Hd5oT0j1G3uL4ZvTuipVMn7YC6vPaJhy6/7EwEae0SVAoBrUMYQbkLGDm85taVWwuPc1a44LTzCQ==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': - resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} - cpu: [arm64] + '@img/sharp-linux-arm@0.35.4': + resolution: {integrity: sha512-7OAS8gI0EReKGVN2HssHlM6umJgxF5VI3xN0p9FA91p/YO+ou5hiNghLdZ5BEHztwaaK5+bLKRf8x/o2L2nk9A==} + engines: {node: '>=20.9.0'} + cpu: [arm] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linuxmusl-x64@1.0.4': - resolution: {integrity: sha512-viYN1KX9m+/hGkJtvYYp+CCLgnJXwiQB39damAO7WMdKWlIhmYTfHjwSbQeUK/20vY154mwezd9HflVFM1wVSw==} - cpu: [x64] + '@img/sharp-linux-ppc64@0.35.4': + resolution: {integrity: sha512-2oYZJeIl4kCcMGk4ouZVjnkCtFrpQFlNEtJ6GbxzhHQchwH0NH/qEb9ykmOl29dqwMq+JhFdZn+1ak2FKhI9fQ==} + engines: {node: '>=20.9.0'} + cpu: [ppc64] os: [linux] + libc: [glibc] - '@img/sharp-libvips-linuxmusl-x64@1.2.4': - resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} - cpu: [x64] + '@img/sharp-linux-riscv64@0.35.4': + resolution: {integrity: sha512-cPbNChoRURAWdebDIHSenxRpgEdy7JkPydSnUxRm9VvKD7m0/xVaR/8Fzlu81pk5nHEvHH87UZUA7cTtwnbJSA==} + engines: {node: '>=20.9.0'} + cpu: [riscv64] os: [linux] + libc: [glibc] - '@img/sharp-linux-arm64@0.33.5': - resolution: {integrity: sha512-JMVv+AMRyGOHtO1RFBiJy/MBsgz0x4AWrT6QoEVVTyh1E39TrCUpTRI7mx9VksGX4awWASxqCYLCV4wBZHAYxA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] + '@img/sharp-linux-s390x@0.35.4': + resolution: {integrity: sha512-RY0JFY8Fd6RonCBtHz+DvadaPkXDSI1AUn6yWL9TipqkZ1vY8w8evqdgyDFnkm4/K1ve1TvZiaePP5oSd4+WVQ==} + engines: {node: '>=20.9.0'} + cpu: [s390x] os: [linux] + libc: [glibc] - '@img/sharp-linux-arm64@0.34.5': - resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - - '@img/sharp-linux-arm@0.33.5': - resolution: {integrity: sha512-JTS1eldqZbJxjvKaAkxhZmBqPRGmxgu+qFKSInv8moZ2AmT5Yib3EQ1c6gp493HvrvV8QgdOXdyaIBrhvFhBMQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm] - os: [linux] - - '@img/sharp-linux-arm@0.34.5': - resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm] - os: [linux] - - '@img/sharp-linux-ppc64@0.34.5': - resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ppc64] - os: [linux] - - '@img/sharp-linux-riscv64@0.34.5': - resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [riscv64] - os: [linux] - - '@img/sharp-linux-s390x@0.33.5': - resolution: {integrity: sha512-y/5PCd+mP4CA/sPDKl2961b+C9d+vPAveS33s6Z3zfASk2j5upL6fXVPZi7ztePZ5CuH+1kW8JtvxgbuXHRa4Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [s390x] - os: [linux] - - '@img/sharp-linux-s390x@0.34.5': - resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [s390x] - os: [linux] - - '@img/sharp-linux-x64@0.33.5': - resolution: {integrity: sha512-opC+Ok5pRNAzuvq1AG0ar+1owsu842/Ab+4qvU879ippJBHvyY5n2mxF1izXqkPYlGuP/M556uh53jRLJmzTWA==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - - '@img/sharp-linux-x64@0.34.5': - resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linux-x64@0.35.4': + resolution: {integrity: sha512-9qvvEAuk8k89TfWUoX2htWjbAMX8p+NxCppjpcg5k6xMsjhBQPTsoIh36h9Qde4WRuGpJeYnOjdosDn/cnv+OA==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] + libc: [glibc] - '@img/sharp-linuxmusl-arm64@0.33.5': - resolution: {integrity: sha512-XrHMZwGQGvJg2V/oRSUfSAfjfPxO+4DkiRh6p2AFjLQztWUuY/o8Mq0eMQVIY7HJ1CDQUJlxGGZRw1a5bqmd1g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [arm64] - os: [linux] - - '@img/sharp-linuxmusl-arm64@0.34.5': - resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-arm64@0.35.4': + resolution: {integrity: sha512-KB5jxpfWQTr0nc3xdHtWChdbifHrBGsd2SM62Eyxrl8afikm+f5qGBU75SJIZBT/S1MC8XyacdlXBMSWq6OURA==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [linux] + libc: [musl] - '@img/sharp-linuxmusl-x64@0.33.5': - resolution: {integrity: sha512-WT+d/cgqKkkKySYmqoZ8y3pxx7lx9vVejxW/W4DOFMYVSkErR+w7mf2u8m/y4+xHe7yY9DAXQMWQhpnMuFfScw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [linux] - - '@img/sharp-linuxmusl-x64@0.34.5': - resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-linuxmusl-x64@0.35.4': + resolution: {integrity: sha512-f+eZJZIQNEEd26RPSW+76chwOf1XtA2Y/O+5ocVyLliHkeih3e+jhLVBdNTd2rS3IbNXK8+ug93Vf5ZXtF5Lxg==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [linux] + libc: [musl] - '@img/sharp-wasm32@0.33.5': - resolution: {integrity: sha512-ykUW4LVGaMcU9lu9thv85CbRMAwfeadCJHRsg2GmeRa/cJxsVY9Rbd57JcMxBkKHag5U/x7TSBpScF4U8ElVzg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [wasm32] + '@img/sharp-wasm32@0.35.4': + resolution: {integrity: sha512-zQnl4Kwp7Q6NHsENtU2T/00Zi+w3AQNwz3+UaTyVBy2FpXrzXzGjndpK61onhZjRtRpQXxCTeqw19bVyXOh7jA==} + engines: {node: '>=20.9.0'} - '@img/sharp-wasm32@0.34.5': - resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-webcontainers-wasm32@0.35.4': + resolution: {integrity: sha512-ESfNkywmCfPNyaZjxooddJQiQ+l/nTpGEOGthxiLnIHXC/CmcBixnfwUleX9mCz9ovrUUvKMap/pm8RYbzfwaA==} + engines: {node: '>=20.9.0'} cpu: [wasm32] - '@img/sharp-win32-arm64@0.34.5': - resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-arm64@0.35.4': + resolution: {integrity: sha512-iNdlBX9gLVvqe2I3uIJSIKTq6wckP/DYxZtcqxm09x5Gi24DnFBmPAWZmr60ZyYMG0xlzo6goG3670ar+RXvRw==} + engines: {node: '>=20.9.0'} cpu: [arm64] os: [win32] - '@img/sharp-win32-ia32@0.33.5': - resolution: {integrity: sha512-T36PblLaTwuVJ/zw/LaH0PdZkRz5rd3SmMHX8GSmR7vtNSP5Z6bQkExdSK7xGWyxLw4sUknBuugTelgw2faBbQ==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [ia32] - os: [win32] - - '@img/sharp-win32-ia32@0.34.5': - resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-ia32@0.35.4': + resolution: {integrity: sha512-kqRsbaa5CS6KHlpxnN7WhE6vAAugXyZButpRdvDWetlv6Qv4N9WTcrWzF7tXfB9T7MsoadqdI8hmwLq6UlLvtw==} + engines: {node: ^20.9.0} cpu: [ia32] os: [win32] - '@img/sharp-win32-x64@0.33.5': - resolution: {integrity: sha512-MpY/o8/8kj+EcnxwvrP4aTJSWw/aZ7JIGR4aBeZkZw5B7/Jn+tY9/VNwtcoGmdT7GfggGIU4kygOMSbYnOrAbg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - cpu: [x64] - os: [win32] - - '@img/sharp-win32-x64@0.34.5': - resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + '@img/sharp-win32-x64@0.35.4': + resolution: {integrity: sha512-XtmnYhBcrORsJ4XJngyzr/EWP0hRZLAZRFaApdKuviyqF78+ylxh2y06ZmtULAMOnObJ3ucpN0AcwSWnMowTRg==} + engines: {node: '>=20.9.0'} cpu: [x64] os: [win32] - '@inquirer/ansi@1.0.2': - resolution: {integrity: sha512-S8qNSZiYzFd0wAcyG5AXCvUHC5Sr7xpZ9wZ2py9XR88jUz8wooStVx5M6dRzczbBWjic9NP7+rY0Xi7qqK/aMQ==} - engines: {node: '>=18'} - - '@inquirer/confirm@5.1.21': - resolution: {integrity: sha512-KR8edRkIsUayMXV+o3Gv+q4jlhENF9nMYUZs9PA2HzrXeHI8M5uDag70U7RJn9yyiMZSbtF5/UexBtAVtZGSbQ==} - engines: {node: '>=18'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/core@10.3.2': - resolution: {integrity: sha512-43RTuEbfP8MbKzedNqBrlhhNKVwoK//vUFNW3Q3vZ88BLcrs4kYpGg+B2mm5p2K/HfygoCxuKwJJiv8PbGmE0A==} - engines: {node: '>=18'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@inquirer/figures@1.0.15': - resolution: {integrity: sha512-t2IEY+unGHOzAaVM5Xx6DEWKeXlDDcNPeDyUpsRc6CUhBfU3VQOEl+Vssh7VNp1dR8MdUJBWhuObjXCsVpjN5g==} + '@isaacs/cliui@9.0.0': + resolution: {integrity: sha512-AokJm4tuBHillT+FpMtxQ60n8ObyXBatq7jD2/JA9dxbDDokKQm8KMht5ibGzLVU9IJDIKK4TPKgMHEYMn3lMg==} engines: {node: '>=18'} - '@inquirer/type@3.0.10': - resolution: {integrity: sha512-BvziSRxfz5Ov8ch0z/n3oijRSEcEsHnhggm4xFZe93DHcUCTlutlq9Ox4SVENAfcRD22UQq7T/atg9Wr3k09eA==} - engines: {node: '>=18'} - peerDependencies: - '@types/node': '>=18' - peerDependenciesMeta: - '@types/node': - optional: true - - '@isaacs/balanced-match@4.0.1': - resolution: {integrity: sha512-yzMTt9lEb8Gv7zRioUilSglI0c0smZ9k5D65677DLWLtWJaXIS3CqcGyUFByYKlnUj6TkjLVs54fBl6+TiGQDQ==} - engines: {node: 20 || >=22} - - '@isaacs/brace-expansion@5.0.0': - resolution: {integrity: sha512-ZT55BDLV0yv0RBm2czMiZ+SqCGO7AvmOM3G/w2xhVPH+te0aKgFjmBvGlL1dH+ql2tgGO3MVrbb3jCKyvpgnxA==} - engines: {node: 20 || >=22} - - '@isaacs/cliui@8.0.2': - resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} - engines: {node: '>=12'} + '@isaacs/fs-minipass@4.0.1': + resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} + engines: {node: '>=18.0.0'} '@istanbuljs/load-nyc-config@1.1.0': resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} engines: {node: '>=8'} - '@istanbuljs/schema@0.1.3': - resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} engines: {node: '>=8'} '@jridgewell/gen-mapping@0.3.13': @@ -1685,8 +1871,8 @@ packages: '@jridgewell/source-map@0.3.11': resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} - '@jridgewell/sourcemap-codec@1.5.5': - resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + '@jridgewell/sourcemap-codec@1.6.0': + resolution: {integrity: sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==} '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} @@ -1694,8 +1880,17 @@ packages: '@jridgewell/trace-mapping@0.3.9': resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} - '@modelcontextprotocol/sdk@1.24.3': - resolution: {integrity: sha512-YgSHW29fuzKKAHTGe9zjNoo+yF8KaQPzDC2W9Pv41E7/57IfY+AMGJ/aDFlgTLcVVELoggKE4syABCE75u3NCw==} + '@keyv/bigmap@1.3.1': + resolution: {integrity: sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==} + engines: {node: '>= 18'} + peerDependencies: + keyv: ^5.6.0 + + '@keyv/serialize@1.1.1': + resolution: {integrity: sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==} + + '@modelcontextprotocol/sdk@1.30.0': + resolution: {integrity: sha512-xKd8OIzlqNzcqcNumGAa6g+PW2kjD5vrpcKOnfldAUPP3j7lnqMPwlTXQm8gF+UwH72z0lqaRbjr9hqGz0eITA==} engines: {node: '>=18'} peerDependencies: '@cfworker/json-schema': ^4.1.1 @@ -1704,84 +1899,31 @@ packages: '@cfworker/json-schema': optional: true - '@mswjs/interceptors@0.40.0': - resolution: {integrity: sha512-EFd6cVbHsgLa6wa4RljGj6Wk75qoHxUSyc5asLyyPSyuhIcdS2Q3Phw6ImS1q+CkALthJRShiYfKANcQMuMqsQ==} - engines: {node: '>=18'} - - '@napi-rs/wasm-runtime@1.0.7': - resolution: {integrity: sha512-SeDnOO0Tk7Okiq6DbXmmBODgOAb9dp9gjlphokTUxmt8U3liIP1ZsozBahH69j/RJv+Rfs6IwUKHTgQYJ/HBAw==} - - '@next/env@16.0.1': - resolution: {integrity: sha512-LFvlK0TG2L3fEOX77OC35KowL8D7DlFF45C0OvKMC4hy8c/md1RC4UMNDlUGJqfCoCS2VWrZ4dSE6OjaX5+8mw==} - - '@next/swc-darwin-arm64@16.0.1': - resolution: {integrity: sha512-R0YxRp6/4W7yG1nKbfu41bp3d96a0EalonQXiMe+1H9GTHfKxGNCGFNWUho18avRBPsO8T3RmdWuzmfurlQPbg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [darwin] - - '@next/swc-darwin-x64@16.0.1': - resolution: {integrity: sha512-kETZBocRux3xITiZtOtVoVvXyQLB7VBxN7L6EPqgI5paZiUlnsgYv4q8diTNYeHmF9EiehydOBo20lTttCbHAg==} - engines: {node: '>= 10'} - cpu: [x64] - os: [darwin] - - '@next/swc-linux-arm64-gnu@16.0.1': - resolution: {integrity: sha512-hWg3BtsxQuSKhfe0LunJoqxjO4NEpBmKkE+P2Sroos7yB//OOX3jD5ISP2wv8QdUwtRehMdwYz6VB50mY6hqAg==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-arm64-musl@16.0.1': - resolution: {integrity: sha512-UPnOvYg+fjAhP3b1iQStcYPWeBFRLrugEyK/lDKGk7kLNua8t5/DvDbAEFotfV1YfcOY6bru76qN9qnjLoyHCQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [linux] - - '@next/swc-linux-x64-gnu@16.0.1': - resolution: {integrity: sha512-Et81SdWkcRqAJziIgFtsFyJizHoWne4fzJkvjd6V4wEkWTB4MX6J0uByUb0peiJQ4WeAt6GGmMszE5KrXK6WKg==} - engines: {node: '>= 10'} + '@napi-rs/lzma-linux-x64-gnu@1.5.1': + resolution: {integrity: sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==} + engines: {node: ^22.20 || ^24.12 || >=25} cpu: [x64] os: [linux] + libc: [glibc] - '@next/swc-linux-x64-musl@16.0.1': - resolution: {integrity: sha512-qBbgYEBRrC1egcG03FZaVfVxrJm8wBl7vr8UFKplnxNRprctdP26xEv9nJ07Ggq4y1adwa0nz2mz83CELY7N6Q==} - engines: {node: '>= 10'} - cpu: [x64] - os: [linux] - - '@next/swc-win32-arm64-msvc@16.0.1': - resolution: {integrity: sha512-cPuBjYP6I699/RdbHJonb3BiRNEDm5CKEBuJ6SD8k3oLam2fDRMKAvmrli4QMDgT2ixyRJ0+DTkiODbIQhRkeQ==} - engines: {node: '>= 10'} - cpu: [arm64] - os: [win32] - - '@next/swc-win32-x64-msvc@16.0.1': - resolution: {integrity: sha512-XeEUJsE4JYtfrXe/LaJn3z1pD19fK0Q6Er8Qoufi+HqvdO4LEPyCxLUt4rxA+4RfYo6S9gMlmzCMU2F+AatFqQ==} - engines: {node: '>= 10'} - cpu: [x64] - os: [win32] - - '@noble/ciphers@1.3.0': - resolution: {integrity: sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==} - engines: {node: ^14.21.3 || >=16} + '@napi-rs/wasm-runtime@1.2.4': + resolution: {integrity: sha512-AJxoUD2/15ESHbvpcyjU274nsAPLuOtPHCk0vKJM5pj//Fg/B1FXNWjPnXTT9PymCYYiHo4zPj0ZomXBKhoy7g==} + engines: {node: ^20.19.0 || ^22.13.0 || >=23.5.0} + peerDependencies: + '@emnapi/core': ^1.7.1 || ^2.0.0-alpha.4 + '@emnapi/runtime': ^1.7.1 || ^2.0.0-alpha.4 - '@noble/ciphers@2.0.1': - resolution: {integrity: sha512-xHK3XHPUW8DTAobU+G0XT+/w+JLM7/8k1UFdB5xg/zTFPnFCobhftzw8wl4Lw2aq/Rvir5pxfZV5fEazmeCJ2g==} + '@noble/ciphers@2.4.0': + resolution: {integrity: sha512-AnjFn0Jv92laAkvMrghlFZq4qQCIN/4DxFV/eooqtC2YTjB7kBeLMS2T9KJX4Dn+ZVXLOwK0lSgqDtx9gvxtiw==} engines: {node: '>= 20.19.0'} - '@noble/curves@1.9.7': - resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} - engines: {node: ^14.21.3 || >=16} - - '@noble/hashes@1.8.0': - resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} - engines: {node: ^14.21.3 || >=16} - - '@noble/hashes@2.0.1': - resolution: {integrity: sha512-XlOlEbQcE9fmuXxrVTXCTlG2nlRXa9Rj3rr5Ue/+tX+nmkgbX720YHh0VR3hBF9xDvwnb8D2shVGOwNx+ulArw==} + '@noble/hashes@2.4.0': + resolution: {integrity: sha512-X5XaVWZIBCT7HHZGm5I7ZQXDwLG+bGXuSrMQAW+7Zvl87h1kmc1ZB1VSRJcpUfoUrGQp4Fkoxm5kZ+Ms+aW+eA==} engines: {node: '>= 20.19.0'} + '@nodable/entities@3.0.0': + resolution: {integrity: sha512-8L9xFeTYKhm49xfIypoe2W5wV1m/3Z58kT+7kR9A8OyFxcPduI4VmxaUMQyKYrRjUoLLSXv6EKKID5Tvj9cUVw==} + '@nodelib/fs.scandir@2.1.5': resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} engines: {node: '>= 8'} @@ -1794,362 +1936,296 @@ packages: resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} engines: {node: '>= 8'} - '@open-draft/deferred-promise@2.2.0': - resolution: {integrity: sha512-CecwLWx3rhxVQF6V4bAgPS5t+So2sTbPgAzafKkVizyi7tlwpcFpdFqq+wqF2OwNBmqFuu6tOyouTuxgpMfzmA==} - - '@open-draft/logger@0.3.0': - resolution: {integrity: sha512-X2g45fzhxH238HKO4xbSr7+wBS8Fvw6ixhTDuvLd5mqh6bJJCFAPwU9mPDxbcrRtfxv4u5IHCEH77BmxvXmmxQ==} - - '@open-draft/until@2.1.0': - resolution: {integrity: sha512-U69T3ItWHvLwGg5eJ0n3I62nWuE6ilHlmz7zM0npLBRvPRd7e6NYmg54vvRtP5mZG7kZqZCFVdsTWo7BPtBujg==} - - '@opentelemetry/api-logs@0.204.0': - resolution: {integrity: sha512-DqxY8yoAaiBPivoJD4UtgrMS8gEmzZ5lnaxzPojzLVHBGqPxgWm4zcuvcUHZiqQ6kRX2Klel2r9y8cA2HAtqpw==} + '@opentelemetry/api-logs@0.220.0': + resolution: {integrity: sha512-CmVa4ImJ+ynfrPMNaAXHET6Bhb44SwzmfyVJFq9ni2jgXJR/l7C6gfVFddNmHP+ZOkP9cf4f9DBe68qVLTHc9w==} engines: {node: '>=8.0.0'} - '@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==} + '@opentelemetry/api@1.9.1': + resolution: {integrity: sha512-gLyJlPHPZYdAk1JENA9LeHejZe1Ti77/pTeFm/nMXmQH/HFZlcS/O2XJB+L8fkbrNSqhdtlvjBVjxwUYanNH5Q==} engines: {node: '>=8.0.0'} - '@opentelemetry/context-async-hooks@2.2.0': - resolution: {integrity: sha512-qRkLWiUEZNAmYapZ7KGS5C4OmBLcP/H2foXeOEaowYCR0wi89fHejrfYfbuLVCMLp/dWZXKvQusdbUEZjERfwQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - - '@opentelemetry/core@2.1.0': - resolution: {integrity: sha512-RMEtHsxJs/GiHHxYT58IY57UXAQTuUnZVco6ymDEqTNlJKTimM4qPUPVe8InNFyBjhHBEAx4k3Q8LtNayBsbUQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.0.0 <1.10.0' - - '@opentelemetry/core@2.2.0': - resolution: {integrity: sha512-FuabnnUm8LflnieVxs6eP7Z383hgQU4W1e3KJS6aOG3RxWxcHyBxH8fDMHNgu/gFx/M2jvTOW/4/PHhLz6bjWw==} + '@opentelemetry/core@2.11.0': + resolution: {integrity: sha512-7YP44XH0tV6+Mb54x2YGf84i7yi+31MBZlE8JwvozkxyTvXbSp10X7cI7YE49ChJ3shMJoBmCJF3+1QFBJctGA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': '>=1.0.0 <1.10.0' - '@opentelemetry/instrumentation-amqplib@0.51.0': - resolution: {integrity: sha512-XGmjYwjVRktD4agFnWBWQXo9SiYHKBxR6Ag3MLXwtLE4R99N3a08kGKM5SC1qOFKIELcQDGFEFT9ydXMH00Luw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-connect@0.48.0': - resolution: {integrity: sha512-OMjc3SFL4pC16PeK+tDhwP7MRvDPalYCGSvGqUhX5rASkI2H0RuxZHOWElYeXkV0WP+70Gw6JHWac/2Zqwmhdw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-dataloader@0.22.0': - resolution: {integrity: sha512-bXnTcwtngQsI1CvodFkTemrrRSQjAjZxqHVc+CJZTDnidT0T6wt3jkKhnsjU/Kkkc0lacr6VdRpCu2CUWa0OKw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-express@0.53.0': - resolution: {integrity: sha512-r/PBafQmFYRjuxLYEHJ3ze1iBnP2GDA1nXOSS6E02KnYNZAVjj6WcDA1MSthtdAUUK0XnotHvvWM8/qz7DMO5A==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-fs@0.24.0': - resolution: {integrity: sha512-HjIxJ6CBRD770KNVaTdMXIv29Sjz4C1kPCCK5x1Ujpc6SNnLGPqUVyJYZ3LUhhnHAqdbrl83ogVWjCgeT4Q0yw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-generic-pool@0.48.0': - resolution: {integrity: sha512-TLv/On8pufynNR+pUbpkyvuESVASZZKMlqCm4bBImTpXKTpqXaJJ3o/MUDeMlM91rpen+PEv2SeyOKcHCSlgag==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-graphql@0.52.0': - resolution: {integrity: sha512-3fEJ8jOOMwopvldY16KuzHbRhPk8wSsOTSF0v2psmOCGewh6ad+ZbkTx/xyUK9rUdUMWAxRVU0tFpj4Wx1vkPA==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-hapi@0.51.0': - resolution: {integrity: sha512-qyf27DaFNL1Qhbo/da+04MSCw982B02FhuOS5/UF+PMhM61CcOiu7fPuXj8TvbqyReQuJFljXE6UirlvoT/62g==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 - - '@opentelemetry/instrumentation-http@0.204.0': - resolution: {integrity: sha512-1afJYyGRA4OmHTv0FfNTrTAzoEjPQUYgd+8ih/lX0LlZBnGio/O80vxA0lN3knsJPS7FiDrsDrWq25K7oAzbkw==} + '@opentelemetry/instrumentation@0.220.0': + resolution: {integrity: sha512-xQx3E2WxP1mDvKzxLxX+CTCtNLa560YJZ3087qYHerl2YmiKpv7AH+dAy7vmx+eVrZ5BwhfWUAVoKOoxCNHcpw==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: '@opentelemetry/api': ^1.3.0 - '@opentelemetry/instrumentation-ioredis@0.52.0': - resolution: {integrity: sha512-rUvlyZwI90HRQPYicxpDGhT8setMrlHKokCtBtZgYxQWRF5RBbG4q0pGtbZvd7kyseuHbFpA3I/5z7M8b/5ywg==} + '@opentelemetry/resources@2.11.0': + resolution: {integrity: sha512-Ie7+8q8MDF4FAEQCKVMTx3ReUvxiIAgIiiW3c9JdmP8+HMcDy20puT+AHjexnExgnbvBxjQ9fjkFDWrikJ2jQA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/instrumentation-kafkajs@0.14.0': - resolution: {integrity: sha512-kbB5yXS47dTIdO/lfbbXlzhvHFturbux4EpP0+6H78Lk0Bn4QXiZQW7rmZY1xBCY16mNcCb8Yt0mhz85hTnSVA==} + '@opentelemetry/sdk-trace-base@2.11.0': + resolution: {integrity: sha512-H19x/TX/LZdqiYOjM7fqtSxwlplC5pgelavqbQdHbhdq0q/AI/TGkM2dfGuuynTXmJPeF2HoZVoPDu+TGoW78A==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/instrumentation-knex@0.49.0': - resolution: {integrity: sha512-NKsRRT27fbIYL4Ix+BjjP8h4YveyKc+2gD6DMZbr5R5rUeDqfC8+DTfIt3c3ex3BIc5Vvek4rqHnN7q34ZetLQ==} + '@opentelemetry/sdk-trace@2.11.0': + resolution: {integrity: sha512-fFnTqGm8/G73GQVnxYi7LXa1ZVYEUvgL6XI1LpvV0bPC7WQ/ZGgKxCSl8FnlZBKto9JHHEFTO6s6CUpvvtwFrA==} engines: {node: ^18.19.0 || >=20.6.0} peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@opentelemetry/api': '>=1.3.0 <1.10.0' - '@opentelemetry/instrumentation-koa@0.52.0': - resolution: {integrity: sha512-JJSBYLDx/mNSy8Ibi/uQixu2rH0bZODJa8/cz04hEhRaiZQoeJ5UrOhO/mS87IdgVsHrnBOsZ6vDu09znupyuA==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@opentelemetry/semantic-conventions@1.43.0': + resolution: {integrity: sha512-eSYWTm620tTk45EKSedaUL8MFYI8hW164hIXsgIHyxu3VobUB3fFCu5t0hQby6OoWRPsG1KkKUG2M5UadiLiVg==} + engines: {node: '>=14'} - '@opentelemetry/instrumentation-lru-memoizer@0.49.0': - resolution: {integrity: sha512-ctXu+O/1HSadAxtjoEg2w307Z5iPyLOMM8IRNwjaKrIpNAthYGSOanChbk1kqY6zU5CrpkPHGdAT6jk8dXiMqw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@oxc-parser/binding-android-arm-eabi@0.150.0': + resolution: {integrity: sha512-oQef2Zu4Prz1KLKznz3HqZzU9uVoA5PMoDZuuLmqms7hKmKSAPzlaMnLllJq3t+rgKmfJJ2siPrpZfFrW06btw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [android] - '@opentelemetry/instrumentation-mongodb@0.57.0': - resolution: {integrity: sha512-KD6Rg0KSHWDkik+qjIOWoksi1xqSpix8TSPfquIK1DTmd9OTFb5PHmMkzJe16TAPVEuElUW8gvgP59cacFcrMQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@oxc-parser/binding-android-arm64@0.150.0': + resolution: {integrity: sha512-B6ofpoFiAUwIZ0MJ2IgHPvZK8FAtL4qzSZRwOkAKIfxEobE1mQC8nDdiFZj7pUaJiVUVCsfkMsBJKedzO8rZvA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] - '@opentelemetry/instrumentation-mongoose@0.51.0': - resolution: {integrity: sha512-gwWaAlhhV2By7XcbyU3DOLMvzsgeaymwP/jktDC+/uPkCmgB61zurwqOQdeiRq9KAf22Y2dtE5ZLXxytJRbEVA==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@oxc-parser/binding-darwin-arm64@0.150.0': + resolution: {integrity: sha512-J+9IHKzx/bSz1JetOfD4zKXSK9sOm4/a7+0qomJODcTL6JsRXGeV/ZdkAPSIDydfFmWzYCraMlQEosSZEyBYkQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] - '@opentelemetry/instrumentation-mysql2@0.51.0': - resolution: {integrity: sha512-zT2Wg22Xn43RyfU3NOUmnFtb5zlDI0fKcijCj9AcK9zuLZ4ModgtLXOyBJSSfO+hsOCZSC1v/Fxwj+nZJFdzLQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@oxc-parser/binding-darwin-x64@0.150.0': + resolution: {integrity: sha512-v6IPfcAcSYrBWXV5Tce1DmxDMXLhEYpIIWiRFPJopgCVscZdLaV4MRQOUxvL3usQlw+yrwYOjBFB9IwBx+jUiQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] - '@opentelemetry/instrumentation-mysql@0.50.0': - resolution: {integrity: sha512-duKAvMRI3vq6u9JwzIipY9zHfikN20bX05sL7GjDeLKr2qV0LQ4ADtKST7KStdGcQ+MTN5wghWbbVdLgNcB3rA==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@oxc-parser/binding-freebsd-x64@0.150.0': + resolution: {integrity: sha512-AoR/4jD02HET0KO0yNT4nbTE+XJUxiO9jB1X/ycEjUE3WrIJ3IjV/Vf+gskhWLcqqeXfvNnkDtBR7epllAm88A==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] - '@opentelemetry/instrumentation-pg@0.57.0': - resolution: {integrity: sha512-dWLGE+r5lBgm2A8SaaSYDE3OKJ/kwwy5WLyGyzor8PLhUL9VnJRiY6qhp4njwhnljiLtzeffRtG2Mf/YyWLeTw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@oxc-parser/binding-linux-arm-gnueabihf@0.150.0': + resolution: {integrity: sha512-A/hycCFjLUrCmLoL5O/vBp40ohlaXO1Ta3v5hqYZxicYFs129wZmgZJggcW4mYGYbZebQLhup+N8JjeQl8qwyw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] - '@opentelemetry/instrumentation-redis@0.53.0': - resolution: {integrity: sha512-WUHV8fr+8yo5RmzyU7D5BIE1zwiaNQcTyZPwtxlfr7px6NYYx7IIpSihJK7WA60npWynfxxK1T67RAVF0Gdfjg==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@oxc-parser/binding-linux-arm-musleabihf@0.150.0': + resolution: {integrity: sha512-pbqahg1Pkz7J4RKmXm30s/iQu99hv64ayXCu8P4p75HcEH5azOdR4eGqiB6lFGkFR3mMpzaYsSKLkS8oJbjmeQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] - '@opentelemetry/instrumentation-tedious@0.23.0': - resolution: {integrity: sha512-3TMTk/9VtlRonVTaU4tCzbg4YqW+Iq/l5VnN2e5whP6JgEg/PKfrGbqQ+CxQWNLfLaQYIUgEZqAn5gk/inh1uQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@oxc-parser/binding-linux-arm64-gnu@0.150.0': + resolution: {integrity: sha512-HV11aRbBQGwqv8bEo+K/6qr88uB4fEe1mhXncMhlVCrj+WpBSraxrUzHaPVmeQRU6x6x8v/3DuCbbo93rpp+fw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [glibc] - '@opentelemetry/instrumentation-undici@0.15.0': - resolution: {integrity: sha512-sNFGA/iCDlVkNjzTzPRcudmI11vT/WAfAguRdZY9IspCw02N4WSC72zTuQhSMheh2a1gdeM9my1imnKRvEEvEg==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.7.0 + '@oxc-parser/binding-linux-arm64-musl@0.150.0': + resolution: {integrity: sha512-k6pVkJqALwtEuP4zukVhGRhdIy4+ofChUIUUsAHHyqDZlNsknmel3JjbggrJiWGaes6h/dIcWmEXsKW4SmK9oQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + libc: [musl] - '@opentelemetry/instrumentation@0.204.0': - resolution: {integrity: sha512-vV5+WSxktzoMP8JoYWKeopChy6G3HKk4UQ2hESCRDUUTZqQ3+nM3u8noVG0LmNfRWwcFBnbZ71GKC7vaYYdJ1g==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@oxc-parser/binding-linux-ppc64-gnu@0.150.0': + resolution: {integrity: sha512-tEFg39mw/rHO5n8GK2DR4ZMFfsPQZtnQIPbsIpjoQRomJc/2tRfsCSmCT6gNit+NZGoeJG5aH9ATDH5bf0WnoQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + libc: [glibc] - '@opentelemetry/instrumentation@0.57.2': - resolution: {integrity: sha512-BdBGhQBh8IjZ2oIIX6F2/Q3LKm/FDDKi6ccYKcBTeilh6SNdNKveDOLk73BkSJjQLJk6qe4Yh+hHw1UPhCDdrg==} - engines: {node: '>=14'} - peerDependencies: - '@opentelemetry/api': ^1.3.0 + '@oxc-parser/binding-linux-riscv64-gnu@0.150.0': + resolution: {integrity: sha512-0JO7IFkoek6HqV589Menx3hJySNXi6quRhO4tq2P7kpEHKEXoDATnoPVUpn5B7gDH2KLkdo751N0uIrGJFCTCw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [glibc] - '@opentelemetry/redis-common@0.38.2': - resolution: {integrity: sha512-1BCcU93iwSRZvDAgwUxC/DV4T/406SkMfxGqu5ojc3AvNI+I9GhV7v0J1HljsczuuhcnFLYqD5VmwVXfCGHzxA==} - engines: {node: ^18.19.0 || >=20.6.0} + '@oxc-parser/binding-linux-riscv64-musl@0.150.0': + resolution: {integrity: sha512-7XPzREnyAS5wHU9aB+49Uaqgoo1gVCklHc3DRlc3fJy2tXD/eAJFN1QFz/crj+Ulup5P1+axNREF+/RGaB/IRA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [riscv64] + os: [linux] + libc: [musl] - '@opentelemetry/resources@2.2.0': - resolution: {integrity: sha512-1pNQf/JazQTMA0BiO5NINUzH0cbLbbl7mntLa4aJNmCCXSj0q03T5ZXXL0zw4G55TjdL9Tz32cznGClf+8zr5A==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@oxc-parser/binding-linux-s390x-gnu@0.150.0': + resolution: {integrity: sha512-7n7ZxcbRWDFaTdyj8M8p0O9OfzoMKm8O6syBAIgcSutbOALq0Bb9G52Me+XH0anMLZV+NgXc726gqgG2q39vcQ==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + libc: [glibc] - '@opentelemetry/sdk-trace-base@2.2.0': - resolution: {integrity: sha512-xWQgL0Bmctsalg6PaXExmzdedSp3gyKV8mQBwK/j9VGdCDu2fmXIb2gAehBKbkXCpJ4HPkgv3QfoJWRT4dHWbw==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': '>=1.3.0 <1.10.0' + '@oxc-parser/binding-linux-x64-gnu@0.150.0': + resolution: {integrity: sha512-Vx0GSA9ZCRTUiczoEQnIIyXkMvtEY8uc6IiwLQtMe5ci2sXPqjrry0Ek5fsPP1k2kCzkML3ow9UOOEgnEDi7Bw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [glibc] - '@opentelemetry/semantic-conventions@1.38.0': - resolution: {integrity: sha512-kocjix+/sSggfJhwXqClZ3i9Y/MI0fp7b+g7kCRm6psy2dsf8uApTRclwG18h8Avm7C9+fnt+O36PspJ/OzoWg==} - engines: {node: '>=14'} + '@oxc-parser/binding-linux-x64-musl@0.150.0': + resolution: {integrity: sha512-ii4/9m3viDLssMnfXU7/Pni/3nYplApuGayceX4qsVGaqqQJCx3tHIH9M/HWIeSty5i8LjS21zPYT6lVIkwLxw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + libc: [musl] - '@opentelemetry/sql-common@0.41.2': - resolution: {integrity: sha512-4mhWm3Z8z+i508zQJ7r6Xi7y4mmoJpdvH0fZPFRkWrdp5fq7hhZ2HhYokEOLkfqSMgPR4Z9EyB3DBkbKGOqZiQ==} - engines: {node: ^18.19.0 || >=20.6.0} - peerDependencies: - '@opentelemetry/api': ^1.1.0 + '@oxc-parser/binding-openharmony-arm64@0.150.0': + resolution: {integrity: sha512-ZtoxX5rez36ZWkwtiEhjkCPnlTPoQ2I7lIL0IYZ1yjxMYohbvoOjBmUIZzrf9W/HouONq0omIfTeCWEY+R380w==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] - '@oxc-project/runtime@0.92.0': - resolution: {integrity: sha512-Z7x2dZOmznihvdvCvLKMl+nswtOSVxS2H2ocar+U9xx6iMfTp0VGIrX6a4xB1v80IwOPC7dT1LXIJrY70Xu3Jw==} + '@oxc-parser/binding-win32-arm64-msvc@0.150.0': + resolution: {integrity: sha512-VqeRb5JX/bKYBrff7TUDvJyKY0914UzuCkuXIGxJS4FUmvMNfqkCbc7Sq90iMz9DlmAtlggwaBYQ9eg3h3ltiw==} engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] - '@oxc-project/runtime@0.98.0': - resolution: {integrity: sha512-F0ldlBv2orG2YqNL0w77deq9yCaO4zEHbanGnW/jaJxGBR8ImekvZb8x42zAHvdzr8J76psibijvHtXfSjbEIQ==} + '@oxc-parser/binding-win32-ia32-msvc@0.150.0': + resolution: {integrity: sha512-EPqJfeZ4Pgg2BJSsCV8GozxV0FDltRzpVtGVa1r2noJu1iu+opOw3gtBWXwIo9odCT/MdFfyHxdy0/CRqs3OqA==} engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ia32] + os: [win32] - '@oxc-project/types@0.93.0': - resolution: {integrity: sha512-yNtwmWZIBtJsMr5TEfoZFDxIWV6OdScOpza/f5YxbqUMJk+j6QX3Cf3jgZShGEFYWQJ5j9mJ6jM0tZHu2J9Yrg==} + '@oxc-parser/binding-win32-x64-msvc@0.150.0': + resolution: {integrity: sha512-n5YMzbqwPQqozbkrexi0lNZrUz5cnPHalYpFWe6Dau7AmKIWNo+y24IwzDuZEQtEdUHuKhXmMMih/MPjOI+CMw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] - '@oxc-project/types@0.98.0': - resolution: {integrity: sha512-Vzmd6FsqVuz5HQVcRC/hrx7Ujo3WEVeQP7C2UNP5uy1hUY4SQvMB+93jxkI1KRHz9a/6cni3glPOtvteN+zpsw==} + '@oxc-project/types@0.150.0': + resolution: {integrity: sha512-rDS5/31E9HfPl/CIzGrn0DOlvBbXFseQ5URJ9sYMfstbKLD/c6Gm9vmRzRGDdAXyOIL4zmO37lc9RIwYqVruZw==} - '@oxc-resolver/binding-android-arm-eabi@11.13.2': - resolution: {integrity: sha512-vWd1NEaclg/t2DtEmYzRRBNQOueMI8tixw/fSNZ9XETXLRJiAjQMYpYeflQdRASloGze6ZelHE/wIBNt4S+pkw==} + '@oxc-resolver/binding-android-arm-eabi@11.24.2': + resolution: {integrity: sha512-y09e0L0SRI2OA2tUIrjBgoV3eH5hvUKXNkJqXmNo5V2WxIjyC7I7aJfRLMEVpA8yi95f90gFDvO0VMgrDw+vwA==} cpu: [arm] os: [android] - '@oxc-resolver/binding-android-arm64@11.13.2': - resolution: {integrity: sha512-jxZrYcxgpI6IuQpguQVAQNrZfUyiYfMVqR4pKVU3PRLCM7AsfXNKp0TIgcvp+l6dYVdoZ1MMMMa5Ayjd09rNOw==} + '@oxc-resolver/binding-android-arm64@11.24.2': + resolution: {integrity: sha512-cl4icWaZFnLdg8m6qtnh5rBMuGbxc/ptStFHLeCNwr+2cZjkjNwQu/jYRS0CHlnPecOJMpuS5M6/BH+0J/YkEg==} cpu: [arm64] os: [android] - '@oxc-resolver/binding-darwin-arm64@11.13.2': - resolution: {integrity: sha512-RDS3HUe1FvgjNS1xfBUqiEJ8938Zb5r7iKABwxEblp3K4ufZZNAtoaHjdUH2TJ0THDmuf0OxxVUO/Y+4Ep4QfQ==} + '@oxc-resolver/binding-darwin-arm64@11.24.2': + resolution: {integrity: sha512-At29QEMF6HajbQvgY8K6OXnHD1x9rad74xBEfmCB6ZqCGsdq75aK7tOYcTbOanMy8qdIBrfL3SMr3p/lfSlb9w==} cpu: [arm64] os: [darwin] - '@oxc-resolver/binding-darwin-x64@11.13.2': - resolution: {integrity: sha512-tDcyWtkUzkt6auJLP2dOjL84BxqHkKW4mz2lNRIGPTq7b+HBraB+m8RdRH6BgqTvbnNECOxR3XAMaKBKC8J51g==} + '@oxc-resolver/binding-darwin-x64@11.24.2': + resolution: {integrity: sha512-A5Kqr1EUj4oIL5CF4WRssq/o5P0Y11cwoFouMRmQ7YnC/A8V93nv1nb7aSU8HwcgmXropjLNkVTl4MN87cu28Q==} cpu: [x64] os: [darwin] - '@oxc-resolver/binding-freebsd-x64@11.13.2': - resolution: {integrity: sha512-fpaeN8Q0kWvKns9uSMg6CcKo7cdgmWt6J91stPf8sdM+EKXzZ0YcRnWWyWF8SM16QcLUPCy5Iwt5Z8aYBGaZYA==} + '@oxc-resolver/binding-freebsd-x64@11.24.2': + resolution: {integrity: sha512-R5xkRBRRz7ceH/P5Jrc6G7FmdUdgpLYyESFAUDVTNQ9K0sGPxcp4ljiwEwEqsvNcQ4sYbMRrWcHHBCu7ksAJVw==} cpu: [x64] os: [freebsd] - '@oxc-resolver/binding-linux-arm-gnueabihf@11.13.2': - resolution: {integrity: sha512-idBgJU5AvSsGOeaIWiFBKbNBjpuduHsJmrG4CBbEUNW/Ykx+ISzcuj1PHayiYX6R9stVsRhj3d2PyymfC5KWRg==} + '@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2': + resolution: {integrity: sha512-k/RuYL4L/R58IBn3wT5ma3Wh4k62bp1eYCFRWCmMsasUOqL+H6sW0VGFadEzKWXFFlz+2uIMoeMk9ySSZJHgbg==} cpu: [arm] os: [linux] - '@oxc-resolver/binding-linux-arm-musleabihf@11.13.2': - resolution: {integrity: sha512-BlBvQUhvvIM/7s96KlKhMk0duR2sj8T7Hyii46/5QnwfN/pHwobvOL5czZ6/SKrHNB/F/qDY4hGsBuB1y7xgTg==} + '@oxc-resolver/binding-linux-arm-musleabihf@11.24.2': + resolution: {integrity: sha512-bnHAak3ujYfH5pKk4NieFNbvYvernfoQDgwLddbZ3OtMYrem87/qjlA+u+aKG0oZcqSLGCful/6/CEA+aeAgaA==} cpu: [arm] os: [linux] - '@oxc-resolver/binding-linux-arm64-gnu@11.13.2': - resolution: {integrity: sha512-lUmDTmYOGpbIK+FBfZ0ySaQTo7g1Ia/WnDnQR2wi/0AtehZIg/ZZIgiT/fD0iRvKEKma612/0PVo8dXdAKaAGA==} + '@oxc-resolver/binding-linux-arm64-gnu@11.24.2': + resolution: {integrity: sha512-vDT3KHgzYp47gmtNOqL2VNhCyl5Zv643eyxm//A68J8DeUGXrvD1pZFiaT4jSfe+RInfnn1R2yVHye4enx6RnA==} cpu: [arm64] os: [linux] + libc: [glibc] - '@oxc-resolver/binding-linux-arm64-musl@11.13.2': - resolution: {integrity: sha512-dkGzOxo+I9lA4Er6qzFgkFevl3JvwyI9i0T/PkOJHva04rb1p9dz8GPogTO9uMK4lrwLWzm/piAu+tHYC7v7+w==} + '@oxc-resolver/binding-linux-arm64-musl@11.24.2': + resolution: {integrity: sha512-+kMlQvbzfyEYtu5FcjE4p+ttBLpKW4d/AsAsuE69BxV6V4twZJeIQZFfD8gh/wqglY0MkPSezWXQH0jBV13MUw==} cpu: [arm64] os: [linux] + libc: [musl] - '@oxc-resolver/binding-linux-ppc64-gnu@11.13.2': - resolution: {integrity: sha512-53kWsjLkVFnoSA7COdps38pBssN48zI8LfsOvupsmQ0/4VeMYb+0Ao9O6r52PtmFZsGB3S1Qjqbjl/Pswj1a3g==} + '@oxc-resolver/binding-linux-ppc64-gnu@11.24.2': + resolution: {integrity: sha512-shjfMhmZ3gq9fv/w7bi3PnZlgOPG+2QAOFf0BJF0EgBSIGZ6PMLN2zbGEblTUYB/NKVDRyYhE2ff3dJ1QqNPkA==} cpu: [ppc64] os: [linux] + libc: [glibc] - '@oxc-resolver/binding-linux-riscv64-gnu@11.13.2': - resolution: {integrity: sha512-MfxN6DMpvmdCbGlheJ+ihy11oTcipqDfcEIQV9ah3FGXBRCZtBOHJpQDk8qI2Y+nCXVr3Nln7OSsOzoC4+rSYQ==} + '@oxc-resolver/binding-linux-riscv64-gnu@11.24.2': + resolution: {integrity: sha512-zGelwFR5oRo+b69k8Lrzun86DyUHzfKN6cnjbR9l7Z7NIRznOE/2ZvPa1IUKqAL2PzAXOdwkfVqNvO1H2RlpAw==} cpu: [riscv64] os: [linux] + libc: [glibc] - '@oxc-resolver/binding-linux-riscv64-musl@11.13.2': - resolution: {integrity: sha512-WXrm4YiRU0ijqb72WHSjmfYaQZ7t6/kkQrFc4JtU+pUE4DZA/DEdxOuQEd4Q43VqmLvICTJWSaZMlCGQ4PSRUg==} + '@oxc-resolver/binding-linux-riscv64-musl@11.24.2': + resolution: {integrity: sha512-qxZ1SWCXJY0eyhAlP6Lmo9F2Nrtx7EkYj9oCgL8apDPCwXwCEDA2U697bbT81JIc2IrVjxO4KX6WU2N+oN9Z4w==} cpu: [riscv64] os: [linux] + libc: [musl] - '@oxc-resolver/binding-linux-s390x-gnu@11.13.2': - resolution: {integrity: sha512-4pISWIlOFRUhWyvGCB3XUhtcwyvwGGhlXhHz7IXCXuGufaQtvR05trvw8U1ZnaPhsdPBkRhOMIedX11ayi5uXw==} + '@oxc-resolver/binding-linux-s390x-gnu@11.24.2': + resolution: {integrity: sha512-sGCecF3cx2DFlH4t/z7ApnOnXqN48p5p5mlHDEnHTAukQa2P+qMVE4CwyWE9W+q/m3QJ7kKfGrIjax31f44oFQ==} cpu: [s390x] os: [linux] + libc: [glibc] - '@oxc-resolver/binding-linux-x64-gnu@11.13.2': - resolution: {integrity: sha512-DVo6jS8n73yNAmCsUOOk2vBeC60j2RauDXQM8p7RDl0afsEaA2le22vD8tky7iNoM5tsxfBmE4sOJXEKgpwWRw==} + '@oxc-resolver/binding-linux-x64-gnu@11.24.2': + resolution: {integrity: sha512-k/VlMMcSzMlahb3/fENM4rTlsJ0s3fFROA0KXPBmKggqmTSaE383sl8F3KCOXPLmVsYfW6hCitMhXCEtNeZxxg==} cpu: [x64] os: [linux] + libc: [glibc] - '@oxc-resolver/binding-linux-x64-musl@11.13.2': - resolution: {integrity: sha512-6WqrE+hQBFP35KdwQjWcZpldbTq6yJmuTVThISu+rY3+j6MaDp2ciLHTr1X68r2H/7ocOIl4k3NnOVIzeRJE3w==} + '@oxc-resolver/binding-linux-x64-musl@11.24.2': + resolution: {integrity: sha512-8hbnZyNi97b/8wapYaIF9+t9GmZKBW2vunaOc3h9HGJptH7b7XpvZqOTBSm/MpTjr7H497BlgOaSfLUdhmy2bw==} cpu: [x64] os: [linux] + libc: [musl] - '@oxc-resolver/binding-wasm32-wasi@11.13.2': - resolution: {integrity: sha512-YpxvQmP2D+mNUkLQZbBjGz20g/pY8XoOBdPPoWMl9X68liFFjXxkPQTrZxWw4zzG/UkTM5z6dPRTyTePRsMcjw==} + '@oxc-resolver/binding-openharmony-arm64@11.24.2': + resolution: {integrity: sha512-MvyGik3a6pVgZ0t/kWlbmFxFLmXQJwgLsY2eYFHLpy0wGwRbfzeIGgDwQ3kXqE30z+kSXennRkCrT7TUvkptNg==} + cpu: [arm64] + os: [openharmony] + + '@oxc-resolver/binding-wasm32-wasi@11.24.2': + resolution: {integrity: sha512-vHcssMPwO08RTvj/c0iOBz90attxyG3wQJ0dTcyEQK43LRpcdLWZlV5feBhv6Isn6ahbQIzHbCgfa81+RiML0Q==} engines: {node: '>=14.0.0'} cpu: [wasm32] - '@oxc-resolver/binding-win32-arm64-msvc@11.13.2': - resolution: {integrity: sha512-1SKBw6KcCmvPBdEw1/Qdpv6eSDf23lCXTWz9VxTe6QUQ/1wR+HZR2uS4q6C8W6jnIswMTQbxpTvVwdRXl+ufeA==} + '@oxc-resolver/binding-win32-arm64-msvc@11.24.2': + resolution: {integrity: sha512-uokJqro2iBqkFvJdKQLP7d8/BUmFwESQFVmIJUQKj1Xn1a/LysJoe1vmeECLF5b3jsV8CAL5sEMJXX6SdK9Nhg==} cpu: [arm64] os: [win32] - '@oxc-resolver/binding-win32-ia32-msvc@11.13.2': - resolution: {integrity: sha512-KEVV7wggDucxRn3vvyHnmTCPXoCT7vWpH18UVLTygibHJvNRP2zl5lBaQcCIdIaYYZjKt1aGI/yZqxZvHoiCdg==} - cpu: [ia32] - os: [win32] - - '@oxc-resolver/binding-win32-x64-msvc@11.13.2': - resolution: {integrity: sha512-6AAdN9v/wO5c3td1yidgNLKYlzuNgfOtEqBq60WE469bJWR7gHgG/S5aLR2pH6/gyPLs9UXtItxi934D+0Estg==} + '@oxc-resolver/binding-win32-x64-msvc@11.24.2': + resolution: {integrity: sha512-UqGPmo56KDfLlfXFAFIrNflHT8tFxWGEivWg3Zeyp4Uy2NlKN1FGPr6/BxcLGG3+kZ6Wp14g5Uj+n71boqZfiw==} cpu: [x64] os: [win32] '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - '@poppinss/colors@4.1.5': - resolution: {integrity: sha512-FvdDqtcRCtz6hThExcFOgW0cWX+xwSMWcRuQe5ZEb2m7cVQOAVZOIMt+/v9RxGiD9/OY16qJBXK4CVKWAPalBw==} - - '@poppinss/dumper@0.6.5': - resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} - - '@poppinss/exception@1.2.2': - resolution: {integrity: sha512-m7bpKCD4QMlFCjA/nKTs23fuvoVFoA83brRKmObCUNmi/9tVu8Ve3w4YQAnJu4q3Tjf5fr685HYIC/IA2zHRSg==} - - '@prisma/instrumentation@6.15.0': - resolution: {integrity: sha512-6TXaH6OmDkMOQvOxwLZ8XS51hU2v4A3vmE2pSijCIiGRJYyNeMcL6nMHQMyYdZRD8wl7LF3Wzc+AMPMV/9Oo7A==} - peerDependencies: - '@opentelemetry/api': ^1.8 - - '@radix-ui/number@1.1.1': - resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - - '@radix-ui/primitive@1.1.3': - resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - - '@radix-ui/react-accessible-icon@1.1.7': - resolution: {integrity: sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==} - peerDependencies: - '@types/react': '*' - '@types/react-dom': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - '@types/react-dom': - optional: true + '@poppinss/colors@4.1.6': + resolution: {integrity: sha512-H9xkIdFswbS8n1d6vmRd8+c10t2Qe+rZITbbDHHkQixH5+2x1FDGmi/0K+WgWiqQFKPSlIYB7jlH6Kpfn6Fleg==} - '@radix-ui/react-accordion@1.2.12': - resolution: {integrity: sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==} + '@poppinss/dumper@0.6.5': + resolution: {integrity: sha512-NBdYIb90J7LfOI32dOewKI1r7wnkiH6m920puQ3qHUeZkxNkQiFnXVWoE6YtFSv6QOiPPf7ys6i+HWWecDz7sw==} + + '@poppinss/exception@1.2.3': + resolution: {integrity: sha512-dCED+QRChTVatE9ibtoaxc+WkdzOSjYTKi/+uacHWIsfodVfpsueo3+DKpgU5Px8qXjgmXkSvhXvSCz3fnP9lw==} + + '@radix-ui/number@1.1.3': + resolution: {integrity: sha512-Road2bidD0uu/1BGDOWNdPI06g0lIRy6IF9GZcIrDK2KGItfor8IQwQa+yM2ERgHM1MmHxaxpTzk0/Jp42lNfA==} + + '@radix-ui/primitive@1.1.7': + resolution: {integrity: sha512-rqWnm76nYT8HoNNqEjpgJ7Pw/DrBj5iBTrmEPo6HTX5+VJyBNOqTdv4g89G63HuR5g0AaENoAcH7Is5fF2kZ8Q==} + + '@radix-ui/react-accessible-icon@1.1.15': + resolution: {integrity: sha512-WTQwcAvQf5sOcuUyi90lKPbhwcvQ+j55cjrSmeaN+L2vKU3DooOvlKw2MDeiJ5IkV5N905KW0/fGojKOBhD11A==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2161,8 +2237,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-alert-dialog@1.1.15': - resolution: {integrity: sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==} + '@radix-ui/react-accordion@1.2.20': + resolution: {integrity: sha512-jDhG9FvAEnlhnjrsINbNXcUa4G+L1KqSkJSunkbKEzFRcAb52jvM0PjPxPRvhe1HNc5F5yc0yzzWeeqlH4yBIg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2174,8 +2250,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-arrow@1.1.7': - resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} + '@radix-ui/react-alert-dialog@1.1.23': + resolution: {integrity: sha512-VAYOiQRqj3GPpYJE0I9J+X8Ip05cyVlNdKOFeiGS2Ou1HHGfpl0BxOyZm6nmVDyU+W+NF3/XLzmjHmVGydhwgA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2187,8 +2263,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-aspect-ratio@1.1.7': - resolution: {integrity: sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==} + '@radix-ui/react-arrow@1.1.15': + resolution: {integrity: sha512-v4zggRcjadnI+ClKDuijlQEW4tw3NoaeHc/PwpKnLoLLKNUG4InLegkstooLcRIUWCs+8L22dGURCVuFfOKfnA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2200,8 +2276,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-avatar@1.1.10': - resolution: {integrity: sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==} + '@radix-ui/react-aspect-ratio@1.1.15': + resolution: {integrity: sha512-fy+dyVR+90nelK8rqIznFlxzx7uPcGbhxH8Nfr2bHb4UfSe+e3hklOC0luK0hDwVwnRX7xTRySpsrQVeW+/oNQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2213,8 +2289,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-avatar@1.1.11': - resolution: {integrity: sha512-0Qk603AHGV28BOBO34p7IgD5m+V5Sg/YovfayABkoDDBM5d3NCx0Mp4gGrjzLGes1jV5eNOE1r3itqOR33VC6Q==} + '@radix-ui/react-avatar@1.2.6': + resolution: {integrity: sha512-4ULOTJ/mqy2hT9GlWa/MFHxHSvH3nJzHnZM1waNsc5Bonv7i70aNenghXmD97S6OJ81ekXONGGt4nT1r0PfEdA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2226,8 +2302,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-checkbox@1.3.3': - resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} + '@radix-ui/react-checkbox@1.3.11': + resolution: {integrity: sha512-Gnptr9pDDQxD3hgq2dtPbtrp/c2qH1mBwIzw3X/ivrMb2e1t0jMTi606fVEqFPaQR1ggXIVQWKj3P2WW9v7zGQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2239,8 +2315,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-collapsible@1.1.12': - resolution: {integrity: sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==} + '@radix-ui/react-collapsible@1.1.20': + resolution: {integrity: sha512-mcGesGplBnzN2sbvJETzpCNfSMyPnb29q1GRLU+Ib7bJrpIG2ywmRoh2V5VbA2uNvKikKUlVbAPks7JDjz4A8Q==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2252,8 +2328,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-collection@1.1.7': - resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} + '@radix-ui/react-collection@1.1.15': + resolution: {integrity: sha512-9W+B9NPF0NaaPh/1NJd3+KqsnlLqU9H7T2rvww+fp+T/evVXdNAyYcnfRQZFOjkR1ajQp3yORlqnI8soawLvNA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2265,8 +2341,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-compose-refs@1.1.2': - resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} + '@radix-ui/react-compose-refs@1.1.5': + resolution: {integrity: sha512-+48PbAAbq3didjJxa+OaWY2ZwgAKsNiRGyeHKszblZMQ+kcpd9pAaT11cMkGEie0vsOi3QdeTE6d5Fe3Gn61kA==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2274,8 +2350,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-context-menu@2.2.16': - resolution: {integrity: sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==} + '@radix-ui/react-context-menu@2.3.7': + resolution: {integrity: sha512-CtXP35dxaB5T3zXSd+E3uHe/QpXcpYnZmxp6OaIbfthtfW4wyb77M23BG+bwIJDtsMwEP/YssdsmNyZu7jhWew==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2287,17 +2363,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-context@1.1.2': - resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-context@1.1.3': - resolution: {integrity: sha512-ieIFACdMpYfMEjF0rEf5KLvfVyIkOz6PDGyNnP+u+4xQ6jny3VCgA4OgXOwNx2aUkxn8zx9fiVcM8CfFYv9Lxw==} + '@radix-ui/react-context@1.2.2': + resolution: {integrity: sha512-RHCUGwKHDr0hDGg4X7ma4JG4/+12qxw8rkh5QKdDldlCvtja6nUx1Ef/8HVrJze81lEsgLQlqjzjGNHantgnQA==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2305,8 +2372,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-dialog@1.1.15': - resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} + '@radix-ui/react-dialog@1.1.23': + resolution: {integrity: sha512-Ksw4WeROkO4rC9k/onilX/Ao2Cr1ku1unMNH+XSCcP4jSXYu7HDsg9n4ojMjVb22XpYjAQ9qfrFlVbru1vXDUA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2318,30 +2385,17 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-direction@1.1.1': - resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-dismissable-layer@1.1.11': - resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} + '@radix-ui/react-direction@1.1.4': + resolution: {integrity: sha512-5pzg4FGQNpExhnhT2zlrP1wZFaYCd1K0nYWoFAdcYoYK868IEigqMX3B3f8yIoRlAhAeDWciLI6ZdCKHF9P4Vg==} peerDependencies: '@types/react': '*' - '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-dropdown-menu@2.1.16': - resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} + '@radix-ui/react-dismissable-layer@1.1.19': + resolution: {integrity: sha512-8g4pfOL9HoKKLWGiypT+dphVqjFfmcXO5GBnhsG6zI+lxAx/8feQpr+1LSN8Re3hiZ+XkLNS4O9ztK11/LzQ6w==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2353,17 +2407,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-focus-guards@1.1.3': - resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-focus-scope@1.1.7': - resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} + '@radix-ui/react-dropdown-menu@2.1.24': + resolution: {integrity: sha512-geq8l2rJkxvkXsT9RMgtUE3P8pITFpTsvYpbySi1IH4fZEABD/Gp85myayFgxk0ktljGMJnCbeFkyTusvSvv7g==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2375,21 +2420,17 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-form@0.1.8': - resolution: {integrity: sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==} + '@radix-ui/react-focus-guards@1.1.6': + resolution: {integrity: sha512-RNOJjfZMTyBM6xYmV3IVGXkPjIhcBAuv48POevAXwrGJhkWZ9p1rFoIS1JFooPuT193AZmRsCPhpoVJxx6OPoQ==} peerDependencies: '@types/react': '*' - '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-hover-card@1.1.15': - resolution: {integrity: sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==} + '@radix-ui/react-focus-scope@1.1.16': + resolution: {integrity: sha512-wmRZ2WWLvmt6KHy2rNPOdPUjwq5xOHY02+m+udwJTn0aNIox/rkskAvJTyTLGhPK6KgrUjlJUJpgmx/+wFiFIQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2401,17 +2442,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-id@1.1.1': - resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-label@2.1.7': - resolution: {integrity: sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==} + '@radix-ui/react-form@0.1.16': + resolution: {integrity: sha512-Q4TLEn2A7TAypxwmd6R9EwrlXDvkfYSDMrq9/887AXAGh+G1rH+kYJKSTv+Si9Y0JPKTwKYv6PviAJosysNimA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2423,8 +2455,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-label@2.1.8': - resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} + '@radix-ui/react-hover-card@1.1.23': + resolution: {integrity: sha512-H8qONfZd3ltrU3+jHCIgITbWo6e1iTKvP9DHdrvYbX48ooRM5FjEDTn16AMwdfuOGkWdZEhpl3PLL/Wk/AnHDQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2436,21 +2468,17 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-menu@2.1.16': - resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} + '@radix-ui/react-id@1.1.4': + resolution: {integrity: sha512-TMQp2llA+RYn7JcjnrMnz7wN4pcVttPZnRZo52PLQsoLVKzNlVwUeHmfePgTgRluXFvlD3GD5g5MOVVTJCO0qA==} peerDependencies: '@types/react': '*' - '@types/react-dom': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc peerDependenciesMeta: '@types/react': optional: true - '@types/react-dom': - optional: true - '@radix-ui/react-menubar@1.1.16': - resolution: {integrity: sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==} + '@radix-ui/react-label@2.1.15': + resolution: {integrity: sha512-o/rdYEwZTTo5tjknnPeyQFU45kUC4i/XyeDPP+HGyi6XqpOP6Zf5Ya5vh/Yfe9Id5JiuWnnAx2XqIeD3UYZt0g==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2462,8 +2490,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-navigation-menu@1.2.14': - resolution: {integrity: sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==} + '@radix-ui/react-menu@2.1.24': + resolution: {integrity: sha512-uW7RVuU6Lp/ZtfeY4b3kL32zccgEWvPv1+cf17ubYzHa9cL8AHokmk36cG/XEiH/smbQvumnieXX9j/e9RqJWA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2475,8 +2503,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-one-time-password-field@0.1.8': - resolution: {integrity: sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==} + '@radix-ui/react-menubar@1.1.24': + resolution: {integrity: sha512-eeVs0vf7cuqXaM0qLQCPcufImiJNVBXdJDLu7ZGYl2732UH23Qat/foNGrr6vYV3/DdTsBqASoggUFgH14OcZA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2488,8 +2516,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-password-toggle-field@0.1.3': - resolution: {integrity: sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==} + '@radix-ui/react-navigation-menu@1.2.22': + resolution: {integrity: sha512-ou7iLEJ+yrhQndkkA4U21XIdS/CS45F4iXIkTZcb6/Ne9EMsOuDudVmCwmDnfFZZ+y1FZqXRNSIgBy+YMvZVZg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2501,8 +2529,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-popover@1.1.15': - resolution: {integrity: sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==} + '@radix-ui/react-one-time-password-field@0.1.16': + resolution: {integrity: sha512-Tj9P6ntAJEw52oq/F0AGknXR4XncxEt7XU47O3xJQOiWfLzEy3d9gtgKfvjSzGxzHkfL+VzvxGu2KTFsloJqXw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2514,8 +2542,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-popper@1.2.8': - resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} + '@radix-ui/react-password-toggle-field@0.1.11': + resolution: {integrity: sha512-4gvFnmDXu3dgj21CqsufzIameRvlRd4SBqaWhcrlrNhRo0Y5i/49AmRJYe1fdAM3G2VNBbmin4b0D6cdQocwgw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2527,8 +2555,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-portal@1.1.9': - resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} + '@radix-ui/react-popover@1.1.23': + resolution: {integrity: sha512-mw58MrBlyHWFisTOYignD0vf/3gdcgAR+9of1s9G/38CbFiUwH1nCDkc0AUM9IrXFgN5Ue8n45j9WCgyM1sbiQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2540,8 +2568,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-presence@1.1.5': - resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} + '@radix-ui/react-popper@1.3.7': + resolution: {integrity: sha512-UsJrrd7w4wuKKTdvd/DNERVlwSlUcyXzjhyDwBk+3aPOsCjOY6ZSbxuw8E6lZTjjfP8Cpd0J8VVkrYUWyGYXyg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2553,8 +2581,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-primitive@2.1.3': - resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} + '@radix-ui/react-portal@1.1.17': + resolution: {integrity: sha512-vKQLcWypUnwZVvfV7UkGahH2g6ySe8M8R+zYBwPrv5byZ9QAW6cQVvNKo7GgmD+p8aYb6D9JBuvy8/WhOno2wQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2566,8 +2594,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-primitive@2.1.4': - resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} + '@radix-ui/react-presence@1.1.10': + resolution: {integrity: sha512-3wyzCQ6+ubRA+D4uv9m95JYLXxmOHp05qjrkjeA7uKHHtjpPggQzc6DAb0URl7j67oR0K2foO4ip27TiX037Bw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2579,8 +2607,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-progress@1.1.7': - resolution: {integrity: sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==} + '@radix-ui/react-primitive@2.1.10': + resolution: {integrity: sha512-MucOnzh6hR5mid6VpkbglRAMYMjKLqRnGBbjXkzjK52fuQDd1qbkx78a5P40mkcnVXJdEVxm26E9OPAiUq7nBg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2592,8 +2620,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-radio-group@1.3.8': - resolution: {integrity: sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==} + '@radix-ui/react-progress@1.1.16': + resolution: {integrity: sha512-5XnomAsoZZCY+KNTxbIghpGqPruZvKFNlvcAljVAOdDRDsH4/OZQxhtwo5wdtoDM5R6MhJBb2sPnDuRFep3lzg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2605,8 +2633,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-roving-focus@1.1.11': - resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} + '@radix-ui/react-radio-group@1.4.7': + resolution: {integrity: sha512-cgYFEkntCxppHZgtSZ+7vh0wbZQ+IC7PPMw8DSnRG27B6kDd32/Zw0OJt7dGDigCoprMuWHjg2PvUn3PYvPFoQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2618,8 +2646,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-scroll-area@1.2.10': - resolution: {integrity: sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==} + '@radix-ui/react-roving-focus@1.1.19': + resolution: {integrity: sha512-V9jI6hDjT7l3jsCQD9bLNvDLM3tH/gdbOTp7Tefp3hbbgCGQoK7tUvrWiRlcoBHIZ809ElXwNQwVo0B98LuTXQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2631,8 +2659,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-select@2.2.6': - resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} + '@radix-ui/react-scroll-area@1.2.18': + resolution: {integrity: sha512-Zn5Cd171wxsO3Dfg8HaW6RifTb9CYTKQJHs/G4+LN1GfmJpaQMZQyQxMprVPHpaz7QY4l9BxK2JwQuzHsXC8nA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2644,8 +2672,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-separator@1.1.7': - resolution: {integrity: sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==} + '@radix-ui/react-select@2.3.7': + resolution: {integrity: sha512-WFGImkmbzcfxeIwq/+4HvRN0pizBwbwQUED4I13ezQsDdfl38ZntN6TmR8XaSzPBqoCToe8rF75j6NPNDSzhbg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2657,8 +2685,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-separator@1.1.8': - resolution: {integrity: sha512-sDvqVY4itsKwwSMEe0jtKgfTh+72Sy3gPmQpjqcQneqQ4PFmr/1I0YA+2/puilhggCe2gJcx5EBAYFkWkdpa5g==} + '@radix-ui/react-separator@1.1.15': + resolution: {integrity: sha512-jOLO4lssEzWpoDu7G+Ze4VjwMRUBt291pnZD0gmalREZipnTX3wadQo7Fy48GCTfe14/YRN6rw/rOJqrE85Wxw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2670,8 +2698,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-slider@1.3.6': - resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} + '@radix-ui/react-slider@1.4.7': + resolution: {integrity: sha512-mTSLf1GC/C0moWjTbvCM6Qn/gBjvlFt1azuWF2v7MN5C3Zq2U2J2lN3ZEYkpujuOU5Ro7A28wkviSxaKnG0BYg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2683,17 +2711,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-slot@1.2.3': - resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} - peerDependencies: - '@types/react': '*' - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true - - '@radix-ui/react-slot@1.2.4': - resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} + '@radix-ui/react-slot@1.3.3': + resolution: {integrity: sha512-qx7oqnYbxnK9kYI9m317qmFmEgo6ywqWvbTogdj7cL9p3/yx4M48p7Rnw5z3H890cL/ow/EeWJsuTykeZVXP5Q==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2701,8 +2720,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-switch@1.2.6': - resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} + '@radix-ui/react-switch@1.3.7': + resolution: {integrity: sha512-48tB/4dn2UVLBCYhTu9AuR63IHl73l/qLbLgxd86noTUor4/K4LFDAcYjK+isP5313qxaFpjPVogE7+Y0/V3Kw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2714,8 +2733,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-tabs@1.1.13': - resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} + '@radix-ui/react-tabs@1.1.21': + resolution: {integrity: sha512-UKxJlZid7FVtsk/WTxj4i4uSEgj2Au+KBbS7SQyTlzMhhn+86Cz3tISZdTa87bfEfcuvZezf2ZsxD4xuEKtkog==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2727,8 +2746,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-toast@1.2.15': - resolution: {integrity: sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==} + '@radix-ui/react-toast@1.2.23': + resolution: {integrity: sha512-ofhyAsYaocRGOs/n0XWdUOSVzEAG6BfrMVM8z0c0kLEWY38w/0WuMFPTJP/HVaZPYkMvHZoKIIhNcjbTCBILPg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2740,8 +2759,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-toggle-group@1.1.11': - resolution: {integrity: sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==} + '@radix-ui/react-toggle-group@1.1.19': + resolution: {integrity: sha512-OtnwuSVjd1Ofi+AdnvhsjQdyuhCDwYs1w9RyB5BN/OavXOVQo42SYqQjwUnbPnaiPFBpQ9aX70dWeee+v2oBLA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2753,8 +2772,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-toggle@1.1.10': - resolution: {integrity: sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==} + '@radix-ui/react-toggle@1.1.18': + resolution: {integrity: sha512-7lonPlKfSacd20GlOBx2ltuVKz9oqWYZz+oMQyOltw6t1y2nyftj2ZmwwUHYn49kqfDWcp8dNZm5NgV+5Z+mug==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2766,8 +2785,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-toolbar@1.1.11': - resolution: {integrity: sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==} + '@radix-ui/react-toolbar@1.1.19': + resolution: {integrity: sha512-Ph0IvtYw4VB12ZnZg+YtrGs8yJQsnizwo/zu0R4Y/nWugtJzA7Pg1eWeuDR9+LSqn+xjamss+UOSOJJJ4gx8jw==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2779,8 +2798,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-tooltip@1.2.8': - resolution: {integrity: sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==} + '@radix-ui/react-tooltip@1.2.16': + resolution: {integrity: sha512-6EamKFRRnlpdadndbZ6LMwycfwkwPte1B42hs6QA0gYhjaOKqW4PZ4pjaW9UrlDX5eVt/OjncE7BFTPL5nmZhg==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2792,8 +2811,8 @@ packages: '@types/react-dom': optional: true - '@radix-ui/react-use-callback-ref@1.1.1': - resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} + '@radix-ui/react-use-callback-ref@1.1.4': + resolution: {integrity: sha512-R6OUY2e2fA6Yn6s+VSx5KBV6Nx8LQEhu+cz7LCej18rQ1HLyg9PSC9jP/ZNx0o6FAIK9c0F1kHylzSxKsdlkrQ==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2801,8 +2820,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-controllable-state@1.2.2': - resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} + '@radix-ui/react-use-controllable-state@1.2.6': + resolution: {integrity: sha512-uEQJGT97ZA/TgP/Hydw47lHu+/vQj6z/0jA+WeTbK1o9Rx45GImjpD0tc3W5ad3D6XTSR6e1yEO0FvGq6WQfVQ==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2810,8 +2829,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-effect-event@0.0.2': - resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} + '@radix-ui/react-use-effect-event@0.0.5': + resolution: {integrity: sha512-7cshFL8HGS/7HEiHH+9kL9HBwp2sa9yX18Knwek6KYWmXwM7pegMgta2AXMQKI+rq3JnfSj9x8wYqFMTdG1Jgg==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2819,8 +2838,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-escape-keydown@1.1.1': - resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} + '@radix-ui/react-use-escape-keydown@1.1.5': + resolution: {integrity: sha512-ge3ipobwSXTj4JyVtswQ7qZj0ZHdtbGuOno/LrgAAeSxtsJ6Vs4Gz5IkPH2bmqpjcLUFoqGhA/mueuIf63UXlA==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2828,8 +2847,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-is-hydrated@0.1.0': - resolution: {integrity: sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==} + '@radix-ui/react-use-is-hydrated@0.1.3': + resolution: {integrity: sha512-umO/aJ+82CpOnhDZUTbILCQf7kU/g0iv+oGs/Q8jw7IkhWBzaEP4sA268PhFAJTFetbwp3ICc6ktpI4TqtxcIw==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2837,8 +2856,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-layout-effect@1.1.1': - resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} + '@radix-ui/react-use-layout-effect@1.1.4': + resolution: {integrity: sha512-K20DkRkUwDnxEYMBPcg3Y6voLkEy5p5QQmszZgLngKKiC7dzBR/aEuK3w1qlx2JWDUNH6FluahYdgR3BP+QbYw==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2846,8 +2865,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-previous@1.1.1': - resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} + '@radix-ui/react-use-previous@1.1.4': + resolution: {integrity: sha512-XoSLhbRbqxFtgJoi2fNHA3C6pDlY34x508vUpUGoFZfvePfHXHbE1lC4FYFMnJWgiCRroSTw6fOsXQoVS9RwZg==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2855,8 +2874,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-rect@1.1.1': - resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} + '@radix-ui/react-use-rect@1.1.4': + resolution: {integrity: sha512-cSOCh6JlkmfjLyNcLiu2nB4v+nm+dkZ+Q5KHWk/soo4U7ZLiEQFKHK9/YmtBHjfCEaU43IBKQOc4/uJmCaiCTQ==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2864,8 +2883,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-use-size@1.1.1': - resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} + '@radix-ui/react-use-size@1.1.4': + resolution: {integrity: sha512-D3anSY15EJoxrihpsXI6SMrmmonnQtR2ni7arO+Lfdg3O95b9hNXxONk8jA5C8ANdF/h5HMAxejgs8PWJ6rlhw==} peerDependencies: '@types/react': '*' react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc @@ -2873,8 +2892,8 @@ packages: '@types/react': optional: true - '@radix-ui/react-visually-hidden@1.2.3': - resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} + '@radix-ui/react-visually-hidden@1.2.11': + resolution: {integrity: sha512-NFS86RYYZb4/exihaESBGOpMJFz8MGLAfu3mOBSGByVnVPC9JPASfYubxd/8KbkQK0sYAv8lVQDEQukDX/qXvQ==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -2886,171 +2905,18 @@ packages: '@types/react-dom': optional: true - '@radix-ui/rect@1.1.1': - resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - - '@react-email/body@0.2.0': - resolution: {integrity: sha512-9GCWmVmKUAoRfloboCd+RKm6X17xn7eGL7HnpAZUnjBXBilWCxsKnLMTC/ixSHDKS/A/057M1Tx6ZUXd89sVBw==} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/button@0.2.0': - resolution: {integrity: sha512-8i+v6cMxr2emz4ihCrRiYJPp2/sdYsNNsBzXStlcA+/B9Umpm5Jj3WJKYpgTPM+aeyiqlG/MMI1AucnBm4f1oQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/code-block@0.2.0': - resolution: {integrity: sha512-eIrPW9PIFgDopQU0e/OPpwCW2QWQDtNZDSsiN4sJO8KdMnWWnXJicnRfzrit5rHwFo+Y98i+w/Y5ScnBAFr1dQ==} - engines: {node: '>=22.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/code-inline@0.0.5': - resolution: {integrity: sha512-MmAsOzdJpzsnY2cZoPHFPk6uDO/Ncpb4Kh1hAt9UZc1xOW3fIzpe1Pi9y9p6wwUmpaeeDalJxAxH6/fnTquinA==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/column@0.0.13': - resolution: {integrity: sha512-Lqq17l7ShzJG/d3b1w/+lVO+gp2FM05ZUo/nW0rjxB8xBICXOVv6PqjDnn3FXKssvhO5qAV20lHM6S+spRhEwQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/components@1.0.1': - resolution: {integrity: sha512-HnL0Y/up61sOBQT2cQg9N/kCoW0bP727gDs2MkFWQYELg6+iIHidMDvENXFC0f1ZE6hTB+4t7sszptvTcJWsDA==} - engines: {node: '>=22.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/container@0.0.15': - resolution: {integrity: sha512-Qo2IQo0ru2kZq47REmHW3iXjAQaKu4tpeq/M8m1zHIVwKduL2vYOBQWbC2oDnMtWPmkBjej6XxgtZByxM6cCFg==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/font@0.0.9': - resolution: {integrity: sha512-4zjq23oT9APXkerqeslPH3OZWuh5X4crHK6nx82mVHV2SrLba8+8dPEnWbaACWTNjOCbcLIzaC9unk7Wq2MIXw==} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/head@0.0.12': - resolution: {integrity: sha512-X2Ii6dDFMF+D4niNwMAHbTkeCjlYYnMsd7edXOsi0JByxt9wNyZ9EnhFiBoQdqkE+SMDcu8TlNNttMrf5sJeMA==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/heading@0.0.15': - resolution: {integrity: sha512-xF2GqsvBrp/HbRHWEfOgSfRFX+Q8I5KBEIG5+Lv3Vb2R/NYr0s8A5JhHHGf2pWBMJdbP4B2WHgj/VUrhy8dkIg==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/hr@0.0.11': - resolution: {integrity: sha512-S1gZHVhwOsd1Iad5IFhpfICwNPMGPJidG/Uysy1AwmspyoAP5a4Iw3OWEpINFdgh9MHladbxcLKO2AJO+cA9Lw==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/html@0.0.11': - resolution: {integrity: sha512-qJhbOQy5VW5qzU74AimjAR9FRFQfrMa7dn4gkEXKMB/S9xZN8e1yC1uA9C15jkXI/PzmJ0muDIWmFwatm5/+VA==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/img@0.0.11': - resolution: {integrity: sha512-aGc8Y6U5C3igoMaqAJKsCpkbm1XjguQ09Acd+YcTKwjnC2+0w3yGUJkjWB2vTx4tN8dCqQCXO8FmdJpMfOA9EQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/link@0.0.12': - resolution: {integrity: sha512-vF+xxQk2fGS1CN7UPQDbzvcBGfffr+GjTPNiWM38fhBfsLv6A/YUfaqxWlmL7zLzVmo0K2cvvV9wxlSyNba1aQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/markdown@0.0.17': - resolution: {integrity: sha512-6op3AfsBC9BJKkhG+eoMFRFWlr0/f3FYbtQrK+VhGzJocEAY0WINIFN+W8xzXr//3IL0K/aKtnH3FtpIuescQQ==} - engines: {node: '>=22.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/preview-server@5.0.5': - resolution: {integrity: sha512-dNZ8G7PqQ+BUGkBRJgo+8PDjEtRj8c2vRzUMA3s7Q6zTfXFrBrSchG37UT5TsL6zi/RAOVN2P0wBZqz60J3hsw==} + '@radix-ui/rect@1.1.3': + resolution: {integrity: sha512-JtyZR+mqgBibTo8xea3B6ZRmzZiM/YeVBtUkas6zMuXjAlfIFIW2FgqeM9eLyvEaYX66vr6DJMK+4U6LV0KhNw==} - '@react-email/preview@0.0.13': - resolution: {integrity: sha512-F7j9FJ0JN/A4d7yr+aw28p4uX7VLWs7hTHtLo7WRyw4G+Lit6Zucq4UWKRxJC8lpsUdzVmG7aBJnKOT+urqs/w==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/render@2.0.0': - resolution: {integrity: sha512-rdjNj6iVzv8kRKDPFas+47nnoe6B40+nwukuXwY4FCwM7XBg6tmYr+chQryCuavUj2J65MMf6fztk1bxOUiSVA==} - engines: {node: '>=22.0.0'} + '@react-email/render@2.1.0': + resolution: {integrity: sha512-F+zE3O6d6sW6Aj2UjvZAA17R7tJKM7kcq2mgV6k4HCT8jeLLFaVP2txMtH1lgqYFRMZ0Gxsd37q2PRyiXLXXxA==} + engines: {node: '>=20.0.0'} peerDependencies: react: ^18.0 || ^19.0 || ^19.0.0-rc react-dom: ^18.0 || ^19.0 || ^19.0.0-rc - '@react-email/row@0.0.12': - resolution: {integrity: sha512-HkCdnEjvK3o+n0y0tZKXYhIXUNPDx+2vq1dJTmqappVHXS5tXS6W5JOPZr5j+eoZ8gY3PShI2LWj5rWF7ZEtIQ==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/section@0.0.16': - resolution: {integrity: sha512-FjqF9xQ8FoeUZYKSdt8sMIKvoT9XF8BrzhT3xiFKdEMwYNbsDflcjfErJe3jb7Wj/es/lKTbV5QR1dnLzGpL3w==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@react-email/tailwind@2.0.1': - resolution: {integrity: sha512-/xq0IDYVY7863xPY7cdI45Xoz7M6CnIQBJcQvbqN7MNVpopfH9f+mhjayV1JGfKaxlGWuxfLKhgi9T2shsnEFg==} - engines: {node: '>=22.0.0'} - peerDependencies: - '@react-email/body': 0.2.0 - '@react-email/button': 0.2.0 - '@react-email/code-block': 0.2.0 - '@react-email/code-inline': 0.0.5 - '@react-email/container': 0.0.15 - '@react-email/heading': 0.0.15 - '@react-email/hr': 0.0.11 - '@react-email/img': 0.0.11 - '@react-email/link': 0.0.12 - '@react-email/preview': 0.0.13 - '@react-email/text': 0.1.5 - react: ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - '@react-email/body': - optional: true - '@react-email/button': - optional: true - '@react-email/code-block': - optional: true - '@react-email/code-inline': - optional: true - '@react-email/container': - optional: true - '@react-email/heading': - optional: true - '@react-email/hr': - optional: true - '@react-email/img': - optional: true - '@react-email/link': - optional: true - '@react-email/preview': - optional: true - - '@react-email/text@0.1.5': - resolution: {integrity: sha512-o5PNHFSE085VMXayxH+SJ1LSOtGsTv+RpNKnTiJDrJUwoBu77G3PlKOsZZQHCNyD28WsQpl9v2WcJLbQudqwPg==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^18.0 || ^19.0 || ^19.0.0-rc - - '@reduxjs/toolkit@2.10.1': - resolution: {integrity: sha512-/U17EXQ9Do9Yx4DlNGU6eVNfZvFJfYpUtRRdLf19PbPjdWBxNlxGZXywQZ1p1Nz8nMkWplTI7iD/23m07nolDA==} + '@reduxjs/toolkit@2.12.0': + resolution: {integrity: sha512-KiT+RzZbp6mQET+Mg+h2c97+9j1sNflUxQkIHI7Yuzf6Peu+OYpmkn6nbHWmLLWj+1ZODUJFwGZ7gx3L9R9EOw==} peerDependencies: react: ^16.9.0 || ^17.0.0 || ^18 || ^19 react-redux: ^7.2.1 || ^8.1.3 || ^9.0.0 @@ -3060,194 +2926,120 @@ packages: react-redux: optional: true - '@rolldown/binding-android-arm64@1.0.0-beta.41': - resolution: {integrity: sha512-Edflndd9lU7JVhVIvJlZhdCj5DkhYDJPIRn4Dx0RUdfc8asP9xHOI5gMd8MesDDx+BJpdIT/uAmVTearteU/mQ==} + '@rolldown/binding-android-arm-eabi@1.2.9': + resolution: {integrity: sha512-tNISae1QEf/vkb3xkRcjV5SEdzPE97We5IVaa2Z8jSszQPZ8U60B/YCYpw4QI7VidYsBtKavczXf+DyDs9WGxw==} engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] + cpu: [arm] os: [android] - '@rolldown/binding-android-arm64@1.0.0-beta.51': - resolution: {integrity: sha512-Ctn8FUXKWWQI9pWC61P1yumS9WjQtelNS9riHwV7oCkknPGaAry4o7eFx2KgoLMnI2BgFJYpW7Im8/zX3BuONg==} + '@rolldown/binding-android-arm64@1.2.9': + resolution: {integrity: sha512-YC8YsI30o606GTZi0VyzYlsDKFP8W61i/QzayHDkLbNEz/IShqAmTa+hsJRj13xTHA0H+6fk4b2UmGn+Q/cMlg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [android] - '@rolldown/binding-darwin-arm64@1.0.0-beta.41': - resolution: {integrity: sha512-XGCzqfjdk7550PlyZRTBKbypXrB7ATtXhw/+bjtxnklLQs0mKP/XkQVOKyn9qGKSlvH8I56JLYryVxl0PCvSNw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-arm64@1.0.0-beta.51': - resolution: {integrity: sha512-EL1aRW2Oq15ShUEkBPsDtLMO8GTqfb/ktM/dFaVzXKQiEE96Ss6nexMgfgQrg8dGnNpndFyffVDb5IdSibsu1g==} + '@rolldown/binding-darwin-arm64@1.2.9': + resolution: {integrity: sha512-IwhlH3qK5urrY8hZiEgGkHKEFN901p/p2bjxCxJlr4GyNnF7wYpUvK+Y43uaRYuC4hpfjzbR3SJC3arX1jGvmw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [darwin] - '@rolldown/binding-darwin-x64@1.0.0-beta.41': - resolution: {integrity: sha512-Ho6lIwGJed98zub7n0xcRKuEtnZgbxevAmO4x3zn3C3N4GVXZD5xvCvTVxSMoeBJwTcIYzkVDRTIhylQNsTgLQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.0.0-beta.51': - resolution: {integrity: sha512-uGtYKlFen9pMIPvkHPWZVDtmYhMQi5g5Ddsndg1gf3atScKYKYgs5aDP4DhHeTwGXQglhfBG7lEaOIZ4UAIWww==} + '@rolldown/binding-darwin-x64@1.2.9': + resolution: {integrity: sha512-XxpJfVzFh+jilRxIXUqcfYAYcunIc/XEzIizsOL1fcJee5Sf7H3mH8WlLmfHfluz5amqR88QQo9izKtmMlavAw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [darwin] - '@rolldown/binding-freebsd-x64@1.0.0-beta.41': - resolution: {integrity: sha512-ijAZETywvL+gACjbT4zBnCp5ez1JhTRs6OxRN4J+D6AzDRbU2zb01Esl51RP5/8ZOlvB37xxsRQ3X4YRVyYb3g==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-freebsd-x64@1.0.0-beta.51': - resolution: {integrity: sha512-JRoVTQtHYbZj1P07JLiuTuXjiBtIa7ag7/qgKA6CIIXnAcdl4LrOf7nfDuHPJcuRKaP5dzecMgY99itvWfmUFQ==} + '@rolldown/binding-freebsd-x64@1.2.9': + resolution: {integrity: sha512-kSfvhmgeWyfkbT3p/1s5vSgboogoah2zkm9fX2zjg2hHxSV7T4KhMWRUUaRk4OXNqoD3QAUeRqLcs1aZOK4U1g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [freebsd] - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.41': - resolution: {integrity: sha512-EgIOZt7UildXKFEFvaiLNBXm+4ggQyGe3E5Z1QP9uRcJJs9omihOnm897FwOBQdCuMvI49iBgjFrkhH+wMJ2MA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.51': - resolution: {integrity: sha512-BKATVnpPZ0TYBW9XfDwyd4kPGgvf964HiotIwUgpMrFOFYWqpZ+9ONNzMV4UFAYC7Hb5C2qgYQk/qj2OnAd4RQ==} + '@rolldown/binding-linux-arm-gnueabihf@1.2.9': + resolution: {integrity: sha512-1RVzG17pxqbTfYLC352JlLt6kKLG+6Hr30n8DlIJqsnV5luUDd2Qdx9Ayw1Cabfyb1K9k0jXEZ7evxkRoT+uiw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm] os: [linux] - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.41': - resolution: {integrity: sha512-F8bUwJq8v/JAU8HSwgF4dztoqJ+FjdyjuvX4//3+Fbe2we9UktFeZ27U4lRMXF1vxWtdV4ey6oCSqI7yUrSEeg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.51': - resolution: {integrity: sha512-xLd7da5jkfbVsBCm1buIRdWtuXY8+hU3+6ESXY/Tk5X5DPHaifrUblhYDgmA34dQt6WyNC2kfXGgrduPEvDI6Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.41': - resolution: {integrity: sha512-MioXcCIX/wB1pBnBoJx8q4OGucUAfC1+/X1ilKFsjDK05VwbLZGRgOVD5OJJpUQPK86DhQciNBrfOKDiatxNmg==} + '@rolldown/binding-linux-arm64-gnu@1.2.9': + resolution: {integrity: sha512-BXqPvZ2drqVD+/Z8UpKwcs4Mp7grM+eGFku4CAEKrEtcbAsUpzREphK1sogCRZGreVPiMkiiBtw0n3TPteuqvw==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [glibc] - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.51': - resolution: {integrity: sha512-EQFXTgHxxTzv3t5EmjUP/DfxzFYx9sMndfLsYaAY4DWF6KsK1fXGYsiupif6qPTViPC9eVmRm78q0pZU/kuIPg==} + '@rolldown/binding-linux-arm64-musl@1.2.9': + resolution: {integrity: sha512-11vWvo8YDwLzukt27J3aYDWU+gg2P7J+ZOmiJ0hkF5BXZDW7pVya7r40MXDy6ya0i9KamoENSVKIugvJNgFXIA==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [linux] + libc: [musl] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.41': - resolution: {integrity: sha512-m66M61fizvRCwt5pOEiZQMiwBL9/y0bwU/+Kc4Ce/Pef6YfoEkR28y+DzN9rMdjo8Z28NXjsDPq9nH4mXnAP0g==} + '@rolldown/binding-linux-ppc64-gnu@1.2.9': + resolution: {integrity: sha512-a1tijMkdwsIARtc0F39ApURROkf3NwqinI6TOiSSWCTR7dT96dffNvMUtDHnq64wKNTIZOIlzKrFvvFUznJiyw==} engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] + cpu: [ppc64] os: [linux] + libc: [glibc] - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.51': - resolution: {integrity: sha512-p5P6Xpa68w3yFaAdSzIZJbj+AfuDnMDqNSeglBXM7UlJT14Q4zwK+rV+8Mhp9MiUb4XFISZtbI/seBprhkQbiQ==} + '@rolldown/binding-linux-s390x-gnu@1.2.9': + resolution: {integrity: sha512-x6SQNdAvv4c3hWqTMaWuawzMX9myaCs/yEmlGsxJzkdClnHW7FbrjQuSiRDhuSYzEYoEMhsaJy9qHG/XNemJPQ==} engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] + cpu: [s390x] os: [linux] + libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.41': - resolution: {integrity: sha512-yRxlSfBvWnnfrdtJfvi9lg8xfG5mPuyoSHm0X01oiE8ArmLRvoJGHUTJydCYz+wbK2esbq5J4B4Tq9WAsOlP1Q==} + '@rolldown/binding-linux-x64-gnu@1.2.9': + resolution: {integrity: sha512-9s0AZ8BFK5/n7B/TBoa2yJE3gI3KURrbXcPBlsAsvjU4VeJKgE90y1YtNxyEUIcHPQkg6/yfF3qihUrcM/Kf0Q==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [glibc] - '@rolldown/binding-linux-x64-musl@1.0.0-beta.51': - resolution: {integrity: sha512-sNVVyLa8HB8wkFipdfz1s6i0YWinwpbMWk5hO5S+XAYH2UH67YzUT13gs6wZTKg2x/3gtgXzYnHyF5wMIqoDAw==} + '@rolldown/binding-linux-x64-musl@1.2.9': + resolution: {integrity: sha512-P7VWAmV+WdJluH7ovnRGoiv2i8To7GAZ+kGzfGup635cyL7SyYl3lSUaA3Gp5THf0n/Co5EyEqb2zbqq+nMOHQ==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [linux] + libc: [musl] - '@rolldown/binding-openharmony-arm64@1.0.0-beta.41': - resolution: {integrity: sha512-PHVxYhBpi8UViS3/hcvQQb9RFqCtvFmFU1PvUoTRiUdBtgHA6fONNHU4x796lgzNlVSD3DO/MZNk1s5/ozSMQg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-openharmony-arm64@1.0.0-beta.51': - resolution: {integrity: sha512-e/JMTz9Q8+T3g/deEi8DK44sFWZWGKr9AOCW5e8C8SCVWzAXqYXAG7FXBWBNzWEZK0Rcwo9TQHTQ9Q0gXgdCaA==} + '@rolldown/binding-openharmony-arm64@1.2.9': + resolution: {integrity: sha512-1qixtsE4BK8h+yS3BfmZ09UhA7O/N4IACva6YBr7EBvCJraByTuRcgOTaiA62Tm0vey3UcKXLOaoGHtYmNGEVg==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [openharmony] - '@rolldown/binding-wasm32-wasi@1.0.0-beta.41': - resolution: {integrity: sha512-OAfcO37ME6GGWmj9qTaDT7jY4rM0T2z0/8ujdQIJQ2x2nl+ztO32EIwURfmXOK0U1tzkyuaKYvE34Pug/ucXlQ==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@rolldown/binding-wasm32-wasi@1.0.0-beta.51': - resolution: {integrity: sha512-We3LWqSu6J9s5Y0MK+N7fUiiu37aBGPG3Pc347EoaROuAwkCS2u9xJ5dpIyLW4B49CIbS3KaPmn4kTgPb3EyPw==} - engines: {node: '>=14.0.0'} - cpu: [wasm32] - - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.41': - resolution: {integrity: sha512-NIYGuCcuXaq5BC4Q3upbiMBvmZsTsEPG9k/8QKQdmrch+ocSy5Jv9tdpdmXJyighKqm182nh/zBt+tSJkYoNlg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.51': - resolution: {integrity: sha512-fj56buHRuMM+r/cb6ZYfNjNvO/0xeFybI6cTkTROJatdP4fvmQ1NS8D/Lm10FCSDEOkqIz8hK3TGpbAThbPHsA==} + '@rolldown/binding-win32-arm64-msvc@1.2.9': + resolution: {integrity: sha512-ok8IQjcEPs1AKZfuEUznVBrJw+gK4soq+bx8b1X2XoMqVClarc1q5JDmVtWXY1xfr6ZuHTAsPXHTgTrqKTZeww==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [arm64] os: [win32] - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.41': - resolution: {integrity: sha512-kANdsDbE5FkEOb5NrCGBJBCaZ2Sabp3D7d4PRqMYJqyLljwh9mDyYyYSv5+QNvdAmifj+f3lviNEUUuUZPEFPw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.51': - resolution: {integrity: sha512-fkqEqaeEx8AySXiDm54b/RdINb3C0VovzJA3osMhZsbn6FoD73H0AOIiaVAtGr6x63hefruVKTX8irAm4Jkt2w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ia32] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.41': - resolution: {integrity: sha512-UlpxKmFdik0Y2VjZrgUCgoYArZJiZllXgIipdBRV1hw6uK45UbQabSTW6Kp6enuOu7vouYWftwhuxfpE8J2JAg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.51': - resolution: {integrity: sha512-CWuLG/HMtrVcjKGa0C4GnuxONrku89g0+CsH8nT0SNhOtREXuzwgjIXNJImpE/A/DMf9JF+1Xkrq/YRr+F/rCg==} + '@rolldown/binding-win32-x64-msvc@1.2.9': + resolution: {integrity: sha512-Ip2mXoU0hM0boq3Rf+ekuT653OROSo6aSYcPT1VHE4q52KvyxgFkQgrgb/IEsxOuvQ2fZZbs8khJAyCEPM24/g==} engines: {node: ^20.19.0 || >=22.12.0} cpu: [x64] os: [win32] - '@rolldown/pluginutils@1.0.0-beta.41': - resolution: {integrity: sha512-ycMEPrS3StOIeb87BT3/+bu+blEtyvwQ4zmo2IcJQy0Rd1DAAhKksA0iUZ3MYSpJtjlPhg0Eo6mvVS6ggPhRbw==} - - '@rolldown/pluginutils@1.0.0-beta.47': - resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==} + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@rolldown/pluginutils@1.0.0-beta.51': - resolution: {integrity: sha512-51/8cNXMrqWqX3o8DZidhwz1uYq0BhHDDSfVygAND1Skx5s1TDw3APSSxCMcFFedwgqGcx34gRouwY+m404BBQ==} - - '@rollup/plugin-babel@5.3.1': - resolution: {integrity: sha512-WFfdLWU/xVWKeRQnKmIAQULUI7Il0gZnBIH/ZFO069wYIfPu+8zrfp/KMW0atmELoRDq8FbiP3VCss9MhCut7Q==} - engines: {node: '>= 10.0.0'} + '@rollup/plugin-babel@6.1.0': + resolution: {integrity: sha512-dFZNuFD2YRcoomP4oYf+DvQNSUA9ih+A3vUqopQx5EdtPGo3WBnQcI/S8pwpz91UsGfL0HsMSOlaMld8HrbubA==} + engines: {node: '>=14.0.0'} peerDependencies: '@babel/core': ^7.0.0 '@types/babel__core': ^7.1.9 - rollup: ^1.20.0||^2.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: '@types/babel__core': optional: true + rollup: + optional: true - '@rollup/plugin-node-resolve@15.3.1': - resolution: {integrity: sha512-tgg6b91pAybXHJQMAAwW9VuWBO6Thi+q7BCNARLwSqlmsHz0XYURtGvh/AuwSADXSI4h/2uHbs7s4FzlZDGSGA==} + '@rollup/plugin-node-resolve@16.0.3': + resolution: {integrity: sha512-lUYM3UBGuM93CnMPG1YocWu7X802BrNF3jW2zny5gQyLQgRFJhV1Sq0Zi74+dh/6NBx1DxFC4b4GXg9wUCG5Qg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^2.78.0||^3.0.0||^4.0.0 @@ -3255,28 +3047,26 @@ packages: rollup: optional: true - '@rollup/plugin-replace@2.4.2': - resolution: {integrity: sha512-IGcu+cydlUMZ5En85jxHH4qj2hta/11BHq95iHEyb2sbgiN0eCdzvUcHw5gt9pBL5lTi4JDYJ1acCoMGpTvEZg==} - peerDependencies: - rollup: ^1.20.0 || ^2.0.0 - - '@rollup/plugin-terser@0.4.4': - resolution: {integrity: sha512-XHeJC5Bgvs8LfukDwWZp7yeqin6ns8RTl2B9avbejt6tZqsqvVoWI7ZTQrcNsfKEDWBTnTxM8nMDkO2IFFbd0A==} + '@rollup/plugin-replace@6.0.3': + resolution: {integrity: sha512-J4RZarRvQAm5IF0/LwUUg+obsm+xZhYnbMXmXROyoSE1ATJe3oXSb9L5MMppdxP2ylNSjv6zFBwKYjcKMucVfA==} engines: {node: '>=14.0.0'} peerDependencies: - rollup: ^2.0.0||^3.0.0||^4.0.0 + rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 peerDependenciesMeta: rollup: optional: true - '@rollup/pluginutils@3.1.0': - resolution: {integrity: sha512-GksZ6pr6TpIjHm8h9lSQ8pi8BE9VeubNT0OMJ3B5uZJ8pz73NPiqOtCog/x2/QzM1ENChPKxMDhiQuRHsqc+lg==} - engines: {node: '>= 8.0.0'} + '@rollup/plugin-terser@1.0.0': + resolution: {integrity: sha512-FnCxhTBx6bMOYQrar6C8h3scPt8/JwIzw3+AJ2K++6guogH5fYaIFia+zZuhqv0eo1RN7W1Pz630SyvLbDjhtQ==} + engines: {node: '>=20.0.0'} peerDependencies: - rollup: ^1.20.0||^2.0.0 + rollup: ^2.0.0||^3.0.0||^4.0.0 + peerDependenciesMeta: + rollup: + optional: true - '@rollup/pluginutils@5.3.0': - resolution: {integrity: sha512-5EdhGZtnu3V88ces7s53hhfK5KSASnJZv8Lulpc04cWO3REESroJXg73DFsOmgbU2BhwV0E20bu2IDZb3VKW4Q==} + '@rollup/pluginutils@5.4.0': + resolution: {integrity: sha512-MfPp06CjRLfXQ3wY0R8vJDYBy/MvVcc9OulEfR0B8Iv9ko+GCNaRZ+EpJYFl27LhKsZK0o420sYCRHCjfCgeUg==} engines: {node: '>=14.0.0'} peerDependencies: rollup: ^1.20.0||^2.0.0||^3.0.0||^4.0.0 @@ -3284,113 +3074,141 @@ packages: rollup: optional: true - '@rollup/rollup-android-arm-eabi@4.53.3': - resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} + '@rollup/rollup-android-arm-eabi@4.63.3': + resolution: {integrity: sha512-w3Jnvi1ocaVm/c7yVPpfB98XeSRBMyzp6njL5MVVbGyXjpmUkN+s6Hp4t0PqhGCCaI1ZHMKXt/w0lA1RCaLVcw==} cpu: [arm] os: [android] - '@rollup/rollup-android-arm64@4.53.3': - resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} + '@rollup/rollup-android-arm64@4.63.3': + resolution: {integrity: sha512-uI/ESiaIbbRYAEhzy8PCUWDp1hB0bjAqM06mW9flOoNO4Q8DQpeoREhBR5Hegfl+wpXiguyJv6XSPzEN7OxyHQ==} cpu: [arm64] os: [android] - '@rollup/rollup-darwin-arm64@4.53.3': - resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} + '@rollup/rollup-darwin-arm64@4.63.3': + resolution: {integrity: sha512-oxhrd1jmXLwWZ83eQYDXxuqRdkqkzrjR3JobKeuUyfdNZo11FuQIvqEOZhyIT7OBHxXoGslDDjN0cQcM6T0TqQ==} cpu: [arm64] os: [darwin] - '@rollup/rollup-darwin-x64@4.53.3': - resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} + '@rollup/rollup-darwin-x64@4.63.3': + resolution: {integrity: sha512-7/YiIMghVE8DrxKvNdorAaJVdriOFgOIpdStnPx8ppx5zfTwC3jBCSEAIzB7JD5404m65THl6H93UTTVUvypmg==} cpu: [x64] os: [darwin] - '@rollup/rollup-freebsd-arm64@4.53.3': - resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} + '@rollup/rollup-freebsd-arm64@4.63.3': + resolution: {integrity: sha512-GXFZRRoMAytaI5z6N3Zhfw0WL18Q0M8r95D5hlC4GqE/lGk8pbSJNUBoOWDfbm6dTciqHj2nU87tI5f6XhQiOg==} cpu: [arm64] os: [freebsd] - '@rollup/rollup-freebsd-x64@4.53.3': - resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} + '@rollup/rollup-freebsd-x64@4.63.3': + resolution: {integrity: sha512-77W+8X3ddYgPxUpB8nZFQs2Mq+wc4HVlcSRtApXLjYBcnPMkttrSnU8VwKQjeWYhMsITHFs5cWBQ8vz1Q+5RHQ==} cpu: [x64] os: [freebsd] - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': - resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} + '@rollup/rollup-linux-arm-gnueabihf@4.63.3': + resolution: {integrity: sha512-FVkwK+iUC+mq+GipVK46rRVticfAPtvPUNlqlGXUDxdVk/UGjQiiiUVPUrEXdSpU2ufU0XxLGyTqDtBidDOVmg==} cpu: [arm] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-arm-musleabihf@4.53.3': - resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} + '@rollup/rollup-linux-arm-musleabihf@4.63.3': + resolution: {integrity: sha512-+aGU1t3398yQOVj1Bz8o3e+KtswxAPvO+mtxtNdfXYMkXIHu7XhhkCD7/DEH9q8tF8uhDnMWvfpUKI8y1sZJsg==} cpu: [arm] os: [linux] + libc: [musl] - '@rollup/rollup-linux-arm64-gnu@4.53.3': - resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} + '@rollup/rollup-linux-arm64-gnu@4.63.3': + resolution: {integrity: sha512-cR0kjpRXR2KJ2oQK8E2KTPtphs+b9hZ8IhTZubNryt/RsqgdOZBQ2Zq0q5UedtiIi0rs3jVhJh55RE1ZHUVGUA==} cpu: [arm64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-arm64-musl@4.53.3': - resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} + '@rollup/rollup-linux-arm64-musl@4.63.3': + resolution: {integrity: sha512-y1RYi4Q3/9ByVWSSt9kX2ustE0B7kFYbJ6zZdVZVyqopZs3yhCTwRfrjIX4vezUJInma/Gs6BOFDJg7yZmJ0IQ==} cpu: [arm64] os: [linux] + libc: [musl] + + '@rollup/rollup-linux-loong64-gnu@4.63.3': + resolution: {integrity: sha512-DNhEA5viIj3Z5bZLE4z4oV8N5ozWqDwyt7T6KG7VdLDJ0nW+rNOYlphBl4/3HQkK75qipPLsVOfStHHOwN9WSg==} + cpu: [loong64] + os: [linux] + libc: [glibc] - '@rollup/rollup-linux-loong64-gnu@4.53.3': - resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} + '@rollup/rollup-linux-loong64-musl@4.63.3': + resolution: {integrity: sha512-17gQCqrIpXBX2Cmi9/TygnVOqGbzsba/iaqcYSL8FY7lNugg+7AiYNs5c5nKWD+NRQha36Sa0CqkJqH4XVHwnQ==} cpu: [loong64] os: [linux] + libc: [musl] - '@rollup/rollup-linux-ppc64-gnu@4.53.3': - resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} + '@rollup/rollup-linux-ppc64-gnu@4.63.3': + resolution: {integrity: sha512-6LwVnZRIyINpdku/yOcI8Tm9YqLmhHK5emmlOOnW9tO0SYEm1FmKPcsSAGp0NBlqR2P04xaND4jvN6sTHqhq8A==} cpu: [ppc64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-riscv64-gnu@4.53.3': - resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} + '@rollup/rollup-linux-ppc64-musl@4.63.3': + resolution: {integrity: sha512-xMUqkTXlEUtI/p5AAukMwBRr1enU3efsTeF+bskeFfk8t1C9rcC8sLREcZXmTfAXEbvRdJVSonVJez3TMlbR3w==} + cpu: [ppc64] + os: [linux] + libc: [musl] + + '@rollup/rollup-linux-riscv64-gnu@4.63.3': + resolution: {integrity: sha512-S3E94co9F9WRRqEaUoQZ38K1gCz6KiM+nL7/3ijq7fDGF3OznjS5TasgYITlvl27GQKtu4lOAOsr5MFwkijvOA==} cpu: [riscv64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-riscv64-musl@4.53.3': - resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} + '@rollup/rollup-linux-riscv64-musl@4.63.3': + resolution: {integrity: sha512-1QtRDwG42x5BJI3s9mxu5rEjDnfbSnk20HQ9/ylTAYnSwYwxMVb+Vgu34wzzTQ7ogqBybebgQNUDAvZVQ38DbA==} cpu: [riscv64] os: [linux] + libc: [musl] - '@rollup/rollup-linux-s390x-gnu@4.53.3': - resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} + '@rollup/rollup-linux-s390x-gnu@4.63.3': + resolution: {integrity: sha512-BQhejF6ZXOpxbngiNTP12GCGQeaDVL2QXGeBVViKIYzFHM5RKxTxwUMB1fr1BeNFphFMpnRqC5QSXFSa4z6UQw==} cpu: [s390x] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-gnu@4.53.3': - resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} + '@rollup/rollup-linux-x64-gnu@4.63.3': + resolution: {integrity: sha512-SXagRwnI2Wlwlitllu59UK/nGVbD1CKPcNqDplHwIC4BqJcpXFjD32d1R/RbuISa95HdQrZM3/7v4bKiowFaLA==} cpu: [x64] os: [linux] + libc: [glibc] - '@rollup/rollup-linux-x64-musl@4.53.3': - resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} + '@rollup/rollup-linux-x64-musl@4.63.3': + resolution: {integrity: sha512-2IPozoEALRCziGqE8O9KMK60PMu5TS1huv4fwoeCexj+WjmcwFtX9CTOVbfXCUqcELAubEwRFPYlzb/WvwY2HQ==} cpu: [x64] os: [linux] + libc: [musl] + + '@rollup/rollup-openbsd-x64@4.63.3': + resolution: {integrity: sha512-AoxqosUHT9IX54hFn2TiN6A7d6ZKTtE6pd2bqWtqkkNJ6HJGaU6FRouGX8L1O7R/ZwsnCnpQrHzb4pDEx+UHRQ==} + cpu: [x64] + os: [openbsd] - '@rollup/rollup-openharmony-arm64@4.53.3': - resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} + '@rollup/rollup-openharmony-arm64@4.63.3': + resolution: {integrity: sha512-d+CaftKgmkFBzCwezMqqy1d0QNNYugqLCMcYVQWBy5SS2YfeMP8Q8ripkgx9O8IyBXXLHrJ+aaCV4U96usv6Yg==} cpu: [arm64] os: [openharmony] - '@rollup/rollup-win32-arm64-msvc@4.53.3': - resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} + '@rollup/rollup-win32-arm64-msvc@4.63.3': + resolution: {integrity: sha512-xXlDF6nR1eOuXbdDy5Hl5fmtY7teUDevF/k0O7IPoZe4Tpmdv+lgdE5JRsnhQtt37ql9P0VF2kAN9a0OCZdo+Q==} cpu: [arm64] os: [win32] - '@rollup/rollup-win32-ia32-msvc@4.53.3': - resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} + '@rollup/rollup-win32-ia32-msvc@4.63.3': + resolution: {integrity: sha512-YtXAgLN+JP7Ay6qG3eWhc7IHMQPzLc8r3uvhAvlJIoCz/4Q32+Bl9Fmnywidh8v1GOIMmymjovfqY9ETAtysvA==} cpu: [ia32] os: [win32] - '@rollup/rollup-win32-x64-gnu@4.53.3': - resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} + '@rollup/rollup-win32-x64-gnu@4.63.3': + resolution: {integrity: sha512-WuWtSJRNo549vzcfZyEgfqb6zeSgn1F+UE5kQ+BCjzz0W4MGCjntUHkZVc1VRuAM7+ULaSyhiPxD1spyewFvkQ==} cpu: [x64] os: [win32] - '@rollup/rollup-win32-x64-msvc@4.53.3': - resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} + '@rollup/rollup-win32-x64-msvc@4.63.3': + resolution: {integrity: sha512-+lIKX7O0+IGe7WuhATaAMMeT7B76vfhXH/l9wLQL+nvyhbw2ohYCKIdWL56JfDu75CWt5oKRP4QFH/jkMtBquA==} cpu: [x64] os: [win32] @@ -3400,73 +3218,91 @@ packages: '@selderee/plugin-htmlparser2@0.11.0': resolution: {integrity: sha512-P33hHGdldxGabLFjPPpaTxVolMrzrcegejx+0GxjrIb9Zv48D8yAIA/QTDR2dFl7Uz7urX8aX6+5bCZslr+gWQ==} - '@sentry-internal/browser-utils@10.26.0': - resolution: {integrity: sha512-rPg1+JZlfp912pZONQAWZzbSaZ9L6R2VrMcCEa+2e2Gqk9um4b+LqF5RQWZsbt5Z0n0azSy/KQ6zAe/zTPXSOg==} - engines: {node: '>=18'} - - '@sentry-internal/feedback@10.26.0': - resolution: {integrity: sha512-0vk9eQP0CXD7Y2WkcCIWHaAqnXOAi18/GupgWLnbB2kuQVYVtStWxtW+OWRe8W/XwSnZ5m6JBTVeokuk/O16DQ==} - engines: {node: '>=18'} - - '@sentry-internal/replay-canvas@10.26.0': - resolution: {integrity: sha512-vs7d/P+8M1L1JVAhhJx2wo15QDhqAipnEQvuRZ6PV7LUcS1un9/Vx49FMxpIkx6JcKADJVwtXrS1sX2hoNT/kw==} - engines: {node: '>=18'} - - '@sentry-internal/replay@10.26.0': - resolution: {integrity: sha512-FMySQnY2/p0dVtFUBgUO+aMdK2ovqnd7Q/AkvMQUsN/5ulyj6KZx3JX3CqOqRtAr1izoCe4Kh2pi5t//sQmvsg==} + '@sentry/browser-utils@10.75.0': + resolution: {integrity: sha512-yZfdQ87RLat/7retF8zA6Z9zCAT12IyaPvIiu+bbi1E1V1OqDpS8MKNa/6LF69Ap7DVTORi9ITEgjlAqTXF0xQ==} engines: {node: '>=18'} - '@sentry/browser@10.26.0': - resolution: {integrity: sha512-uvV4hnkt8bh8yP0disJ0fszy8FdnkyGtzyIVKdeQZbNUefwbDhd3H0KJrAHhJ5ocULMH3B+dipdPmw2QXbEflg==} + '@sentry/browser@10.75.0': + resolution: {integrity: sha512-CKGSJLWISQ6LgMaGnMpY+XvwWQ2iiHTayUs6SGLIvYeaGo2GTjS/Z4pnbCVHb2t1VxLZksyehgcC6ZYGJeQpzQ==} engines: {node: '>=18'} - '@sentry/cloudflare@10.26.0': - resolution: {integrity: sha512-iBFFEuzin3rpFEOIQ/y3QYPBOAJmHHyAtdEicNFp2R4FvRZJ+Ut3nHV5gSMbwsiArCyfFFKz101/CNdSj569wQ==} + '@sentry/cloudflare@10.75.0': + resolution: {integrity: sha512-2TvEXTihK8tNT0KB7WraoiSsSJ9dX6h4F7Wr0+k5rldPH9G1l6zc+6xP/u9CCB+m44XOHiI2omPGDkQ9uEo1ew==} engines: {node: '>=18'} peerDependencies: - '@cloudflare/workers-types': ^4.x + '@cloudflare/workers-types': ^4.x || ^5.x + wrangler: ^4.x peerDependenciesMeta: '@cloudflare/workers-types': optional: true + wrangler: + optional: true + + '@sentry/conventions@0.16.0': + resolution: {integrity: sha512-fO9PLmHdVURcSPUpWCItWAtgKiMwGdJHbovoSEyLplX5sxs2ugvI4CBPTrkkgqhObnZOD0CnWBKDzSVQYBKEyQ==} + engines: {node: '>=14'} - '@sentry/core@10.26.0': - resolution: {integrity: sha512-TjDe5QI37SLuV0q3nMOH8JcPZhv2e85FALaQMIhRILH9Ce6G7xW5GSjmH91NUVq8yc3XtiqYlz/EenEZActc4Q==} + '@sentry/core@10.75.0': + resolution: {integrity: sha512-5wDQpQqjJ6RHdPR+z6Q+47XlwoxRKBv0yyB0LKHqL/1azPOQbR+nllyLmmQDcoJpaksuLSmLA1q6hFX7gjDT2w==} engines: {node: '>=18'} - '@sentry/node-core@10.26.0': - resolution: {integrity: sha512-7OrHVn8XAsq9mMVMlpL18XTKQEVcLOJSo0n2M7QGKfFk/OfVtSFMcUWGqN1qhYtT9aMTr2bjtR5+BI33djnNTQ==} + '@sentry/feedback@10.75.0': + resolution: {integrity: sha512-YLVAFQXELJAOg7ke4oLkd8t5l0fJUockLlTQJg/2Trh7SB5Q4mkSwlnAkEAqDQ618vnpFsG/tnYMwtfZeffHjA==} + engines: {node: '>=18'} + + '@sentry/node-core@10.75.0': + resolution: {integrity: sha512-+E3KSX1oMqhpWQ23hj6NblIVUzLy3T2oceU7DfMX1s1ar+npaQZxR5K0/cMGcQgS1LLm8Jqwqo/lrZlKTCDm5A==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 - '@opentelemetry/context-async-hooks': ^1.30.1 || ^2.1.0 '@opentelemetry/core': ^1.30.1 || ^2.1.0 + '@opentelemetry/exporter-trace-otlp-http': '>=0.57.0 <1' '@opentelemetry/instrumentation': '>=0.57.1 <1' - '@opentelemetry/resources': ^1.30.1 || ^2.1.0 '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - '@opentelemetry/semantic-conventions': ^1.37.0 + peerDependenciesMeta: + '@opentelemetry/api': + optional: true + '@opentelemetry/core': + optional: true + '@opentelemetry/exporter-trace-otlp-http': + optional: true + '@opentelemetry/instrumentation': + optional: true + '@opentelemetry/sdk-trace-base': + optional: true - '@sentry/node@10.26.0': - resolution: {integrity: sha512-VUwNoKYhRpnHQSj9lty1TgooO+1wcpS1V0K87HU8sZEas5gx3Ujiouk5ocPjlgbKreoYOApgOnEEIq5W/hfQcQ==} + '@sentry/node@10.75.0': + resolution: {integrity: sha512-XdYW+SEiscQnuugh1hMldfnHurmleKSTSDqgfro6Y1yd7s0r2csnZ5/SEYxIeL4lSl1QXg1lIA1pBmAXjcdnKA==} engines: {node: '>=18'} - '@sentry/opentelemetry@10.26.0': - resolution: {integrity: sha512-ASJdOwn6NwMH2ZeBrnGJI+l/xkJp1AOiQ5FWkvTqLc/vHX+r3PDMO7c+koecY+LiZxSzZF4IV8sALXfOh6UnwA==} + '@sentry/opentelemetry@10.75.0': + resolution: {integrity: sha512-reJoMtuHMuaiztoDVoaeitc22eHlTAvz2qpFhibWyzukJlF8oXB+o8EvDN9mmDDMedU89c//cXRcnPBlJvUxcw==} engines: {node: '>=18'} peerDependencies: '@opentelemetry/api': ^1.9.0 - '@opentelemetry/context-async-hooks': ^1.30.1 || ^2.1.0 '@opentelemetry/core': ^1.30.1 || ^2.1.0 '@opentelemetry/sdk-trace-base': ^1.30.1 || ^2.1.0 - '@opentelemetry/semantic-conventions': ^1.37.0 - '@sentry/react@10.26.0': - resolution: {integrity: sha512-Qi0/FVXAalwQNr8zp0tocViH3+MRelW8ePqj3TdMzapkbXRuh07czdGgw8Zgobqcb7l4rRCRAUo2sl/H3KVkIw==} + '@sentry/react@10.75.0': + resolution: {integrity: sha512-ghWv99h7k4WgMucqBhf4jZn+G0Owm5gCBCVKOKu88UDCWUd9aVJ8FGosAkATp/x/ogcZTnqG2dcXBD+1U+BJeA==} engines: {node: '>=18'} peerDependencies: react: ^16.14.0 || 17.x || 18.x || 19.x - '@sindresorhus/is@7.1.1': - resolution: {integrity: sha512-rO92VvpgMc3kfiTjGT52LEtJ8Yc5kCWhZjLQ3LwlA4pSgPpQO7bVpYXParOD8Jwf+cVQECJo3yP/4I8aZtUQTQ==} + '@sentry/replay-canvas@10.75.0': + resolution: {integrity: sha512-LNokI5Ud22nZ/o2il/2SfbNIARupWrbS6Mh9jZroZTjD38FN0Oi9vIexj6h1HN81C6+lP2Tmpaj+fl3/wOizzA==} + engines: {node: '>=18'} + + '@sentry/replay@10.75.0': + resolution: {integrity: sha512-p4xxEo/ayiMZG9tygr09YjqYAd52uq8Qi0EVoRRgUe70nQda0HVPVW519JLq0G+Th/5O5sKME9y1layLU3xlPg==} + engines: {node: '>=18'} + + '@sentry/server-utils@10.75.0': + resolution: {integrity: sha512-7fIa9vFGNzB13hmxl8Sip3xImSkqpc4wETzuQ7CLzVOwPvwI6y/gVEm0pxRhtJSq8SzfOp26eJWl80u8v78Osg==} + engines: {node: '>=18'} + + '@sindresorhus/is@7.2.0': + resolution: {integrity: sha512-P1Cz1dWaFfR4IR+U13mqqiGsLFf1KbayybWwdd2vfctdV6hDpUkgCY0nKOLLTMSoRd/jJNjtbqzf13K8DCCXQw==} engines: {node: '>=18'} '@sindresorhus/merge-streams@4.0.0': @@ -3476,86 +3312,81 @@ packages: '@socket.io/component-emitter@3.1.2': resolution: {integrity: sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==} - '@speed-highlight/core@1.2.12': - resolution: {integrity: sha512-uilwrK0Ygyri5dToHYdZSjcvpS2ZwX0w5aSt3GCEN9hrjxWCoeV4Z2DTXuxjwbntaLQIEEAlCeNQss5SoHvAEA==} + '@speed-highlight/core@1.2.24': + resolution: {integrity: sha512-qeW2e1l78afw8VhRPfPQ1Gjj+KU5XFQ/OFV5ti6eTa9bruO7mJyZtA4vw0ofqmA3tKCkROE9xLk3VZoeRc98nw==} '@stablelib/base64@1.0.1': resolution: {integrity: sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==} - '@standard-schema/spec@1.0.0': - resolution: {integrity: sha512-m2bOd0f2RT9k8QJx1JN85cZYyH1RqFBdlwtkSlf4tBDYLCiiZnv1fIIwacK6cqwXavOydf0NPToMQgpKq+dVlA==} - '@standard-schema/spec@1.1.0': resolution: {integrity: sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==} '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} - '@surma/rollup-plugin-off-main-thread@2.2.3': - resolution: {integrity: sha512-lR8q/9W7hZpMWweNiAKU7NQerBnzQQLvi8qnTDU/fxItPhtZVMbPV3lbCwjhIlNBe9Bbr5V+KHshvWmVSG9cxQ==} + '@tailwindcss/node@4.3.3': + resolution: {integrity: sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==} - '@swc/helpers@0.5.15': - resolution: {integrity: sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==} - - '@tailwindcss/node@4.1.17': - resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} - - '@tailwindcss/oxide-android-arm64@4.1.17': - resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-android-arm64@4.3.3': + resolution: {integrity: sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==} + engines: {node: '>= 20'} cpu: [arm64] os: [android] - '@tailwindcss/oxide-darwin-arm64@4.1.17': - resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-darwin-arm64@4.3.3': + resolution: {integrity: sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==} + engines: {node: '>= 20'} cpu: [arm64] os: [darwin] - '@tailwindcss/oxide-darwin-x64@4.1.17': - resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-darwin-x64@4.3.3': + resolution: {integrity: sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==} + engines: {node: '>= 20'} cpu: [x64] os: [darwin] - '@tailwindcss/oxide-freebsd-x64@4.1.17': - resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-freebsd-x64@4.3.3': + resolution: {integrity: sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==} + engines: {node: '>= 20'} cpu: [x64] os: [freebsd] - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': - resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': + resolution: {integrity: sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==} + engines: {node: '>= 20'} cpu: [arm] os: [linux] - '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': - resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': + resolution: {integrity: sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [glibc] - '@tailwindcss/oxide-linux-arm64-musl@4.1.17': - resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': + resolution: {integrity: sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==} + engines: {node: '>= 20'} cpu: [arm64] os: [linux] + libc: [musl] - '@tailwindcss/oxide-linux-x64-gnu@4.1.17': - resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': + resolution: {integrity: sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [glibc] - '@tailwindcss/oxide-linux-x64-musl@4.1.17': - resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-linux-x64-musl@4.3.3': + resolution: {integrity: sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==} + engines: {node: '>= 20'} cpu: [x64] os: [linux] + libc: [musl] - '@tailwindcss/oxide-wasm32-wasi@4.1.17': - resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} + '@tailwindcss/oxide-wasm32-wasi@4.3.3': + resolution: {integrity: sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==} engines: {node: '>=14.0.0'} cpu: [wasm32] bundledDependencies: @@ -3566,85 +3397,84 @@ packages: - '@emnapi/wasi-threads' - tslib - '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': - resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': + resolution: {integrity: sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==} + engines: {node: '>= 20'} cpu: [arm64] os: [win32] - '@tailwindcss/oxide-win32-x64-msvc@4.1.17': - resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} - engines: {node: '>= 10'} + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': + resolution: {integrity: sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==} + engines: {node: '>= 20'} cpu: [x64] os: [win32] - '@tailwindcss/oxide@4.1.17': - resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} - engines: {node: '>= 10'} + '@tailwindcss/oxide@4.3.3': + resolution: {integrity: sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==} + engines: {node: '>= 20'} - '@tailwindcss/typography@0.5.19': - resolution: {integrity: sha512-w31dd8HOx3k9vPtcQh5QHP9GwKcgbMp87j58qi6xgiBnFFtKEAgCWnDw4qUT8aHwkCp8bKvb/KGKWWHedP0AAg==} + '@tailwindcss/typography@0.5.20': + resolution: {integrity: sha512-hwbzQuNUfcPvbegQFatVPl/MY/tcM9KLl963hQ5laJKPh81TEZ1+dNG9PirGvcaDBkp+BCshExAyKVPW91dozw==} peerDependencies: - tailwindcss: '>=3.0.0 || insiders || >=4.0.0-alpha.20 || >=4.0.0-beta.1' + tailwindcss: '>=3.0.0 || >=4.0.0 || insiders' - '@tailwindcss/vite@4.1.17': - resolution: {integrity: sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==} + '@tailwindcss/vite@4.3.3': + resolution: {integrity: sha512-yYU8cogLeSh/ms2jh8Fj7jaba/EWa7Ja6GoUqYZaraEuCI5YS6ms6ObZgjjedm+jm6XZjdNRWBpPP6Z86oOxcw==} peerDependencies: - vite: ^5.2.0 || ^6 || ^7 + vite: ^5.2.0 || ^6 || ^7 || ^8 - '@tanstack/history@1.139.0': - resolution: {integrity: sha512-l6wcxwDBeh/7Dhles23U1O8lp9kNJmAb2yNjekR6olZwCRNAVA8TCXlVCrueELyFlYZqvQkh0ofxnzG62A1Kkg==} - engines: {node: '>=12'} + '@tanstack/history@1.162.4': + resolution: {integrity: sha512-utTS5L2OkeYUzXGohL1Z8sefu1GLNOJcxe8Hd6iIdc/Xo1K1nDB2JEp4iSFhvYh33xKC9V91TxrS8qfrpoKobQ==} + engines: {node: '>=20.19'} - '@tanstack/query-core@5.90.10': - resolution: {integrity: sha512-EhZVFu9rl7GfRNuJLJ3Y7wtbTnENsvzp+YpcAV7kCYiXni1v8qZh++lpw4ch4rrwC0u/EZRnBHIehzCGzwXDSQ==} + '@tanstack/query-core@5.103.1': + resolution: {integrity: sha512-rms8HqTGp6zA00dM+cUQ2eBcgzNJefuu5CAMB37i/6MiGT1zulPOytCFu2a0qjLqVR2n1jENPj9woqFQNuCzWA==} - '@tanstack/react-query@5.90.10': - resolution: {integrity: sha512-BKLss9Y8PQ9IUjPYQiv3/Zmlx92uxffUOX8ZZNoQlCIZBJPT5M+GOMQj7xislvVQ6l1BstBjcX0XB/aHfFYVNw==} + '@tanstack/react-query@5.103.1': + resolution: {integrity: sha512-rmAPPApNEK17VXRJhtE1rja53n23VV5w30C0saCgJhhX+EpdUnVqMGV/s5nnzV43X75KTHKzuoiuxSzGTBIkag==} peerDependencies: react: ^18 || ^19 - '@tanstack/react-router@1.139.3': - resolution: {integrity: sha512-lhqK0DnbA7PgHOnmhzOoWVzx8qd8oEpR4cOUbxAjwb3+ExFQWrEvRf9+ZdSxs49ZrtZL2S2UltxBv3vBV4Si5g==} - engines: {node: '>=12'} + '@tanstack/react-router@1.170.38': + resolution: {integrity: sha512-iHM9b0aDJbuvftmkiQXawzoqsdV68p2Re2safbVLCnxafe+iLKV++2i3hI/BMAP6uR92/Mjw94JKJJfD7pbwHQ==} + engines: {node: '>=20.19'} peerDependencies: react: '>=18.0.0 || >=19.0.0' react-dom: '>=18.0.0 || >=19.0.0' - '@tanstack/react-store@0.8.0': - resolution: {integrity: sha512-1vG9beLIuB7q69skxK9r5xiLN3ztzIPfSQSs0GfeqWGO2tGIyInZx0x1COhpx97RKaONSoAb8C3dxacWksm1ow==} + '@tanstack/react-store@0.11.1': + resolution: {integrity: sha512-HaIGKI3YLmjBYIvy5DFDY23oNaYZIsTZfngey07Uh5iLVJgM3bIGCnZeOFOqzjFld9JHWcaHJnasD/bKoGKwJQ==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - '@tanstack/react-table@8.21.3': - resolution: {integrity: sha512-5nNMTSETP4ykGegmVkhjcS8tTLW6Vl4axfEGQN3v0zdHYbK4UfoqfPChclTrJ4EoK9QynqAu9oUf8VEmrpZ5Ww==} - engines: {node: '>=12'} + '@tanstack/react-table@9.2.4': + resolution: {integrity: sha512-Rzp1Q4e0/nIgEjmISYR5HeEgLTNtrG+C7NFZf/AbCxPO5hg+zC3yNGwcoECigUk8SFzzvhXbd2rFdtP2ZiGrfA==} + engines: {node: '>=20'} peerDependencies: - react: '>=16.8' - react-dom: '>=16.8' + react: '>=18' - '@tanstack/router-cli@1.139.3': - resolution: {integrity: sha512-HGTe7N0AzXFuteTDRj3RZT3ZfAVJ+XI5uaLGVHMQ0Cmc4wma0k1yyurKDVjsFFLeZk2NZQ+RcaHhNiS8iHRTwQ==} - engines: {node: '>=12'} + '@tanstack/router-cli@1.167.38': + resolution: {integrity: sha512-Vi8wB1L4ustvGb1rGvV4wUgAxvTbLs+QGtDsZM9FQ0IbLJ2tCNs4AjJMu++lYW7O1/TDcXyYnjRPZmFLUjAEXA==} + engines: {node: '>=20.19'} hasBin: true - '@tanstack/router-core@1.139.3': - resolution: {integrity: sha512-j3v1e739jmozBdtnmA45xHQHjCC2aKqBtfkMT3t2ZPijVrueaVP6qNRIAWmDK4ZSqd67TF5wP8vyqeTShJsEQQ==} - engines: {node: '>=12'} + '@tanstack/router-core@1.171.32': + resolution: {integrity: sha512-X86Jqk3vB2KJcUfS6oLi7B7yxbaa59QEhZRPPP1fRx3k+Jw/Fu1UYVBcRtdwK/OccQnrlQdVoKvNO3QXmyEBOw==} + engines: {node: '>=20.19'} - '@tanstack/router-generator@1.139.3': - resolution: {integrity: sha512-zq/ZC+1rx7pGNqYOthHSm0jxioNqm7JszYDcZPAZVhHT2Qhen02b7PzW8M7Qx4FU+ldXgnhpenDN5/jqYYClfQ==} - engines: {node: '>=12'} + '@tanstack/router-generator@1.167.38': + resolution: {integrity: sha512-lkqgFleDgfkW+QONVMKBs+ZGDUF0v9R9FkplS/GZvKDFpfnu+tZxmGlV2pryU1TDxyuSyjh56AtIla3NMrlScw==} + engines: {node: '>=20.19'} - '@tanstack/router-plugin@1.139.3': - resolution: {integrity: sha512-ymv5mr2IULgrZblzYeYUVZXzz3fzW1OzoDZh5cs5gEetRcEpXQ6XL8KG4pCkIQ04AJcrtXEWt1yZxi01XjZWxw==} - engines: {node: '>=12'} + '@tanstack/router-plugin@1.168.40': + resolution: {integrity: sha512-ifiXjjR4uivxwRDhgYAcfyrcu+Mwx+vlG0QjjQ7N5C5sKmzpt5UtsL21TNVvZDSZl2Vae8DcL84Z02fOs8ZZMQ==} + engines: {node: '>=20.19'} peerDependencies: - '@rsbuild/core': '>=1.0.2' - '@tanstack/react-router': ^1.139.3 - vite: '>=5.0.0 || >=6.0.0 || >=7.0.0' - vite-plugin-solid: ^2.11.10 + '@rsbuild/core': '>=1.0.2 || ^2.0.0' + '@tanstack/react-router': ^1.170.38 + vite: '>=5.0.0 || >=6.0.0 || >=7.0.0 || >=8.0.0' + vite-plugin-solid: ^2.11.10 || ^3.0.0-0 webpack: '>=5.92.0' peerDependenciesMeta: '@rsbuild/core': @@ -3658,31 +3488,37 @@ packages: webpack: optional: true - '@tanstack/router-utils@1.139.0': - resolution: {integrity: sha512-jT7D6NimWqoFSkid4vCno8gvTyfL1+NHpgm3es0B2UNhKKRV3LngOGilm1m6v8Qvk/gy6Fh/tvB+s+hBl6GhOg==} - engines: {node: '>=12'} + '@tanstack/router-utils@1.162.3': + resolution: {integrity: sha512-Icb0xGuG1+54IV0WMLRcc3ErTx2HeJWyPG661FkQ8UT6guoBq1FJjFRqlG/JS0xi4mFFkBhvwO7tbLa32f3yxA==} + engines: {node: '>=20.19'} - '@tanstack/store@0.8.0': - resolution: {integrity: sha512-Om+BO0YfMZe//X2z0uLF2j+75nQga6TpTJgLJQBiq85aOyZNIhkCgleNcud2KQg4k4v9Y9l+Uhru3qWMPGTOzQ==} + '@tanstack/store@0.11.1': + resolution: {integrity: sha512-mzTOBhypOuDJAy/D8n2MfUZ1HFkXnmSETviRyhqEC8LUE7/IZQExOTxMANj3KjTofYTkFNpBY67qaVrT41YccA==} - '@tanstack/table-core@8.21.3': - resolution: {integrity: sha512-ldZXEhOBb8Is7xLs01fR3YEc3DERiz5silj8tnGkFZytt1abEvl/GhUmCE0PMLaMPTa3Jk4HbKmRlHmu+gCftg==} - engines: {node: '>=12'} + '@tanstack/table-core@9.2.4': + resolution: {integrity: sha512-GwdDyGGr6UXAtubF14yAwcXvdaogqfsQgIk89Suebjxob/Rjq2xvfmXsjDF1rQmKmhHsJm9TOY7myxv3i6geJw==} + engines: {node: '>=20'} - '@tanstack/virtual-file-routes@1.139.0': - resolution: {integrity: sha512-9PImF1d1tovTUIpjFVa0W7Fwj/MHif7BaaczgJJfbv3sDt1Gh+oW9W9uCw9M3ndEJynnp5ZD/TTs0RGubH5ssg==} - engines: {node: '>=12'} + '@tanstack/virtual-file-routes@1.162.0': + resolution: {integrity: sha512-uhOeFyxLcU41HzvrxsGpiWdcMbScY1EDgbZ5K7DVRMYInbLYWAC0EA/kx9wXAoSM8q82bUG2hRl8+EAjE6XAbA==} + engines: {node: '>=20.19'} - '@testing-library/dom@10.4.1': - resolution: {integrity: sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==} + '@testing-library/dom@10.4.2': + resolution: {integrity: sha512-yzr2S9HyAIdhz2/6qHgbs665Q7PKVcDF05vsOlHPxG1mo36gKVesdYVeDLnXgfjJ03CrKRk08knc6+E/9m8v2Q==} 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/jest-dom@7.0.1': + resolution: {integrity: sha512-oMDTC3oA+6CXSO2JZnvOI7CA6oVub6kij5ggk9ohwye5slmkwxYDXcPOVxgMw/RQlticjtO0C1RZkR97HgrWMw==} + engines: {node: '>=22', npm: '>=6', yarn: '>=1'} + peerDependencies: + '@testing-library/dom': '>=10 <11' + vitest: '>= 0.32' + peerDependenciesMeta: + vitest: + optional: true - '@testing-library/react@16.3.0': - resolution: {integrity: sha512-kFSyxiEDwv1WLl2fgsq6pPBbw5aWKrsY2/noi1Id0TK0UParSF62oFQFGHXIyaG4pp2tEub/Zlel+fjjZILDsw==} + '@testing-library/react@16.3.3': + resolution: {integrity: sha512-Uo193NgQbPMz6lrrhtRQQFcMC6Re/ELLFbbuVL30WDlZxlpZf9/lMHTAVxPRLw1q1iu9OJmR1c2BLiENRstdBg==} engines: {node: '>=18'} peerDependencies: '@testing-library/dom': ^10.0.0 @@ -3696,66 +3532,56 @@ packages: '@types/react-dom': optional: true - '@testing-library/user-event@14.6.1': - resolution: {integrity: sha512-vq7fv0rnt+QTXgPxr5Hjc210p6YKq2kmdziLgnsZGgLJ9e6VAShx1pACLuRjd/AS/sr7phAR58OIIpf0LlmQNw==} + '@testing-library/user-event@14.6.7': + resolution: {integrity: sha512-MPCpX8bxe8zS+JmmTwLp8jd0dy1rAm60Te/SL8JrQM3qvQJcBOs1d7IefJMyZzqM3EWBrDn/LWDt1BCGu4ASfg==} engines: {node: '>=12', npm: '>=6'} peerDependencies: '@testing-library/dom': '>=7.21.4' - '@trpc/client@11.7.2': - resolution: {integrity: sha512-OQxqUMfpDvjcszo9dbnqWQXnW2L5IbrKSz2H7l8s+mVM3EvYw7ztQ/gjFIN3iy0NcamiQfd4eE6qjcb9Lm+63A==} + '@trickfilm400/rollup-plugin-off-main-thread@3.0.0-pre1': + resolution: {integrity: sha512-/67zpWDBLV+oYAEL682s1ktXL0HgqX76f6gaVGkGnVZlBbm1zd0v4Bz8MFF2GGhoX9rvfq3KSQHubFHwa6w6/Q==} + engines: {node: '>=12'} + + '@trpc/client@11.19.0': + resolution: {integrity: sha512-0MKkPq6MejsKB5Opca1Rl22KVIaqo2+A1EiXyZ8EGUsl9TLrPdpGn+Usux20TZKFwnSC2+wI/WilqNJaP4ODfw==} + hasBin: true peerDependencies: - '@trpc/server': 11.7.2 + '@trpc/server': 11.19.0 typescript: '>=5.7.2' - '@trpc/react-query@11.7.2': - resolution: {integrity: sha512-IcLDMqx2mvlGRxkr0/m37TtPvRQ8nonITH3EwYv436x0Igx8eduR9z4tdgGBsjJY9e5W1G7cZ4zKCwrizSimFQ==} + '@trpc/react-query@11.19.0': + resolution: {integrity: sha512-TrqZBa/6weXX27mf0P2dMCI65duqO3B/wf9BkP1MezUWSUg7SRGJrIv6K8vjgjeHdafFBI1mmcqPEYXHF4AlVQ==} peerDependencies: '@tanstack/react-query': ^5.80.3 - '@trpc/client': 11.7.2 - '@trpc/server': 11.7.2 + '@trpc/client': 11.19.0 + '@trpc/server': 11.19.0 react: '>=18.2.0' - react-dom: '>=18.2.0' typescript: '>=5.7.2' - '@trpc/server@11.7.2': - resolution: {integrity: sha512-AgB26PXY69sckherIhCacKLY49rxE2XP5h38vr/KMZTbLCL1p8IuIoKPjALTcugC2kbyQ7Lbqo2JDVfRSmPmfQ==} + '@trpc/server@11.19.0': + resolution: {integrity: sha512-7C1goiDurz82yFKtZUbEzjXd0Rg/jyisaIZQhdvus+1l7E6mwcEYZXjZ1US/HF8kOyz1LERL8UN3bcboJtjcyQ==} + hasBin: true peerDependencies: typescript: '>=5.7.2' '@ts-morph/common@0.27.0': resolution: {integrity: sha512-Wf29UqxWDpc+i61k3oIOzcUfQt79PIT9y/MWfAGlrkjg6lBC1hwDECLXPVJAhWjiGbfBCxZd65F/LIZF3+jeJQ==} - '@tybys/wasm-util@0.10.1': - resolution: {integrity: sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==} + '@tybys/wasm-util@0.10.4': + resolution: {integrity: sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==} '@types/aria-query@5.0.4': resolution: {integrity: sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==} - '@types/babel__core@7.20.5': - resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - - '@types/babel__generator@7.27.0': - resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - - '@types/babel__template@7.4.4': - resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - - '@types/babel__traverse@7.28.0': - resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - '@types/bcrypt@6.0.0': resolution: {integrity: sha512-/oJGukuH3D2+D+3H4JWLaAsJ/ji86dhRidzZ/Od7H/i8g+aCmvkeCc6Ni/f9uxGLSQVCRZkX2/lqEFG2BvWtlQ==} - '@types/better-sqlite3@7.6.13': - resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} + '@types/better-sqlite3@9.6.0': + resolution: {integrity: sha512-ZEEwBSgMu7GYJOynoagg5X9JbxfL6dTJDsgViJIqh67jV44kyOr9RXfmFjLK5rzC4MWssP06t9hu/JwGDnUbCg==} '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - '@types/connect@3.4.38': - resolution: {integrity: sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==} - '@types/cors@2.8.19': resolution: {integrity: sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==} @@ -3777,8 +3603,8 @@ packages: '@types/d3-scale@4.0.9': resolution: {integrity: sha512-dLmtwB8zkAeO/juAMfnV+sItKjlsw2lKdZVVy6LRr0cBmegxSABiLEpGVmSJJ8O08i4+sGR6qQtb6WtuwJdvVw==} - '@types/d3-shape@3.1.7': - resolution: {integrity: sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==} + '@types/d3-shape@3.2.0': + resolution: {integrity: sha512-kVd74ta9eof3eJOvbNd1vGKS/XERRyQbT26Og63hIsvDO84cjD5gEOhsXf26w3FSoNlPVz84DOFcKv/oou+fMw==} '@types/d3-time@3.0.4': resolution: {integrity: sha512-yuzZug1nkAAaBlBBikKZTgzCeA+k1uy4ZFwWANOfKw5z5LRhV0gNA7gNkKm7HoK+HRN0wX3EkxGk0fpbWhmB7g==} @@ -3789,55 +3615,37 @@ packages: '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - '@types/estree@0.0.39': - resolution: {integrity: sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw==} + '@types/esrecurse@4.3.1': + resolution: {integrity: sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==} - '@types/estree@1.0.8': - resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - '@types/mysql@2.15.27': - resolution: {integrity: sha512-YfWiV16IY0OeBfBCk8+hXKmdTKrKlwKN1MNKAPBu5JYxLwBEZl7QzeEpGnlZb3VMGJrrGmB84gXiH+ofs/TezA==} - '@types/node-cron@3.0.11': resolution: {integrity: sha512-0ikrnug3/IyneSHqCBeslAhlK2aBfYek1fGo4bP4QnZPmiqSGRK+Oy7ZMisLWkesffJvQ1cqAcBnJC+8+nxIAg==} - '@types/node@22.19.1': - resolution: {integrity: sha512-LCCV0HdSZZZb34qifBsyWlUmok6W7ouER+oQIGBScS8EsZsQbrtFTUrDX4hOl+CS6p7cnNC4td+qrSVGSCTUfQ==} + '@types/node@24.13.5': + resolution: {integrity: sha512-TXyindR+lBr22aJIdMQzCFHPHR6cR4js838mRDCSz5hOKWZvZwsXSSiXDmjRj4iJmgl+sR9O+1mkoVBSMadNug==} - '@types/node@24.10.1': - resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} + '@types/node@26.6.1': + resolution: {integrity: sha512-VqGJBMCtdhqkBUCcBLvywI0NJ+KLuVzgNnlBUNFOQjqVxzo2lxLUNg1DSey8+u2u6ktswSAxg+s68QLzWHNOuA==} - '@types/pg-pool@2.0.6': - resolution: {integrity: sha512-TaAUE5rq2VQYxab5Ts7WZhKNmuN78Q6PiFonTDdpbx8a1H0M1vhy3rhiMjl+e2iHmogyMw7jZF4FrE6eJUy5HQ==} - - '@types/pg@8.15.5': - resolution: {integrity: sha512-LF7lF6zWEKxuT3/OR8wAZGzkg4ENGXFNyiV/JeOt9z5B+0ZVwbql9McqX5c/WStFq1GaGso7H1AzP/qSzmlCKQ==} - - '@types/react-dom@19.2.3': - resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + '@types/react-dom@19.3.0': + resolution: {integrity: sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==} peerDependencies: - '@types/react': ^19.2.0 + '@types/react': ^19.3.0 - '@types/react@19.2.6': - resolution: {integrity: sha512-p/jUvulfgU7oKtj6Xpk8cA2Y1xKTtICGpJYeJXz2YVO2UcvjQgeRMLDGfDeqeRW2Ta+0QNFwcc8X3GH8SxZz6w==} + '@types/react@19.3.0': + resolution: {integrity: sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==} '@types/resolve@1.20.2': resolution: {integrity: sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==} - '@types/sanitize-html@2.16.0': - resolution: {integrity: sha512-l6rX1MUXje5ztPT0cAFtUayXF06DqPhRyfVXareEN5gGCFaP/iwsxIyKODr9XDhfxPpN6vXUFNfo5kZMXCxBtw==} - - '@types/shimmer@1.2.0': - resolution: {integrity: sha512-UE7oxhQLLd9gub6JKIAhDq06T0F6FnztwMNRvYgjeQSBeMc1ZG/tA47EwfduvkuQS8apbkM/lpLpWsaCeYsXVg==} - - '@types/statuses@2.0.6': - resolution: {integrity: sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==} - - '@types/tedious@4.0.14': - resolution: {integrity: sha512-KHPsfX/FoVbUGbyYvk1q9MMQHLPeRZhRJZdO45Q4YjvFkv4hMNghCWTvy7rdKessBsmtz4euWCWAB6/tVpI1Iw==} + '@types/sanitize-html@2.16.1': + resolution: {integrity: sha512-n9wjs8bCOTyN/ynwD8s/nTcTreIHB1vf31vhLMGqUPNHaweKC4/fAl4Dj+hUlCTKYgm4P3k83fmiFfzkZ6sgMA==} '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} @@ -3845,117 +3653,259 @@ packages: '@types/use-sync-external-store@0.0.6': resolution: {integrity: sha512-zFDAD+tlpf2r4asuHEj0XH6pY6i0g5NeAHPn+15wk3BV6JA69eERFXC1gyGThDkVa1zCyKr5jox1+2LbV/AMLg==} - '@typescript-eslint/eslint-plugin@8.47.0': - resolution: {integrity: sha512-fe0rz9WJQ5t2iaLfdbDc9T80GJy0AeO453q8C3YCilnGozvOyCG5t+EZtg7j7D88+c3FipfP/x+wzGnh1xp8ZA==} + '@types/validate-npm-package-name@4.0.2': + resolution: {integrity: sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==} + + '@types/ws@8.18.1': + resolution: {integrity: sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==} + + '@typescript-eslint/eslint-plugin@8.70.0': + resolution: {integrity: sha512-/v8HZt6RlyIZxB3ntehELOcUcfxKPVGWXnQdJuHRmzrqgF8nQypcC/oxGW+Ot4VGKDq81XugPKxx0n5PBtf9PA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - '@typescript-eslint/parser': ^8.47.0 - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + '@typescript-eslint/parser': ^8.70.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/parser@8.47.0': - resolution: {integrity: sha512-lJi3PfxVmo0AkEY93ecfN+r8SofEqZNGByvHAI3GBLrvt1Cw6H5k1IM02nSzu0RfUafr2EvFSw0wAsZgubNplQ==} + '@typescript-eslint/parser@8.70.0': + resolution: {integrity: sha512-zYvrmj9Yxd63UGaXw+kdt6A0F0s0qveJyuatIM77bYC2DE4pgmg7a50u8LR7PRtXd0x+h+Tl3eXabGm06SWd3Q==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/project-service@8.47.0': - resolution: {integrity: sha512-2X4BX8hUeB5JcA1TQJ7GjcgulXQ+5UkNb0DL8gHsHUHdFoiCTJoYLTpib3LtSDPZsRET5ygN4qqIWrHyYIKERA==} + '@typescript-eslint/project-service@8.70.0': + resolution: {integrity: sha512-hFHbTNqhU9G+2eKFXCBVb1tjFT/LceiJ4+HfLO4pTpDI0KHi6iajpcFFkaSQ9gXmCh7n82A0PthaayEdN6mspQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/scope-manager@8.47.0': - resolution: {integrity: sha512-a0TTJk4HXMkfpFkL9/WaGTNuv7JWfFTQFJd6zS9dVAjKsojmv9HT55xzbEpnZoY+VUb+YXLMp+ihMLz/UlZfDg==} + '@typescript-eslint/scope-manager@8.70.0': + resolution: {integrity: sha512-8nP3Kwh5hlgZ4FicGvmznAmJe8UL4sdU8tLukrPaMuQmDuk4Y8xYfzu/aYZW4xT2JCgc7H/TpDI5cGlxcWJSqQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/tsconfig-utils@8.47.0': - resolution: {integrity: sha512-ybUAvjy4ZCL11uryalkKxuT3w3sXJAuWhOoGS3T/Wu+iUu1tGJmk5ytSY8gbdACNARmcYEB0COksD2j6hfGK2g==} + '@typescript-eslint/tsconfig-utils@8.70.0': + resolution: {integrity: sha512-adnkeeNq9Sq1sUf4+FRVc0KdgYghzsgFpZSQVZVvY0LCuUuN0FnQgyGzCJeC4fW1cdXseBAjU2EOqUIjbNcZUw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/type-utils@8.47.0': - resolution: {integrity: sha512-QC9RiCmZ2HmIdCEvhd1aJELBlD93ErziOXXlHEZyuBo3tBiAZieya0HLIxp+DoDWlsQqDawyKuNEhORyku+P8A==} + '@typescript-eslint/type-utils@8.70.0': + resolution: {integrity: sha512-NUMKIhYVaVIVLnRL9CRt+VVcuLgSHUCpXn4/+K8wql+vdInUzvx8BjUO1oJ7cG9shjFJKtF8F8Hh2kCh3/KBVw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/types@8.47.0': - resolution: {integrity: sha512-nHAE6bMKsizhA2uuYZbEbmp5z2UpffNrPEqiKIeN7VsV6UY/roxanWfoRrf6x/k9+Obf+GQdkm0nPU+vnMXo9A==} + '@typescript-eslint/types@8.70.0': + resolution: {integrity: sha512-asTOIYhDg4zdzOScCyaytrsV3cR6B4ecPQlXw/dJIm7J/MZTtCtfVII9JD8Geh4jTCrK/Xe6cg5UevoleMcoJQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@typescript-eslint/typescript-estree@8.47.0': - resolution: {integrity: sha512-k6ti9UepJf5NpzCjH31hQNLHQWupTRPhZ+KFF8WtTuTpy7uHPfeg2NM7cP27aCGajoEplxJDFVCEm9TGPYyiVg==} + '@typescript-eslint/typescript-estree@8.70.0': + resolution: {integrity: sha512-d9NmHMPEKQ7QCLLm1jI3zmoQBwT5KwFYjXBJ9ymZfKCUU+5rmTRykKAFvH5Qn/ZCds3CEAFS9OC9M/jkl0X2bA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - typescript: '>=4.8.4 <6.0.0' + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/utils@8.47.0': - resolution: {integrity: sha512-g7XrNf25iL4TJOiPqatNuaChyqt49a/onq5YsJ9+hXeugK+41LVg7AxikMfM02PC6jbNtZLCJj6AUcQXJS/jGQ==} + '@typescript-eslint/utils@8.70.0': + resolution: {integrity: sha512-oZmtKJz/4fufZ2p3+Cn3ijEojcdfR+1zYDH2xKYrEly0dR/Q/1xUPRCOlKGxod78nWlU2UnDe09GZ3TaknBFGA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - '@typescript-eslint/visitor-keys@8.47.0': - resolution: {integrity: sha512-SIV3/6eftCy1bNzCQoPmbWsRLujS8t5iDIZ4spZOBHqrM+yfX2ogg8Tt3PDTAVKw3sSCiUgg30uOAvK2r9zGjQ==} + '@typescript-eslint/visitor-keys@8.70.0': + resolution: {integrity: sha512-BoC8PiO4Hkdo0TVJh9Ntxr5MxPDI7/oFsrygN5ADelFSeXG/qgNuucIGA+L5Z6JpPTE/uRfcTWtscjbUaufepQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - '@vercel/oidc@3.1.0': - resolution: {integrity: sha512-Fw28YZpRnA3cAHHDlkt7xQHiJ0fcL+NRcIqsocZQUSmbzeIKRpwttJjik5ZGanXP+vlA4SbTg+AbA3bP363l+w==} + '@typescript/typescript-aix-ppc64@7.0.2': + resolution: {integrity: sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [aix] + + '@typescript/typescript-darwin-arm64@7.0.2': + resolution: {integrity: sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [darwin] + + '@typescript/typescript-darwin-x64@7.0.2': + resolution: {integrity: sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [darwin] + + '@typescript/typescript-freebsd-arm64@7.0.2': + resolution: {integrity: sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [freebsd] + + '@typescript/typescript-freebsd-x64@7.0.2': + resolution: {integrity: sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [freebsd] + + '@typescript/typescript-linux-arm64@7.0.2': + resolution: {integrity: sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [linux] + + '@typescript/typescript-linux-arm@7.0.2': + resolution: {integrity: sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==} + engines: {node: '>=16.20.0'} + cpu: [arm] + os: [linux] + + '@typescript/typescript-linux-loong64@7.0.2': + resolution: {integrity: sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==} + engines: {node: '>=16.20.0'} + cpu: [loong64] + os: [linux] + + '@typescript/typescript-linux-mips64el@7.0.2': + resolution: {integrity: sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==} + engines: {node: '>=16.20.0'} + cpu: [mips64el] + os: [linux] + + '@typescript/typescript-linux-ppc64@7.0.2': + resolution: {integrity: sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==} + engines: {node: '>=16.20.0'} + cpu: [ppc64] + os: [linux] + + '@typescript/typescript-linux-riscv64@7.0.2': + resolution: {integrity: sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==} + engines: {node: '>=16.20.0'} + cpu: [riscv64] + os: [linux] + + '@typescript/typescript-linux-s390x@7.0.2': + resolution: {integrity: sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==} + engines: {node: '>=16.20.0'} + cpu: [s390x] + os: [linux] + + '@typescript/typescript-linux-x64@7.0.2': + resolution: {integrity: sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [linux] + + '@typescript/typescript-netbsd-arm64@7.0.2': + resolution: {integrity: sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [netbsd] + + '@typescript/typescript-netbsd-x64@7.0.2': + resolution: {integrity: sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [netbsd] + + '@typescript/typescript-openbsd-arm64@7.0.2': + resolution: {integrity: sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [openbsd] + + '@typescript/typescript-openbsd-x64@7.0.2': + resolution: {integrity: sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [openbsd] + + '@typescript/typescript-sunos-x64@7.0.2': + resolution: {integrity: sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [sunos] + + '@typescript/typescript-win32-arm64@7.0.2': + resolution: {integrity: sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==} + engines: {node: '>=16.20.0'} + cpu: [arm64] + os: [win32] + + '@typescript/typescript-win32-x64@7.0.2': + resolution: {integrity: sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==} + engines: {node: '>=16.20.0'} + cpu: [x64] + os: [win32] + + '@vercel/oidc@3.2.0': + resolution: {integrity: sha512-UycprH3T6n3jH0k44NHMa7pnFHGu/N05MjojYr+Mc6I7obkoLIJujSWwin1pCvdy/eOxrI/l3uDLQsmcrOb4ug==} engines: {node: '>= 20'} - '@vitejs/plugin-react@5.1.1': - resolution: {integrity: sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==} + '@vitejs/plugin-react@6.1.1': + resolution: {integrity: sha512-yxLaQV9gkhS8ezJqCM6+ndU7mDY6gqAg75NQ+0IjwEI8IYOmQCgkRwHKVSfWXW076DsqMo0Dk+0FK1U+M5RgFw==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: - vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + oxc-transform-react: ^0.145.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + oxc-transform-react: + optional: true - '@vitest/coverage-v8@4.0.13': - resolution: {integrity: sha512-w77N6bmtJ3CFnL/YHiYotwW/JI3oDlR3K38WEIqegRfdMSScaYxwYKB/0jSNpOTZzUjQkG8HHEz4sdWQMWpQ5g==} + '@vitest/coverage-v8@5.0.1': + resolution: {integrity: sha512-FRC8ACiudC3dI6MTplzRSYWHDRnIv2IPfbzs4FdoJNsMal/35sWV8hwIfV8ZcqzSPy+uXHeMVONt9CEqtOU17w==} peerDependencies: - '@vitest/browser': 4.0.13 - vitest: 4.0.13 + '@vitest/browser': 5.0.1 + vitest: 5.0.1 peerDependenciesMeta: '@vitest/browser': optional: true - '@vitest/expect@4.0.13': - resolution: {integrity: sha512-zYtcnNIBm6yS7Gpr7nFTmq8ncowlMdOJkWLqYvhr/zweY6tFbDkDi8BPPOeHxEtK1rSI69H7Fd4+1sqvEGli6w==} + '@vitest/istanbul-lib-coverage@1.0.1': + resolution: {integrity: sha512-k3DJZ8LhMBK9NS4SclF1ASD3OgXEWDorbIcPTRDK0/Zae6fRvu+fJRxtFdLfHsa9Y24beCdPnoNZ4LviTNstfA==} + engines: {node: '>=22'} - '@vitest/mocker@4.0.13': - resolution: {integrity: sha512-eNCwzrI5djoauklwP1fuslHBjrbR8rqIVbvNlAnkq1OTa6XT+lX68mrtPirNM9TnR69XUPt4puBCx2Wexseylg==} + '@vitest/istanbul-lib-report@1.0.1': + resolution: {integrity: sha512-1EOLRfsTMnyAr3+kEAsP4o9dhaDlGPpD7H5iLBBeq//YpNB1VIahkPhB+eRp9N2Dkfw8oySROjE3yf9XDeaIkQ==} + engines: {node: '>=22'} + + '@vitest/mocker@5.0.1': + resolution: {integrity: sha512-6K1DoBNAPGvuOcSsGA4D6x+5zEEff/KmOOP3uetT2TrGpVfI+HRHRnJJfKi5ib/g1vx8IYHQD8s0pbJz8WQI7Q==} peerDependencies: msw: ^2.4.9 - vite: ^6.0.0 || ^7.0.0-0 + vite: ^6.0.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: msw: optional: true vite: optional: true - '@vitest/pretty-format@4.0.13': - resolution: {integrity: sha512-ooqfze8URWbI2ozOeLDMh8YZxWDpGXoeY3VOgcDnsUxN0jPyPWSUvjPQWqDGCBks+opWlN1E4oP1UYl3C/2EQA==} + '@vitest/pretty-format@5.0.1': + resolution: {integrity: sha512-6guWwj5d9bguuefTOvJoq387tfpkzSv554YdUEGzjJH2PnnmvzTLQ1UQSuAk5wBFVhf2CUmy/S/palOcb6dmpA==} - '@vitest/runner@4.0.13': - resolution: {integrity: sha512-9IKlAru58wcVaWy7hz6qWPb2QzJTKt+IOVKjAx5vb5rzEFPTL6H4/R9BMvjZ2ppkxKgTrFONEJFtzvnyEpiT+A==} + '@vitest/spy@5.0.1': + resolution: {integrity: sha512-rbto/mF/SGERxEgYOek7Xm6B9b+y+mVoo+f4b2LymYO8zM1b7uB5nHuhVMTP2hxdzgxvGiZYGxGIaMvL5y180Q==} - '@vitest/snapshot@4.0.13': - resolution: {integrity: sha512-hb7Usvyika1huG6G6l191qu1urNPsq1iFc2hmdzQY3F5/rTgqQnwwplyf8zoYHkpt7H6rw5UfIw6i/3qf9oSxQ==} + '@vitest/ui@5.0.1': + resolution: {integrity: sha512-7PvQu/X9/pQoHYfNLAYL22qsD4/+sx2k7zpUA7XvjW0sc40r3/r0lGZ2fsEyOHMuO8Q1KjiO1QQVjJdnWUy/WQ==} + peerDependencies: + vitest: 5.0.1 - '@vitest/spy@4.0.13': - resolution: {integrity: sha512-hSu+m4se0lDV5yVIcNWqjuncrmBgwaXa2utFLIrBkQCQkt+pSwyZTPFQAZiiF/63j8jYa8uAeUZ3RSfcdWaYWw==} + '@vitest/utils@5.0.1': + resolution: {integrity: sha512-E9+yEA+jsfaoxZcUHFzEqUrQcoNh2EwrPT5efIqkUPUwD5Ua2Li9BRWaYeRwvzvdLgTSVrre8oKNeyrfg7KkdQ==} - '@vitest/ui@4.0.13': - resolution: {integrity: sha512-MFV6GhTflgBj194+vowTB2iLI5niMZhqiW7/NV7U4AfWbX/IAtsq4zA+gzCLyGzpsQUdJlX26hrQ1vuWShq2BQ==} - peerDependencies: - vitest: 4.0.13 + '@workflow/serde@4.1.0': + resolution: {integrity: sha512-pav4F2BoirECWR7Nf1TKt+2eETcBj7jj4cBefQ8VXQCA6NPkaKeLfj/zMgi+3zYV5ZIBT4GuUiphsj0/b9hPQQ==} - '@vitest/utils@4.0.13': - resolution: {integrity: sha512-ydozWyQ4LZuu8rLp47xFUWis5VOKMdHjXCWhs1LuJsTNKww+pTHQNK4e0assIB9K80TxFyskENL6vCu3j34EYA==} + abbrev@5.0.0: + resolution: {integrity: sha512-/XrFJgzQQQHpti1raDJC6m4ws6aNktmjBlhk8Fdlk7LwCEuDoieEJJY9OFHjfiFJFFRM2tK+Ky/IsfbbmlMu1w==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} @@ -3965,44 +3915,34 @@ packages: resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} engines: {node: '>= 0.6'} - 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-walk@8.3.2: - resolution: {integrity: sha512-cjkyv4OtNCIeqhHrfS81QWXoCBPExR/J62oyEqepVw8WaQeSqpW2uhuLPh1m9eWhDuOo/jUXVTlifvesOWp/4A==} - engines: {node: '>=0.4.0'} - - acorn@8.14.0: - resolution: {integrity: sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==} - engines: {node: '>=0.4.0'} - hasBin: true - - acorn@8.15.0: - resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} + acorn@8.18.0: + resolution: {integrity: sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==} engines: {node: '>=0.4.0'} hasBin: true - agent-base@7.1.4: - resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} - engines: {node: '>= 14'} - aggregate-error@3.1.0: resolution: {integrity: sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==} engines: {node: '>=8'} - ai@6.0.19: - resolution: {integrity: sha512-LCqc4/ecL2jNvUfJ3vwz+UPuZvtPDONEjZJSw9XtYCjI6FuyBu9oJKlPMK2Mlj/10bWaNoJ+PnI+tDZLl4y06A==} - engines: {node: '>=18'} + ai@7.0.106: + resolution: {integrity: sha512-0W9AlZfyhOlPyE9ZXCFisg0uxxrmQMGdoVUz0ewRg5J+xAhVBomSspktqYeGWABFbQrYyWRVibnvSf24pTeE2w==} + engines: {node: '>=22'} peerDependencies: zod: ^3.25.76 || ^4.1.8 + ajv-formats@2.1.1: + resolution: {integrity: sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==} + peerDependencies: + ajv: ^8.0.0 + peerDependenciesMeta: + ajv: + optional: true + ajv-formats@3.0.1: resolution: {integrity: sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==} peerDependencies: @@ -4011,18 +3951,22 @@ packages: ajv: optional: true - ajv@6.12.6: - resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} - ajv@8.17.1: - resolution: {integrity: sha512-B/gBuNg5SiMTrPkC+A2+cW0RszwxYmn6VYxB/inlBStS5nx6xHIt/ehKRhIMhqusl7a8LjQoZnjCs5vhwxOQ1g==} + ajv@8.20.0: + resolution: {integrity: sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==} + + ansi-colors@4.1.3: + resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} + engines: {node: '>=6'} ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - ansi-regex@6.2.2: - resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + ansi-regex@6.3.0: + resolution: {integrity: sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==} engines: {node: '>=12'} ansi-styles@4.3.0: @@ -4037,16 +3981,15 @@ packages: resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} engines: {node: '>=12'} - ansis@4.2.0: - resolution: {integrity: sha512-HqZ5rWlFjGiV0tDm3UxxgNRqsOTniqoKZu0pIAfh7TZQMGuZK+hH0drySty0si0QXj1ieop4+SkSfPZBPPkHig==} + ansis@4.4.0: + resolution: {integrity: sha512-9k3v7xcHwgdO/DruxGIg4HtjvlAZlcnsX/mzqUb1t3NkYnl9kK2UJ+Gq0io+vQf7iT//BD/HB/NBkUR1LWxoeA==} engines: {node: '>=14'} any-promise@1.3.0: resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} - anymatch@3.1.3: - resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} - engines: {node: '>= 8'} + anynum@1.0.1: + resolution: {integrity: sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==} append-transform@2.0.0: resolution: {integrity: sha512-7yeyCEurROLQJFv5Xj4lEGTy0borxepjFv1g22oAdqFu//SrAlDl1O1Nxx15SH1RoliUml6p8dwJW9jvZughhg==} @@ -4084,12 +4027,12 @@ packages: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - ast-types@0.16.1: - resolution: {integrity: sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==} + ast-types@0.16.3: + resolution: {integrity: sha512-FvWoWYfSCM6kRxCSH+MGLHIKKGRL6A6AW7Zek2O32REPQRdg131428uRTKMBYAeRd3XXAaHDS60Wpri7CdKDrA==} engines: {node: '>=4'} - ast-v8-to-istanbul@0.3.8: - resolution: {integrity: sha512-szgSZqUxI5T8mLKvS7WTjF9is+MVbOeLADU73IseOcrqhxr/VAvy6wfoVE39KnKzA7JRhjF5eUagNlHwvZPlKQ==} + ast-v8-to-istanbul@1.0.6: + resolution: {integrity: sha512-fvpl29helSO2w/z7utIbrkNXILdrLwDwAMH2I/zPKlGf5244+gf+B4cyS1sANcrPY2h+hWCGSgC8N61s/+AF9A==} async-function@1.0.0: resolution: {integrity: sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==} @@ -4102,67 +4045,101 @@ packages: resolution: {integrity: sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==} engines: {node: '>= 4.0.0'} - atomically@2.1.0: - resolution: {integrity: sha512-+gDffFXRW6sl/HCwbta7zK4uNqbPjv4YJEAdz7Vu+FLQHe77eZ4bvbJGi4hE0QPeJlMYMA3piXEr1UL3dAwx7Q==} + atomically@1.7.0: + resolution: {integrity: sha512-Xcz9l0z7y9yQ9rdDaxlmaI4uJHf/T8g9hOEzJcsEqX2SjCj4J20uK7+ldkDHMbpJDK76wF7xEIgxc/vSlsfw5w==} + engines: {node: '>=10.12.0'} + + atomically@2.1.1: + resolution: {integrity: sha512-P4w9o2dqARji6P7MHprklbfiArZAWvo07yW7qs3pdljb3BWr12FIB7W+p0zJiuiVsUpRO0iZn1kFFcpPegg0tQ==} available-typed-arrays@1.0.7: resolution: {integrity: sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==} engines: {node: '>= 0.4'} - babel-dead-code-elimination@1.0.10: - resolution: {integrity: sha512-DV5bdJZTzZ0zn0DC24v3jD7Mnidh6xhKa4GfKCbq3sfW8kaWhDdZjP3i81geA8T33tdYqWKw4D3fVv0CwEgKVA==} + babel-dead-code-elimination@1.0.12: + resolution: {integrity: sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==} - babel-plugin-polyfill-corejs2@0.4.14: - resolution: {integrity: sha512-Co2Y9wX854ts6U8gAAPXfn0GmAyctHuK8n0Yhfjd6t30g7yvKjspvvOo9yG+z52PZRgFErt7Ka2pYnXCjLKEpg==} + babel-plugin-polyfill-corejs2@0.4.17: + resolution: {integrity: sha512-aTyf30K/rqAsNwN76zYrdtx8obu0E4KoUME29B1xj+B3WxgvWkp943vYQ+z8Mv3lw9xHXMHpvSPOBxzAkIa94w==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-corejs3@0.13.0: - resolution: {integrity: sha512-U+GNwMdSFgzVmfhNm8GJUX88AadB3uo9KpJqS3FaqNIPKgySuvMb+bHPsOmmuWyIcuqZj/pzt1RUIUZns4y2+A==} + babel-plugin-polyfill-corejs3@0.14.2: + resolution: {integrity: sha512-coWpDLJ410R781Npmn/SIBZEsAetR4xVi0SxLMXPaMO4lSf1MwnkGYMtkFxew0Dn8B3/CpbpYxN0JCgg8mn67g==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 - babel-plugin-polyfill-regenerator@0.6.5: - resolution: {integrity: sha512-ISqQ2frbiNU9vIJkzg7dlPpznPZ4jOiUQ1uSmB0fEHeowtN3COYRsXr/xexn64NpU13P06jc/L5TgiJXOgrbEg==} + babel-plugin-polyfill-regenerator@0.6.8: + resolution: {integrity: sha512-M762rNHfSF1EV3SLtnCJXFoQbbIIz0OyRwnCmV0KPC7qosSfCO0QLTSuJX3ayAebubhE6oYBAYPrBA5ljowaZg==} peerDependencies: '@babel/core': ^7.4.0 || ^8.0.0-0 <8.0.0 balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - base64-js@1.5.1: - resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} base64id@2.0.0: resolution: {integrity: sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==} engines: {node: ^4.5.0 || >= 5.9} - baseline-browser-mapping@2.9.2: - resolution: {integrity: sha512-PxSsosKQjI38iXkmb3d0Y32efqyA0uW4s41u4IVBsLlWLhCiYNpH/AfNOVWRqCQBlD8TFJTz6OUWNd4DFJCnmw==} + baseline-browser-mapping@2.11.25: + resolution: {integrity: sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==} + engines: {node: '>=6.0.0'} hasBin: true bcrypt@6.0.0: resolution: {integrity: sha512-cU8v/EGSrnH+HnxV2z0J7/blxH8gq7Xh2JFT6Aroax7UohdmiJJlxApMxtKfuI7z68NvvVcmR78k2LbT6efhRg==} engines: {node: '>= 18'} - better-auth@1.4.1: - resolution: {integrity: sha512-HDVE69Nw6Y1FPTcmFEmPolfsjMfVB5U823Ij9yWBoM8MdHZ2lA3JVus4xQJ2oRE1riJTlcSLFcgJKWGD7V7hmw==} + better-auth@1.7.5: + resolution: {integrity: sha512-aKE0Zt2EPTpFvmq4/oATNyG/mAfc6JUqWkW9pzGlrVnzUb0lso7GJ9BPxD6JPhLqYV1a9zOAb0uAz1Q5fm+eHA==} peerDependencies: '@lynx-js/react': '*' - '@sveltejs/kit': '*' - next: '*' - react: '*' - react-dom: '*' - solid-js: '*' - svelte: '*' - vue: '*' + '@prisma/client': ^5.0.0 || ^6.0.0 || ^7.0.0 + '@sveltejs/kit': ^2.0.0 + '@tanstack/react-start': ^1.0.0 + '@tanstack/solid-start': ^1.0.0 + drizzle-kit: '>=0.31.4 || >=1.0.0-beta.1' + drizzle-orm: ^0.45.2 || >=1.0.0-rc.1 <2.0.0 + mongodb: ^6.0.0 || ^7.0.0 + mysql2: ^3.0.0 + next: ^14.0.0 || ^15.0.0 || ^16.0.0 + pg: ^8.0.0 + prisma: ^5.0.0 || ^6.0.0 || ^7.0.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + solid-js: ^1.0.0 + svelte: ^4.0.0 || ^5.0.0 + vitest: ^2.0.0 || ^3.0.0 || ^4.0.0 || ^5.0.0 + vue: ^3.0.0 peerDependenciesMeta: '@lynx-js/react': optional: true + '@prisma/client': + optional: true '@sveltejs/kit': optional: true + '@tanstack/react-start': + optional: true + '@tanstack/solid-start': + optional: true + drizzle-kit: + optional: true + drizzle-orm: + optional: true + mongodb: + optional: true + mysql2: + optional: true next: optional: true + pg: + optional: true + prisma: + optional: true react: optional: true react-dom: @@ -4171,62 +4148,61 @@ packages: optional: true svelte: optional: true + vitest: + optional: true vue: optional: true - better-call@1.1.0: - resolution: {integrity: sha512-7CecYG+yN8J1uBJni/Mpjryp8bW/YySYsrGEWgFe048ORASjq17keGjbKI2kHEOSc6u8pi11UxzkJ7jIovQw6w==} - - better-sqlite3@12.4.6: - resolution: {integrity: sha512-gaYt9yqTbQ1iOxLpJA8FPR5PiaHP+jlg8I5EX0Rs2KFwNzhBsF40KzMZS5FwelY7RG0wzaucWdqSAJM3uNCPCg==} - engines: {node: 20.x || 22.x || 23.x || 24.x || 25.x} - - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} - - binary-extensions@2.3.0: - resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} - engines: {node: '>=8'} + better-call@1.4.0: + resolution: {integrity: sha512-bBKOT4vv1kZLDgxVePdilk/Jwkn+dtRRsmi3DzHcDP+WnswyVl6dR59l2HEeP/0cB+bDoopASAesWDPIdd/zZA==} + peerDependencies: + zod: ^4.0.0 + peerDependenciesMeta: + zod: + optional: true - bindings@1.5.0: - resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + better-sqlite3@13.0.3: + resolution: {integrity: sha512-RbOBxmLBG8uvFUc15X9+9SFemKcQ0WBuISBVkpuiaUB2qblC8UWlHEjdWVoZ8AdhSwmoEgsiXKfopX0CQxaACQ==} + engines: {node: '>=22'} - bl@4.1.0: - resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} + bidi-js@1.1.0: + resolution: {integrity: sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==} blake3-wasm@2.1.5: resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} - body-parser@2.2.1: - resolution: {integrity: sha512-nfDwkulwiZYQIGwxdy0RUmowMhKcFVcYXUU7m4QlKYim1rUtg83xm2yjZ40QjDuc291AJjjeSc9b++AWHSgSHw==} + body-parser@2.3.0: + resolution: {integrity: sha512-2cGmJupaNgg+QUwVLAucDuWuoMZ6EX9iHDRswZ5lsNYEmwPaRknMPCLZz07yTzVq/83p4o/wzbDZbBrTvGGTIw==} engines: {node: '>=18'} - brace-expansion@1.1.12: - resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} + brace-expansion@2.1.7: + resolution: {integrity: sha512-uZbew1NqdmPDTMJ8ah1y+b+9QEJrfkXFk3RcTQw3X0jW/xRUvFKsg1CfQdSYGdTbXZWExtU3J3ccxtnfw1Fi0g==} - brace-expansion@2.0.2: - resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} + brace-expansion@5.0.12: + resolution: {integrity: sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==} + engines: {node: 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==} + browserslist@4.29.0: + resolution: {integrity: sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true buffer-from@1.1.2: resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} - buffer@5.7.1: - resolution: {integrity: sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==} + bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} bundle-require@5.1.0: resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} peerDependencies: - esbuild: '>=0.25.0' + esbuild: '>=0.28.1' bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} @@ -4236,6 +4212,9 @@ packages: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} + cacheable@2.5.0: + resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==} + caching-transform@4.0.0: resolution: {integrity: sha512-kpqOvwXnjjN44D89K5ccQC+RUrsy7jB/XLlRrx0D7/2HNcTPqzsb6XgYoErwko6QsV184CA2YgS1fxDiiDZMWA==} engines: {node: '>=8'} @@ -4244,8 +4223,8 @@ packages: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - call-bind@1.0.8: - resolution: {integrity: sha512-oKlSFMcMwpUg2ednkhQ454wfWiU/ul3CkJe/PEHcTKuiX6RpbehUiFMXu13HalGZxfUwCQzZG747YXBn1im9ww==} + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} engines: {node: '>= 0.4'} call-bound@1.0.4: @@ -4260,40 +4239,34 @@ packages: resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} engines: {node: '>=6'} - caniuse-lite@1.0.30001756: - resolution: {integrity: sha512-4HnCNKbMLkLdhJz3TToeVWHSnfJvPaq6vu/eRP0Ahub/07n484XHhBF5AJoSGHdVrS8tKFauUQz8Bp9P7LVx7A==} - - caniuse-lite@1.0.30001759: - resolution: {integrity: sha512-Pzfx9fOKoKvevQf8oCXoyNRQ5QyxJj+3O0Rqx2V5oxT61KGx8+n6hV/IUyJeifUci2clnmmKVpvtiqRzgiWjSw==} + caniuse-lite@1.0.30001810: + resolution: {integrity: sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==} - chai@6.2.1: - resolution: {integrity: sha512-p4Z49OGG5W/WBCPSS/dH3jQ73kD6tiMmUM+bckNK6Jr5JHMG3k9bg/BvKR8lKmtVBKmOiuVaV2ws8s9oSbwysg==} + chai@6.2.2: + resolution: {integrity: sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==} engines: {node: '>=18'} - chalk@4.1.2: - resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} - engines: {node: '>=10'} - chalk@5.6.2: resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} - 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'} - chownr@1.1.4: - resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + chokidar@5.0.0: + resolution: {integrity: sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==} + engines: {node: '>= 20.19.0'} + + chownr@3.0.0: + resolution: {integrity: sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==} + engines: {node: '>=18'} - citty@0.1.6: - resolution: {integrity: sha512-tskPPKEs8D2KPafUypv2gxwJP8h/OaJmC82QQGGDQcHvXX43xF2VDACcJVmZ0EuSxkpO9Kc4MlrA3q0+FG58AQ==} + citty@0.2.2: + resolution: {integrity: sha512-+6vJA3L98yv+IdfKGZHBNiGW5KHn22e/JwID0Strsz8h4S/csAu/OuICwxrg44k5MRiZHWIo8XXuJgQTriRP4w==} - cjs-module-lexer@1.4.3: - resolution: {integrity: sha512-9z8TZaGM1pfswYeXrUpzPrkx8UnWYdhJclsiYMm6x/w5+nN+8Tf/LnAgfLGQCm59qAOxU8WwHEq2vNwF6i4j+Q==} + cjs-module-lexer@2.2.1: + resolution: {integrity: sha512-Ca8swihM+/4yKecYHY52kgJd300hi2lADU/a1RxNTRe+RJ9jvqQlESpbz9DnG9mowez8qwXHB8qYdIUw9e+F5Q==} class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} @@ -4310,13 +4283,6 @@ packages: resolution: {integrity: sha512-ywqV+5MmyL4E7ybXgKys4DugZbX0FC6LnwrhjuykIjnK9k8OQacQ7axGKnjDXWNhns0xot3bZI5h55H8yo9cJg==} engines: {node: '>=6'} - cli-width@4.1.0: - resolution: {integrity: sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==} - engines: {node: '>= 12'} - - client-only@0.0.1: - resolution: {integrity: sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==} - cliui@6.0.0: resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} @@ -4324,6 +4290,10 @@ packages: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} + cliui@9.0.1: + resolution: {integrity: sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==} + engines: {node: '>=20'} + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} @@ -4334,6 +4304,11 @@ packages: react: ^18 || ^19 || ^19.0.0-rc react-dom: ^18 || ^19 || ^19.0.0-rc + cn@0.2.6: + resolution: {integrity: sha512-+i4L0zUGgRcEnhsxueVrP7iBGxBx5iD0WOTYg1MwFEu2ZyCmH5Ov2V1cul2Ht5UchRQQgftCf4be/RxspuW6QQ==} + engines: {node: '>=20'} + hasBin: true + code-block-writer@13.0.3: resolution: {integrity: sha512-Oofo0pq3IKnsFtuHqSF7TqBfr71aeyZDVJ0HpmqB7FBM2qEigL0iPONSCZSO9pE9dZTAxANe5XHG9Uy0YMv8cg==} @@ -4344,13 +4319,6 @@ packages: color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - color-string@1.9.1: - resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==} - - color@4.2.3: - resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==} - engines: {node: '>=12.5.0'} - commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -4359,8 +4327,8 @@ packages: resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} engines: {node: '>=18'} - commander@14.0.2: - resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} engines: {node: '>=20'} commander@2.20.3: @@ -4377,44 +4345,46 @@ packages: commondir@1.0.1: resolution: {integrity: sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==} - concat-map@0.0.1: - resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - - concurrently@9.2.1: - resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} - engines: {node: '>=18'} + concurrently@10.0.5: + resolution: {integrity: sha512-JaP/CoftUrCcAFW/g//RbgEGwlelnEae6cfBLgH6ZdO6s8jPkn6p9SB9u6pdVxYXoiSnFqseOlHfrEfF82TVOg==} + engines: {node: '>=22'} hasBin: true - conf@15.0.2: - resolution: {integrity: sha512-JBSrutapCafTrddF9dH3lc7+T2tBycGF4uPkI4Js+g4vLLEhG6RZcFi3aJd5zntdf5tQxAejJt8dihkoQ/eSJw==} + conf@10.2.0: + resolution: {integrity: sha512-8fLl9F04EJqjSqH+QjITQfJF8BrOVaYr1jewVgSRAEWePfxT0sku4w2hrGQ60BC/TNLGQ2pgxNlTbWQmMPFvXg==} + engines: {node: '>=12'} + + conf@15.1.0: + resolution: {integrity: sha512-Uy5YN9KEu0WWDaZAVJ5FAmZoaJt9rdK6kH+utItPyGsCqCgaTKkrmZx3zoE0/3q6S3bcp3Ihkk+ZqPxWxFK5og==} engines: {node: '>=20'} confbox@0.1.8: resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} - confbox@0.2.2: - resolution: {integrity: sha512-1NB+BKqhtNipMsov4xI/NnhCKp9XG9NamYp5PVm9klAT0fsrNPjaFICsCFhNhwZJKNh7zB/3q8qXz0E9oaMNtQ==} - consola@3.4.2: resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} engines: {node: ^14.18.0 || >=16.10.0} - content-disposition@1.0.1: - resolution: {integrity: sha512-oIXISMynqSqm241k6kcQ5UwttDILMK4BiurCfGEREw6+X9jkkpEe5T9FZaApyLGGOnFuyMWZpdolTXMtvEJ08Q==} + content-disposition@1.1.0: + resolution: {integrity: sha512-5jRCH9Z/+DRP7rkvY83B+yGIGX96OYdJmzngqnw2SBSxqCFPd0w2km3s5iawpGX8krnwSGmF0FW5Nhr0Hfai3g==} engines: {node: '>=18'} content-type@1.0.5: resolution: {integrity: sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==} engines: {node: '>= 0.6'} + content-type@2.1.0: + resolution: {integrity: sha512-mj7UPXE0jaqaOsukNZRUEfEi2AcL7C/vwmwcHV0O97eO1E1pxBZuyjlZrx5seTaNBg1U6+o35wpa35Qfcc+7ag==} + engines: {node: '>=18'} + convert-source-map@1.9.0: resolution: {integrity: sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==} convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - cookie-es@2.0.0: - resolution: {integrity: sha512-RAj4E421UYRgqokKUmotqAwuplYw15qtdXfY+hGzgCJ/MBjCVZcSoHK/kH9kocfjRjcDME7IiDWR/1WX1TM2Pg==} + cookie-es@3.1.1: + resolution: {integrity: sha512-UaXxwISYJPTr9hwQxMFYZ7kNhSXboMXP+Z3TRX6f1/NyaGPfuNUZOWP1pUEb75B2HjfklIYLVRfWiFZJyC6Npg==} cookie-signature@1.2.2: resolution: {integrity: sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg==} @@ -4424,27 +4394,24 @@ packages: resolution: {integrity: sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==} engines: {node: '>= 0.6'} - cookie@1.0.2: - resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} - engines: {node: '>=18'} - cookie@1.1.1: resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} engines: {node: '>=18'} - copy-anything@4.0.5: - resolution: {integrity: sha512-7Vv6asjS4gMOuILabD3l739tsaxFQmC+a7pLZm02zyvs8p977bL3zEgq3yDk5rn9B0PbYgIv++jmHcuUab4RhA==} + copy-anything@4.1.0: + resolution: {integrity: sha512-ufbM3smX/Jbnpk5wcQjzd1MgBpzmqfNETUAyZNrGwU9foRlyHoGzMMBBCRzEhQLBjZfFDE1W2ufPXX2vdWkV8Q==} engines: {node: '>=18'} - core-js-compat@3.47.0: - resolution: {integrity: sha512-IGfuznZ/n7Kp9+nypamBhvwdwLsW6KC8IOaURw2doAK5e98AG3acVLdh0woOnEqCfUtS+Vu882JE4k/DAm3ItQ==} + core-js-compat@3.50.0: + resolution: {integrity: sha512-XGpFGbMLHwSt74YLTKho7Ib242qi6O8MSX+sRokV4oz7iKXvQWGYZthjIhjRGMxjzVkAubBO512dKGYcefmX3Q==} + engines: {node: '>=6.4.0'} - cors@2.8.5: - resolution: {integrity: sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==} + cors@2.8.6: + resolution: {integrity: sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==} engines: {node: '>= 0.10'} - cosmiconfig@9.0.0: - resolution: {integrity: sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==} + cosmiconfig@9.0.2: + resolution: {integrity: sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==} engines: {node: '>=14'} peerDependencies: typescript: '>=4.9.5' @@ -4460,8 +4427,8 @@ packages: resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==} engines: {node: '>=8'} - css-tree@3.1.0: - resolution: {integrity: sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==} + css-tree@3.2.1: + resolution: {integrity: sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==} engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0} css.escape@1.5.1: @@ -4472,10 +4439,6 @@ packages: engines: {node: '>=4'} hasBin: true - cssstyle@5.3.3: - resolution: {integrity: sha512-OytmFH+13/QXONJcC75QNdMtKpceNk3u8ThBjyyYjkEcy/ekBwR1mMAuNvi3gdBPW3N5TlCzQ0WZw8H0lN/bDw==} - engines: {node: '>=20'} - csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} @@ -4491,8 +4454,8 @@ packages: resolution: {integrity: sha512-wR/XK3D3XcLIZwpbvQwQ5fK+8Ykds1ip7A2Txe0yxncXSdq1L9skcG7blcedkOX+ZcgxGAmLX1FrRGbADwzi0w==} engines: {node: '>=12'} - d3-format@3.1.0: - resolution: {integrity: sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==} + d3-format@3.1.2: + resolution: {integrity: sha512-AJDdYOdnyRDV5b6ArilzCPPwc1ejkHcoyFarqlPqT7zRYjhavcT3uSrqcMvsgh2CgoPbK3RCwyHaVyxYcP2Arg==} engines: {node: '>=12'} d3-interpolate@3.0.1: @@ -4523,13 +4486,9 @@ packages: resolution: {integrity: sha512-ndfJ/JxxMd3nw31uyKoY2naivF+r29V+Lc0svZxe1JvvIRmi8hUsrMvdOwgS1o6uBHmiz91geQ0ylPP0aj1VUA==} engines: {node: '>=12'} - data-uri-to-buffer@4.0.1: - resolution: {integrity: sha512-0R9ikRb668HB7QDxT1vkpuUBtqc53YyAwMwGeUFKRojY/NWKvdZ+9UYtRfGmhqNbRkTSVpMbmyhXipFFv2cb/A==} - engines: {node: '>= 12'} - - data-urls@6.0.0: - resolution: {integrity: sha512-BnBS08aLUM+DKamupXs3w2tJJoqU+AkaE/+6vQxi/G/DPmIZFJJp9Dkb1kM03AZx8ADehDUZgsNxju3mPXZYIA==} - engines: {node: '>=20'} + data-urls@7.0.0: + resolution: {integrity: sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} data-view-buffer@1.0.2: resolution: {integrity: sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==} @@ -4543,6 +4502,13 @@ packages: resolution: {integrity: sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==} engines: {node: '>= 0.4'} + dayjs@1.11.23: + resolution: {integrity: sha512-QDTCU0M0MxR3hQfnlDJfwekQiaanm1ubOD231u73WBckQ/fsamwRLiE2GBz6D3a/xF1NgfiDLJjXBa1hYOYTtQ==} + + debounce-fn@4.0.0: + resolution: {integrity: sha512-8pYCQiL9Xdcg0UPSD3d+0KMlOjp+KGU5EPwYddgzQ7DATsg4fuUDjQtsYLmWjnk2obnNHgV3vE2Y4jejSOJVBQ==} + engines: {node: '>=10'} + debounce-fn@6.0.0: resolution: {integrity: sha512-rBMW+F2TXryBwB54Q0d8drNEI+TfoS9JpNTAoVpukbWEhjXQq4rySFYLaqXMFXwdv61Zb2OHtj5bviSoimqxRQ==} engines: {node: '>=18'} @@ -4551,15 +4517,6 @@ packages: resolution: {integrity: sha512-Xks6RUDLZFdz8LIdR6q0MTH44k7FikOmnh5xkSjMig6ch45afc8sjTjRQf3P6ax8dMgcQrYO/AR2RGWURrruqw==} engines: {node: '>=18'} - debug@4.3.7: - resolution: {integrity: sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==} - engines: {node: '>=6.0'} - peerDependencies: - supports-color: '*' - peerDependenciesMeta: - supports-color: - optional: true - debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} @@ -4579,22 +4536,14 @@ packages: decimal.js@10.6.0: resolution: {integrity: sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==} - decompress-response@6.0.0: - resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==} - engines: {node: '>=10'} - - dedent@1.7.0: - resolution: {integrity: sha512-HGFtf8yhuhGhqO07SV79tRp+br4MnbdjeVxotpn1QBl30pcLLCQjX5b2295ll0fv8RKDKsmWYrl05usHM9CewQ==} + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} peerDependencies: babel-plugin-macros: ^3.1.0 peerDependenciesMeta: babel-plugin-macros: optional: true - deep-extend@0.6.0: - resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==} - engines: {node: '>=4.0.0'} - deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} @@ -4602,6 +4551,14 @@ packages: resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} engines: {node: '>=0.10.0'} + default-browser-id@5.0.1: + resolution: {integrity: sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==} + engines: {node: '>=18'} + + default-browser@5.5.1: + resolution: {integrity: sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==} + engines: {node: '>=18'} + default-require-extensions@3.0.1: resolution: {integrity: sha512-eXTJmRbm2TIt9MgWTsOH1wEuhew6XGZcMeGKCtLedIg/NCsg1iBePXkceTdK4Fii7pzmN9tGsZhKzZ4h7O/fxw==} engines: {node: '>=8'} @@ -4610,12 +4567,20 @@ packages: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} + define-lazy-prop@2.0.0: + resolution: {integrity: sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==} + engines: {node: '>=8'} + + define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} - defu@6.1.4: - resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + defu@6.1.7: + resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} depd@2.0.0: resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} @@ -4632,8 +4597,8 @@ packages: detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - diff@8.0.2: - resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} + diff@8.0.4: + resolution: {integrity: sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==} engines: {node: '>=0.3.1'} dom-accessibility-api@0.5.16: @@ -4645,30 +4610,50 @@ packages: dom-serializer@2.0.0: resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==} + dom-serializer@3.1.1: + resolution: {integrity: sha512-4MEa38/QexBob6gFNwu+EGdWvhJ1OKuNwdYY3Y3NyeWDQfnGeDYQUDfIRzWu5B5gsv03so2Uxd28YC6zrsx3Lw==} + engines: {node: '>=20.19.0'} + domelementtype@2.3.0: resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==} + domelementtype@3.0.0: + resolution: {integrity: sha512-umCQid3jKbDmVjx8jGaW7uUykm4DEUeyV21hPxNMo2nV955DhUThwqyOIDtreepP31hl84X7G5U9ZfsWvIB3Pg==} + engines: {node: '>=20.19.0'} + domhandler@5.0.3: resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==} engines: {node: '>= 4'} + domhandler@6.0.1: + resolution: {integrity: sha512-gYzvtM72ZtxQO0T048kd6HWSbbGCNOUwcnfQ01cqIJ4X2IYKFFHZ5mKvrQETcFXxsRObZulDaKmy//R7TPtsBg==} + engines: {node: '>=20.19.0'} + domutils@3.2.2: resolution: {integrity: sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==} - dot-prop@10.1.0: - resolution: {integrity: sha512-MVUtAugQMOff5RnBy2d9N31iG0lNwg1qAoAOn7pOK5wf94WIaE3My2p3uwTQuvS2AcqchkcR3bHByjaM0mmi7Q==} + domutils@4.0.2: + resolution: {integrity: sha512-qI4JLRKnSzqFqr7hAlS5xQDusBCjKSEG4t4+7aNrIQMHBcsC2TGEhuyABJdYkgSewL57PNLYEiibY2iPKhKpaA==} + engines: {node: '>=20.19.0'} + + dot-prop@10.2.0: + resolution: {integrity: sha512-BTJ9aZYL3vCfZlZOBLy9v8TUqWGQ0pzFnygKwFZt5udj6viBoFIBviKPUoZLDCPn1FoXffv6McQFDenrm5Krfw==} engines: {node: '>=20'} - dotenv@17.2.3: - resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} + dot-prop@6.0.1: + resolution: {integrity: sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA==} + engines: {node: '>=10'} + + dotenv@17.4.2: + resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} - drizzle-kit@0.31.7: - resolution: {integrity: sha512-hOzRGSdyKIU4FcTSFYGKdXEjFsncVwHZ43gY3WU5Bz9j5Iadp6Rh6hxLSQ1IWXpKLBKt/d5y1cpSPcV+FcoQ1A==} + drizzle-kit@0.31.10: + resolution: {integrity: sha512-7OZcmQUrdGI+DUNNsKBn1aW8qSoKuTH7d0mYgSP8bAzdFzKoovxEFnoGQp2dVs82EOJeYycqRtciopszwUf8bw==} hasBin: true - drizzle-orm@0.44.7: - resolution: {integrity: sha512-quIpnYznjU9lHshEOAYLoZ9s3jweleHlZIAWR/jX9gAWNg/JhQ1wj0KGRf7/Zm+obRrYd9GjPVJg790QY9N5AQ==} + drizzle-orm@0.45.2: + resolution: {integrity: sha512-kY0BSaTNYWnoDMVoyY8uxmyHjpJW1geOmBMdSSicKo9CIIWkSxMIj2rkeSR51b8KAPB7m+qysjuHme5nKP+E5Q==} peerDependencies: '@aws-sdk/client-rds-data': '>=3' '@cloudflare/workers-types': '>=4' @@ -4769,13 +4754,6 @@ packages: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - eastasianwidth@0.2.0: - resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} - - eciesjs@0.4.16: - resolution: {integrity: sha512-dS5cbA9rA2VR4Ybuvhg6jvdmp46ubLn3E+px8cG/35aEDNclrqoCjg6mt0HYZ/M+OoESS3jSkCrqk1kWAEhWAw==} - engines: {bun: '>=1', deno: '>=2', node: '>=16'} - ee-first@1.1.1: resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} @@ -4784,8 +4762,8 @@ packages: engines: {node: '>=0.10.0'} hasBin: true - electron-to-chromium@1.5.264: - resolution: {integrity: sha512-1tEf0nLgltC3iy9wtlYDlQDc5Rg9lEKVjEmIHJ21rI9OcqkvD45K1oyNIRA4rR1z3LgJ7KeGzEBojVcV6m4qjA==} + electron-to-chromium@1.5.432: + resolution: {integrity: sha512-4qa5o+sI3qFR+p1C6wZvY99x6q/3tR34n+ezZvWiJ9s0HJaaKwN6h1HTupFfv4fiSdQYMZWtVFBuzHdAXo1BnA==} emoji-regex@10.6.0: resolution: {integrity: sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==} @@ -4793,39 +4771,37 @@ packages: emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - emoji-regex@9.2.2: - resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} - encodeurl@2.0.0: resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} engines: {node: '>= 0.8'} - end-of-stream@1.4.5: - resolution: {integrity: sha512-ooEGc6HP26xXq/N+GCGOT0JKCLDGrq2bQUZrQ7gyrJiZANJ/8YDTxTpQBXGMn+WbIQXNVpyWymm7KYVICQnyOg==} - engine.io-parser@5.2.3: resolution: {integrity: sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==} engines: {node: '>=10.0.0'} - engine.io@6.6.4: - resolution: {integrity: sha512-ZCkIjSYNDyGn0R6ewHDtXgns/Zre/NT6Agvq1/WobF7JXgFff4SeDroKiCO3fNJreU9YG429Sc81o4w5ok/W5g==} + engine.io@6.6.10: + resolution: {integrity: sha512-9/lX2bdlizlCXMHRMOIm03VBQHQYC7VvydcxtTAUJRxNW1QzM/2PMFSmr6h/lCiMHcyCP6abK+t9Q+j4vekk8Q==} engines: {node: '>=10.2.0'} - enhanced-resolve@5.18.3: - resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} + enhanced-resolve@5.25.1: + resolution: {integrity: sha512-nGXts5znJzmWPu+mIE9izCOzdg63oJca2mDzGWWTth7sr4aCToKcoyFVBQwN75Ij5Pf6p510EwkTqViTRzDV+w==} engines: {node: '>=10.13.0'} + enquirer@2.4.1: + resolution: {integrity: sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==} + engines: {node: '>=8.6'} + entities@4.5.0: resolution: {integrity: sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==} engines: {node: '>=0.12'} - entities@6.0.1: - resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} + entities@7.0.1: + resolution: {integrity: sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==} engines: {node: '>=0.12'} - entities@7.0.0: - resolution: {integrity: sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ==} - engines: {node: '>=0.12'} + entities@8.1.0: + resolution: {integrity: sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==} + engines: {node: '>=20.19.0'} env-paths@2.2.1: resolution: {integrity: sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==} @@ -4841,8 +4817,12 @@ packages: error-stack-parser-es@1.0.5: resolution: {integrity: sha512-5qucVt2XcuGMcEGgWI7i+yZpmpByQ8J1lHhcL7PwqCwu9FPP3VUXzT4ltHe5i2z9dePwEHcDVOAfSnHsOlCXRA==} - es-abstract@1.24.0: - resolution: {integrity: sha512-WSzPgsdLtTcQwm4CROfS5ju2Wa1QQcVeT37jFjYzdFz1r9ahadC8B8/a4qxJxM+09F18iumCdRmlr96ZYkQvEg==} + es-abstract-get@1.0.0: + resolution: {integrity: sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==} + engines: {node: '>= 0.4'} + + es-abstract@1.24.2: + resolution: {integrity: sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==} engines: {node: '>= 0.4'} es-define-property@1.0.1: @@ -4853,37 +4833,32 @@ packages: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - es-module-lexer@1.7.0: - resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} + es-module-lexer@2.3.2: + resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} - es-object-atoms@1.1.1: - resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} + es-module-lexer@3.0.2: + resolution: {integrity: sha512-BuIB67FngDSyQ/dpQNOZybwdEBDUGJQvOqwWr4ha/ufYiqzuEwPkKO2zLhRAgay28tStRIHUeWmszZAJo3GCOg==} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} engines: {node: '>= 0.4'} es-set-tostringtag@2.1.0: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - es-to-primitive@1.3.0: - resolution: {integrity: sha512-w+5mJ3GuFL+NjVtJlvydShqE1eN3h3PbI7/5LAsYJP/2qtuMXjfL2LpHSRqo4b4eSF5K/DH1JXKUAHSB2UW50g==} + es-to-primitive@1.3.4: + resolution: {integrity: sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==} engines: {node: '>= 0.4'} - es-toolkit@1.42.0: - resolution: {integrity: sha512-SLHIyY7VfDJBM8clz4+T2oquwTQxEzu263AyhVK4jREOAwJ+8eebaa4wM3nlvnAqhDrMm2EsA6hWHaQsMPQ1nA==} + es-toolkit@1.52.0: + resolution: {integrity: sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==} es6-error@4.1.1: resolution: {integrity: sha512-Um/+FxMr9CISWh0bi5Zv0iOD+4cFh5qLeks1qhAopKVAJw3drgKbKySikp7wGhDL0HPeaja0P5ULZrxLkniUVg==} - es6-promise@4.2.8: - resolution: {integrity: sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==} - - esbuild-register@3.6.0: - resolution: {integrity: sha512-H2/S7Pm8a9CL1uhp9OvjwrBh5Pvx0H8qVOxNu8Wed9Y7qv56MPtq+GGM8RJpq6glYJn9Wspr8uw7l55uyinNeg==} - peerDependencies: - esbuild: '>=0.25.0' - - esbuild@0.27.0: - resolution: {integrity: sha512-jd0f4NHbD6cALCyGElNpGAOtWxSq46l9X/sWB0Nzd5er4Kz2YTm+Vl0qKFT9KUJvD8+fiO8AvoHhFvEatfVixA==} + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} engines: {node: '>=18'} hasBin: true @@ -4903,41 +4878,32 @@ packages: peerDependencies: eslint: '>=8.0.0' - eslint-plugin-no-relative-import-paths@1.6.1: - resolution: {integrity: sha512-YZNeOnsOrJcwhFw0X29MXjIzu2P/f5X2BZDPWw1R3VUYBRFxNIh77lyoL/XrMU9ewZNQPcEvAgL/cBOT1P330A==} - - eslint-plugin-react-hooks@7.0.1: - resolution: {integrity: sha512-O0d0m04evaNzEPoSW+59Mezf8Qt0InfgGIBJnpC0h3NH/WjUAR7BIKUfysC6todmtiZ/A0oUVS8Gce0WhBrHsA==} + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} engines: {node: '>=18'} peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - - eslint-plugin-react-perf@3.3.3: - resolution: {integrity: sha512-EzPdxsRJg5IllCAH9ny/3nK7sv9251tvKmi/d3Ouv5KzI8TB3zNhzScxL9wnh9Hvv8GYC5LEtzTauynfOEYiAw==} - engines: {node: '>=6.9.1'} - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0 + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 - eslint-plugin-react-refresh@0.4.24: - resolution: {integrity: sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==} + eslint-plugin-react-refresh@0.5.7: + resolution: {integrity: sha512-XhJSzLljuYD4UjNuFGJu2v7aD3sqNVK12w5/DCUfrNfHWegZo2+TsavNx8MuxMwEquuFAzNbNfXKU0WoZ+YUIg==} peerDependencies: - eslint: '>=8.40' + eslint: ^9 || ^10 - eslint-scope@8.4.0: - resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint-scope@9.1.2: + resolution: {integrity: sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} 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.1: - resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + eslint@10.10.0: + resolution: {integrity: sha512-NPXn6r5zl4uET1DAVPaOwzX3rut4c0wcmw3dWJAfOsTM5+TogXo0DDjz8pwm/hL8cyVNpHqeK4JpN0NjnyFFNw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} hasBin: true peerDependencies: jiti: '*' @@ -4945,17 +4911,17 @@ packages: jiti: optional: true - espree@10.4.0: - resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + espree@11.2.0: + resolution: {integrity: sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} esprima@4.0.1: resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} engines: {node: '>=4'} hasBin: true - esquery@1.6.0: - resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} engines: {node: '>=0.10'} esrecurse@4.3.0: @@ -4966,9 +4932,6 @@ packages: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} - estree-walker@1.0.1: - resolution: {integrity: sha512-1fMXF3YP4pZZVozF8j/ZLfvnR8NSIljt56UhbZ5PeeDmmGHpgpdwQt7ITlGvYaQukCvuBRMLEiKiYC+oeIg4cg==} - estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -4979,15 +4942,19 @@ packages: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} + eta@4.6.0: + resolution: {integrity: sha512-lW6is4T1NFOYnmqGZIfvixqj7A7sSvScF+DN8EK6K58xI5MZ5UvYe0GjopxOXQtZvUn4eDdVuZ8XSoYWTMEKwA==} + engines: {node: '>=20'} + etag@1.8.1: resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} engines: {node: '>= 0.6'} - eventemitter3@5.0.1: - resolution: {integrity: sha512-GWkBvjiSZK87ELrYOSESUYeVIc9mvLLf/nXalMOS5dYrgZq9o5OVkbZAVM06CVxYsCwH9BDZFPlQTlPA1j4ahA==} + eventemitter3@5.0.4: + resolution: {integrity: sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==} - eventsource-parser@3.0.6: - resolution: {integrity: sha512-Vo1ab+QXPzZ4tCa8SwIHJFaSzy4R6SHf7BY79rFBDf0idraZWAkYrDjDj8uWaSm3S2TK+hJ7/t1CEmZ7jXw+pg==} + eventsource-parser@3.1.1: + resolution: {integrity: sha512-EKN1vKAMcZ8MlYMpaNuxN6R9yakzH6uajHcHVTqWJzvu5pWw9DyhbP35HH8MVBQ+dZjAfDxk+A8NiR9KWaXiyQ==} engines: {node: '>=18.0.0'} eventsource@3.0.7: @@ -5002,20 +4969,15 @@ packages: resolution: {integrity: sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==} engines: {node: ^18.19.0 || >=20.5.0} - exit-hook@2.2.1: - resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} - engines: {node: '>=6'} - - expand-template@2.0.3: - resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} - engines: {node: '>=6'} - - expect-type@1.2.2: - resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} + expect-type@1.4.0: + resolution: {integrity: sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==} engines: {node: '>=12.0.0'} - express-rate-limit@7.5.1: - resolution: {integrity: sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw==} + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + + express-rate-limit@8.7.0: + resolution: {integrity: sha512-hOwV7WOxXfjRpAM1DSJWZDXx3GhplwD8IfwuwvogD8i1Qnkgosw/H45s4ZnFAUHDAhPjlY9hLBvJhKmGMyY26g==} engines: {node: '>= 16'} peerDependencies: express: '>= 4.11' @@ -5024,9 +4986,6 @@ packages: resolution: {integrity: sha512-hIS4idWWai69NezIdRt2xFVofaF4j+6INOpJlVOLDO8zXGpUVEVzIYk12UUi2JzjEzWL3IOAxcTubgz9Po0yXw==} engines: {node: '>= 18'} - exsolve@1.0.8: - resolution: {integrity: sha512-LmDxfWXwcTArk8fUEnOfSZpHOJ6zOMUJKOtFLFqJLoKJetuQG874Uc7/Kki7zFLzYybmZhp1M7+98pfMqeX8yA==} - fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} @@ -5043,15 +5002,18 @@ packages: fast-sha256@1.3.0: resolution: {integrity: sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==} - fast-uri@3.1.0: - resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} + fast-uri@3.1.8: + resolution: {integrity: sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==} - fast-xml-parser@5.3.2: - resolution: {integrity: sha512-n8v8b6p4Z1sMgqRmqLJm3awW4NX7NkaKPfb3uJIBTSH7Pdvufi3PQ3/lJLQrvxcMYl7JI2jnDO90siPEpD8JBA==} + fast-xml-builder@1.3.1: + resolution: {integrity: sha512-pIM/1n3ntFXKYrUZwW7QCK0gAW7XY+wzj1YMIV3tLDvPj/V+zTGJK5e3/4WJfwj0qWw2ElNXiTixda/R+3YSug==} + + fast-xml-parser@5.11.1: + resolution: {integrity: sha512-TBw6K/fxoQGGjCmZDw9w/ZwP3uDcnTM4YH/g+PFRWr8sbe5idXtxNN6vITh4+1ruCZaho6uBFurElsA7F0zzgw==} hasBin: true - fastq@1.19.1: - resolution: {integrity: sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==} + fastq@1.20.3: + resolution: {integrity: sha512-XKv5nnLs6nLF71NgiKJLIZFLkPyIEuOselLG7ujZnGrRfQK8HpvY+WqKhAJUAdLomwVHErVS4LfxFlPq0/FTAw==} fd-package-json@2.0.0: resolution: {integrity: sha512-jKmm9YtsNXN789RS/0mSzOC1NUq9mkVd65vbSSVsKdjGvYXBuE4oWe2QOEoFeRmJg+lPuZxpmrfFclNhoRMneQ==} @@ -5065,29 +5027,21 @@ packages: picomatch: optional: true - feedsmith@2.6.0: - resolution: {integrity: sha512-XtLpe+bQr1uUGbwERq49/w6QfwlPv3pb/jgUA9i/dzJuCno8+XqUeeCEfnA03YT5cuHU0y683dxnkKcYjpW6xw==} - - fetch-blob@3.2.0: - resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} - engines: {node: ^12.20 || >= 14.13} + feedsmith@3.0.0: + resolution: {integrity: sha512-ePtwtkyWHAN0nkzSdOUJ6pTHdj5Zwh78vL3tmbEJOCXl5ixrdd3J+uve21rZstpn3odjS3Dh3j6hOFN4PTg9ag==} - fflate@0.8.2: - resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} + fflate@0.8.3: + resolution: {integrity: sha512-tbZNuJrLwGUp3zshBtdy4W+ORxZuIh8a5ilyIEQDC5rY1f3U20JMry0Ll3WBzU58EZKsEuJFXhb5gwv8CsPvgA==} figures@6.1.0: resolution: {integrity: sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==} engines: {node: '>=18'} - file-entry-cache@8.0.0: - resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} - engines: {node: '>=16.0.0'} - - file-uri-to-path@1.0.0: - resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + file-entry-cache@11.1.5: + resolution: {integrity: sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==} - filelist@1.0.4: - resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} + filelist@1.0.6: + resolution: {integrity: sha512-5giy2PkLYY1cP39p17Ech+2xlpTRL9HLspOfEgm0L6CwBXBTgsK5ou0JtzYuepxkaQ/tvhCFIJ5uXo0OrM2DxA==} fill-range@7.1.1: resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} @@ -5101,6 +5055,10 @@ packages: resolution: {integrity: sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==} engines: {node: '>=8'} + find-up@3.0.0: + resolution: {integrity: sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==} + engines: {node: '>=6'} + find-up@4.1.0: resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} engines: {node: '>=8'} @@ -5112,12 +5070,11 @@ packages: fix-dts-default-cjs-exports@1.0.1: resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} - flat-cache@4.0.1: - resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} - engines: {node: '>=16'} + flat-cache@6.1.23: + resolution: {integrity: sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==} - flatted@3.3.3: - resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} + flatted@3.4.4: + resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} for-each@0.3.5: resolution: {integrity: sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==} @@ -5131,31 +5088,21 @@ packages: resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} engines: {node: '>=14'} - formatly@0.3.0: - resolution: {integrity: sha512-9XNj/o4wrRFyhSMJOvsuyMwy8aUfBaZ1VrqHVfohyXf0Sw0e+yfKG+xZaY3arGCOMdwFsqObtzVOc1gU9KiT9w==} + formatly@0.7.0: + resolution: {integrity: sha512-7CXJtIIA0zy/u12StsYk25qVKxvdLA2ep2sTNxK3ov0mGNIIDqIvAXDSgTnAfDJFsPfWjuz0WjfYSdpvnLA5Tg==} engines: {node: '>=18.3.0'} hasBin: true - formdata-polyfill@4.0.10: - resolution: {integrity: sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==} - engines: {node: '>=12.20.0'} - - forwarded-parse@2.1.2: - resolution: {integrity: sha512-alTFZZQDKMporBH77856pXgzhEzaUVmLCDk+egLgIgHst3Tpndzz8MnKe+GzRJRfvVdn69HhpW7cmXzvtLvJAw==} - forwarded@0.2.0: resolution: {integrity: sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==} engines: {node: '>= 0.6'} - framer-motion@12.23.24: - resolution: {integrity: sha512-HMi5HRoRCTou+3fb3h9oTLyJGBxHfW+HnNE25tAXOvVx/IvwMHK0cx7IR4a2ZU6sh3IX1Z+4ts32PcYBOqka8w==} + framer-motion@13.4.0: + resolution: {integrity: sha512-HCpqKM9BTu6UYKtj0u6J1QNxojnnirNcghcSDZ+SkpiL3myxvtsgXPS3ZGEELC2eSma7YiA937rAEXtRyydSXQ==} peerDependencies: - '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 peerDependenciesMeta: - '@emotion/is-prop-valid': - optional: true react: optional: true react-dom: @@ -5168,20 +5115,14 @@ packages: fromentries@1.3.2: resolution: {integrity: sha512-cHEpEQHUg0f8XdtZCc2ZAhrHzKzT0MrFUTcvx+hfxYu7rGMDc5SKoXFh+n4YigxsHXRzc6OrCshdR1bWH6HHyg==} - fs-constants@1.0.0: - resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} - - fs-extra@11.3.2: - resolution: {integrity: sha512-Xr9F6z6up6Ws+NjzMCZc6WXg2YFRlrLP9NQDO3VQrWrfiojdhS56TzueT88ze0uBdCTwEIhQ3ptnmKeWGFAe0A==} + fs-extra@11.4.0: + resolution: {integrity: sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==} engines: {node: '>=14.14'} fs-extra@9.1.0: resolution: {integrity: sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==} engines: {node: '>=10'} - fs.realpath@1.0.0: - resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} - fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} @@ -5190,8 +5131,8 @@ packages: function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - function.prototype.name@1.1.8: - resolution: {integrity: sha512-e5iwyodOHhbMr/yNrc7fDYG4qlbIvI5gajyzPnb5TCwyhjApznQh1BMFou9b30SevY43gCJKXycoCBjMbsuW0Q==} + function.prototype.name@1.2.0: + resolution: {integrity: sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==} engines: {node: '>= 0.4'} functions-have-names@1.2.3: @@ -5200,9 +5141,6 @@ packages: fuzzysort@3.1.0: resolution: {integrity: sha512-sR9BNCjBg6LNgwvxlBd0sBABvQitkLzoVY9MYYROQVX/FvfJ4Mai9LsGhDgd8qYdds0bY77VzYd5iuB+v5rwQQ==} - fzf@0.5.2: - resolution: {integrity: sha512-Tt4kuxLXFKHy8KT40zwsUPUkg1CrsgY25FxA2U/j/0WgEDCk3ddc/zLTCCcbSHX9FcKtLuVaDGtGE/STWC+j3Q==} - generator-function@2.0.1: resolution: {integrity: sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==} engines: {node: '>= 0.4'} @@ -5215,8 +5153,8 @@ packages: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - get-east-asian-width@1.4.0: - resolution: {integrity: sha512-QZjmEOC+IT1uk6Rx0sX22V6uHWVwbdbxf1faPqJ1QhLdGgsRGCZoyaQBm/piRdJy/D2um6hM1UP7ZEeQ4EkP+Q==} + get-east-asian-width@1.7.0: + resolution: {integrity: sha512-XjH1AECxf0giL2V1aU8vKyRR2ppRUb5c0EvT7zuJTokQ74bNo52zOtghqdWIqrhUD79fo3x0WfKZdOqxF6LG1Q==} engines: {node: '>=18'} get-intrinsic@1.3.0: @@ -5254,11 +5192,8 @@ packages: resolution: {integrity: sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==} engines: {node: '>= 0.4'} - get-tsconfig@4.13.0: - resolution: {integrity: sha512-1VKTZJCwBrvbd+Wn3AOgQP/2Av+TfTCOlE4AcRJE72W1ksZXbAx8PPBR9RzgTeSPzlPMHrbANMH3LbltH73wxQ==} - - github-from-package@0.0.0: - resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + get-tsconfig@4.14.3: + resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==} glob-parent@5.1.2: resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} @@ -5268,24 +5203,18 @@ packages: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - glob-to-regexp@0.4.1: - resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} - glob@11.1.0: resolution: {integrity: sha512-vuNwKSaKiqm7g0THUBu2x7ckSs3XJLXE+2ssL7/MfTGPLLcrJQ/4Uq1CjPTtO5cCIiRxqvN6Twy1qOwhL0Xjcw==} engines: {node: 20 || >=22} + 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 hasBin: true - glob@7.2.3: - resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} - deprecated: Glob versions prior to v9 are no longer supported - - globals@14.0.0: - resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} - engines: {node: '>=18'} + glob@13.0.6: + resolution: {integrity: sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw==} + engines: {node: 18 || 20 || >=22} - globals@16.5.0: - resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + globals@17.12.0: + resolution: {integrity: sha512-cezEd/DTyyht9cvSSURyygXPfy04GtWO/5e6ZPvH7fCtjKz9PYOmuawphw1Ctd1f6C+5JypXfGD7ahNMXvevBA==} engines: {node: '>=18'} globalthis@1.0.4: @@ -5299,13 +5228,6 @@ packages: graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - graphemer@1.4.0: - resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - - graphql@16.12.0: - resolution: {integrity: sha512-DKKrynuQRne0PNpEbzuEdHlYOMksHSUI8Zc9Unei5gTsMNA2/vMpoMz/yKba50pejK56qj98qM0SjYxAKi13gQ==} - engines: {node: ^12.22.0 || ^14.16.0 || ^16.0.0 || >=17.0.0} - has-bigints@1.1.0: resolution: {integrity: sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==} engines: {node: '>= 0.4'} @@ -5333,12 +5255,13 @@ packages: resolution: {integrity: sha512-Hrp5vIK/xr5SkeN2onO32H0MgNZ0f17HRNH39WfL0SYUNOTZ5Lz1TJ8Pajo/87dYGEFlLMm7mIc/k/s6Bvz9HQ==} engines: {node: '>=8'} - hasown@2.0.2: - resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} - engines: {node: '>= 0.4'} + hashery@1.5.1: + resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} + engines: {node: '>=20'} - headers-polyfill@4.0.3: - resolution: {integrity: sha512-IScLbePpkvO846sIwOtOTDjutRMWdXdJmXdMvk6gCBHxFO8d+QKOQedyZSxFTTFYRSmlgSTDtXqqq4pcenBXLQ==} + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} hermes-estree@0.25.1: resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} @@ -5346,16 +5269,19 @@ packages: hermes-parser@0.25.1: resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} - hoist-non-react-statics@3.3.2: - resolution: {integrity: sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==} - - hono@4.10.6: - resolution: {integrity: sha512-BIdolzGpDO9MQ4nu3AUuDwHZZ+KViNm+EZ75Ae55eMXMqLVhDFqEMXxtUe9Qh8hjL+pIna/frs2j6Y2yD5Ua/g==} + hono@4.13.8: + resolution: {integrity: sha512-/Gng7NfoykZl2pjukW5Z6+8Yxm3BPRf86GTbQnt0SbySkvax4fyL4H3HhY1cCpBGmiW9XDRFzRV+CXK2W8QudQ==} engines: {node: '>=16.9.0'} - html-encoding-sniffer@4.0.0: - resolution: {integrity: sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==} - engines: {node: '>=18'} + hookified@1.15.1: + resolution: {integrity: sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==} + + hookified@2.2.0: + resolution: {integrity: sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==} + + html-encoding-sniffer@6.0.0: + resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} @@ -5364,6 +5290,16 @@ packages: resolution: {integrity: sha512-qY60FjREgVZL03vJU6IfMV4GDjGBIoOyvuFdpBDIX9yTlDw0TjxVBQp+P8NvpdIXNJvfWBTNul7fsAQJq2FNpg==} engines: {node: '>=14'} + html5parser@3.0.0: + resolution: {integrity: sha512-iNpSopa+4YHX50UOk825tBy7MghmXHo/ZpLskBYN0kAr1xhH8GlIMk5bLRXcZlfP3AnLUcSuFMu8C4MdOUxA8A==} + + htmlparser2@10.1.0: + resolution: {integrity: sha512-VTZkM9GWRAtEpveh7MSF6SjjrpNVNNVJfFup7xTY3UpFtm67foy9HDVXneLtFVt4pMz5kZtgNcvCniNFb1hlEQ==} + + htmlparser2@12.0.0: + resolution: {integrity: sha512-Tz7u1i95/g2x2jz81+x0FBVhBhY5aRTvD3tXXdFaljuNdzDLJ8UGNRrTcj2cgQvAg3iW/h77Fz15nLW0L0CrZw==} + engines: {node: '>=20.19.0'} + htmlparser2@8.0.2: resolution: {integrity: sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==} @@ -5371,14 +5307,6 @@ packages: resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} engines: {node: '>= 0.8'} - http-proxy-agent@7.0.2: - resolution: {integrity: sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==} - engines: {node: '>= 14'} - - https-proxy-agent@7.0.6: - resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} - engines: {node: '>= 14'} - human-signals@2.1.0: resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} engines: {node: '>=10.17.0'} @@ -5387,37 +5315,31 @@ packages: resolution: {integrity: sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==} engines: {node: '>=18.18.0'} - iconv-lite@0.6.3: - resolution: {integrity: sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==} - engines: {node: '>=0.10.0'} - - iconv-lite@0.7.0: - resolution: {integrity: sha512-cf6L2Ds3h57VVmkZe+Pn+5APsT7FpqJtEhhieDCvrE2MK5Qk9MyffgQyuxQTm6BChfeZNtcOLHp9IcWRVcIcBQ==} + iconv-lite@0.7.3: + resolution: {integrity: sha512-IKXpvIzjnC9XTAUbVBcMfGS0EPaIXtW6v+zr+RRp+hqULEpo0owZax6wyRwPOJbWbzjYspQwusTsfVr0ifh4uQ==} engines: {node: '>=0.10.0'} idb@7.1.1: resolution: {integrity: sha512-gchesWBzyvGHRO9W8tzUWFDycow5gwjvFKfyV9FF32Y7F50yZMp7mP+T2mJIWFx49zicqyC4uefHM17o6xKIVQ==} - ieee754@1.2.1: - resolution: {integrity: sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==} - ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - ignore@7.0.5: - resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + ignore@7.0.9: + resolution: {integrity: sha512-brTTsvFRt5C1gGHtPst/281UjPD5t9fBqbgoMPlVWy11ZLTPfu7HxK4ZYqO9H7o/yC9rSTCI85EaQ4OoY12qYw==} engines: {node: '>= 4'} - immer@10.2.0: - resolution: {integrity: sha512-d/+XTN3zfODyjr89gM3mPq1WNX2B8pYsu7eORitdwyA2sBubnTl3laYlBk4sXY5FUa5qTZGBDPJICVbvqzjlbw==} + immer@11.1.18: + resolution: {integrity: sha512-EQyQtLiYW029lyoczMl/Hh4Xu7cDecSc58JRYpHyL4tIAu3eqd1yJzQX04d2BZHDkzFFvm6qJEJWOtfDSWAXbQ==} 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==} + import-in-the-middle@3.5.1: + resolution: {integrity: sha512-mPKuL8bPQzecui2KK6Gb+M8JvJoHnhS1FeYGa22QopBmlevF5F0FE6ued/B5EgHDeIoMTONIpDWWFKUPOG0DBQ==} + engines: {node: '>=18'} imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} @@ -5427,16 +5349,9 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} - inflight@1.0.6: - resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} - deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. - inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} - ini@1.3.8: - resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==} - internal-slot@1.1.0: resolution: {integrity: sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==} engines: {node: '>= 0.4'} @@ -5445,10 +5360,18 @@ packages: resolution: {integrity: sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==} engines: {node: '>=12'} + ip-address@10.7.2: + resolution: {integrity: sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==} + engines: {node: '>= 12'} + ipaddr.js@1.9.1: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + ipaddr.js@2.5.0: + resolution: {integrity: sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==} + engines: {node: '>= 10'} + is-array-buffer@3.0.5: resolution: {integrity: sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==} engines: {node: '>= 0.4'} @@ -5456,9 +5379,6 @@ packages: is-arrayish@0.2.1: resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} - is-arrayish@0.3.4: - resolution: {integrity: sha512-m6UrgzFVUYawGBh1dUsWR5M2Clqic9RVXC/9f8ceNlv2IcO9j9J/z8UoCLPqtsPBFNzEpfR3xftohbfqDx8EQA==} - is-async-function@2.1.1: resolution: {integrity: sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==} engines: {node: '>= 0.4'} @@ -5467,10 +5387,6 @@ packages: 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'} @@ -5479,8 +5395,8 @@ packages: resolution: {integrity: sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==} engines: {node: '>= 0.4'} - is-core-module@2.16.1: - resolution: {integrity: sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==} + is-core-module@2.17.0: + resolution: {integrity: sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==} engines: {node: '>= 0.4'} is-data-view@1.0.2: @@ -5491,6 +5407,20 @@ packages: resolution: {integrity: sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==} engines: {node: '>= 0.4'} + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-docker@3.0.0: + resolution: {integrity: sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + hasBin: true + + is-document.all@1.0.0: + resolution: {integrity: sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==} + engines: {node: '>= 0.4'} + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} @@ -5511,6 +5441,15 @@ packages: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} + is-in-ssh@1.0.0: + resolution: {integrity: sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==} + engines: {node: '>=20'} + + is-inside-container@1.0.0: + resolution: {integrity: sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==} + engines: {node: '>=14.16'} + hasBin: true + is-interactive@2.0.0: resolution: {integrity: sha512-qP1vozQRI+BMOPcjFzrjXuQvdak2pHNUMZoeG2eRbiSqyvbEf/wQtEOTOX1guk6E3t36RkaqiSt8A/6YElNxLQ==} engines: {node: '>=12'} @@ -5526,9 +5465,6 @@ packages: resolution: {integrity: sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==} engines: {node: '>= 0.4'} - is-node-process@1.2.0: - resolution: {integrity: sha512-Vg4o6/fqPxIjtxgUH5QLJhwZ7gW5diGCVlXpuUfELC62CuxM1iHcRe51f2W1FDy04Ai4KJkagKjx3XaqyfRKXw==} - is-number-object@1.1.1: resolution: {integrity: sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==} engines: {node: '>= 0.4'} @@ -5541,6 +5477,10 @@ packages: resolution: {integrity: sha512-l4RyHgRqGN4Y3+9JHVrNqO+tN0rV5My76uW5/nuO4K1b6vw5G8d/cmFjP9tRfEsdhZNt0IFdZuK/c2Vr4Nb+Qg==} engines: {node: '>=0.10.0'} + is-obj@2.0.0: + resolution: {integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==} + engines: {node: '>=8'} + is-obj@3.0.0: resolution: {integrity: sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==} engines: {node: '>=12'} @@ -5549,8 +5489,8 @@ packages: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - is-plain-object@5.0.0: - resolution: {integrity: sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==} + is-plain-object@5.1.0: + resolution: {integrity: sha512-bUi/yjmtKYcRVUtWRGr0UA6xEFh2I6zWUwMrUXB3s7bmYCaZ8a+0ZsTRkrawh/mzlSD1Y0Ph8bp/U+TvBpWDNw==} engines: {node: '>=0.10.0'} is-potential-custom-element-name@1.0.1: @@ -5610,6 +5550,9 @@ packages: resolution: {integrity: sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==} engines: {node: '>=18'} + is-unsafe@2.0.2: + resolution: {integrity: sha512-HgbIHPBH0KHHCcjLfGsCvhtPTVxjaAZlXjwdz7/GQC40SjSe4sfQsar8J5VFo8JOSbarkpV0OLG95bbaNd9aAQ==} + is-weakmap@2.0.2: resolution: {integrity: sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==} engines: {node: '>= 0.4'} @@ -5622,27 +5565,35 @@ packages: resolution: {integrity: sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==} engines: {node: '>= 0.4'} - is-what@5.5.0: - resolution: {integrity: sha512-oG7cgbmg5kLYae2N5IVd3jm2s+vldjxJzK1pcu9LfpGuQ93MQSzo0okvRna+7y5ifrD+20FE8FvjusyGaz14fw==} - engines: {node: '>=18'} - is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + is-wsl@3.1.1: + resolution: {integrity: sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==} + engines: {node: '>=16'} + isarray@2.0.5: resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} - isbot@5.1.32: - resolution: {integrity: sha512-VNfjM73zz2IBZmdShMfAUg10prm6t7HFUQmNAEOAVS4YH92ZrZcvkMcGX6cIgBJAzWDzPent/EeAtYEHNPNPBQ==} + isbot@5.2.2: + resolution: {integrity: sha512-iQcBXcd+Rv/pkubRyGh2utW2j1oPG5hZY6TUhVPpqK4G+o3IbxpJNx04hgksjc/N7GK5pEorUxDeg31cFgEk/w==} engines: {node: '>=18'} isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - isexe@3.1.1: - resolution: {integrity: sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==} - engines: {node: '>=16'} + isexe@3.1.5: + resolution: {integrity: sha512-6B3tLtFqtQS4ekarvLVMZ+X+VlvQekbe4taUkf/rhVO3d/h0M2rfARm/pXLcPEsjjMsFgrFgSrhQIxcSVrBz8w==} + engines: {node: '>=18'} + + isexe@4.0.0: + resolution: {integrity: sha512-FFUtZMpoZ8RqHS3XeXEmHWLA4thH+ZxCv2lOiPIn1Xc7CxrqhWzNSDzD+/chS/zbYezmiwWLdQC09JdQKmthOw==} + engines: {node: '>=20'} istanbul-lib-coverage@3.2.2: resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} @@ -5656,9 +5607,9 @@ packages: resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} engines: {node: '>=10'} - istanbul-lib-processinfo@2.0.3: - resolution: {integrity: sha512-NkwHbo3E00oybX6NGJi6ar0B29vxyvNwoC7eJ4G4Yq28UfY758Hgn/heV8VRFhevPED4LXfFz0DQ8z/0kw9zMg==} - engines: {node: '>=8'} + istanbul-lib-processinfo@3.0.1: + resolution: {integrity: sha512-s3mX05h5wGZeScG6XnOanygPh4SJu5ujMc9YbvpnLGXWy1cRiGbp0NdVcjHxgoZt3WfQppfBsa0y+gWdYJ2pGQ==} + engines: {node: 20 || >=22} istanbul-lib-report@3.0.1: resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} @@ -5668,16 +5619,12 @@ packages: resolution: {integrity: sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==} engines: {node: '>=10'} - istanbul-lib-source-maps@5.0.6: - resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} - engines: {node: '>=10'} - istanbul-reports@3.2.0: resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} engines: {node: '>=8'} - jackspeak@4.1.1: - resolution: {integrity: sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ==} + jackspeak@4.2.3: + resolution: {integrity: sha512-ykkVRwrYvFm1nb2AJfKKYPr0emF6IiXDYUaFx4Zn9ZuIH7MrzEZ3sD5RlqGXNRpHtvUHJyOnCEFxOlNDtGo7wg==} engines: {node: 20 || >=22} jake@10.9.4: @@ -5685,43 +5632,40 @@ packages: engines: {node: '>=10'} hasBin: true - jiti@2.4.2: - resolution: {integrity: sha512-rg9zJN+G4n2nfJl5MW3BMygZX56zKPNVEYYqq7adpmMh4Jn2QNEwhvQlFy6jPVdcod7txZtKHWnyZiA3a0zP7A==} - hasBin: true - jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - jose@6.1.2: - resolution: {integrity: sha512-MpcPtHLE5EmztuFIqB0vzHAWJPpmN1E6L4oo+kze56LIs3MyXIj9ZHMDxqOvkP38gBR7K1v3jqd4WU2+nrfONQ==} + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true - jose@6.1.3: - resolution: {integrity: sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ==} + jose@6.2.12: + resolution: {integrity: sha512-9NiFmJEex0sy2Dk58j2UGBSHgUs2ypF9eZSu4L6vjOX3Dp96Sw1F3uL+H+D1sx02jZZdzUT0HgvCy59CuvXcWw==} joycon@3.1.1: resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} engines: {node: '>=10'} + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - js-tokens@9.0.1: - resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - - js-yaml@3.14.2: - resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + js-yaml@3.15.2: + resolution: {integrity: sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==} hasBin: true - js-yaml@4.1.1: - resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} + js-yaml@4.3.2: + resolution: {integrity: sha512-SFNOvSJ+Dgf/9An904Yx+CgSlIPCkIpao4qo51lpee25TIRejdH3rhR4EZMGoNx3/TP3O+wzWuiTFl4sqbltzA==} hasBin: true - jsdom@27.2.0: - resolution: {integrity: sha512-454TI39PeRDW1LgpyLPyURtB4Zx1tklSr6+OFOipsxGUH1WMTvk6C65JQdrj455+DP2uJ1+veBEHTGFKWVLFoA==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + jsdom@30.1.0: + resolution: {integrity: sha512-h/Q+H+KmlGf49ITw3TrykSVbg04S75S2O7ZtJc9gMGOWBrQRZmx5AJIKLtJ01e6Kszl+/tpFthCVqxNifxhoqg==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} peerDependencies: - canvas: ^3.0.0 + canvas: ^3.2.3 peerDependenciesMeta: canvas: optional: true @@ -5731,9 +5675,6 @@ packages: engines: {node: '>=6'} hasBin: true - json-buffer@3.0.1: - resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - json-parse-even-better-errors@2.3.1: resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} @@ -5743,6 +5684,9 @@ packages: json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} + json-schema-typed@7.0.3: + resolution: {integrity: sha512-7DE8mpG+/fVw+dTpjbxnx47TaMnDfOI1jwft9g1VybltZCduyRQPJPvc+zzKY9WPHxhPWczyFuYa6I8Mw4iU5A==} + json-schema-typed@8.0.2: resolution: {integrity: sha512-fQhoXdcvc3V28x7C7BMs4P5+kNlgUURe2jmUT1T//oBRMDrqy1QPelJimwZGo7Hg9VPV3EQV5Bnq4hbFy2vetA==} @@ -5757,15 +5701,15 @@ packages: engines: {node: '>=6'} hasBin: true - jsonfile@6.2.0: - resolution: {integrity: sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg==} + jsonfile@6.2.1: + resolution: {integrity: sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==} jsonpointer@5.0.1: resolution: {integrity: sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==} engines: {node: '>=0.10.0'} - keyv@4.5.4: - resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + keyv@5.6.0: + resolution: {integrity: sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==} kleur@3.0.3: resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} @@ -5775,17 +5719,17 @@ packages: resolution: {integrity: sha512-o+NO+8WrRiQEE4/7nwRJhN1HWpVmJm511pBHUxPLtp0BUISzlBplORYSmTclCnJvQq2tKu/sgl3xVpkc7ZWuQQ==} engines: {node: '>=6'} - knip@5.70.1: - resolution: {integrity: sha512-tGRjOivkHPV+YoVVDz0oKSlvCAY6d009Mlhufs4Y+7VWl/Ky073+KURcrgMLzJVy4pkpZvoxYu3wmC0gK7XS5g==} - engines: {node: '>=18.18.0'} + knip@6.37.0: + resolution: {integrity: sha512-NKCYuoGKJ+o2AuoCuV1mDvfMYnSSWfDXqxwmzxeHyd8fftjNRl8TBUg3fbSrtJjhm7Vj6sc1PX3WZnZhECs9EQ==} + engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - peerDependencies: - '@types/node': '>=18' - typescript: '>=5.0.4 <7' - kysely@0.28.8: - resolution: {integrity: sha512-QUOgl5ZrS9IRuhq5FvOKFSsD/3+IA6MLE81/bOOTRA/YQpKDza2sFdN5g6JCB9BOpqMJDGefLCQ9F12hRS13TA==} - engines: {node: '>=20.0.0'} + kysely@0.29.6: + resolution: {integrity: sha512-hHaB8C/rfzDDtr/t8YZwxAuPJTT0zHyaPoVzcXwDYhYNAgH/4sIfVhi/XLLIY+bL/FqaIJnjATDbi8ObSELmxg==} + engines: {node: '>=22.0.0'} + + launder@1.7.1: + resolution: {integrity: sha512-mU6WRz5EusL9ZZuiZ5SO4Y6C0P9PAUR9iwdb6bzj4KDihm28DiHFw+/yk9DBH4f+Pv1wuzQ4e2jV3oQ7mkIqvw==} leac@0.6.0: resolution: {integrity: sha512-y+SqErxb8h7nE/fiEX07jsbuhrpO9lL8eca7/Y1nuWV2moNlXhyd59iDGcRf6moVyDMbmTNzL40SUyrFU/yDpg==} @@ -5798,74 +5742,152 @@ packages: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - lightningcss-android-arm64@1.30.2: - resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-android-arm64@1.33.0: + resolution: {integrity: sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - lightningcss-darwin-arm64@1.30.2: - resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-arm64@1.33.0: + resolution: {integrity: sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - lightningcss-darwin-x64@1.30.2: - resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-darwin-x64@1.33.0: + resolution: {integrity: sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - lightningcss-freebsd-x64@1.30.2: - resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-freebsd-x64@1.33.0: + resolution: {integrity: sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - lightningcss-linux-arm-gnueabihf@1.30.2: - resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm-gnueabihf@1.33.0: + resolution: {integrity: sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - lightningcss-linux-arm64-gnu@1.30.2: - resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-gnu@1.33.0: + resolution: {integrity: sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + libc: [glibc] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] - lightningcss-linux-arm64-musl@1.30.2: - resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} + lightningcss-linux-arm64-musl@1.33.0: + resolution: {integrity: sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] + libc: [musl] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] + + lightningcss-linux-x64-gnu@1.33.0: + resolution: {integrity: sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + libc: [glibc] - lightningcss-linux-x64-gnu@1.30.2: - resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] - lightningcss-linux-x64-musl@1.30.2: - resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} + lightningcss-linux-x64-musl@1.33.0: + resolution: {integrity: sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] + libc: [musl] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] - lightningcss-win32-arm64-msvc@1.30.2: - resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} + lightningcss-win32-arm64-msvc@1.33.0: + resolution: {integrity: sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - lightningcss-win32-x64-msvc@1.30.2: - resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss-win32-x64-msvc@1.33.0: + resolution: {integrity: sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - lightningcss@1.30.2: - resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + lightningcss@1.33.0: + resolution: {integrity: sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==} engines: {node: '>= 12.0.0'} lilconfig@3.1.3: @@ -5879,6 +5901,10 @@ packages: resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + locate-path@3.0.0: + resolution: {integrity: sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==} + engines: {node: '>=6'} + locate-path@5.0.0: resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} engines: {node: '>=8'} @@ -5893,15 +5919,6 @@ packages: lodash.flattendeep@4.4.0: resolution: {integrity: sha512-uHaJFihxmJcEX3kT4I23ABqKKalJ/zDrDg0lsFtc1h+3uw49SIJ5beyhx5ExVRti3AvKoOJngIj7xz3oylPdWQ==} - lodash.merge@4.6.2: - resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - - lodash.sortby@4.7.0: - resolution: {integrity: sha512-HDWXG8isMntAyRF5vZ7xKuEvOhT4AhlRt/3czTSjvGUxjYCBVRQY48ViDHyfYz9VIoBkW4TMGQNapx+l3RUwdA==} - - lodash@4.17.21: - resolution: {integrity: sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==} - log-symbols@6.0.0: resolution: {integrity: sha512-i24m8rpwhmPIS4zscNzK6MSEhk0DUWa/8iYQWxhffV8jkI4Phvs3F+quL5xvS0gdQR0FyTCMMH33Y78dDTzzIw==} engines: {node: '>=18'} @@ -5910,15 +5927,15 @@ packages: resolution: {integrity: sha512-ja1E3yCr9i/0hmBVaM0bfwDjnGy8I/s6PP4DFp+yP+a+mrHO4Rm7DtmnqROTUkHIkqffC84YY7AeqX6oFk0WFg==} engines: {node: '>=18'} - lru-cache@11.2.2: - resolution: {integrity: sha512-F9ODfyqML2coTIsQpSkRHnLSZMtkU8Q+mSfcaIyKwy58u+8k5nvAYeiNhsyMARvzNcXJ9QfWVrcPsC9e9rAxtg==} + lru-cache@11.5.2: + resolution: {integrity: sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==} engines: {node: 20 || >=22} lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - lucide-react@0.554.0: - resolution: {integrity: sha512-St+z29uthEJVx0Is7ellNkgTEhaeSoA42I7JjOCBCrc5X6LYMGSv0P/2uS5HDLTExP5tpiqRD2PyUEOS6s9UXA==} + lucide-react@1.47.0: + resolution: {integrity: sha512-o8C23aXpNQypRY73W7fW02EyvWJinEMXgKeGjFoKym0zj3Q73hD97A1IQps1g8C14HTGsOpZL0Am+xjfgFZAbg==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -5926,14 +5943,14 @@ packages: resolution: {integrity: sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==} hasBin: true - magic-string@0.25.9: - resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} - magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - magicast@0.5.1: - resolution: {integrity: sha512-xrHS24IxaLrvuo613F719wvOIv9xPHFWQHuvGUBmPnCA/3MQxKI3b+r7n1jAoDHmsbC5bRhTZYR77invLAxVnw==} + magic-string@1.4.1: + resolution: {integrity: sha512-8lyCu36ErXR0J9uaGKlKQoiLZKmtI63YGLE8G2o9jyRPdr4X47LusSOwgOJOzcVtp81fTAAjxR7BwKz682Jhow==} + + magicast@0.5.5: + resolution: {integrity: sha512-UicdXN8zQ3JHlxVq+28afMXPr1z7WNY6+7EJnzTdQWkTAlMLF5fNCCKxJHBQwGaNGR11581EiQmQzx73+MvszA==} make-dir@3.1.0: resolution: {integrity: sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==} @@ -5952,11 +5969,11 @@ packages: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - mdn-data@2.12.2: - resolution: {integrity: sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==} + mdn-data@2.27.1: + resolution: {integrity: sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==} - media-typer@1.1.0: - resolution: {integrity: sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==} + media-typer@1.1.1: + resolution: {integrity: sha512-yz3xRaG20c6/BOzvYoDaGtPmGscs7YivItZEEqe6GbwNfHuxu9YNmvnEkMzKldAGY4/80pRcQRZSEnhquk9XuQ==} engines: {node: '>= 0.8'} merge-descriptors@2.0.0: @@ -5990,78 +6007,63 @@ packages: resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} engines: {node: '>=18'} - mime@3.0.0: - resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} - engines: {node: '>=10.0.0'} - hasBin: true - mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} + mimic-fn@3.1.0: + resolution: {integrity: sha512-Ysbi9uYW9hFyfrThdDEQuykN4Ey6BuwPD2kpI5ES/nFTDn/98yxYNLZJcgUAKPT/mcrLLKaGzJR9YVxJrIdASQ==} + engines: {node: '>=8'} + mimic-function@5.0.1: resolution: {integrity: sha512-VP79XUPxV2CigYP3jWwAUFSku2aKqBH7uTAapFWCBqutsbmDo96KY5o8uh6U+/YSIn5OxJnXp73beVkpqMIGhA==} engines: {node: '>=18'} - mimic-response@3.1.0: - resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==} - engines: {node: '>=10'} - min-indent@1.0.1: resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==} engines: {node: '>=4'} - miniflare@4.20251118.1: - resolution: {integrity: sha512-uLSAE/DvOm392fiaig4LOaatxLjM7xzIniFRG5Y3yF9IduOYLLK/pkCPQNCgKQH3ou0YJRHnTN+09LPfqYNTQQ==} - engines: {node: '>=18.0.0'} - hasBin: true - - minimatch@10.1.1: - resolution: {integrity: sha512-enIvLvRAFZYXJzkCYG5RKmPfrFArdLv+R+lbQ53BmIMLIry74bjKzX6iHAm8WYamJkhSSEabrWN5D97XnKObjQ==} - engines: {node: 20 || >=22} + miniflare@5.20260918.0-alpha: + resolution: {integrity: sha512-vyIes7yW/OTzHtz4GhcBCTohZfqk2eQNiIkngZ07VRA5Qu24aNgW/TrFwlPkMLMjWDQ8R4JJBBHR/KX+liSDtg==} + engines: {node: '>=22.0.0'} - minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@10.2.6: + resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} + engines: {node: 18 || 20 || >=22} - minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + minimatch@5.1.9: + resolution: {integrity: sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==} engines: {node: '>=10'} - minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} - minimist@1.2.8: resolution: {integrity: sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==} - minipass@7.1.2: - resolution: {integrity: sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==} + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} engines: {node: '>=16 || 14 >=14.17'} - mkdirp-classic@0.5.3: - resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + minizlib@3.1.0: + resolution: {integrity: sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==} + engines: {node: '>= 18'} - mlly@1.8.0: - resolution: {integrity: sha512-l8D9ODSRWLe2KHJSifWGwBqpTZXIXTeo8mlKjY+E2HAakaTeNpqAyBZ8GSqLzHgw4XmHmC8whvpjJNMbFZN7/g==} + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} module-details-from-path@1.0.4: resolution: {integrity: sha512-EGWKgxALGMgzvxYF1UyGTy0HXX/2vHLkw6+NvDKW2jypWbHpjQuj4UMcqQWXHERJhVGKikolT06G3bcKe4fi7w==} - motion-dom@12.23.23: - resolution: {integrity: sha512-n5yolOs0TQQBRUFImrRfs/+6X4p3Q4n1dUEqt/H58Vx7OW6RF+foWEgmTVDhIWJIMXOuNNL0apKH2S16en9eiA==} + motion-dom@13.3.0: + resolution: {integrity: sha512-AmAnB6pHdZ1vHGzWzuzteG6Q3j1lHKeX/lbST6jGlgm0cjvLUgaCk1xhOuPMOy5SgovN6wnnUdwFrkcsus7Ftg==} - motion-utils@12.23.6: - resolution: {integrity: sha512-eAWoPgr4eFEOFfg2WjIsMoqJTW6Z8MTUCgn/GZ3VRpClWBdnbjryiA3ZSNLyxCTmCQx4RmYX6jX1iWHbenUPNQ==} + motion-utils@13.3.0: + resolution: {integrity: sha512-sgSschQp7EseHInIlR7hBbMuvet3RA0bs28KPZAXJcGKGdxHGvh1ogpYDilY3bOMtl73EqPNmp75sAKHYPU5sg==} - motion@12.23.24: - resolution: {integrity: sha512-Rc5E7oe2YZ72N//S3QXGzbnXgqNrTESv8KKxABR20q2FLch9gHLo0JLyYo2hZ238bZ9Gx6cWhj9VO0IgwbMjCw==} + motion@13.4.0: + resolution: {integrity: sha512-aiNSA29N+vgV5p5cJSB5cFzx8KTuuxB99z8zGtxsaqlwKtBK6sq8YgPRpkVQLkbJMOcLDU0q/ShdT95qpBy/0g==} peerDependencies: - '@emotion/is-prop-valid': '*' react: ^18.0.0 || ^19.0.0 react-dom: ^18.0.0 || ^19.0.0 peerDependenciesMeta: - '@emotion/is-prop-valid': - optional: true react: optional: true react-dom: @@ -6074,35 +6076,18 @@ packages: ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} - msw@2.12.4: - resolution: {integrity: sha512-rHNiVfTyKhzc0EjoXUBVGteNKBevdjOlVC6GlIRXpy+/3LHEIGRovnB5WPjcvmNODVQ1TNFnoa7wsGbd0V3epg==} - engines: {node: '>=18'} - hasBin: true - peerDependencies: - typescript: '>= 4.8.x' - peerDependenciesMeta: - typescript: - optional: true - - mute-stream@2.0.0: - resolution: {integrity: sha512-WWdIxpyjEn+FhQJQQv9aQAYlHoNVdzIzUySNV1gHUPDSdZJ3yZn7pAAbQcV7B56Mvu881q9FZV+0Vx2xC44VWA==} - engines: {node: ^18.17.0 || >=20.5.0} - mz@2.7.0: resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} - nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + nanoid@3.3.19: + resolution: {integrity: sha512-Y2tUNy4ouw6tq5oDSKeQYGOyhkUBhNOcGV/02KC+6kd9eDGqdZd++mjMiIDilrBYvjEnCYvVtsuHCuP+okSfug==} engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true - nanostores@1.1.0: - resolution: {integrity: sha512-yJBmDJr18xy47dbNVlHcgdPrulSn1nhSE6Ns9vTG+Nx9VPT6iV1MD6aQFp/t52zpf82FhLLTXAXr30NuCnxvwA==} + nanostores@1.5.3: + resolution: {integrity: sha512-rQLB6eV4f2AW/n3L0JmwCROpaisYy9EDEADvEFSd1C/qG8hB6O5TPlh9A791JRbJr4CnMQBzptDcvD9OR1+6WA==} engines: {node: ^20.0.0 || >=22.0.0} - napi-build-utils@2.0.0: - resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} - natural-compare@1.4.0: resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} @@ -6110,63 +6095,39 @@ packages: resolution: {integrity: sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==} engines: {node: '>= 0.6'} - negotiator@1.0.0: - resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} - engines: {node: '>= 0.6'} - - next@16.0.1: - resolution: {integrity: sha512-e9RLSssZwd35p7/vOa+hoDFggUZIUbZhIUSLZuETCwrCVvxOs87NamoUzT+vbcNAL8Ld9GobBnWOA6SbV/arOw==} - engines: {node: '>=20.9.0'} - deprecated: This version has a security vulnerability. Please upgrade to a patched version. See https://nextjs.org/blog/CVE-2025-66478 for more details. - hasBin: true - peerDependencies: - '@opentelemetry/api': ^1.1.0 - '@playwright/test': ^1.51.1 - babel-plugin-react-compiler: '*' - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - sass: ^1.3.0 - peerDependenciesMeta: - '@opentelemetry/api': - optional: true - '@playwright/test': - optional: true - babel-plugin-react-compiler: - optional: true - sass: - optional: true - - node-abi@3.85.0: - resolution: {integrity: sha512-zsFhmbkAzwhTft6nd3VxcG0cvJsT70rL+BIGHWVq5fi6MwGrHwzqKaxXE+Hl2GmnGItnDKPPkO5/LQqjVkIdFg==} - engines: {node: '>=10'} + negotiator@1.1.0: + resolution: {integrity: sha512-NMPBRMJgiQHjbd8phG3Vebdx4kZ1H121rbl5IkMqeOsahptB9BKo/d7oJ3zTXqTgagn2bWlNSXkh0QUGM31RYg==} + engines: {node: '>=18'} - node-addon-api@8.5.0: - resolution: {integrity: sha512-/bRZty2mXUIFY/xU5HLvveNHlswNJej+RnxBjOMkidWfwZzgTbPG1E3K5TOxRLOR+5hX7bSofy8yf1hZevMS8A==} + node-addon-api@8.9.2: + resolution: {integrity: sha512-VijLXbi3UACN69I0JVXJsX4tjACjNoQDgv2gTF6sx2wWEi8tkSg2eX8p5gSIFi8z2+DL3oHmY6OyKce38SDolg==} engines: {node: ^18 || ^20 || >= 21} - node-cron@4.2.1: - resolution: {integrity: sha512-lgimEHPE/QDgFlywTd8yTR61ptugX3Qer29efeyWw2rv259HtGBNn1vZVmp8lB9uo9wC0t/AT4iGqXxia+CJFg==} - engines: {node: '>=6.0.0'} - - node-domexception@1.0.0: - resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==} - engines: {node: '>=10.5.0'} - deprecated: Use your platform's native DOMException instead - - node-fetch@3.3.2: - resolution: {integrity: sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==} - engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + node-cron@4.6.0: + resolution: {integrity: sha512-Si/bzYiKRHOB8/a99T2+SDGN582ONDMSTlJr5oCkT6GtnqPjZ2s10eoQRYkW9ZHwjVxONL+W8Fb+qR0AHMQsdg==} + engines: {node: '>=20'} node-gyp-build@4.8.4: resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} hasBin: true + node-gyp@13.0.2: + resolution: {integrity: sha512-SXTvw3PxznpowYhJSOD9mVQBgDaCTWXffX+wQZsQ7PbcTV86TsXCUcSZhHnskFQvrvn/OdSzJPMsptT2pIj9ww==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} + hasBin: true + node-preload@0.2.1: resolution: {integrity: sha512-RM5oyBy45cLEoHqCeh+MNuFAxO0vTFBLskvQbOKnEE7YTTSN4tbN8QWDIPQ6L+WvKsB/qLEGpYe2ZZ9d4W9OIQ==} engines: {node: '>=8'} - node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + node-releases@2.0.56: + resolution: {integrity: sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A==} + engines: {node: '>=18'} + + nopt@10.0.1: + resolution: {integrity: sha512-df3sBr/6ax9hSGuC3CspvLlbnX8cP5L5nZwXF8cGN8l0zSWR6BvzmQ6jPUKjvo6+/xdpkNvEcucBNUdBeeV13g==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} + hasBin: true normalize-path@3.0.0: resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} @@ -6180,14 +6141,14 @@ packages: resolution: {integrity: sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==} engines: {node: '>=18'} - nyc@17.1.0: - resolution: {integrity: sha512-U42vQ4czpKa0QdI1hu950XuNhYqgoM+ZF1HT+VuUHL9hPfDPVvNQyltmMqdE9bUHMVa+8yNbc3QKTj8zQhlVxQ==} - engines: {node: '>=18'} + nyc@18.0.0: + resolution: {integrity: sha512-G5UyHinFkB1BxqGTrmZdB6uIYH0+v7ZnVssuflUDi+J+RhKWyAhRT1RCehBSI6jLFLuUUgFDyLt49mUtdO1XeQ==} + engines: {node: 20 || >=22} hasBin: true - nypm@0.6.0: - resolution: {integrity: sha512-mn8wBFV9G9+UFHIrq+pZ2r2zL4aPau/by3kJb3cM7+5tQHMt6HGQB8FDIeKFYp8o0D2pnH6nVsO88N4AmUxIWg==} - engines: {node: ^14.16.0 || >=16.10.0} + nypm@0.6.6: + resolution: {integrity: sha512-vRyr0r4cbBapw07Xw8xrj9Teq3o7MUD35rSaTcanDbW+aK2XHDgJFiU6ZTj2GBw7Q12ysdsyFss+Vdz4hQ0Y6Q==} + engines: {node: '>=18'} hasBin: true object-assign@4.1.1: @@ -6210,6 +6171,10 @@ packages: resolution: {integrity: sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==} engines: {node: '>= 0.4'} + obug@2.2.1: + resolution: {integrity: sha512-XrsrhT5sybtKI6wakr2SPOlGZWWYbUXZ7a0jT8/QOeAPau+1X/bSegNe5YR75oJmEZQbKningirmGOEJCIk61Q==} + engines: {node: '>=12.20.0'} + on-finished@2.4.1: resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} engines: {node: '>= 0.8'} @@ -6225,6 +6190,14 @@ packages: resolution: {integrity: sha512-VXJjc87FScF88uafS3JllDgvAm+c/Slfz06lorj2uAY34rlUu0Nt+v8wreiImcrgAjjIHp1rXpTDlLOGw29WwQ==} engines: {node: '>=18'} + open@11.0.4: + resolution: {integrity: sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==} + engines: {node: '>=20'} + + open@8.4.2: + resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} + engines: {node: '>=12'} + optionator@0.9.4: resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} engines: {node: '>= 0.8.0'} @@ -6233,15 +6206,16 @@ packages: resolution: {integrity: sha512-weP+BZ8MVNnlCm8c0Qdc1WSWq4Qn7I+9CJGm7Qali6g44e/PUzbjNqJX5NJ9ljlNMosfJvg1fKEGILklK9cwnw==} engines: {node: '>=18'} - outvariant@1.4.3: - resolution: {integrity: sha512-+Sl2UErvtsoajRDKCE5/dBz4DIvHXQQnAxtQTF04OJxY0+DyZXSo5P5Bb7XYWOh81syohlYL24hbDwxedPUJCA==} - - own-keys@1.0.1: - resolution: {integrity: sha512-qFOyK5PjiWZd+QQIh+1jhdb9LpxTF0qs7Pm8o5QHYZ0M3vKqSqzsZaEB6oWlxZ+q2sJBMI/Ktgd2N5ZwQoRHfg==} + own-keys@1.0.2: + resolution: {integrity: sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==} engines: {node: '>= 0.4'} - oxc-resolver@11.13.2: - resolution: {integrity: sha512-1SXVyYQ9bqMX3uZo8Px81EG7jhZkO9PvvR5X9roY5TLYVm4ZA7pbPDNlYaDBBeF9U+YO3OeMNoHde52hrcCu8w==} + oxc-parser@0.150.0: + resolution: {integrity: sha512-zwajKw1GUa57IOdafIS7/yOObGF2NihwIfZfs5yJTRprMSkiwhWOc/k+n8bwnUPbHr2/XsjfBO8KyTPaW3VpWg==} + engines: {node: ^20.19.0 || >=22.12.0} + + oxc-resolver@11.24.2: + resolution: {integrity: sha512-FY91FiDBj7ls5MsFS9jN3tjz2o0/zsdSsymlakySaBwVJZorHhkWyICLZMKxlu1R9vYo+sd3z1jwb4J8x7bNDw==} p-limit@2.3.0: resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} @@ -6251,6 +6225,10 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-locate@3.0.0: + resolution: {integrity: sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==} + engines: {node: '>=6'} + p-locate@4.1.0: resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} engines: {node: '>=8'} @@ -6274,8 +6252,8 @@ packages: package-json-from-dist@1.0.1: resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} - package-manager-detector@1.6.0: - resolution: {integrity: sha512-61A5ThoTiDG/C8s8UMZwSorAGwMJ0ERVGj2OjoW5pAalsNOg15+iQiPzrLJ4jhZ1HJzmC2PIHT2oEiH3R5fzNA==} + package-manager-detector@1.8.0: + resolution: {integrity: sha512-yQA4H19AmPEoMUeavPMDIe1higySl/gH/yaQrkT/s07Qp+7pp2hYz30N3z2l5BkjVkF9Ow6o0wjJamm2y7Sn0A==} parent-module@1.0.1: resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} @@ -6292,8 +6270,8 @@ packages: parse-srcset@1.0.2: resolution: {integrity: sha512-/2qh0lav6CmI15FzA3i/2Bzk2zCgQhGMkvhOhKNcBVQ1ldgpbfiNTVslmooUmWJcADi1f1kIeynbDRVzNlfR6Q==} - parse5@8.0.0: - resolution: {integrity: sha512-9m4m5GSgXjL4AjumKzq1Fgfp3Z8rsvjRNbnkVwfu2ImRqE5D0LnY2QfDen18FSY9C573YU5XxSapdHZTZ2WolA==} + parse5@8.0.1: + resolution: {integrity: sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==} parseley@0.12.1: resolution: {integrity: sha512-e6qHKe3a9HWr0oMRVDTRhKce+bRO8VGQR3NyVwcjwrbhMmFCX9KszEV35+rn4AdilFAq9VPxP/Fe1wC9Qjd2lw==} @@ -6305,13 +6283,17 @@ packages: path-browserify@1.0.1: resolution: {integrity: sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==} + path-exists@3.0.0: + resolution: {integrity: sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==} + engines: {node: '>=4'} + path-exists@4.0.0: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} - path-is-absolute@1.0.1: - resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} - engines: {node: '>=0.10.0'} + path-expression-matcher@1.6.2: + resolution: {integrity: sha512-enSlaiat05iasnzmgNxRj8reFdj3puY2QpNgP1aPIaVfT6nn9ICuPoFlKHk8EN22HcwewshO+mN2DGbkCEOtqQ==} + engines: {node: '>=14.0.0'} path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} @@ -6324,15 +6306,15 @@ packages: path-parse@1.0.7: resolution: {integrity: sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==} - path-scurry@2.0.1: - resolution: {integrity: sha512-oWyT4gICAu+kaA7QWk/jvCHWarMKNs6pXOGWKDTr7cw4IGcUbW+PeTfbaQiLGheFRpjo6O9J0PmyMfQPjH71oA==} - engines: {node: 20 || >=22} + path-scurry@2.0.2: + resolution: {integrity: sha512-3O/iVVsJAPsOnpwWIeD+d6z/7PmqApyQePUtCndjatj/9I5LylHvt5qluFaBT3I5h3r1ejfR056c+FCv+NnNXg==} + engines: {node: 18 || 20 || >=22} path-to-regexp@6.3.0: resolution: {integrity: sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==} - path-to-regexp@8.3.0: - resolution: {integrity: sha512-7jdwVIRtsP8MYpdXSwOS0YdD0Du+qOoF/AEPIt88PcCFrZCzx41oxku1jD88hZBwbNUIEfpqvuhjFaMAqMTWnA==} + path-to-regexp@8.4.2: + resolution: {integrity: sha512-qRcuIdP69NPm4qbACK+aDogI5CBDMi1jKe0ry5rSQJz8JVLsC7jV8XpiJjGRLLol3N+R5ihGYcrPLTno6pAdBA==} pathe@2.0.3: resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} @@ -6340,28 +6322,21 @@ packages: peberminta@0.9.0: resolution: {integrity: sha512-XIxfHpEuSJbITd1H3EeQwpcZbTLHc+VVr8ANI9t5sit565tsI4/xK3KWTUFE2e6QiangUkh3B0jihzmGnNrRsQ==} - pg-int8@1.0.1: - resolution: {integrity: sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==} - engines: {node: '>=4.0.0'} - - pg-protocol@1.10.3: - resolution: {integrity: sha512-6DIBgBQaTKDJyxnXaLiLR8wBpQQcGWuAESkRBX/t6OwA8YsqP+iVSiond2EDy6Y/dsGk8rh/jtax3js5NeV7JQ==} - - 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.1: - resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + picomatch@2.3.2: + resolution: {integrity: sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==} engines: {node: '>=8.6'} - picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + picomatch@4.0.7: + resolution: {integrity: sha512-qcJu88Q2IWqJsDD529JKMdwGm/dvInW4HvQnRwiH9JtihJvzGOscDtHE3x1pBKeUOTysQ8kVmLnJ2kJu7yhcGA==} engines: {node: '>=12'} + picospinner@3.1.2: + resolution: {integrity: sha512-0Z++uU8mvB0EvCPAEUq9BGiPcSravzJ+RPdXfjYlzXffqsogisiKRQqI6ctrSSJ6n985vxrgKtQ5n4sRINcJZg==} + engines: {node: '>=18.0.0'} + pirates@4.0.7: resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} engines: {node: '>= 6'} @@ -6377,13 +6352,17 @@ packages: pkg-types@1.3.1: resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} - pkg-types@2.3.0: - resolution: {integrity: sha512-SIqCzDRg0s9npO5XQ3tNZioRY1uK06lA41ynBC1YmFTmnY6FjUjVt6s4LoADmwoig1qqD0oK8h1p/8mlMx8Oig==} + pkg-up@3.1.0: + resolution: {integrity: sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==} + engines: {node: '>=8'} possible-typed-array-names@1.1.0: resolution: {integrity: sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==} engines: {node: '>= 0.4'} + postal-mime@2.7.6: + resolution: {integrity: sha512-UUlyE2KlxmvwMGq060onF/VWU3zD6dVW31FwokQ5v26jWd35fbs2MoTFzh+jXnPwAyV2MULMKXcBInGOl5TO6Q==} + postcss-load-config@6.0.1: resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} engines: {node: '>= 18'} @@ -6406,46 +6385,28 @@ packages: resolution: {integrity: sha512-IQ7TZdoaqbT+LCpShg46jnZVlhWD2w6iQYAcYXfHARZ7X1t/UGhhceQDs5X0cGqKvYlHNOuv7Oa1xmb0oQuA3w==} engines: {node: '>=4'} - postcss@8.4.31: - resolution: {integrity: sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==} - engines: {node: ^10 || ^12 || >=14} - - postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} - - postgres-array@2.0.0: - resolution: {integrity: sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==} - engines: {node: '>=4'} - - postgres-bytea@1.0.0: - resolution: {integrity: sha512-xy3pmLuQqRBZBXDULy7KbaitYqLcmxigw14Q5sj8QBVLqEwXfeybIKVWiqAXTlcvdvb0+xkOtDbfQMOf4lST1w==} - engines: {node: '>=0.10.0'} + postcss-selector-parser@7.1.6: + resolution: {integrity: sha512-7qASPzhKF2l2KLboRZux8CCTRMdGiV08vWmyKzPz22qZ7ZjQBOeY7rNzNoCLSUiftJ7HUq0GERHmxw/t0dCdMw==} + engines: {node: '>=4'} - postgres-date@1.0.7: - resolution: {integrity: sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==} - engines: {node: '>=0.10.0'} + postcss@8.5.28: + resolution: {integrity: sha512-RRuzqDtt5Y9h3quz5hWhK+TPnsmVs6WwSU6LkJMeY4HstUEDuYTG8UJSdawMRzmzAtV+KEoG8N3Qg2qLy5vM/A==} + engines: {node: ^10 || ^12 || >=14} - postgres-interval@1.2.0: - resolution: {integrity: sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==} - engines: {node: '>=0.10.0'} + powershell-utils@0.1.0: + resolution: {integrity: sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==} + engines: {node: '>=20'} - prebuild-install@7.1.3: - resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} - engines: {node: '>=10'} - hasBin: true + powershell-utils@0.2.1: + resolution: {integrity: sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==} + engines: {node: '>=20'} prelude-ls@1.2.1: resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} engines: {node: '>= 0.8.0'} - prettier@3.6.2: - resolution: {integrity: sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==} - engines: {node: '>=14'} - hasBin: true - - prettier@3.7.4: - resolution: {integrity: sha512-v6UNi1+3hSlVvv8fSaoUbggEM5VErKmmpGA7Pl3HF8V6uKY7rvClBOJlH6yNwQtfTueNkGVpOv/mtWL9L4bgRA==} + prettier@3.9.8: + resolution: {integrity: sha512-WRFq3Wn3WId7LLROfMLdH7xaFr2jR62wU8nLO6rQUOLOxNZUviyJQs1M0iIhLexSFy+L+w0ch66wtoO2jRjG0A==} engines: {node: '>=14'} hasBin: true @@ -6461,14 +6422,18 @@ packages: resolution: {integrity: sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==} engines: {node: ^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0} - pretty-ms@9.3.0: - resolution: {integrity: sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ==} + pretty-ms@9.3.1: + resolution: {integrity: sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==} engines: {node: '>=18'} prismjs@1.30.0: resolution: {integrity: sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==} engines: {node: '>=6'} + proc-log@7.0.0: + resolution: {integrity: sha512-FYgfaA69XZ93zaXLoMNQ+ViDXGGBgR8aLh03txzcFhV+9xOXx7+8DLCULrKKpR9+GsH9ZfHm82aSUPpozX0Ztg==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} + process-on-spawn@1.1.0: resolution: {integrity: sha512-JOnOPQ/8TZgjs1JIH/m9ni7FfimjNa/PRx7y/Wb5qdItsnhO0jE4AT7fC0HjC28DUQWDr50dwSYZLdRMlqDq3Q==} engines: {node: '>=8'} @@ -6477,29 +6442,27 @@ packages: resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} engines: {node: '>= 6'} - proxy-addr@2.0.7: - resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} + proxy-addr@2.0.8: + resolution: {integrity: sha512-5nnx0yGyVUcY6t9RnWcARWtwT9F1D8O9rt08htPvnd49W1IgZtmLkhu9WfMzQj1cFxjHIO6connUNVW5k7AVyQ==} engines: {node: '>= 0.10'} - pump@3.0.3: - resolution: {integrity: sha512-todwxLMY7/heScKmntwQG8CXVkWUOdYxIvY2s0VWAAMh/nd8SoYiRaKjlr7+iCs984f2P8zvrfWcDDYVb73NfA==} - punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} - qs@6.14.0: - resolution: {integrity: sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==} - engines: {node: '>=0.6'} + qified@0.10.1: + resolution: {integrity: sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==} + engines: {node: '>=20'} - querystringify@2.2.0: - resolution: {integrity: sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==} + qs@6.16.0: + resolution: {integrity: sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==} + engines: {node: '>=0.6'} queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} - radix-ui@1.4.3: - resolution: {integrity: sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==} + radix-ui@1.6.7: + resolution: {integrity: sha512-QBdhh1arIEUvPC0dQ5+nwWAxt7+N+oP/9jPwjJkGFoSk/sqxg32gJtSXGtFh8frAIcS6oC9cx2Q+7KYCQLOAeA==} peerDependencies: '@types/react': '*' '@types/react-dom': '*' @@ -6511,39 +6474,35 @@ packages: '@types/react-dom': optional: true - randombytes@2.1.0: - resolution: {integrity: sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==} - - range-parser@1.2.1: - resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + range-parser@1.3.0: + resolution: {integrity: sha512-hek2mFQpPuI4E1BBKrSto+BU3e3x4xuarsbiwr3+lf7p44juvFMV0XFWQAP3xUyqXA4RrXLIoaSUGbSt056ZMw==} engines: {node: '>= 0.6'} raw-body@3.0.2: resolution: {integrity: sha512-K5zQjDllxWkf7Z5xJdV0/B0WTNqx6vxG70zJE4N0kBs4LovmEYWJzQGxC9bS9RAKu3bgM40lrd5zoLJ12MQ5BA==} engines: {node: '>= 0.10'} - rc@1.2.8: - resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==} - hasBin: true - - react-dom@19.2.0: - resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} + react-dom@19.3.0: + resolution: {integrity: sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==} peerDependencies: - react: ^19.2.0 + react: ^19.3.0 - react-email@5.0.5: - resolution: {integrity: sha512-O0BCyg2zR/3CsEYqoeDQuJL6W8oHYSPmvzIeSbFa5XXdtofmgizCLThbs50lcP7wGCTkDvdJIZ6XWUt2aRU6zA==} + react-email@6.9.5: + resolution: {integrity: sha512-XkUFa4S3XGbVQegdGSvkShsEOn/j9t3yL5MXRf5A2l4K+RzXNPK2TZLOgI/bXfWu2WRyKWb9aVDtfLLuyBMi2A==} engines: {node: '>=20.0.0'} hasBin: true + peerDependencies: + react: ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^18.0 || ^19.0 || ^19.0.0-rc - react-hook-form@7.66.1: - resolution: {integrity: sha512-2KnjpgG2Rhbi+CIiIBQQ9Df6sMGH5ExNyFl4Hw9qO7pIqMBR8Bvu9RQyjl3JM4vehzCh9soiNUM/xYMswb2EiA==} + react-hook-form@7.88.0: + resolution: {integrity: sha512-QRaLOWhX93YCnMiRfnOFRSwWXZNt8qhm2JTZwypoDvKpSffTJHmpzMXt8U6PV5UThvL3IiiLDUWe2nHMtz6Mmw==} engines: {node: '>=18.0.0'} peerDependencies: react: ^16.8.0 || ^17 || ^18 || ^19 - react-intersection-observer@10.0.0: - resolution: {integrity: sha512-JJRgcnFQoVXmbE5+GXr1OS1NDD1gHk0HyfpLcRf0575IbJz+io8yzs4mWVlfaqOQq1FiVjLvuYAdEEcrrCfveg==} + react-intersection-observer@11.0.1: + resolution: {integrity: sha512-BIZ1M40GPSKDIT1MJbXK7SB0BwBaTKr84QfZCs5asKer7YMOYLzMi+RI1F4VStbZLGHoosJmd+aOQDDipUV1gA==} peerDependencies: react: ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -6551,17 +6510,14 @@ packages: react-dom: optional: true - react-is@16.13.1: - resolution: {integrity: sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==} - react-is@17.0.2: resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==} - react-is@18.3.1: - resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + react-is@19.3.0: + resolution: {integrity: sha512-UpMYezM4v5/18F28aC66AEsjXIgE02kyEMH6yLdgLXu/UTfa1Ntwck/nNLrbqJsEXW7gPb0coNO9FQse9WTovA==} - react-redux@9.2.0: - resolution: {integrity: sha512-ROY9fvHhwOD9ySfrF0wmvu//bKCQ6AeZZq1nJNtbDC+kk5DuSuNX/n6YWYF/SYy7bSba4D4FSz8DJeKY/S/r+g==} + react-redux@9.3.0: + resolution: {integrity: sha512-KQopgqFo/p/fgmAs5qz6p5RWaNAzq40WAu7fJIXnQpYxFPbJYtsJPWvGeF2rOBaY/kEuV77AVsX8TsQzKm+A/g==} peerDependencies: '@types/react': ^18.2.25 || ^19 react: ^18.0 || ^19 @@ -6572,10 +6528,6 @@ packages: redux: optional: true - react-refresh@0.18.0: - resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} - engines: {node: '>=0.10.0'} - react-remove-scroll-bar@2.3.8: resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} engines: {node: '>=10'} @@ -6586,8 +6538,8 @@ packages: '@types/react': optional: true - react-remove-scroll@2.7.1: - resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} engines: {node: '>=10'} peerDependencies: '@types/react': '*' @@ -6606,28 +6558,24 @@ packages: '@types/react': optional: true - react@19.2.0: - resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + react@19.3.0: + resolution: {integrity: sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==} engines: {node: '>=0.10.0'} - readable-stream@3.6.2: - resolution: {integrity: sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==} - engines: {node: '>= 6'} - - 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==} + readdirp@5.1.1: + resolution: {integrity: sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==} + engines: {node: '>= 20.19.0'} + + recast@0.23.21: + resolution: {integrity: sha512-mFAyJq9vUbSTARLZUvAEf1z3YxlvAwswbmxMx2mPA/MSm4KmpwvwvhsH/NIrZhyOuwD60Lzyw2qh83uCbgTPYw==} engines: {node: '>= 4'} - recharts@3.5.0: - resolution: {integrity: sha512-jWqBtu8L3VICXWa3g/y+bKjL8DDHSRme7DHD/70LQ/Tk0di1h11Y0kKC0nPh6YJ2oaa0k6anIFNhg6SfzHWdEA==} + recharts@3.10.1: + resolution: {integrity: sha512-QXFrvt6IVcw7eeZCoyXTwkIJAX3Dv1nyVhMicXJ47GsGDDpcN8z6o644DibE9XjpBTThtsomLKnTV6lc+cVFUA==} engines: {node: '>=18'} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 @@ -6668,8 +6616,8 @@ packages: regjsgen@0.8.0: resolution: {integrity: sha512-RvwtGe3d7LvWiDQXeQw8p5asZUmfU1G/l6WbUXeHta7Y2PEIvBTwH6E2EfmYUK8pxcxEdEmaomqyp0vZZ7C+3Q==} - regjsparser@0.13.0: - resolution: {integrity: sha512-NZQZdC5wOE/H3UT28fVGL+ikOZcEzfMGk/c3iN9UGxzWHMa1op7274oyiUVrAG4B2EuFhus8SvkaYnhvW92p9Q==} + regjsparser@0.13.3: + resolution: {integrity: sha512-ycwFAS14Jw4mppvmK4GR/J6u3WpWpjkEApehuHtLc/8VpPNpDMbQ4WjqwplXifGeyKOzHSFLmSPqzksDQE2Sfg==} hasBin: true release-zalgo@1.0.0: @@ -6684,21 +6632,18 @@ packages: 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'} + require-in-the-middle@8.0.1: + resolution: {integrity: sha512-QT7FVMXfWOYFbeRBF6nu+I6tr2Tf3u0q8RIEjNob/heKY/nh7drD/k7eeMFmSQgnTtCzLDcCu/XEnpW2wk4xCQ==} + engines: {node: '>=9.3.0 || >=8.10.0 <9.0.0'} require-main-filename@2.0.0: resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} - requires-port@1.0.0: - resolution: {integrity: sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ==} - - reselect@5.1.1: - resolution: {integrity: sha512-K/BG6eIky/SBpzfHZv/dd+9JBFiS4SWV7FIujVyJRux6e45+73RaUHXLmIR1f7WOMaQ0U1km6qwklRQxpJJY0w==} + reselect@5.2.0: + resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} - resend@6.5.2: - resolution: {integrity: sha512-Yl83UvS8sYsjgmF8dVbNPzlfpmb3DkLUk3VwsAbkaEFo9UMswpNuPGryHBXGk+Ta4uYMv5HmjVk3j9jmNkcEDg==} + resend@6.28.1: + resolution: {integrity: sha512-5VWOcDiWKBt0NWYKXwzY9WJ+LbpQLYw9M6j1DDJYPk7TloHfWOJyaY4EFKoR/KPL0N4m5yO3o96iDoYOX7v+GA==} engines: {node: '>=20'} peerDependencies: '@react-email/render': '*' @@ -6717,8 +6662,8 @@ packages: resolve-pkg-maps@1.0.0: resolution: {integrity: sha512-seS2Tj26TBVOC2NIc2rOe2y2ZO7efxITtLZcGSOnHHNOQ7CkiUBfw0Iw2ck6xkIhPwLhKNLS8BO+hEpngQlqzw==} - resolve@1.22.11: - resolution: {integrity: sha512-RfqAvLnMl313r7c9oclB1HhUEAezcpLjz95wFH4LVuhk9JF/r22qmVP9AMmOU4vMX7Q8pN8jwNg/CSpdFnMjTQ==} + resolve@1.22.12: + resolution: {integrity: sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==} engines: {node: '>= 0.4'} hasBin: true @@ -6726,138 +6671,46 @@ packages: resolution: {integrity: sha512-oMA2dcrw6u0YfxJQXm342bFKX/E4sG9rbTzO9ptUcR/e8A33cHuvStiYOwH7fszkZlZ1z/ta9AAoPk2F4qIOHA==} engines: {node: '>=18'} - rettime@0.7.0: - resolution: {integrity: sha512-LPRKoHnLKd/r3dVxcwO7vhCW+orkOGj9ViueosEBK6ie89CijnfRlhaDhHq/3Hxu4CkWQtxwlBG0mzTQY6uQjw==} - reusify@1.1.0: resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} engines: {iojs: '>=1.0.0', node: '>=0.10.0'} - rimraf@3.0.2: - resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} - deprecated: Rimraf versions prior to v4 are no longer supported - hasBin: true - - rolldown-vite@7.1.14: - resolution: {integrity: sha512-eSiiRJmovt8qDJkGyZuLnbxAOAdie6NCmmd0NkTC0RJI9duiSBTfr8X2mBYJOUFzxQa2USaHmL99J9uMxkjCyw==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - esbuild: '>=0.25.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 - peerDependenciesMeta: - '@types/node': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - rolldown-vite@7.2.7: - resolution: {integrity: sha512-N6a9KgNZ0xgCJ6/Ej2FQ7W8D3fOzDwFw7CLWZ2ubZknVrs9NdNkx25AFEuNbSwQO76VEHp4N7YatsZwp/ST1Gg==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - esbuild: '>=0.25.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 - peerDependenciesMeta: - '@types/node': - optional: true - esbuild: - optional: true - jiti: - optional: true - less: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true - - rolldown@1.0.0-beta.41: - resolution: {integrity: sha512-U+NPR0Bkg3wm61dteD2L4nAM1U9dtaqVrpDXwC36IKRHpEO/Ubpid4Nijpa2imPchcVNHfxVFwSSMJdwdGFUbg==} - engines: {node: ^20.19.0 || >=22.12.0} + rimraf@6.1.3: + resolution: {integrity: sha512-LKg+Cr2ZF61fkcaK1UdkH2yEBBKnYjTyWzTJT6KNPcSPaiT7HSdhtMXQuN5wkTX0Xu72KQ1l8S42rlmexS2hSA==} + engines: {node: 20 || >=22} hasBin: true - rolldown@1.0.0-beta.51: - resolution: {integrity: sha512-ZRLgPlS91l4JztLYEZnmMcd3Umcla1hkXJgiEiR4HloRJBBoeaX8qogTu5Jfu36rRMVLndzqYv0h+M5gJAkUfg==} + rolldown@1.2.9: + resolution: {integrity: sha512-hx/Pv0N1haXRb11qkfnK5MXB/iqr7i0yjWQqmO9uHqZpBgQSqzc8UsSnEpalsh+j1I8qQ2CkXAkJC8Br3dKSlg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true - rollup@2.79.2: - resolution: {integrity: sha512-fS6iqSPZDs3dr/y7Od6y5nha8dW1YnbgtsyotCVvoFGKbERG++CVRFv1meyGDE1SNItQA8BrnCw7ScdAhRJ3XQ==} - engines: {node: '>=10.0.0'} - hasBin: true - - rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + rollup@4.63.3: + resolution: {integrity: sha512-1i2XreiAoMMXuPGD6Msj2xWrMMkHojNRKivInxGQcg7/1KuPuYlfUutLyh4drnOxUTHX9cHI4wFoat8D/NKaBw==} engines: {node: '>=18.0.0', npm: '>=8.0.0'} hasBin: true - rou3@0.5.1: - resolution: {integrity: sha512-OXMmJ3zRk2xeXFGfA3K+EOPHC5u7RDFG7lIOx0X1pdnhUkI8MdVrbV+sNsD80ElpUZ+MRHdyxPnFthq9VHs8uQ==} + rou3@0.9.2: + resolution: {integrity: sha512-3SOzvaAg8rkHrXtRjpCvCvbyO5to9oOO27Z/XqHEYXfMRVSw/qMIVdmaOk9W2lcRLtR6dlqTjo9hDeJk70QBYQ==} router@2.2.0: resolution: {integrity: sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ==} engines: {node: '>= 18'} + run-applescript@7.1.0: + resolution: {integrity: sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==} + engines: {node: '>=18'} + run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} rxjs@7.8.2: resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} - safe-array-concat@1.1.3: - resolution: {integrity: sha512-AURm5f0jYEOydBj7VQlVvDrjeFgthDdEF5H1dP+6mNpoXOMo1quQqJ4wvJDyRZ9+pO3kGWoOdmV08cSv2aJV6Q==} + safe-array-concat@1.1.4: + resolution: {integrity: sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==} engines: {node: '>=0.4'} - safe-buffer@5.2.1: - resolution: {integrity: sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==} - safe-push-apply@1.0.0: resolution: {integrity: sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==} engines: {node: '>= 0.4'} @@ -6869,15 +6722,16 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} - sanitize-html@2.17.0: - resolution: {integrity: sha512-dLAADUSS8rBwhaevT12yCezvioCA+bmUTPH/u57xKPT8d++voeYE6HeluA/bPbQ15TwDBG2ii+QZIEmYx8VdxA==} + sanitize-html@2.17.7: + resolution: {integrity: sha512-PGtEkc9cbnedU3s9TmzDbpsZ8w086g/0Q8k8/oIO1NLNU3i5k9yn835CrjJSajp1KMmkisbO1qPXxNKO3welAg==} + engines: {node: '>=22.12.0'} saxes@6.0.0: resolution: {integrity: sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==} engines: {node: '>=v12.22.7'} - scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + scheduler@0.28.0: + resolution: {integrity: sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==} selderee@0.11.0: resolution: {integrity: sha512-5TF+l7p4+OsnP8BCCvSyZiSPc4x4//p5uPwK8TCnVPJYRmU2aYKMpOXvw8zM5a5JvuuCGN1jmsMwuU2W02ukfA==} @@ -6886,37 +6740,38 @@ packages: resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} hasBin: true - semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + semver@7.8.5: + resolution: {integrity: sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==} engines: {node: '>=10'} hasBin: true - send@1.2.0: - resolution: {integrity: sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw==} + send@1.2.1: + resolution: {integrity: sha512-1gnZf7DFcoIcajTjTwjwuDjzuz4PPcY2StKPlsGAQ1+YH20IRVrBaXSWmdjowTJ6u8Rc01PoYOGHXfP1mYcZNQ==} engines: {node: '>= 18'} - serialize-javascript@6.0.2: - resolution: {integrity: sha512-Saa1xPByTTq2gdeFZYLLo+RFE35NHZkAbqZeWNd3BpzppeVisAqpDjcp8dyf6uIvEqJRd46jemmyA4iFIeVk8g==} + serialize-javascript@7.1.1: + resolution: {integrity: sha512-k3CMsaIvvdSwm8oLB4MXSl0wH2/cwlH7xGcnRd2DaeRmBkbzYmyT8j0tsX60DwD1eRwHTpNpH8ljKu9oUT1MeQ==} + engines: {node: '>=20.0.0'} - seroval-plugins@1.4.0: - resolution: {integrity: sha512-zir1aWzoiax6pbBVjoYVd0O1QQXgIL3eVGBMsBsNmM8Ukq90yGaWlfx0AB9dTS8GPqrOrbXn79vmItCUP9U3BQ==} + seroval-plugins@1.6.7: + resolution: {integrity: sha512-4Nk35ttD3DTDJW4hgw5StsVAPeU6qnDFnULAouw6tQ7oLTV/ICXrWpsXo2EE52eSP2joUMazbVf52mFEcADqRw==} engines: {node: '>=10'} peerDependencies: seroval: ^1.0 - seroval@1.4.0: - resolution: {integrity: sha512-BdrNXdzlofomLTiRnwJTSEAaGKyHHZkbMXIywOh7zlzp4uZnXErEwl9XZ+N1hJSNpeTtNxWvVwN0wUzAIQ4Hpg==} + seroval@1.6.7: + resolution: {integrity: sha512-AeDcLh0yO2SFm9W71essgnSzLV9DI8ZH0x0knXn2DMnUZj728mpLbxjlbB6IqKCmqh8JA3cEqRyGoNkt584JcQ==} engines: {node: '>=10'} - serve-static@2.2.0: - resolution: {integrity: sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ==} + serve-static@2.2.1: + resolution: {integrity: sha512-xRXBn0pPqQTVQiC8wyQrKs2MOlX24zQ0POGaj0kultvoOCstBQM5yvOhAVSUwOMjQtTvsPWoNCHfPGwaaQJhTw==} engines: {node: '>= 18'} set-blocking@2.0.0: resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} - set-cookie-parser@2.7.2: - resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + set-cookie-parser@3.1.2: + resolution: {integrity: sha512-5/r/lTwbJ3zQ+qwdUFZYeRNqda7P5HD8zQKqlSjdGt1/S0cjLAphHusj4Y58ahDtWn/g32xrIS58/ikOvwl0Lw==} set-function-length@1.2.2: resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} @@ -6933,17 +6788,19 @@ packages: setprototypeof@1.2.0: resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} - shadcn@3.5.1: - resolution: {integrity: sha512-yLbIDouYv8Xz25BxV/GAGC/46R7/oNwoXIs/IFIYXK47+fKcFIYzThtBqJwFEZTzkkvqJCo+MBg0K9QLTmhFmQ==} + shadcn@4.21.0: + resolution: {integrity: sha512-UU2mFNusW8C5rvadKdH69vERYZqUlOOlXBcf0MYhYLdTGP6DPti7X4qovCu+RTfCqsAgq/T+YfE0Vnttxh9aiw==} + engines: {node: '>=20.18.1'} hasBin: true - sharp@0.33.5: - resolution: {integrity: sha512-haPVm1EkS9pgvHrQ/F3Xy+hgcuMV0Wm9vfIBSiwZ05k+xgb0PkBQpGsAA/oWdDobNaZTH5ppvHtzCFbnSEwHVw==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} - - sharp@0.34.5: - resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} - engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + sharp@0.35.4: + resolution: {integrity: sha512-n++8XWcj+jCOr2IOl7h8LbKnGBDY4aPbmprMONBNFdn0ImXqpGVv5zliDs0V9HbmbCQLpbuo2ej9rAoOQTvMDA==} + engines: {node: '>=20.9.0'} + peerDependencies: + '@types/node': '*' + peerDependenciesMeta: + '@types/node': + optional: true shebang-command@2.0.0: resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} @@ -6953,15 +6810,12 @@ packages: resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} engines: {node: '>=8'} - shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + shell-quote@1.9.0: + resolution: {integrity: sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==} engines: {node: '>= 0.4'} - shimmer@1.2.1: - resolution: {integrity: sha512-sQTKC1Re/rM6XyFM6fIAGHRPVGvyXfgzIDvzoq608vM+jeyVD0Tu1E6Np0Kc2zAIFWIj963V2800iF/9LPieQw==} - - side-channel-list@1.0.0: - resolution: {integrity: sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==} + side-channel-list@1.0.1: + resolution: {integrity: sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==} engines: {node: '>= 0.4'} side-channel-map@1.0.1: @@ -6972,8 +6826,8 @@ packages: resolution: {integrity: sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==} engines: {node: '>= 0.4'} - side-channel@1.1.0: - resolution: {integrity: sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==} + side-channel@1.1.1: + resolution: {integrity: sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==} engines: {node: '>= 0.4'} siginfo@2.0.0: @@ -6986,15 +6840,6 @@ packages: resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} engines: {node: '>=14'} - simple-concat@1.0.1: - resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} - - simple-get@4.0.1: - resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} - - simple-swizzle@0.2.4: - resolution: {integrity: sha512-nAu1WFPQSMNr2Zn9PGSZK9AGn4t/y97lEm+MXTtUDwfP0ksAIX4nO+6ruD9Jwut4C49SB1Ws+fbXsm/yScWOHw==} - sirv@3.0.2: resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} engines: {node: '>=18'} @@ -7002,29 +6847,42 @@ packages: sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} - smob@1.5.0: - resolution: {integrity: sha512-g6T+p7QO8npa+/hNx9ohv1E5pVCmWrVCUzUXJyLdMmftX6ER0oiWY/w9knEonLpnOp6b6FenKnMfR8gqwWdwig==} + smart-buffer@4.2.0: + resolution: {integrity: sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==} + engines: {node: '>= 6.0.0', npm: '>= 3.0.0'} + + smob@1.6.2: + resolution: {integrity: sha512-RQsvleCbF8cVHEv+xuDGaA4pOizFqJ0GgjtMSRo6oP8pnN7WsigHgVGey6aILRBKv4W2YOMHLqbKdnB6hpB9fw==} + engines: {node: '>=20.0.0'} - smol-toml@1.5.2: - resolution: {integrity: sha512-QlaZEqcAH3/RtNyet1IPIYPsEWAaYyXXv1Krsi+1L/QHppjX4Ifm8MQsBISz9vE8cHicIq3clogsheili5vhaQ==} + smol-toml@1.8.0: + resolution: {integrity: sha512-kCZr2V3ch9i00x8zXRhjUNVcjG9ijES5dDudkXvUVCT5QlJNQWElSJdZqyPemffHoLNUYwOcou0Fy+ojN0uHSQ==} engines: {node: '>= 18'} - socket.io-adapter@2.5.5: - resolution: {integrity: sha512-eLDQas5dzPgOWCk9GuuJC2lBqItuhKI4uxGgo9aIV7MYbk2h9Q6uULEh8WBzThoI7l+qU9Ast9fVUmkqPP9wYg==} + socket.io-adapter@2.5.8: + resolution: {integrity: sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==} - socket.io-parser@4.2.4: - resolution: {integrity: sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==} + socket.io-parser@4.2.7: + resolution: {integrity: sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==} engines: {node: '>=10.0.0'} - socket.io@4.8.1: - resolution: {integrity: sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==} + socket.io@4.8.3: + resolution: {integrity: sha512-2Dd78bqzzjE6KPkD5fHZmDAKRNe3J15q+YHDrIsy9WEkqttc7GY+kT9OBLSMaPbQaEd0x1BjcmtMtXkfpc+T5A==} engines: {node: '>=10.2.0'} - sonner@2.0.7: - resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + socks@2.8.10: + resolution: {integrity: sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==} + engines: {node: '>= 10.0.0', npm: '>= 3.0.0'} + + sonner@2.0.8: + resolution: {integrity: sha512-UM/ByIoFra8yzV75n1o0Puu0bw5U/9UNnDacrJNspekBewIfsQ3D6ez1nvlWpt7aTsO6rujQtifBpycwIivqlg==} peerDependencies: + '@types/react': ^18.0.0 || ^19.0.0 react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true source-map-js@1.2.1: resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} @@ -7041,17 +6899,12 @@ packages: resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} engines: {node: '>= 12'} - source-map@0.8.0-beta.0: - resolution: {integrity: sha512-2ymg6oRBpebeZi9UUNsgQ89bhx01TcTkmNTGnNO88imTmbSgy4nfujrgVEFKWpMTEGA11EDkTt7mqObTPdigIA==} - engines: {node: '>= 8'} - deprecated: The work that was done in this beta branch won't be included in future versions - - sourcemap-codec@1.4.8: - resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} - deprecated: Please use @jridgewell/sourcemap-codec instead + source-map@0.8.0: + resolution: {integrity: sha512-d8EqvL+k/SOXCreS/SUzg2ciyHqBBLcN/yuRjFsbvVhHTE2pgei7oAhmPM7kWFbkX6OSMQfUq4KbkF3au9lhYQ==} + engines: {node: '>= 12'} - spawn-wrap@2.0.0: - resolution: {integrity: sha512-EeajNjfN9zMnULLwhZZQU3GWBoFNkbngTUPfaawT4RkMiviTxcX0qfhVbGey39mfctfDHkWtuecgQ8NJcyQWHg==} + spawn-wrap@3.0.0: + resolution: {integrity: sha512-z+s5vv4KzFPJVddGab0xX2n7kQPGMdNUX5l9T8EJqsXdKTWpcxmAqWHpsgHEXoC1taGBCc7b79bi62M5kdbrxQ==} engines: {node: '>=8'} sprintf-js@1.0.3: @@ -7060,12 +6913,15 @@ packages: stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + standardwebhooks@1.1.1: + resolution: {integrity: sha512-bCbX9ZEyFkWPsRz7Bl3NuQUJohmwGSev/yhr7vhaGPlc4AfIrspIRa6cPTBuI1ItmrTDJ4d/S2hCsfe4+vQGnQ==} + statuses@2.0.2: resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} engines: {node: '>= 0.8'} - std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + std-env@4.2.0: + resolution: {integrity: sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==} stdin-discarder@0.2.2: resolution: {integrity: sha512-UhDfHmA92YAlNnCfhmq0VeNL5bDbiZGg7sZ2IvPsXubGkiNa9EC+tUTsjBRsYUAz87btI6/1wf4XoVvQ3uRnmQ==} @@ -7075,44 +6931,30 @@ packages: resolution: {integrity: sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==} engines: {node: '>= 0.4'} - stoppable@1.1.0: - resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} - engines: {node: '>=4', npm: '>=6'} - - strict-event-emitter@0.5.1: - resolution: {integrity: sha512-vMgjE/GGEPEFnhFub6pa4FmJBRBVOLpIII2hvCZ8Kzb7K0hlHo7mQv6xYrBvCL2LtAIBwFUK8wvuJgTVSQ5MFQ==} - string-width@4.2.3: resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} engines: {node: '>=8'} - string-width@5.1.2: - resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} - engines: {node: '>=12'} - string-width@7.2.0: resolution: {integrity: sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==} engines: {node: '>=18'} - string.prototype.matchall@4.0.12: - resolution: {integrity: sha512-6CC9uyBL+/48dYizRf7H7VAYCMCNTBeM78x/VTUe9bFEaxBepPJDa1Ow99LqI/1yF7kuy7Q3cQsYMrcjGUcskA==} + string.prototype.matchall@4.1.0: + resolution: {integrity: sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==} engines: {node: '>= 0.4'} - string.prototype.trim@1.2.10: - resolution: {integrity: sha512-Rs66F0P/1kedk5lyYyH9uBzuiI/kNRmwJAR9quK6VOtIpZ2G+hMZd+HQbbv25MgCA6gEffoMZYxlTod4WcdrKA==} + string.prototype.trim@1.2.11: + resolution: {integrity: sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==} engines: {node: '>= 0.4'} - string.prototype.trimend@1.0.9: - resolution: {integrity: sha512-G7Ok5C6E/j4SGfyLCloXTrngQIQU3PWtXGst3yM7Bea9FRURf1S42ZHlZZtsNque2FN2PoUhfZXYLNWwEr4dLQ==} + string.prototype.trimend@1.0.10: + resolution: {integrity: sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==} engines: {node: '>= 0.4'} string.prototype.trimstart@1.0.8: resolution: {integrity: sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==} engines: {node: '>= 0.4'} - string_decoder@1.3.0: - resolution: {integrity: sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==} - stringify-object@3.3.0: resolution: {integrity: sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw==} engines: {node: '>=4'} @@ -7125,8 +6967,8 @@ packages: resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} engines: {node: '>=8'} - strip-ansi@7.1.2: - resolution: {integrity: sha512-gmBGslpoQJtgnMAvOVqGZpEz9dyoKTCzy2nfz/n8aIFhN/jCE/rCmcxabB6jOOHV+0WNnylOxaxBQPSvcWklhA==} + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} engines: {node: '>=12'} strip-bom@3.0.0: @@ -7153,20 +6995,12 @@ packages: resolution: {integrity: sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==} engines: {node: '>=8'} - strip-json-comments@2.0.1: - resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==} - engines: {node: '>=0.10.0'} - - strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - strip-json-comments@5.0.3: resolution: {integrity: sha512-1tB5mhVo7U+ETBKNf92xT4hrQa3pm0MZ0PQvuDnWgAAGHDsfp4lPSpiS6psrSiet87wyGPh9ft6wmhOMQ0hDiw==} engines: {node: '>=14.16'} - strnum@2.1.1: - resolution: {integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==} + strnum@2.4.2: + resolution: {integrity: sha512-rDG3Ah4TV0k1hWvLSzkZtMmLN9+eS+h3knq4MP6A42Y3Yh5qGNnOUs1jJkoSr8FG5dsL28c7KgkIBzSEykqtuw==} stubborn-fs@2.0.0: resolution: {integrity: sha512-Y0AvSwDw8y+nlSNFXMm2g6L51rBGdAQT20J3YSOqxC53Lo3bjWRtr2BKcfYoAf352WYpsZSTURrA0tqhfgudPA==} @@ -7174,19 +7008,6 @@ packages: stubborn-utils@1.0.2: resolution: {integrity: sha512-zOh9jPYI+xrNOyisSelgym4tolKTJCQd5GBhK0+0xJvcYDcwlOoxF/rnFKQ2KRZknXSG9jWAp66fwP6AxN9STg==} - styled-jsx@5.1.6: - resolution: {integrity: sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==} - engines: {node: '>= 12.0.0'} - peerDependencies: - '@babel/core': '*' - babel-plugin-macros: '*' - react: '>= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0' - peerDependenciesMeta: - '@babel/core': - optional: true - babel-plugin-macros: - optional: true - sucrase@3.35.1: resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} engines: {node: '>=16 || 14 >=14.17'} @@ -7204,43 +7025,36 @@ packages: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} - supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} - supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - svix@1.76.1: - resolution: {integrity: sha512-CRuDWBTgYfDnBLRaZdKp9VuoPcNUq9An14c/k+4YJ15Qc5Grvf66vp0jvTltd4t7OIRj+8lM1DAgvSgvf7hdLw==} - - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + systeminformation@5.33.12: + resolution: {integrity: sha512-7x1LtTPaopmrXUJmnxW6I98YIDihwiZEETD+hzI9X/GGIghcz8r38vlZ+TAqwQTOhPuZPB1xn/AJ2GPzvn9JfQ==} + engines: {node: '>=10.0.0'} + os: [darwin, linux, win32, freebsd, openbsd, netbsd, sunos, android] + hasBin: true - tabbable@6.3.0: - resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + tabbable@6.5.0: + resolution: {integrity: sha512-wieBHXygIm7OyQOu5hQlkk62/WyCFYGlWg7L6/ZCUZwx0o398Zkn4pVmMyfYhfMG8kGrj/Krt8eIk6UKC6VzwA==} tagged-tag@1.0.0: resolution: {integrity: sha512-yEFYrVhod+hdNyx7g5Bnkkb0G6si8HJurOoOEgC8B/O0uXLHlaey/65KRv6cuWBNhBgHKAROVpc7QyYqE5gFng==} engines: {node: '>=20'} - tailwind-merge@3.4.0: - resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + tailwind-merge@3.7.0: + resolution: {integrity: sha512-XPPUyAc+cvspz3lHTcR/QgPfW2A0lv/xQNIjX3HGhLR+Nq2lHaLq5MtTesHn8GUr3W3DguT2KT5x3NVgRtYwmA==} - tailwindcss@4.1.17: - resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} + tailwindcss@4.3.3: + resolution: {integrity: sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==} - tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} engines: {node: '>=6'} - tar-fs@2.1.4: - resolution: {integrity: sha512-mDAjwmZdh7LTT6pNleZ05Yt65HC3E+NiQzl672vQG38jIrehtJk/J3mNwIg+vShQPcLF/LV7CMnDW6vjj6sfYQ==} - - tar-stream@2.2.0: - resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} - engines: {node: '>=6'} + tar@7.5.22: + resolution: {integrity: sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==} + engines: {node: '>=18'} temp-dir@2.0.0: resolution: {integrity: sha512-aoBAniQmmwtcKp/7BzsH8Cxzv8OL736p7v1ihGb5e9DJ9kTwGWHrQrVB5+lfVDzfGrdRzXch+ig7LHaY1JTOrg==} @@ -7250,14 +7064,14 @@ packages: resolution: {integrity: sha512-G13vtMYPT/J8A4X2SjdtBTphZlrp1gKv6hZiOjw14RCWg6GbHuQBGtjlx75xLbYV/wEc0D7G5K4rxKP/cXk8Bw==} engines: {node: '>=10'} - terser@5.44.1: - resolution: {integrity: sha512-t/R3R/n0MSwnnazuPpPNVO60LX0SKL45pyl9YlvxIdkH0Of7D5qM2EVe+yASRIlY5pZ73nclYJfNANGWPwFDZw==} + terser@5.51.2: + resolution: {integrity: sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==} engines: {node: '>=10'} hasBin: true - test-exclude@6.0.0: - resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} - engines: {node: '>=8'} + test-exclude@8.0.0: + resolution: {integrity: sha512-ZOffsNrXYggvU1mDGHk54I96r26P8SyMjO5slMKSc7+IWmtB/MQKnEC2fP51imB3/pT6YK5cT5E8f+Dd9KdyOQ==} + engines: {node: 20 || >=22} thenify-all@1.6.0: resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} @@ -7269,32 +7083,34 @@ packages: tiny-invariant@1.3.3: resolution: {integrity: sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==} - tiny-warning@1.0.3: - resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==} - - tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + tinybench@6.1.4: + resolution: {integrity: sha512-9APumHG7r4yOk4X4WlkmE71aZcv1gvin1czO3OQ1U9iJcFA5Ja/ygyb0vPOVHTthFozUYs8CLoLUlM8grb2lTQ==} + engines: {node: '>=20.0.0'} tinyexec@0.3.2: resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - tinyexec@1.0.2: - resolution: {integrity: sha512-W/KYk+NFhkmsYpuHq5JykngiOCnxeVL8v8dFnqxSD8qEEdRfXk1SDM6JzNqcERbcGYj9tMrDQBYV9cjgnunFIg==} + tinyexec@1.3.0: + resolution: {integrity: sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==} engines: {node: '>=18'} - tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + tinyexec@1.3.1: + resolution: {integrity: sha512-GCvB3aoys96IuDFBMcTB46JOR6mdMtAToqwiW8JlWhsoh1mhHi/xn9ss/Dg7N555GiJyEt2qzoG/NHCwM6h1EA==} + engines: {node: '>=18'} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} engines: {node: '>=12.0.0'} - tinyrainbow@3.0.3: - resolution: {integrity: sha512-PSkbLUoxOFRzJYjjxHJt9xro7D+iilgMX/C9lawzVuYiIdcihh9DXmVibBe8lmcFrRi/VzlPjBxbN7rH24q8/Q==} + tinyrainbow@3.1.1: + resolution: {integrity: sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==} engines: {node: '>=14.0.0'} - tldts-core@7.0.19: - resolution: {integrity: sha512-lJX2dEWx0SGH4O6p+7FPwYmJ/bu1JbcGJ8RLaG9b7liIgZ85itUVEPbMtWRVrde/0fnDPEPHW10ZsKW3kVsE9A==} + tldts-core@7.4.13: + resolution: {integrity: sha512-mbYsrih5FRtGxs3Usvl/PqwJsNpp+jsmrdFviiK02teHDG0/HebBG/pqCylje3kzgXYzuLoHJF/0mz9W53t8Xg==} - tldts@7.0.19: - resolution: {integrity: sha512-8PWx8tvC4jDB39BQw1m4x8y5MH1BcQ5xHeL2n7UVFulMPH/3Q0uiamahFJ3lXA0zO2SUyRXuVVbWSDmstlt9YA==} + tldts@7.4.13: + resolution: {integrity: sha512-iHtaIWWIbMDkCeJdTBzZFGgbluE5J+oHlb2g7+oAz1S1gpuVpabRZdQyd471Vl8UUkcz2vXSL8xZH2kyCe8tfA==} hasBin: true to-regex-range@5.0.1: @@ -7309,13 +7125,10 @@ packages: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - tough-cookie@6.0.0: - resolution: {integrity: sha512-kXuRi1mtaKMrsLUxz3sQYvVl37B0Ns6MzfrtV5DvJceE9bPyspOqk9xxv7XbZWcfLWbFmm997vl83qUWVJA64w==} + tough-cookie@6.0.2: + resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} engines: {node: '>=16'} - tr46@1.0.1: - resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} - tr46@6.0.0: resolution: {integrity: sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==} engines: {node: '>=20'} @@ -7324,8 +7137,8 @@ packages: resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} hasBin: true - ts-api-utils@2.1.0: - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} engines: {node: '>=18.12'} peerDependencies: typescript: '>=4.8.4' @@ -7362,14 +7175,11 @@ packages: typescript: optional: true - tsx@4.20.6: - resolution: {integrity: sha512-ytQKuwgmrrkDTFP4LjR0ToE2nqgy886GpvRSpU0JAnrdBYppuY5rLkRUYPU1yCryb24SsKBTL/hlDQAEFVwtZg==} + tsx@4.23.13: + resolution: {integrity: sha512-BL5MGkRln6aDYhb0xbQlEAGw743BaZYWdbWtdJOBriYJboKgUUYCadFp2/FpBBZquBC/ezNBn7wMMPx7FDZUDw==} engines: {node: '>=18.0.0'} hasBin: true - tunnel-agent@0.6.0: - resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} - tw-animate-css@1.4.0: resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} @@ -7385,17 +7195,13 @@ packages: resolution: {integrity: sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==} engines: {node: '>=8'} - type-fest@5.2.0: - resolution: {integrity: sha512-xxCJm+Bckc6kQBknN7i9fnP/xobQRsRQxR01CztFkp/h++yfVxUUcmMgfR2HttJx/dpWjS9ubVuyspJv24Q9DA==} + type-fest@5.10.0: + resolution: {integrity: sha512-NoSdpq/WEiAg5sjmBkmV/hfxv6HJH4NqPNrqjtSO5CwRmpsDfaf4begxW34KdJykH/l1yHtwBWQkCRdoXO8mPA==} engines: {node: '>=20'} - type-fest@5.3.0: - resolution: {integrity: sha512-d9CwU93nN0IA1QL+GSNDdwLAu1Ew5ZjTwupvedwg3WdfoH6pIDvYQ2hV0Uc2nKBLPq7NB5apCx57MLS5qlmO5g==} - engines: {node: '>=20'} - - type-is@2.0.1: - resolution: {integrity: sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw==} - engines: {node: '>= 0.6'} + type-is@2.1.0: + resolution: {integrity: sha512-faYHw0anBbc/kWF3zFTEnxSFOAGUX9GFbOBthvDdLsIlEoWOFOtS0zgCiQYwIskL9iGXZL3kAXD8OoZ4GmMATA==} + engines: {node: '>= 18'} typed-array-buffer@1.0.3: resolution: {integrity: sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==} @@ -7405,50 +7211,67 @@ packages: resolution: {integrity: sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==} engines: {node: '>= 0.4'} - typed-array-byte-offset@1.0.4: - resolution: {integrity: sha512-bTlAFB/FBYMcuX81gbL4OcpH5PmlFHqlCCpAl8AlEzMz5k53oNDvN8p1PNOWLEmI2x4orp3raOFB51tv9X+MFQ==} + typed-array-byte-offset@1.0.5: + resolution: {integrity: sha512-0FHJvLPqZ7KJzp17O13jfsAjsqazgrxBu2zEK95PmUz8lv2+GjRuxUInCr2Rk9Dms3ihN21zJ929ZO43yJ95QQ==} engines: {node: '>= 0.4'} - typed-array-length@1.0.7: - resolution: {integrity: sha512-3KS2b+kL7fsuk/eJZ7EQdnEmQoaho/r6KUef7hxvltNA5DR8NAUM+8wJMbJyZ4G9/7i3v5zPBIMN5aybAh2/Jg==} + typed-array-length@1.0.8: + resolution: {integrity: sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==} engines: {node: '>= 0.4'} typedarray-to-buffer@3.1.5: resolution: {integrity: sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q==} - typescript-eslint@8.47.0: - resolution: {integrity: sha512-Lwe8i2XQ3WoMjua/r1PHrCTpkubPYJCAfOurtn+mtTzqB6jNd+14n9UN1bJ4s3F49x9ixAm0FLflB/JzQ57M8Q==} + typescript-eslint@8.70.0: + resolution: {integrity: sha512-P/W5cz70/cQAuKfY3xwQMWWTV7BvJ0mAQmi+9mBcsVPaBUpd6Ohpa+fECv9rBFrQcig86jAiNBFNWUqnTjr4pw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' - typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + typescript@6.0.3: + resolution: {integrity: sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==} engines: {node: '>=14.17'} hasBin: true - ufo@1.6.1: - resolution: {integrity: sha512-9a4/uxlTWJ4+a5i0ooc1rU7C7YOw3wT+UGqdeNNHWnOF9qcMBgLRS+4IYUqbczewFx4mLEig6gawh7X6mFlEkA==} + typescript@7.0.2: + resolution: {integrity: sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==} + engines: {node: '>=16.20.0'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} uint8array-extras@1.5.0: resolution: {integrity: sha512-rvKSBiC5zqCCiDZ9kAOszZcDvdAHwwIKJG33Ykj43OKcWsnmcBRL09YTU4nOeHZ8Y2a7l1MgTd08SBe9A8Qj6A==} engines: {node: '>=18'} + unbash@4.0.11: + resolution: {integrity: sha512-FoSOKV7NEofQSkAefMVHam4ZPKYMxjAydxiV72UFEDNV/YofxjGfiZ2A9pZjdL/lRJzTjcu4PABo1JYJX8N5iQ==} + engines: {node: '>=14'} + unbox-primitive@1.1.0: resolution: {integrity: sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==} engines: {node: '>= 0.4'} - undici-types@6.21.0: - resolution: {integrity: sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==} + undici-types@7.18.2: + resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} + + undici-types@8.9.0: + resolution: {integrity: sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==} - undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici@7.29.0: + resolution: {integrity: sha512-IDxfleLmmbSskfWSUATiN1nfn2rDuvnMOqb5CWR92iIfojA0Ud+ulOAAEQ57LPr9rWmsreUyf5lwyao+7GNNVw==} + engines: {node: '>=20.18.1'} - undici@7.14.0: - resolution: {integrity: sha512-Vqs8HTzjpQXZeXdpsfChQTlafcMQaaIwnGwLam1wudSSjlJeQ3bw1j+TLPePgrCnCpUXx7Ba5Pdpf5OBih62NQ==} + undici@7.29.1: + resolution: {integrity: sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==} engines: {node: '>=20.18.1'} + undici@8.10.2: + resolution: {integrity: sha512-/y4/bH9YNU5hi9NIrpOuvGXFcxrj3CMrV+/AYpowAYTpHn8gX/XPFjNy766FPoYY0miQhdW977JFWKGNhBdwyQ==} + engines: {node: '>=22.19.0'} + unenv@2.0.0-rc.24: resolution: {integrity: sha512-i7qRCmY42zmCwnYlh9H2SvLEypEFGye5iRmEMKjcGi7zk9UquigRjFtTLz0TYqr0ZGLZhaMHl/foy1bZR+Cwlw==} @@ -7484,19 +7307,48 @@ packages: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} - unplugin@2.3.11: - resolution: {integrity: sha512-5uKD0nqiYVzlmCRs01Fhs2BdkEgBS3SAVP6ndrBsuK42iC2+JHyxM05Rm9G8+5mkmRtzMZGY8Ct5+mliZxU/Ww==} - engines: {node: '>=18.12.0'} - - until-async@3.0.2: - resolution: {integrity: sha512-IiSk4HlzAMqTUseHHe3VhIGyuFmN90zMTpD3Z3y8jeQbzLIq500MVM7Jq2vUAnTKAFPJrqwkzr6PoTcPhGcOiw==} + unplugin@3.4.0: + resolution: {integrity: sha512-9skdIFlCsPdFV7wUfZxNsFInlW+7nJmGu2gkTu0OUhF56aXGsHab9x52/QhdJ4lC7ZDPWTxbiC4ANqVlsuaW3w==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@farmfe/core': '*' + '@rsbuild/core': '*' + '@rspack/core': '*' + bun-types-no-globals: '*' + esbuild: '>=0.28.1' + rolldown: '*' + rollup: '*' + unloader: '*' + vite: '*' + webpack: '*' + peerDependenciesMeta: + '@farmfe/core': + optional: true + '@rsbuild/core': + optional: true + '@rspack/core': + optional: true + bun-types-no-globals: + optional: true + esbuild: + optional: true + rolldown: + optional: true + rollup: + optional: true + unloader: + optional: true + vite: + optional: true + webpack: + optional: true upath@1.2.0: resolution: {integrity: sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg==} engines: {node: '>=4'} - update-browserslist-db@1.2.2: - resolution: {integrity: sha512-E85pfNzMQ9jpKkA7+TJAi4TJN+tBCuWh5rUcS/sv6cFi+1q9LYDwDI5dpUL0u/73EElyQ8d3TEaeW4sPedBqYA==} + update-browserslist-db@1.3.3: + resolution: {integrity: sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==} hasBin: true peerDependencies: browserslist: '>= 4.21.0' @@ -7504,9 +7356,6 @@ packages: uri-js@4.4.1: resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} - url-parse@1.5.10: - resolution: {integrity: sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==} - use-callback-ref@1.3.3: resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} engines: {node: '>=10'} @@ -7527,21 +7376,17 @@ packages: '@types/react': optional: true - use-sync-external-store@1.6.0: - resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + use-sync-external-store@1.7.0: + resolution: {integrity: sha512-6L+EeigHMQhdaIPNIFUKwfWJSwWFQ8gJbJ2DLOs5sDIegTwR9fRxvnM3uciHKjIZhFz+KAv2emhWMRvDmMcY8A==} peerDependencies: react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 util-deprecate@1.0.2: resolution: {integrity: sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==} - uuid@10.0.0: - resolution: {integrity: sha512-8XkAphELsDnEGrDxUOHB3RGvXz6TeuYSGEZBOjtTtPm2lwhGBjLgOzLHB63IUWfBpNucQjND6d3AOudO+H3RWQ==} - hasBin: true - - uuid@8.3.2: - resolution: {integrity: sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==} - hasBin: true + validate-npm-package-name@7.0.2: + resolution: {integrity: sha512-hVDIBwsRruT73PbK7uP5ebUt+ezEtCmzZz3F59BSr2F6OVFnJ/6h8liuvdLrQ88Xmnk6/+xGGuq+pG9WwTuy3A==} + engines: {node: ^20.17.0 || >=22.9.0} vary@1.1.2: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} @@ -7556,40 +7401,83 @@ packages: victory-vendor@37.3.6: resolution: {integrity: sha512-SbPDPdDBYp+5MJHhBCAyI7wKM3d5ivekigc2Dk2s7pgbZ9wIgIBYGVw4zGHBml/qTFbexrofXW6Gu4noGxrOwQ==} - vite-plugin-pwa@1.1.0: - resolution: {integrity: sha512-VsSpdubPzXhHWVINcSx6uHRMpOHVHQcHsef1QgkOlEoaIDAlssFEW88LBq1a59BuokAhsh2kUDJbaX1bZv4Bjw==} + vite-plugin-pwa@1.3.0: + resolution: {integrity: sha512-c5kMgN+ITrOtHXp8PAtk2uOIEea6XjP/unCGxOWWBzQ6qa65qj/awHg0wf+QF9E/2u9vh86LqxPwzEPNbM2r5A==} engines: {node: '>=16.0.0'} peerDependencies: '@vite-pwa/assets-generator': ^1.0.0 - vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - workbox-build: ^7.3.0 - workbox-window: ^7.3.0 + vite: ^3.1.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 + workbox-build: ^7.4.1 + workbox-window: ^7.4.1 peerDependenciesMeta: '@vite-pwa/assets-generator': optional: true - vitest@4.0.13: - resolution: {integrity: sha512-QSD4I0fN6uZQfftryIXuqvqgBxTvJ3ZNkF6RWECd82YGAYAfhcppBLFXzXJHQAAhVFyYEuFTrq6h0hQqjB7jIQ==} - engines: {node: ^20.0.0 || ^22.0.0 || >=24.0.0} + vite@8.3.0: + resolution: {integrity: sha512-lhZBVvEHefgE+HQZC9O7EBJgCU/nVzFNl7vkS4RE0APtWLP02/8QVIkQtzBxPquh7lq5/78NHipTj7ODQ6XuyQ==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.7.1 + esbuild: '>=0.28.1' + 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 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@5.0.1: + resolution: {integrity: sha512-iA95lQbKEkvrtTkdAgnWbXfbipWiiWe/hDl2P5tMi6WFwD76G0NxXAGp/M9EOcYupeGJRr6wppMc7CoA41TQjg==} + engines: {node: ^22.12.0 || ^24.0.0 || >=26.0.0} hasBin: true peerDependencies: '@edge-runtime/vm': '*' '@opentelemetry/api': ^1.9.0 - '@types/debug': ^4.1.12 - '@types/node': ^20.0.0 || ^22.0.0 || >=24.0.0 - '@vitest/browser-playwright': 4.0.13 - '@vitest/browser-preview': 4.0.13 - '@vitest/browser-webdriverio': 4.0.13 - '@vitest/ui': 4.0.13 + '@types/node': ^22.0.0 || >=24.0.0 + '@vitest/browser-playwright': 5.0.1 + '@vitest/browser-preview': 5.0.1 + '@vitest/browser-webdriverio': ^5.0.0-beta.5 || >=5.0.0 + '@vitest/coverage-istanbul': 5.0.1 + '@vitest/coverage-v8': 5.0.1 + '@vitest/ui': 5.0.1 happy-dom: '*' jsdom: '*' + vite: ^6.4.0 || ^7.0.0 || ^8.0.0 peerDependenciesMeta: '@edge-runtime/vm': optional: true '@opentelemetry/api': optional: true - '@types/debug': - optional: true '@types/node': optional: true '@vitest/browser-playwright': @@ -7598,6 +7486,10 @@ packages: optional: true '@vitest/browser-webdriverio': optional: true + '@vitest/coverage-istanbul': + optional: true + '@vitest/coverage-v8': + optional: true '@vitest/ui': optional: true happy-dom: @@ -7613,34 +7505,24 @@ packages: resolution: {integrity: sha512-3hu+tD8YzSLGuFYtPRb48vdhKMi0KQV5sn+uWr8+7dMEq/2G/dtLrdDinkLjqq5TIbIBjYJ4Ax/n3YiaW7QM8A==} engines: {node: 20 || >=22} - web-streams-polyfill@3.3.3: - resolution: {integrity: sha512-d2JWLCivmZYTSIoge9MsgFCZrt571BikcWGYkjC1khllbTeDlGqZ2D8vD8E/lJa8WGWbb7Plm8/XJYV7IJHZZw==} - engines: {node: '>= 8'} - - webidl-conversions@4.0.2: - resolution: {integrity: sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==} - - webidl-conversions@8.0.0: - resolution: {integrity: sha512-n4W4YFyz5JzOfQeA8oN7dUYpR+MBP3PIUsn2jLjWXwK5ASUzt0Jc/A5sAUZoCYFJRGF0FBKJ+1JjN43rNdsQzA==} + webidl-conversions@8.0.1: + resolution: {integrity: sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==} engines: {node: '>=20'} webpack-virtual-modules@0.6.2: resolution: {integrity: sha512-66/V2i5hQanC51vBQKPH4aI8NMAcBW59FVBs+rC7eGHupMyfn34q7rZIE+ETlJ+XTevqfUhVVBgSUNSW2flEUQ==} - whatwg-encoding@3.1.1: - resolution: {integrity: sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==} - engines: {node: '>=18'} - - whatwg-mimetype@4.0.0: - resolution: {integrity: sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==} - engines: {node: '>=18'} - - whatwg-url@15.1.0: - resolution: {integrity: sha512-2ytDk0kiEj/yu90JOAp44PVPUkO9+jVhyf+SybKlRHSDlvOOZhdPIrr7xTH64l4WixO2cP+wQIcgujkGBPPz6g==} + whatwg-mimetype@5.0.0: + resolution: {integrity: sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==} engines: {node: '>=20'} - whatwg-url@7.1.0: - resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} + whatwg-url@16.0.1: + resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + + whatwg-url@17.1.1: + resolution: {integrity: sha512-ohjk1mdUebJVadRt3bAhQhx8lSnISq+GDttK79LFl8EHQkAPvzwctoasC4hs8tBt6kLAncBWWyq1N52qEfKvDw==} + engines: {node: ^22.14.0 || >=24.0.0} when-exit@2.1.5: resolution: {integrity: sha512-VGkKJ564kzt6Ms1dbgPP/yuIoQCrsFAnRbptpC5wOEsDaNsbCB2bnfnaA8i/vRs5tjUSEOtIuvl9/MyVsvQZCg==} @@ -7660,8 +7542,8 @@ packages: which-module@2.0.1: resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} - which-typed-array@1.1.19: - resolution: {integrity: sha512-rEvr90Bck4WZt9HHFC4DJMsjvu7x+r6bImz0/BrbWb7A2djJ8hnZMrWnHo9F8ssv0OMErasDhftrfROTyqSDrw==} + which-typed-array@1.1.23: + resolution: {integrity: sha512-JMh8aK+1B/0bk/YNupICmH5MgCq6yNLKYQUfsZtSDLLCCmxUkHjUY+oOlIa90lO7lHN1woAfpenLdlKpXy9o+A==} engines: {node: '>= 0.4'} which@2.0.2: @@ -7674,6 +7556,11 @@ packages: engines: {node: ^16.13.0 || >=18.0.0} hasBin: true + which@7.0.0: + resolution: {integrity: sha512-RancgH2dmbLdHl6LRhEqvklWMgl/Hdnun0Y90KhBOLkMefg8Qa7/Zel8Sm+8HEcP6DEjzsWzpkuBQEZok58isA==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} + hasBin: true + why-is-node-running@2.3.0: resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} engines: {node: '>=8'} @@ -7683,72 +7570,66 @@ packages: resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} engines: {node: '>=0.10.0'} - workbox-background-sync@7.3.0: - resolution: {integrity: sha512-PCSk3eK7Mxeuyatb22pcSx9dlgWNv3+M8PqPaYDokks8Y5/FX4soaOqj3yhAZr5k6Q5JWTOMYgaJBpbw11G9Eg==} + workbox-background-sync@7.4.1: + resolution: {integrity: sha512-HhT7KE8tOWDm02wRNshXUnUPofMlhenF2DBdUnDPOubhizzPeItkYTmAB6td1Z2cjYPa98vzEiPLEuzn5hN66g==} - workbox-broadcast-update@7.3.0: - resolution: {integrity: sha512-T9/F5VEdJVhwmrIAE+E/kq5at2OY6+OXXgOWQevnubal6sO92Gjo24v6dCVwQiclAF5NS3hlmsifRrpQzZCdUA==} + workbox-broadcast-update@7.4.1: + resolution: {integrity: sha512-uAlgslKLvbQY+suirIdnBCSYrcgBhjp81Nj4l1lj/Jmj0MJO2CJERnCJjT0GFVwmReV0N+zs78K6gqd5gr9/+A==} - workbox-build@7.3.0: - resolution: {integrity: sha512-JGL6vZTPlxnlqZRhR/K/msqg3wKP+m0wfEUVosK7gsYzSgeIxvZLi1ViJJzVL7CEeI8r7rGFV973RiEqkP3lWQ==} - engines: {node: '>=16.0.0'} - - workbox-cacheable-response@7.3.0: - resolution: {integrity: sha512-eAFERIg6J2LuyELhLlmeRcJFa5e16Mj8kL2yCDbhWE+HUun9skRQrGIFVUagqWj4DMaaPSMWfAolM7XZZxNmxA==} - - workbox-core@7.3.0: - resolution: {integrity: sha512-Z+mYrErfh4t3zi7NVTvOuACB0A/jA3bgxUN3PwtAVHvfEsZxV9Iju580VEETug3zYJRc0Dmii/aixI/Uxj8fmw==} + workbox-build@7.4.1: + resolution: {integrity: sha512-SDhxIvEAde9Gy/5w4Yo1Jh/M49Z0qE3q0oteyE8zGq0DScxFqVBcCtIXFuLtmtxRQZCMbf0prco4VyEu3KBQuw==} + engines: {node: '>=20.0.0'} - workbox-core@7.4.0: - resolution: {integrity: sha512-6BMfd8tYEnN4baG4emG9U0hdXM4gGuDU3ectXuVHnj71vwxTFI7WOpQJC4siTOlVtGqCUtj0ZQNsrvi6kZZTAQ==} + workbox-cacheable-response@7.4.1: + resolution: {integrity: sha512-8xaFoJdDc2OjrlbbL3gEeBO1WKcMwRqwLRupgqahYXu75yXajPLuwrbXMrIGZuWYXrQwk0xDjOxZ/ujCy/oJYw==} - workbox-expiration@7.3.0: - resolution: {integrity: sha512-lpnSSLp2BM+K6bgFCWc5bS1LR5pAwDWbcKt1iL87/eTSJRdLdAwGQznZE+1czLgn/X05YChsrEegTNxjM067vQ==} + workbox-core@7.4.1: + resolution: {integrity: sha512-DT+vu46eh/2vRsSHTY4Xmc32Z1rr9PRlQUXr1Dx30ZuXRWwOsvZgGgcwxcasubQLQmbTNYZjv44LkBAQ4tT5tQ==} - workbox-google-analytics@7.3.0: - resolution: {integrity: sha512-ii/tSfFdhjLHZ2BrYgFNTrb/yk04pw2hasgbM70jpZfLk0vdJAXgaiMAWsoE+wfJDNWoZmBYY0hMVI0v5wWDbg==} + workbox-expiration@7.4.1: + resolution: {integrity: sha512-lRKUF7b+OGbeXkQk1s6MHXOa3d7Xxf7Of31W6c6hCfipfIyrtdWZ89stq21AHZMaoG7VNFoHply4Ox+rU31TWg==} - workbox-navigation-preload@7.3.0: - resolution: {integrity: sha512-fTJzogmFaTv4bShZ6aA7Bfj4Cewaq5rp30qcxl2iYM45YD79rKIhvzNHiFj1P+u5ZZldroqhASXwwoyusnr2cg==} + workbox-google-analytics@7.4.1: + resolution: {integrity: sha512-Mks1JwLEt++ZAkF6sS1OpSh9RtAMIsiDgRpK+codiHGIPXeaUOgi4cPc3GFadUl8V5QPeypEk8Oxgl3HlwVzHw==} - workbox-precaching@7.3.0: - resolution: {integrity: sha512-ckp/3t0msgXclVAYaNndAGeAoWQUv7Rwc4fdhWL69CCAb2UHo3Cef0KIUctqfQj1p8h6aGyz3w8Cy3Ihq9OmIw==} + workbox-navigation-preload@7.4.1: + resolution: {integrity: sha512-C4KVsjPcYKJOhr631AxR9XoG2rLF3QiTk5aMv36MXOjtWvm8axwNFAtKUPGsWUwLXXAMgYM1En7fsvndaXeXRQ==} - workbox-range-requests@7.3.0: - resolution: {integrity: sha512-EyFmM1KpDzzAouNF3+EWa15yDEenwxoeXu9bgxOEYnFfCxns7eAxA9WSSaVd8kujFFt3eIbShNqa4hLQNFvmVQ==} + workbox-precaching@7.4.1: + resolution: {integrity: sha512-cdr/9qByww7yzEp7zg/qI4ukUrrNjQLgN+ONQRpjy/VqGQXwkgHwr00KksGJK8v0VifwDXBb8a4cWNZH71jn3Q==} - workbox-recipes@7.3.0: - resolution: {integrity: sha512-BJro/MpuW35I/zjZQBcoxsctgeB+kyb2JAP5EB3EYzePg8wDGoQuUdyYQS+CheTb+GhqJeWmVs3QxLI8EBP1sg==} + workbox-range-requests@7.4.1: + resolution: {integrity: sha512-7i2oxAUE82gHdAJBCAQ04JzNOdRPqzuOzGfoUyJpFSmeqBNYGPrAH8GPoPjUQTfp+NycwrD2H68VtuF8qxv0vQ==} - workbox-routing@7.3.0: - resolution: {integrity: sha512-ZUlysUVn5ZUzMOmQN3bqu+gK98vNfgX/gSTZ127izJg/pMMy4LryAthnYtjuqcjkN4HEAx1mdgxNiKJMZQM76A==} + workbox-recipes@7.4.1: + resolution: {integrity: sha512-gnbVfmV4/TtmQaM4x9AtuXhcdstJsep3XMVeztOrQVPT+R6+6DeBjGTCQ7fFCXm+4GEHUA5VEBTyi5+4gWGeog==} - workbox-strategies@7.3.0: - resolution: {integrity: sha512-tmZydug+qzDFATwX7QiEL5Hdf7FrkhjaF9db1CbB39sDmEZJg3l9ayDvPxy8Y18C3Y66Nrr9kkN1f/RlkDgllg==} + workbox-routing@7.4.1: + resolution: {integrity: sha512-yubJGErZOusuidAenaL5ypfhQOa7urxP/f8E0ws7FPb4039RiWXUWBAyUkmUoOL/BcQGen3h0J8872d51IYxtA==} - workbox-streams@7.3.0: - resolution: {integrity: sha512-SZnXucyg8x2Y61VGtDjKPO5EgPUG5NDn/v86WYHX+9ZqvAsGOytP0Jxp1bl663YUuMoXSAtsGLL+byHzEuMRpw==} + workbox-strategies@7.4.1: + resolution: {integrity: sha512-GZxpaw9NbmOelj7667uZ2kpk5BFpOGbO4X0qjwh5ls8XQ8C+Lha5LQchTiUzsTFSS+NlUpftYAyOVXvQUrcqOQ==} - workbox-sw@7.3.0: - resolution: {integrity: sha512-aCUyoAZU9IZtH05mn0ACUpyHzPs0lMeJimAYkQkBsOWiqaJLgusfDCR+yllkPkFRxWpZKF8vSvgHYeG7LwhlmA==} + workbox-streams@7.4.1: + resolution: {integrity: sha512-HWWtraKUbJknd9kgqGcpQ3G114HOPYvqs8HaJMDs2ebLNAimDkVDaWfAXE6Ybl+m8U6KsCE6pWyLYuigWmnAXw==} - workbox-window@7.3.0: - resolution: {integrity: sha512-qW8PDy16OV1UBaUNGlTVcepzrlzyzNW/ZJvFQQs2j2TzGsg6IKjcpZC1RSquqQnTOafl5pCj5bGfAHlCjOOjdA==} + workbox-sw@7.4.1: + resolution: {integrity: sha512-fez5f2DUlDJWTFYkCWQpY10N8gtztd849NswCbVFk0QlcSM4HT5A8x4g4ii650yem4I8tHY0R7JZahwp3ltIPw==} - workbox-window@7.4.0: - resolution: {integrity: sha512-/bIYdBLAVsNR3v7gYGaV4pQW3M3kEPx5E8vDxGvxo6khTrGtSSCS7QiFKv9ogzBgZiy0OXLP9zO28U/1nF1mfw==} + workbox-window@7.4.1: + resolution: {integrity: sha512-notZDH2u8VXaqyuD7xaqIfEFi6SRM4SUSd7ewe9PDsVqADuepxX2ZMY3uvuZGxzY5ZOsGC/vD3A/3smFtJt4/A==} - workerd@1.20251118.0: - resolution: {integrity: sha512-Om5ns0Lyx/LKtYI04IV0bjIrkBgoFNg0p6urzr2asekJlfP18RqFzyqMFZKf0i9Gnjtz/JfAS/Ol6tjCe5JJsQ==} + workerd@1.20260918.1: + resolution: {integrity: sha512-NsjfQlBNQ0iEniv/STOy4zbp8s5k60PzL1Ter02Eg44arbDhHtf6UOs03E31XDRmmBFxSIkAZuCyld3RKH1wqA==} engines: {node: '>=16'} hasBin: true - wrangler@4.50.0: - resolution: {integrity: sha512-+nuZuHZxDdKmAyXOSrHlciGshCoAPiy5dM+t6mEohWm7HpXvTHmWQGUf/na9jjWlWJHCJYOWzkA1P5HBJqrIEA==} - engines: {node: '>=20.0.0'} + wrangler@4.135.0: + resolution: {integrity: sha512-WrNBQSfIG6YcILJcodYr5ty8vgkzGsV8YX+kfd+uZ5/Bd8cUW0GnUIRKAVfn5kYKqh1m/BPcji9h1d7mE8euFw==} + engines: {node: '>=22.0.0'} hasBin: true peerDependencies: - '@cloudflare/workers-types': ^4.20251118.0 + '@cloudflare/workers-types': ^5.20260918.1 peerDependenciesMeta: '@cloudflare/workers-types': optional: true @@ -7761,9 +7642,9 @@ packages: resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} engines: {node: '>=10'} - wrap-ansi@8.1.0: - resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} - engines: {node: '>=12'} + wrap-ansi@9.0.2: + resolution: {integrity: sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==} + engines: {node: '>=18'} wrappy@1.0.2: resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} @@ -7771,8 +7652,8 @@ packages: write-file-atomic@3.0.3: resolution: {integrity: sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q==} - ws@8.17.1: - resolution: {integrity: sha512-6XQFvXTkbfUOZOKKILFG1PDK2NDQs4azKQl26T0YS5CxqWLgXajbPZ+h4gZekJyRqFU8pvnbAbbs/3TgRPy+GQ==} + ws@8.21.0: + resolution: {integrity: sha512-Vsp28b7DRcimFQvrqu2Wek3z1iYxDCWqHYB8Qsnk/S4RfaCQzPGPyBNuVjJV3cd6UiKtUtp6sNM77gWvzcCH+g==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -7783,8 +7664,8 @@ packages: utf-8-validate: optional: true - ws@8.18.0: - resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + ws@8.21.3: + resolution: {integrity: sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==} engines: {node: '>=10.0.0'} peerDependencies: bufferutil: ^4.0.1 @@ -7795,29 +7676,21 @@ packages: utf-8-validate: optional: true - ws@8.18.3: - resolution: {integrity: sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg==} - 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 + wsl-utils@1.0.0: + resolution: {integrity: sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==} + engines: {node: '>=20'} xml-name-validator@5.0.0: resolution: {integrity: sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==} engines: {node: '>=18'} + xml-naming@0.3.0: + resolution: {integrity: sha512-ghig2TBE/H11aOVgmahA3MhimvkBr6JIYknH/Dhdk10nXwdbIqBJsbfMxpvFPG8bAw77gN29aQWvKpmVoPlvPQ==} + engines: {node: '>=16.0.0'} + 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'} - y18n@4.0.3: resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} @@ -7828,6 +7701,15 @@ packages: yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + yallist@5.0.0: + resolution: {integrity: sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==} + engines: {node: '>=18'} + + yaml@2.9.1: + resolution: {integrity: sha512-3NxN8+78OdzbT7C/WjGsyfPAtJaN3FNDsWxv7Y7mcDsT/oOmgW8BpyQQFFBnvZE3j9Y2Sdz1ULFLezL7Eb2yFw==} + engines: {node: '>= 14.6'} + hasBin: true + yargs-parser@18.1.3: resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} engines: {node: '>=6'} @@ -7836,24 +7718,32 @@ packages: resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} engines: {node: '>=12'} + yargs-parser@22.0.0: + resolution: {integrity: sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yargs@15.4.1: resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} engines: {node: '>=8'} - yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + yargs@17.7.3: + resolution: {integrity: sha512-GZtjxm/J/4TSxuL3FNYjCmLktBTnIw/rVmKSIyKeYAZpmJB2ig9VauCC5xsa82GNKVKDAqpOn3KVzNt0zmrU0g==} engines: {node: '>=12'} + yargs@18.0.0: + resolution: {integrity: sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==} + engines: {node: ^20.19.0 || ^22.12.0 || >=23} + yocto-queue@0.1.0: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} - yoctocolors-cjs@2.1.3: - resolution: {integrity: sha512-U/PBtDf35ff0D8X8D0jfdzHYEPFxAI7jJlxZXwCSez5M3190m+QobIfh+sWDWSHMCWWJN2AWamkegn6vr6YBTw==} - engines: {node: '>=18'} + yocto-spinner@1.2.2: + resolution: {integrity: sha512-DODGl1wJjA/s5pnJFKau9lIYHT81lnhob1i3e1TjxZRxEhWRKl74nTbWE6H5KlkViQQTo/Z29YFdxzTZAMY3ng==} + engines: {node: '>=18.19'} - yoctocolors@2.1.2: - resolution: {integrity: sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug==} + yoctocolors@2.2.0: + resolution: {integrity: sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==} engines: {node: '>=18'} youch-core@0.3.3: @@ -7862,10 +7752,10 @@ packages: youch@4.1.0-beta.10: resolution: {integrity: sha512-rLfVLB4FgQneDr0dv1oddCVZmKjcJ6yX6mS4pU82Mq/Dt9a3cLZQ62pDBL4AUO+uVrCvtWz3ZFUL2HFAFJ/BXQ==} - zod-to-json-schema@3.25.0: - resolution: {integrity: sha512-HvWtU2UG41LALjajJrML6uQejQhNJx+JBO9IflpSja4R03iNWfKXrj6W2h7ljuLyc1nKS+9yDyL/9tD1U/yBnQ==} + zod-to-json-schema@3.25.2: + resolution: {integrity: sha512-O/PgfnpT1xKSDeQYSCfRI5Gy3hPf91mKVDuYLUHZJMiDFptvP41MSnWofm8dnCm0256ZNfZIM7DSzuSMAFnjHA==} peerDependencies: - zod: ^3.25 || ^4 + zod: ^3.25.28 || ^4 zod-validation-error@4.0.2: resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} @@ -7873,1304 +7763,1259 @@ packages: peerDependencies: zod: ^3.25.0 || ^4.0.0 - zod@3.22.3: - resolution: {integrity: sha512-EjIevzuJRiRPbVH4mGc8nApb/lVLKVpmUhAaR5R5doKGfAnGJ6Gr3CViAVjP+4FWSxCsybeWQdcgCtbX+7oZug==} - zod@3.25.76: resolution: {integrity: sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==} - zod@4.1.12: - resolution: {integrity: sha512-JInaHOamG8pt5+Ey8kGmdcAcg3OL9reK8ltczgHTAwNhMys/6ThXHityHxVV2p3fkw/c+MAvBHFVYHFZDmjMCQ==} + zod@4.6.5: + resolution: {integrity: sha512-v5l/aFXZQeai4awLbOpSoHecE9UiMrnfx75tEXLjNonXVARxQ5mOeipTjROUchszUNCqnE+hqAMujRsRHsut2Q==} snapshots: - '@acemir/cssom@0.9.24': {} + '@adobe/css-tools@4.5.0': {} - '@adobe/css-tools@4.4.4': {} - - '@ai-sdk/gateway@3.0.10(zod@4.1.12)': + '@ai-sdk/gateway@4.0.86(zod@4.6.5)': dependencies: - '@ai-sdk/provider': 3.0.2 - '@ai-sdk/provider-utils': 4.0.4(zod@4.1.12) - '@vercel/oidc': 3.1.0 - zod: 4.1.12 + '@ai-sdk/provider': 4.0.17 + '@ai-sdk/provider-utils': 5.0.44(zod@4.6.5) + '@vercel/oidc': 3.2.0 + zod: 4.6.5 - '@ai-sdk/openai@3.0.7(zod@4.1.12)': + '@ai-sdk/openai@4.0.70(zod@4.6.5)': dependencies: - '@ai-sdk/provider': 3.0.2 - '@ai-sdk/provider-utils': 4.0.4(zod@4.1.12) - zod: 4.1.12 + '@ai-sdk/provider': 4.0.17 + '@ai-sdk/provider-utils': 5.0.44(zod@4.6.5) + zod: 4.6.5 - '@ai-sdk/provider-utils@4.0.4(zod@4.1.12)': + '@ai-sdk/provider-utils@5.0.44(zod@4.6.5)': dependencies: - '@ai-sdk/provider': 3.0.2 + '@ai-sdk/provider': 4.0.17 '@standard-schema/spec': 1.1.0 - eventsource-parser: 3.0.6 - zod: 4.1.12 + '@workflow/serde': 4.1.0 + eventsource-parser: 3.1.1 + undici: 7.29.1 + zod: 4.6.5 - '@ai-sdk/provider@3.0.2': + '@ai-sdk/provider@4.0.17': dependencies: json-schema: 0.4.0 - '@antfu/ni@25.0.0': - dependencies: - ansis: 4.2.0 - fzf: 0.5.2 - package-manager-detector: 1.6.0 - tinyexec: 1.0.2 - - '@apideck/better-ajv-errors@0.3.6(ajv@8.17.1)': + '@apideck/better-ajv-errors@0.3.7(ajv@8.20.0)': dependencies: - ajv: 8.17.1 - json-schema: 0.4.0 + ajv: 8.20.0 jsonpointer: 5.0.1 leven: 3.1.0 - '@apm-js-collab/code-transformer@0.8.2': {} - - '@apm-js-collab/tracing-hooks@0.3.1': - dependencies: - '@apm-js-collab/code-transformer': 0.8.2 - debug: 4.4.3 - module-details-from-path: 1.0.4 - transitivePeerDependencies: - - supports-color - - '@asamuzakjp/css-color@4.1.0': + '@asamuzakjp/css-color@7.0.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: 11.2.2 + '@csstools/css-calc': 3.4.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.1))(@csstools/css-tokenizer@4.0.1) + '@csstools/css-color-parser': 4.2.3(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.1))(@csstools/css-tokenizer@4.0.1) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.1) + '@csstools/css-tokenizer': 4.0.1 + lru-cache: 11.5.2 - '@asamuzakjp/dom-selector@6.7.4': + '@asamuzakjp/dom-selector@9.2.0': dependencies: - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 - css-tree: 3.1.0 + bidi-js: 1.1.0 + css-tree: 3.2.1 is-potential-custom-element-name: 1.0.1 - lru-cache: 11.2.2 + lru-cache: 11.5.2 - '@asamuzakjp/nwsapi@2.3.9': {} - - '@babel/code-frame@7.27.1': + '@babel/code-frame@7.29.7': dependencies: - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-validator-identifier': 7.29.7 js-tokens: 4.0.0 picocolors: 1.1.1 - '@babel/compat-data@7.28.5': {} + '@babel/compat-data@7.29.7': {} - '@babel/core@7.28.5': + '@babel/core@7.29.7(supports-color@10.2.2)': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@10.2.2) + '@babel/types': 7.29.8 '@jridgewell/remapping': 2.3.5 convert-source-map: 2.0.0 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) gensync: 1.0.0-beta.2 json5: 2.2.3 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/generator@7.28.5': + '@babel/generator@7.29.8': dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 jsesc: 3.1.0 - '@babel/helper-annotate-as-pure@7.27.3': + '@babel/helper-annotate-as-pure@7.29.7': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.8 - '@babel/helper-compilation-targets@7.27.2': + '@babel/helper-compilation-targets@7.29.7': dependencies: - '@babel/compat-data': 7.28.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.1 + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.29.0 lru-cache: 5.1.1 semver: 6.3.1 - '@babel/helper-create-class-features-plugin@7.28.5(@babel/core@7.28.5)': + '@babel/helper-create-class-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@10.2.2) + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.8(supports-color@10.2.2) semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/helper-create-regexp-features-plugin@7.28.5(@babel/core@7.28.5)': + '@babel/helper-create-regexp-features-plugin@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 regexpu-core: 6.4.0 semver: 6.3.1 - '@babel/helper-define-polyfill-provider@0.6.5(@babel/core@7.28.5)': + '@babel/helper-define-polyfill-provider@0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - debug: 4.4.3 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + debug: 4.4.3(supports-color@10.2.2) lodash.debounce: 4.0.8 - resolve: 1.22.11 + resolve: 1.22.12 transitivePeerDependencies: - supports-color - '@babel/helper-globals@7.28.0': {} + '@babel/helper-globals@7.29.7': {} - '@babel/helper-member-expression-to-functions@7.28.5': + '@babel/helper-member-expression-to-functions@7.29.7(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.8(supports-color@10.2.2) + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helper-module-imports@7.27.1': + '@babel/helper-module-imports@7.29.7(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.8(supports-color@10.2.2) + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/helper-optimise-call-expression@7.27.1': + '@babel/helper-optimise-call-expression@7.29.7': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.8 - '@babel/helper-plugin-utils@7.27.1': {} + '@babel/helper-plugin-utils@7.29.7': {} - '@babel/helper-remap-async-to-generator@7.27.1(@babel/core@7.28.5)': + '@babel/helper-remap-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-wrap-function': 7.28.3 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-wrap-function': 7.29.7(supports-color@10.2.2) + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/helper-replace-supers@7.27.1(@babel/core@7.28.5)': + '@babel/helper-replace-supers@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-member-expression-to-functions': 7.28.5 - '@babel/helper-optimise-call-expression': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-member-expression-to-functions': 7.29.7(supports-color@10.2.2) + '@babel/helper-optimise-call-expression': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/helper-skip-transparent-expression-wrappers@7.27.1': + '@babel/helper-skip-transparent-expression-wrappers@7.29.7(supports-color@10.2.2)': dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/traverse': 7.29.8(supports-color@10.2.2) + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helper-string-parser@7.27.1': {} + '@babel/helper-string-parser@7.29.7': {} - '@babel/helper-validator-identifier@7.28.5': {} + '@babel/helper-validator-identifier@7.29.7': {} - '@babel/helper-validator-option@7.27.1': {} + '@babel/helper-validator-option@7.29.7': {} - '@babel/helper-wrap-function@7.28.3': + '@babel/helper-wrap-function@7.29.7(supports-color@10.2.2)': dependencies: - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@10.2.2) + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - '@babel/helpers@7.28.4': + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + + '@babel/parser@7.29.2': dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 + '@babel/types': 7.29.8 - '@babel/parser@7.28.5': + '@babel/parser@7.29.9': dependencies: - '@babel/types': 7.28.5 + '@babel/types': 7.29.8 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-bugfix-firefox-class-in-computed-class-key@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-bugfix-safari-class-field-initializer-scope@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.28.3(@babel/core@7.28.5)': + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5)': + '@babel/plugin-proposal-private-property-in-object@7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) - '@babel/plugin-syntax-import-assertions@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-import-assertions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-import-attributes@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-jsx@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-typescript@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.28.5)': + '@babel/plugin-syntax-unicode-sets-regex@7.18.6(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-arrow-functions@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-arrow-functions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-async-generator-functions@7.28.0(@babel/core@7.28.5)': + '@babel/plugin-transform-async-generator-functions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-async-to-generator@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-async-to-generator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-remap-async-to-generator': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-remap-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-block-scoped-functions@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-block-scoped-functions@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-block-scoping@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-block-scoping@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-class-properties@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-class-properties@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-class-static-block@7.28.3(@babel/core@7.28.5)': + '@babel/plugin-transform-class-static-block@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-classes@7.28.4(@babel/core@7.28.5)': + '@babel/plugin-transform-classes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-globals': 7.28.0 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-computed-properties@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-computed-properties@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/template': 7.27.2 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/template': 7.29.7 - '@babel/plugin-transform-destructuring@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-destructuring@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-dotall-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-dotall-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-duplicate-keys@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-duplicate-keys@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-duplicate-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-dynamic-import@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-dynamic-import@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-explicit-resource-management@7.28.0(@babel/core@7.28.5)': + '@babel/plugin-transform-explicit-resource-management@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-exponentiation-operator@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-exponentiation-operator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-export-namespace-from@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-export-namespace-from@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-for-of@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-for-of@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-function-name@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-function-name@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-json-strings@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-json-strings@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-logical-assignment-operators@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-logical-assignment-operators@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-member-expression-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-member-expression-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-modules-amd@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-amd@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-commonjs@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-commonjs@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-systemjs@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-systemjs@7.29.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-modules-umd@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-modules-umd@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-named-capturing-groups-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-named-capturing-groups-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-new-target@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-new-target@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-nullish-coalescing-operator@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-nullish-coalescing-operator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-numeric-separator@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-numeric-separator@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-object-rest-spread@7.28.4(@babel/core@7.28.5)': + '@babel/plugin-transform-object-rest-spread@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/traverse': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/traverse': 7.29.8(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-object-super@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-object-super@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-replace-supers': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-replace-supers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-optional-catch-binding@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-optional-catch-binding@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-optional-chaining@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-optional-chaining@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-parameters@7.27.7(@babel/core@7.28.5)': + '@babel/plugin-transform-parameters@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-private-methods@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-private-methods@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-private-property-in-object@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-private-property-in-object@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 transitivePeerDependencies: - supports-color - '@babel/plugin-transform-property-literals@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-property-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regenerator@7.28.4(@babel/core@7.28.5)': + '@babel/plugin-transform-regenerator@7.29.8(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-regexp-modifiers@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-regexp-modifiers@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-reserved-words@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-reserved-words@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-shorthand-properties@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-shorthand-properties@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-spread@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-spread@7.29.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-sticky-regex@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-sticky-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-template-literals@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-template-literals@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-typeof-symbol@7.27.1(@babel/core@7.28.5)': + '@babel/plugin-transform-typeof-symbol@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 - '@babel/plugin-transform-typescript@7.28.5(@babel/core@7.28.5)': + '@babel/plugin-transform-typescript@7.29.9(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-annotate-as-pure': 7.27.3 - '@babel/helper-create-class-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-skip-transparent-expression-wrappers': 7.27.1 - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-annotate-as-pure': 7.29.7 + '@babel/helper-create-class-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-skip-transparent-expression-wrappers': 7.29.7(supports-color@10.2.2) + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) transitivePeerDependencies: - supports-color - '@babel/plugin-transform-unicode-escapes@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-unicode-property-regex@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-unicode-regex@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/plugin-transform-unicode-sets-regex@7.27.1(@babel/core@7.28.5)': - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-create-regexp-features-plugin': 7.28.5(@babel/core@7.28.5) - '@babel/helper-plugin-utils': 7.27.1 - - '@babel/preset-env@7.28.5(@babel/core@7.28.5)': - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/core': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.28.3(@babel/core@7.28.5) - '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.28.5) - '@babel/plugin-syntax-import-assertions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-import-attributes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.28.5) - '@babel/plugin-transform-arrow-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-async-generator-functions': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-async-to-generator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoped-functions': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-block-scoping': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-class-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-class-static-block': 7.28.3(@babel/core@7.28.5) - '@babel/plugin-transform-classes': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-computed-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-destructuring': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-dotall-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-duplicate-keys': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-dynamic-import': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-explicit-resource-management': 7.28.0(@babel/core@7.28.5) - '@babel/plugin-transform-exponentiation-operator': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-export-namespace-from': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-for-of': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-function-name': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-json-strings': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-logical-assignment-operators': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-member-expression-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-amd': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-systemjs': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-modules-umd': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-named-capturing-groups-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-new-target': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-nullish-coalescing-operator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-numeric-separator': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-object-rest-spread': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-object-super': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-optional-catch-binding': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-optional-chaining': 7.28.5(@babel/core@7.28.5) - '@babel/plugin-transform-parameters': 7.27.7(@babel/core@7.28.5) - '@babel/plugin-transform-private-methods': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-private-property-in-object': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-property-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-regenerator': 7.28.4(@babel/core@7.28.5) - '@babel/plugin-transform-regexp-modifiers': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-reserved-words': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-shorthand-properties': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-spread': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-sticky-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-template-literals': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typeof-symbol': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-escapes': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-property-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-regex': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-unicode-sets-regex': 7.27.1(@babel/core@7.28.5) - '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.28.5) - babel-plugin-polyfill-corejs2: 0.4.14(@babel/core@7.28.5) - babel-plugin-polyfill-corejs3: 0.13.0(@babel/core@7.28.5) - babel-plugin-polyfill-regenerator: 0.6.5(@babel/core@7.28.5) - core-js-compat: 3.47.0 + '@babel/plugin-transform-unicode-escapes@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-property-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-transform-unicode-sets-regex@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-create-regexp-features-plugin': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/preset-env@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + '@babel/plugin-bugfix-firefox-class-in-computed-class-key': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-bugfix-safari-class-field-initializer-scope': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-bugfix-safari-rest-destructuring-rhs-array': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-proposal-private-property-in-object': 7.21.0-placeholder-for-preset-env.2(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-import-assertions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-syntax-unicode-sets-regex': 7.18.6(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-arrow-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-async-generator-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-async-to-generator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-block-scoped-functions': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-block-scoping': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-class-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-class-static-block': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-classes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-computed-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-destructuring': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-dotall-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-duplicate-keys': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-duplicate-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-dynamic-import': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-explicit-resource-management': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-exponentiation-operator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-export-namespace-from': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-for-of': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-function-name': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-json-strings': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-logical-assignment-operators': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-member-expression-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-modules-amd': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-modules-systemjs': 7.29.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-modules-umd': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-named-capturing-groups-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-new-target': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-nullish-coalescing-operator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-numeric-separator': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-object-rest-spread': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-object-super': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-optional-catch-binding': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-optional-chaining': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-parameters': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-private-methods': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-private-property-in-object': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-property-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-regenerator': 7.29.8(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-regexp-modifiers': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-reserved-words': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-shorthand-properties': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-spread': 7.29.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-sticky-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-template-literals': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-typeof-symbol': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-unicode-escapes': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-unicode-property-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-unicode-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-unicode-sets-regex': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/preset-modules': 0.1.6-no-external-plugins(@babel/core@7.29.7(supports-color@10.2.2)) + babel-plugin-polyfill-corejs2: 0.4.17(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + babel-plugin-polyfill-corejs3: 0.14.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + babel-plugin-polyfill-regenerator: 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + core-js-compat: 3.50.0 semver: 6.3.1 transitivePeerDependencies: - supports-color - '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.28.5)': + '@babel/preset-modules@0.1.6-no-external-plugins(@babel/core@7.29.7(supports-color@10.2.2))': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/types': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/types': 7.29.8 esutils: 2.0.3 - '@babel/preset-typescript@7.28.5(@babel/core@7.28.5)': + '@babel/preset-typescript@7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - '@babel/helper-validator-option': 7.27.1 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-modules-commonjs': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-plugin-utils': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2)) + '@babel/plugin-transform-modules-commonjs': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/plugin-transform-typescript': 7.29.9(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/runtime@7.28.4': {} + '@babel/runtime@7.29.7': {} + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 - '@babel/template@7.27.2': + '@babel/traverse@7.29.0(supports-color@10.2.2)': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.2 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color - '@babel/traverse@7.28.5': + '@babel/traverse@7.29.8(supports-color@10.2.2)': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - debug: 4.4.3 + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.8 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.9 + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@babel/types@7.28.5': + '@babel/types@7.29.8': dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 '@bcoe/v8-coverage@1.0.2': {} - '@better-auth/core@1.4.1(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.1.0)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.1.0)': + '@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3)': + dependencies: + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@opentelemetry/semantic-conventions': 1.43.0 + '@standard-schema/spec': 1.1.0 + better-call: 1.4.0(zod@4.6.5) + jose: 6.2.12 + kysely: 0.29.6 + nanostores: 1.5.3 + zod: 4.6.5 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + + '@better-auth/drizzle-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6))': + dependencies: + '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3) + '@better-auth/utils': 0.4.2 + optionalDependencies: + drizzle-orm: 0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6) + + '@better-auth/kysely-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(kysely@0.29.6)': + dependencies: + '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3) + '@better-auth/utils': 0.4.2 + optionalDependencies: + kysely: 0.29.6 + + '@better-auth/memory-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)': + dependencies: + '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3) + '@better-auth/utils': 0.4.2 + + '@better-auth/mongo-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)': + dependencies: + '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3) + '@better-auth/utils': 0.4.2 + + '@better-auth/prisma-adapter@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)': + dependencies: + '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3) + '@better-auth/utils': 0.4.2 + + '@better-auth/telemetry@1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)': + dependencies: + '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3) + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + + '@better-auth/utils@0.4.2': dependencies: - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.18 - '@standard-schema/spec': 1.0.0 - better-call: 1.1.0 - jose: 6.1.2 - kysely: 0.28.8 - nanostores: 1.1.0 - zod: 4.1.12 + '@noble/hashes': 2.4.0 - '@better-auth/telemetry@1.4.1(@better-auth/core@1.4.1(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.1.0)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.1.0))': + '@better-auth/utils@0.5.0': dependencies: - '@better-auth/core': 1.4.1(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.1.0)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.1.0) - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.18 + '@noble/hashes': 2.4.0 + + '@better-fetch/fetch@1.3.2': {} - '@better-auth/utils@0.3.0': {} + '@bramus/specificity@2.4.2': + dependencies: + css-tree: 3.2.1 - '@better-fetch/fetch@1.1.18': {} + '@cacheable/memory@2.2.0': + dependencies: + '@cacheable/utils': 2.5.0 + '@keyv/bigmap': 1.3.1(keyv@5.6.0) + hookified: 1.15.1 + keyv: 5.6.0 - '@cloudflare/kv-asset-handler@0.4.0': + '@cacheable/utils@2.5.0': dependencies: - mime: 3.0.0 + hashery: 1.5.1 + keyv: 5.6.0 - '@cloudflare/unenv-preset@2.7.11(unenv@2.0.0-rc.24)(workerd@1.20251118.0)': + '@cloudflare/kv-asset-handler@0.5.0': {} + + '@cloudflare/unenv-preset@2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260918.1)': dependencies: unenv: 2.0.0-rc.24 optionalDependencies: - workerd: 1.20251118.0 + workerd: 1.20260918.1 - '@cloudflare/workerd-darwin-64@1.20251118.0': + '@cloudflare/workerd-darwin-64@1.20260918.1': optional: true - '@cloudflare/workerd-darwin-arm64@1.20251118.0': + '@cloudflare/workerd-darwin-arm64@1.20260918.1': optional: true - '@cloudflare/workerd-linux-64@1.20251118.0': + '@cloudflare/workerd-linux-64@1.20260918.1': optional: true - '@cloudflare/workerd-linux-arm64@1.20251118.0': + '@cloudflare/workerd-linux-arm64@1.20260918.1': optional: true - '@cloudflare/workerd-windows-64@1.20251118.0': + '@cloudflare/workerd-windows-64@1.20260918.1': optional: true - '@cloudflare/workers-types@4.20251121.0': {} + '@cloudflare/workers-types@5.20260918.1': {} '@cspotcode/source-map-support@0.8.1': dependencies: '@jridgewell/trace-mapping': 0.3.9 - '@csstools/color-helpers@5.1.0': {} + '@csstools/color-helpers@6.1.1': {} - '@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-calc@3.4.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.1))(@csstools/css-tokenizer@4.0.1)': dependencies: - '@csstools/css-parser-algorithms': 3.0.5(@csstools/css-tokenizer@3.0.4) - '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.1) + '@csstools/css-tokenizer': 4.0.1 - '@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-color-parser@4.2.3(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.1))(@csstools/css-tokenizer@4.0.1)': 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/color-helpers': 6.1.1 + '@csstools/css-calc': 3.4.0(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.1))(@csstools/css-tokenizer@4.0.1) + '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.1) + '@csstools/css-tokenizer': 4.0.1 - '@csstools/css-parser-algorithms@3.0.5(@csstools/css-tokenizer@3.0.4)': + '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.1)': dependencies: - '@csstools/css-tokenizer': 3.0.4 + '@csstools/css-tokenizer': 4.0.1 - '@csstools/css-syntax-patches-for-csstree@1.0.17': {} + '@csstools/css-syntax-patches-for-csstree@1.1.14(css-tree@3.2.1)': + optionalDependencies: + css-tree: 3.2.1 - '@csstools/css-tokenizer@3.0.4': {} + '@csstools/css-tokenizer@4.0.1': {} - '@dotenvx/dotenvx@1.51.1': + '@dotenvx/dotenvx@1.75.1': dependencies: + '@dotenvx/primitives': 0.8.0 commander: 11.1.0 - dotenv: 17.2.3 - eciesjs: 0.4.16 + conf: 10.2.0 + dotenv: 17.4.2 + enquirer: 2.4.1 + env-paths: 2.2.1 execa: 5.1.1 - fdir: 6.5.0(picomatch@4.0.3) + fdir: 6.5.0(picomatch@4.0.7) ignore: 5.3.2 object-treeify: 1.1.33 - picomatch: 4.0.3 + open: 8.4.2 + picomatch: 4.0.7 + systeminformation: 5.33.12 + undici: 7.29.1 which: 4.0.0 + yocto-spinner: 1.2.2 + + '@dotenvx/primitives@0.8.0': {} '@drizzle-team/brocli@0.10.2': {} - '@ecies/ciphers@0.2.5(@noble/ciphers@1.3.0)': + '@emnapi/core@1.11.2': dependencies: - '@noble/ciphers': 1.3.0 + '@emnapi/wasi-threads': 1.2.2 + tslib: 2.8.1 + optional: true - '@emnapi/core@1.7.1': + '@emnapi/runtime@1.11.2': dependencies: - '@emnapi/wasi-threads': 1.1.0 tslib: 2.8.1 optional: true - '@emnapi/runtime@1.7.1': + '@emnapi/runtime@1.11.3': dependencies: tslib: 2.8.1 optional: true - '@emnapi/wasi-threads@1.1.0': + '@emnapi/wasi-threads@1.2.2': dependencies: tslib: 2.8.1 optional: true '@esbuild-kit/core-utils@3.3.2': dependencies: - esbuild: 0.27.0 + esbuild: 0.28.2 source-map-support: 0.5.21 '@esbuild-kit/esm-loader@2.6.5': dependencies: '@esbuild-kit/core-utils': 3.3.2 - get-tsconfig: 4.13.0 + get-tsconfig: 4.14.3 - '@esbuild/aix-ppc64@0.27.0': + '@esbuild/aix-ppc64@0.28.2': optional: true - '@esbuild/android-arm64@0.27.0': + '@esbuild/android-arm64@0.28.2': optional: true - '@esbuild/android-arm@0.27.0': + '@esbuild/android-arm@0.28.2': optional: true - '@esbuild/android-x64@0.27.0': + '@esbuild/android-x64@0.28.2': optional: true - '@esbuild/darwin-arm64@0.27.0': + '@esbuild/darwin-arm64@0.28.2': optional: true - '@esbuild/darwin-x64@0.27.0': + '@esbuild/darwin-x64@0.28.2': optional: true - '@esbuild/freebsd-arm64@0.27.0': + '@esbuild/freebsd-arm64@0.28.2': optional: true - '@esbuild/freebsd-x64@0.27.0': + '@esbuild/freebsd-x64@0.28.2': optional: true - '@esbuild/linux-arm64@0.27.0': + '@esbuild/linux-arm64@0.28.2': optional: true - '@esbuild/linux-arm@0.27.0': + '@esbuild/linux-arm@0.28.2': optional: true - '@esbuild/linux-ia32@0.27.0': + '@esbuild/linux-ia32@0.28.2': optional: true - '@esbuild/linux-loong64@0.27.0': + '@esbuild/linux-loong64@0.28.2': optional: true - '@esbuild/linux-mips64el@0.27.0': + '@esbuild/linux-mips64el@0.28.2': optional: true - '@esbuild/linux-ppc64@0.27.0': + '@esbuild/linux-ppc64@0.28.2': optional: true - '@esbuild/linux-riscv64@0.27.0': + '@esbuild/linux-riscv64@0.28.2': optional: true - '@esbuild/linux-s390x@0.27.0': + '@esbuild/linux-s390x@0.28.2': optional: true - '@esbuild/linux-x64@0.27.0': + '@esbuild/linux-x64@0.28.2': optional: true - '@esbuild/netbsd-arm64@0.27.0': + '@esbuild/netbsd-arm64@0.28.2': optional: true - '@esbuild/netbsd-x64@0.27.0': + '@esbuild/netbsd-x64@0.28.2': optional: true - '@esbuild/openbsd-arm64@0.27.0': + '@esbuild/openbsd-arm64@0.28.2': optional: true - '@esbuild/openbsd-x64@0.27.0': + '@esbuild/openbsd-x64@0.28.2': optional: true - '@esbuild/openharmony-arm64@0.27.0': + '@esbuild/openharmony-arm64@0.28.2': optional: true - '@esbuild/sunos-x64@0.27.0': + '@esbuild/sunos-x64@0.28.2': optional: true - '@esbuild/win32-arm64@0.27.0': + '@esbuild/win32-arm64@0.28.2': optional: true - '@esbuild/win32-ia32@0.27.0': + '@esbuild/win32-ia32@0.28.2': optional: true - '@esbuild/win32-x64@0.27.0': + '@esbuild/win32-x64@0.28.2': optional: true - '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': + '@eslint-community/eslint-utils@4.10.1(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))': dependencies: - eslint: 9.39.1(jiti@2.6.1) + eslint: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) eslint-visitor-keys: 3.4.3 '@eslint-community/regexpp@4.12.2': {} - '@eslint/config-array@0.21.1': + '@eslint/config-array@0.23.5(supports-color@10.2.2)': dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3 - minimatch: 3.1.2 + '@eslint/object-schema': 3.0.5 + debug: 4.4.3(supports-color@10.2.2) + minimatch: 10.2.6 transitivePeerDependencies: - supports-color - '@eslint/config-helpers@0.4.2': + '@eslint/config-helpers@0.7.0': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.2.1 - '@eslint/core@0.17.0': + '@eslint/core@1.2.1': dependencies: '@types/json-schema': 7.0.15 - '@eslint/eslintrc@3.3.1': - dependencies: - ajv: 6.12.6 - 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.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - - '@eslint/js@9.39.1': {} + '@eslint/js@10.0.1(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))': + optionalDependencies: + eslint: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) - '@eslint/object-schema@2.1.7': {} + '@eslint/object-schema@3.0.5': {} - '@eslint/plugin-kit@0.4.1': + '@eslint/plugin-kit@0.7.3': dependencies: - '@eslint/core': 0.17.0 + '@eslint/core': 1.2.1 levn: 0.4.1 - '@floating-ui/core@1.7.3': + '@exodus/bytes@1.15.1(@noble/hashes@2.4.0)': + optionalDependencies: + '@noble/hashes': 2.4.0 + + '@floating-ui/core@1.8.0': dependencies: - '@floating-ui/utils': 0.2.10 + '@floating-ui/utils': 0.2.12 - '@floating-ui/dom@1.7.4': + '@floating-ui/dom@1.8.0': dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 + '@floating-ui/core': 1.8.0 + '@floating-ui/utils': 0.2.12 - '@floating-ui/react-dom@2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@floating-ui/react-dom@2.1.9(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@floating-ui/dom': 1.7.4 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@floating-ui/dom': 1.8.0 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) - '@floating-ui/react@0.27.16(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@floating-ui/react@0.27.20(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@floating-ui/utils': 0.2.10 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - tabbable: 6.3.0 + '@floating-ui/react-dom': 2.1.9(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@floating-ui/utils': 0.2.12 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + tabbable: 6.5.0 - '@floating-ui/utils@0.2.10': {} + '@floating-ui/utils@0.2.12': {} - '@hono/node-server@1.19.6(hono@4.10.6)': + '@hono/node-server@2.1.1(hono@4.13.8)': dependencies: - hono: 4.10.6 + hono: 4.13.8 - '@hono/trpc-server@0.4.1(@trpc/server@11.7.2(typescript@5.9.3))(hono@4.10.6)': + '@hono/trpc-server@0.4.2(@trpc/server@11.19.0(typescript@6.0.3))(hono@4.13.8)': dependencies: - '@trpc/server': 11.7.2(typescript@5.9.3) - hono: 4.10.6 + '@trpc/server': 11.19.0(typescript@6.0.3) + hono: 4.13.8 - '@hookform/resolvers@5.2.2(react-hook-form@7.66.1(react@19.2.0))': + '@hookform/resolvers@5.9.1(@standard-schema/spec@1.1.0)(ajv-formats@2.1.1(ajv@8.20.0))(ajv@8.20.0)(react-hook-form@7.88.0(react@19.3.0))(zod@4.6.5)': dependencies: '@standard-schema/utils': 0.3.0 - react-hook-form: 7.66.1(react@19.2.0) + react-hook-form: 7.88.0(react@19.3.0) + optionalDependencies: + '@standard-schema/spec': 1.1.0 + ajv: 8.20.0 + ajv-formats: 2.1.1(ajv@8.20.0) + zod: 4.6.5 - '@humanfs/core@0.19.1': {} + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 - '@humanfs/node@0.16.7': + '@humanfs/node@0.16.8': dependencies: - '@humanfs/core': 0.19.1 + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 '@humanwhocodes/retry': 0.4.3 + '@humanfs/types@0.15.0': {} + '@humanwhocodes/module-importer@1.0.1': {} '@humanwhocodes/retry@0.4.3': {} - '@img/colour@1.0.0': {} - - '@img/sharp-darwin-arm64@0.33.5': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.0.4 - optional: true - - '@img/sharp-darwin-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-darwin-arm64': 1.2.4 - optional: true + '@img/colour@1.1.0': {} - '@img/sharp-darwin-x64@0.33.5': + '@img/sharp-darwin-arm64@0.35.4': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.0.4 + '@img/sharp-libvips-darwin-arm64': 1.3.3 optional: true - '@img/sharp-darwin-x64@0.34.5': + '@img/sharp-darwin-x64@0.35.4': optionalDependencies: - '@img/sharp-libvips-darwin-x64': 1.2.4 - optional: true - - '@img/sharp-libvips-darwin-arm64@1.0.4': - optional: true - - '@img/sharp-libvips-darwin-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-darwin-x64@1.0.4': - optional: true - - '@img/sharp-libvips-darwin-x64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-arm64@1.0.4': - optional: true - - '@img/sharp-libvips-linux-arm64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-arm@1.0.5': - optional: true - - '@img/sharp-libvips-linux-arm@1.2.4': - optional: true - - '@img/sharp-libvips-linux-ppc64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-riscv64@1.2.4': - optional: true - - '@img/sharp-libvips-linux-s390x@1.0.4': - optional: true - - '@img/sharp-libvips-linux-s390x@1.2.4': - optional: true - - '@img/sharp-libvips-linux-x64@1.0.4': + '@img/sharp-libvips-darwin-x64': 1.3.3 optional: true - '@img/sharp-libvips-linux-x64@1.2.4': + '@img/sharp-freebsd-wasm32@0.35.4': + dependencies: + '@img/sharp-wasm32': 0.35.4 optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.0.4': + '@img/sharp-libvips-darwin-arm64@1.3.3': optional: true - '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + '@img/sharp-libvips-darwin-x64@1.3.3': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.0.4': + '@img/sharp-libvips-linux-arm64@1.3.3': optional: true - '@img/sharp-libvips-linuxmusl-x64@1.2.4': + '@img/sharp-libvips-linux-arm@1.3.3': optional: true - '@img/sharp-linux-arm64@0.33.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.0.4 + '@img/sharp-libvips-linux-ppc64@1.3.3': optional: true - '@img/sharp-linux-arm64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-riscv64@1.3.3': optional: true - '@img/sharp-linux-arm@0.33.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.0.5 + '@img/sharp-libvips-linux-s390x@1.3.3': optional: true - '@img/sharp-linux-arm@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-x64@1.3.3': optional: true - '@img/sharp-linux-ppc64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64@1.3.3': optional: true - '@img/sharp-linux-riscv64@0.34.5': - optionalDependencies: - '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64@1.3.3': optional: true - '@img/sharp-linux-s390x@0.33.5': + '@img/sharp-linux-arm64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.0.4 + '@img/sharp-libvips-linux-arm64': 1.3.3 optional: true - '@img/sharp-linux-s390x@0.34.5': + '@img/sharp-linux-arm@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.3.3 optional: true - '@img/sharp-linux-x64@0.33.5': + '@img/sharp-linux-ppc64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.0.4 + '@img/sharp-libvips-linux-ppc64': 1.3.3 optional: true - '@img/sharp-linux-x64@0.34.5': + '@img/sharp-linux-riscv64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.3.3 optional: true - '@img/sharp-linuxmusl-arm64@0.33.5': + '@img/sharp-linux-s390x@0.35.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 + '@img/sharp-libvips-linux-s390x': 1.3.3 optional: true - '@img/sharp-linuxmusl-arm64@0.34.5': + '@img/sharp-linux-x64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.3.3 optional: true - '@img/sharp-linuxmusl-x64@0.33.5': + '@img/sharp-linuxmusl-arm64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 optional: true - '@img/sharp-linuxmusl-x64@0.34.5': + '@img/sharp-linuxmusl-x64@0.35.4': optionalDependencies: - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.3.3 optional: true - '@img/sharp-wasm32@0.33.5': + '@img/sharp-wasm32@0.35.4': dependencies: - '@emnapi/runtime': 1.7.1 + '@emnapi/runtime': 1.11.3 optional: true - '@img/sharp-wasm32@0.34.5': + '@img/sharp-webcontainers-wasm32@0.35.4': dependencies: - '@emnapi/runtime': 1.7.1 - optional: true - - '@img/sharp-win32-arm64@0.34.5': + '@img/sharp-wasm32': 0.35.4 optional: true - '@img/sharp-win32-ia32@0.33.5': + '@img/sharp-win32-arm64@0.35.4': optional: true - '@img/sharp-win32-ia32@0.34.5': + '@img/sharp-win32-ia32@0.35.4': optional: true - '@img/sharp-win32-x64@0.33.5': + '@img/sharp-win32-x64@0.35.4': optional: true - '@img/sharp-win32-x64@0.34.5': - optional: true - - '@inquirer/ansi@1.0.2': {} - - '@inquirer/confirm@5.1.21(@types/node@24.10.1)': - dependencies: - '@inquirer/core': 10.3.2(@types/node@24.10.1) - '@inquirer/type': 3.0.10(@types/node@24.10.1) - optionalDependencies: - '@types/node': 24.10.1 - - '@inquirer/core@10.3.2(@types/node@24.10.1)': - dependencies: - '@inquirer/ansi': 1.0.2 - '@inquirer/figures': 1.0.15 - '@inquirer/type': 3.0.10(@types/node@24.10.1) - cli-width: 4.1.0 - mute-stream: 2.0.0 - signal-exit: 4.1.0 - wrap-ansi: 6.2.0 - yoctocolors-cjs: 2.1.3 - optionalDependencies: - '@types/node': 24.10.1 - - '@inquirer/figures@1.0.15': {} - - '@inquirer/type@3.0.10(@types/node@24.10.1)': - optionalDependencies: - '@types/node': 24.10.1 - - '@isaacs/balanced-match@4.0.1': {} - - '@isaacs/brace-expansion@5.0.0': - dependencies: - '@isaacs/balanced-match': 4.0.1 + '@isaacs/cliui@9.0.0': {} - '@isaacs/cliui@8.0.2': + '@isaacs/fs-minipass@4.0.1': dependencies: - string-width: 5.1.2 - string-width-cjs: string-width@4.2.3 - strip-ansi: 7.1.2 - strip-ansi-cjs: strip-ansi@6.0.1 - wrap-ansi: 8.1.0 - wrap-ansi-cjs: wrap-ansi@7.0.0 + minipass: 7.1.3 '@istanbuljs/load-nyc-config@1.1.0': dependencies: camelcase: 5.3.1 find-up: 4.1.0 get-package-type: 0.1.0 - js-yaml: 3.14.2 + js-yaml: 3.15.2 resolve-from: 5.0.0 - '@istanbuljs/schema@0.1.3': {} + '@istanbuljs/schema@0.1.6': {} '@jridgewell/gen-mapping@0.3.13': dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 '@jridgewell/trace-mapping': 0.3.31 '@jridgewell/remapping@2.3.5': @@ -9185,90 +9030,63 @@ snapshots: '@jridgewell/gen-mapping': 0.3.13 '@jridgewell/trace-mapping': 0.3.31 - '@jridgewell/sourcemap-codec@1.5.5': {} + '@jridgewell/sourcemap-codec@1.6.0': {} '@jridgewell/trace-mapping@0.3.31': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 '@jridgewell/trace-mapping@0.3.9': dependencies: '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 - '@modelcontextprotocol/sdk@1.24.3(zod@3.25.76)': + '@keyv/bigmap@1.3.1(keyv@5.6.0)': dependencies: - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) + hashery: 1.5.1 + hookified: 1.15.1 + keyv: 5.6.0 + + '@keyv/serialize@1.1.1': {} + + '@modelcontextprotocol/sdk@1.30.0(supports-color@10.2.2)(zod@3.25.76)': + dependencies: + '@hono/node-server': 2.1.1(hono@4.13.8) + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) content-type: 1.0.5 - cors: 2.8.5 + cors: 2.8.6 cross-spawn: 7.0.6 eventsource: 3.0.7 - eventsource-parser: 3.0.6 - express: 5.2.1 - express-rate-limit: 7.5.1(express@5.2.1) - jose: 6.1.3 + eventsource-parser: 3.1.1 + express: 5.2.1(supports-color@10.2.2) + express-rate-limit: 8.7.0(express@5.2.1(supports-color@10.2.2))(supports-color@10.2.2) + hono: 4.13.8 + jose: 6.2.12 + json-schema-typed: 8.0.2 pkce-challenge: 5.0.1 raw-body: 3.0.2 zod: 3.25.76 - zod-to-json-schema: 3.25.0(zod@3.25.76) + zod-to-json-schema: 3.25.2(zod@3.25.76) transitivePeerDependencies: - supports-color - '@mswjs/interceptors@0.40.0': - dependencies: - '@open-draft/deferred-promise': 2.2.0 - '@open-draft/logger': 0.3.0 - '@open-draft/until': 2.1.0 - is-node-process: 1.2.0 - outvariant: 1.4.3 - strict-event-emitter: 0.5.1 - - '@napi-rs/wasm-runtime@1.0.7': - dependencies: - '@emnapi/core': 1.7.1 - '@emnapi/runtime': 1.7.1 - '@tybys/wasm-util': 0.10.1 - optional: true - - '@next/env@16.0.1': {} - - '@next/swc-darwin-arm64@16.0.1': - optional: true - - '@next/swc-darwin-x64@16.0.1': - optional: true - - '@next/swc-linux-arm64-gnu@16.0.1': - optional: true - - '@next/swc-linux-arm64-musl@16.0.1': - optional: true - - '@next/swc-linux-x64-gnu@16.0.1': - optional: true - - '@next/swc-linux-x64-musl@16.0.1': + '@napi-rs/lzma-linux-x64-gnu@1.5.1': optional: true - '@next/swc-win32-arm64-msvc@16.0.1': - optional: true - - '@next/swc-win32-x64-msvc@16.0.1': + '@napi-rs/wasm-runtime@1.2.4(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2)': + dependencies: + '@emnapi/core': 1.11.2 + '@emnapi/runtime': 1.11.2 + '@tybys/wasm-util': 0.10.4 optional: true - '@noble/ciphers@1.3.0': {} - - '@noble/ciphers@2.0.1': {} + '@noble/ciphers@2.4.0': {} - '@noble/curves@1.9.7': - dependencies: - '@noble/hashes': 1.8.0 - - '@noble/hashes@1.8.0': {} + '@noble/hashes@2.4.0': {} - '@noble/hashes@2.0.1': {} + '@nodable/entities@3.0.0': {} '@nodelib/fs.scandir@2.1.5': dependencies: @@ -9280,1519 +9098,1116 @@ snapshots: '@nodelib/fs.walk@1.2.8': dependencies: '@nodelib/fs.scandir': 2.1.5 - fastq: 1.19.1 - - '@open-draft/deferred-promise@2.2.0': {} - - '@open-draft/logger@0.3.0': - dependencies: - is-node-process: 1.2.0 - outvariant: 1.4.3 - - '@open-draft/until@2.1.0': {} - - '@opentelemetry/api-logs@0.204.0': - dependencies: - '@opentelemetry/api': 1.9.0 - - '@opentelemetry/api-logs@0.57.2': - dependencies: - '@opentelemetry/api': 1.9.0 - - '@opentelemetry/api@1.9.0': {} - - '@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - - '@opentelemetry/core@2.1.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.38.0 - - '@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/semantic-conventions': 1.38.0 - - '@opentelemetry/instrumentation-amqplib@0.51.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-connect@0.48.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - '@types/connect': 3.4.38 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-dataloader@0.22.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-express@0.53.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - transitivePeerDependencies: - - supports-color - - '@opentelemetry/instrumentation-fs@0.24.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + fastq: 1.20.3 - '@opentelemetry/instrumentation-generic-pool@0.48.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/api-logs@0.220.0': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + '@opentelemetry/api': 1.9.1 - '@opentelemetry/instrumentation-graphql@0.52.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + '@opentelemetry/api@1.9.1': {} - '@opentelemetry/instrumentation-hapi@0.51.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1)': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - transitivePeerDependencies: - - supports-color + '@opentelemetry/api': 1.9.1 + '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/instrumentation-http@0.204.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/instrumentation@0.220.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2)': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.1.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - forwarded-parse: 2.1.2 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/api-logs': 0.220.0 + import-in-the-middle: 3.5.1 + require-in-the-middle: 8.0.1(supports-color@10.2.2) transitivePeerDependencies: - supports-color - '@opentelemetry/instrumentation-ioredis@0.52.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/resources@2.11.0(@opentelemetry/api@1.9.1)': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/redis-common': 0.38.2 - '@opentelemetry/semantic-conventions': 1.38.0 - transitivePeerDependencies: - - supports-color + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/instrumentation-kafkajs@0.14.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-trace-base@2.11.0(@opentelemetry/api@1.9.1)': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - transitivePeerDependencies: - - supports-color + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/instrumentation-knex@0.49.0(@opentelemetry/api@1.9.0)': + '@opentelemetry/sdk-trace@2.11.0(@opentelemetry/api@1.9.1)': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - transitivePeerDependencies: - - supports-color + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/resources': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/semantic-conventions': 1.43.0 - '@opentelemetry/instrumentation-koa@0.52.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - transitivePeerDependencies: - - supports-color + '@opentelemetry/semantic-conventions@1.43.0': {} - '@opentelemetry/instrumentation-lru-memoizer@0.49.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-android-arm-eabi@0.150.0': + optional: true - '@opentelemetry/instrumentation-mongodb@0.57.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-android-arm64@0.150.0': + optional: true - '@opentelemetry/instrumentation-mongoose@0.51.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-darwin-arm64@0.150.0': + optional: true - '@opentelemetry/instrumentation-mysql2@0.51.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-darwin-x64@0.150.0': + optional: true - '@opentelemetry/instrumentation-mysql@0.50.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - '@types/mysql': 2.15.27 - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-freebsd-x64@0.150.0': + optional: true - '@opentelemetry/instrumentation-pg@0.57.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - '@opentelemetry/sql-common': 0.41.2(@opentelemetry/api@1.9.0) - '@types/pg': 8.15.5 - '@types/pg-pool': 2.0.6 - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-linux-arm-gnueabihf@0.150.0': + optional: true - '@opentelemetry/instrumentation-redis@0.53.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/redis-common': 0.38.2 - '@opentelemetry/semantic-conventions': 1.38.0 - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-linux-arm-musleabihf@0.150.0': + optional: true - '@opentelemetry/instrumentation-tedious@0.23.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - '@types/tedious': 4.0.14 - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-linux-arm64-gnu@0.150.0': + optional: true - '@opentelemetry/instrumentation-undici@0.15.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-linux-arm64-musl@0.150.0': + optional: true - '@opentelemetry/instrumentation@0.204.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/api-logs': 0.204.0 - import-in-the-middle: 1.15.0 - require-in-the-middle: 7.5.2 - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-linux-ppc64-gnu@0.150.0': + optional: true - '@opentelemetry/instrumentation@0.57.2(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@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.3 - shimmer: 1.2.1 - transitivePeerDependencies: - - supports-color + '@oxc-parser/binding-linux-riscv64-gnu@0.150.0': + optional: true - '@opentelemetry/redis-common@0.38.2': {} + '@oxc-parser/binding-linux-riscv64-musl@0.150.0': + optional: true - '@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 + '@oxc-parser/binding-linux-s390x-gnu@0.150.0': + optional: true - '@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 + '@oxc-parser/binding-linux-x64-gnu@0.150.0': + optional: true - '@opentelemetry/semantic-conventions@1.38.0': {} + '@oxc-parser/binding-linux-x64-musl@0.150.0': + optional: true - '@opentelemetry/sql-common@0.41.2(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) + '@oxc-parser/binding-openharmony-arm64@0.150.0': + optional: true - '@oxc-project/runtime@0.92.0': {} + '@oxc-parser/binding-win32-arm64-msvc@0.150.0': + optional: true - '@oxc-project/runtime@0.98.0': {} + '@oxc-parser/binding-win32-ia32-msvc@0.150.0': + optional: true - '@oxc-project/types@0.93.0': {} + '@oxc-parser/binding-win32-x64-msvc@0.150.0': + optional: true - '@oxc-project/types@0.98.0': {} + '@oxc-project/types@0.150.0': {} - '@oxc-resolver/binding-android-arm-eabi@11.13.2': + '@oxc-resolver/binding-android-arm-eabi@11.24.2': optional: true - '@oxc-resolver/binding-android-arm64@11.13.2': + '@oxc-resolver/binding-android-arm64@11.24.2': optional: true - '@oxc-resolver/binding-darwin-arm64@11.13.2': + '@oxc-resolver/binding-darwin-arm64@11.24.2': optional: true - '@oxc-resolver/binding-darwin-x64@11.13.2': + '@oxc-resolver/binding-darwin-x64@11.24.2': optional: true - '@oxc-resolver/binding-freebsd-x64@11.13.2': + '@oxc-resolver/binding-freebsd-x64@11.24.2': optional: true - '@oxc-resolver/binding-linux-arm-gnueabihf@11.13.2': + '@oxc-resolver/binding-linux-arm-gnueabihf@11.24.2': optional: true - '@oxc-resolver/binding-linux-arm-musleabihf@11.13.2': + '@oxc-resolver/binding-linux-arm-musleabihf@11.24.2': optional: true - '@oxc-resolver/binding-linux-arm64-gnu@11.13.2': + '@oxc-resolver/binding-linux-arm64-gnu@11.24.2': optional: true - '@oxc-resolver/binding-linux-arm64-musl@11.13.2': + '@oxc-resolver/binding-linux-arm64-musl@11.24.2': optional: true - '@oxc-resolver/binding-linux-ppc64-gnu@11.13.2': + '@oxc-resolver/binding-linux-ppc64-gnu@11.24.2': optional: true - '@oxc-resolver/binding-linux-riscv64-gnu@11.13.2': + '@oxc-resolver/binding-linux-riscv64-gnu@11.24.2': optional: true - '@oxc-resolver/binding-linux-riscv64-musl@11.13.2': + '@oxc-resolver/binding-linux-riscv64-musl@11.24.2': optional: true - '@oxc-resolver/binding-linux-s390x-gnu@11.13.2': + '@oxc-resolver/binding-linux-s390x-gnu@11.24.2': optional: true - '@oxc-resolver/binding-linux-x64-gnu@11.13.2': + '@oxc-resolver/binding-linux-x64-gnu@11.24.2': optional: true - '@oxc-resolver/binding-linux-x64-musl@11.13.2': + '@oxc-resolver/binding-linux-x64-musl@11.24.2': optional: true - '@oxc-resolver/binding-wasm32-wasi@11.13.2': - dependencies: - '@napi-rs/wasm-runtime': 1.0.7 + '@oxc-resolver/binding-openharmony-arm64@11.24.2': optional: true - '@oxc-resolver/binding-win32-arm64-msvc@11.13.2': + '@oxc-resolver/binding-wasm32-wasi@11.24.2': + dependencies: + '@emnapi/core': 1.11.2 + '@emnapi/runtime': 1.11.2 + '@napi-rs/wasm-runtime': 1.2.4(@emnapi/core@1.11.2)(@emnapi/runtime@1.11.2) optional: true - '@oxc-resolver/binding-win32-ia32-msvc@11.13.2': + '@oxc-resolver/binding-win32-arm64-msvc@11.24.2': optional: true - '@oxc-resolver/binding-win32-x64-msvc@11.13.2': + '@oxc-resolver/binding-win32-x64-msvc@11.24.2': optional: true '@polka/url@1.0.0-next.29': {} - '@poppinss/colors@4.1.5': + '@poppinss/colors@4.1.6': dependencies: kleur: 4.1.5 '@poppinss/dumper@0.6.5': dependencies: - '@poppinss/colors': 4.1.5 - '@sindresorhus/is': 7.1.1 + '@poppinss/colors': 4.1.6 + '@sindresorhus/is': 7.2.0 supports-color: 10.2.2 - '@poppinss/exception@1.2.2': {} - - '@prisma/instrumentation@6.15.0(@opentelemetry/api@1.9.0)': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/instrumentation': 0.57.2(@opentelemetry/api@1.9.0) - transitivePeerDependencies: - - supports-color - - '@radix-ui/number@1.1.1': {} - - '@radix-ui/primitive@1.1.3': {} + '@poppinss/exception@1.2.3': {} - '@radix-ui/react-accessible-icon@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@radix-ui/number@1.1.3': {} - '@radix-ui/react-accordion@1.2.12(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@radix-ui/primitive@1.1.7': {} - '@radix-ui/react-alert-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-accessible-icon@1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-accordion@1.2.20(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collapsible': 1.1.20(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-aspect-ratio@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-alert-dialog@1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-avatar@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-arrow@1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-avatar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-aspect-ratio@1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-context': 1.1.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-avatar@1.2.6(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-collapsible@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-checkbox@1.3.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-size': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-collapsible@1.1.20(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - react: 19.2.0 - optionalDependencies: - '@types/react': 19.2.6 + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-collection@1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-slot': 1.3.3(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-compose-refs@1.1.5(@types/react@19.3.0)(react@19.3.0)': + dependencies: + react: 19.3.0 + optionalDependencies: + '@types/react': 19.3.0 - '@radix-ui/react-context-menu@2.2.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-context-menu@2.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-context@1.1.2(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-context@1.2.2(@types/react@19.3.0)(react@19.3.0)': dependencies: - react: 19.2.0 + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-context@1.1.3(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-dialog@1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - react: 19.2.0 - optionalDependencies: - '@types/react': 19.2.6 - - '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-slot': 1.3.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) aria-hidden: 1.2.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-remove-scroll: 2.7.1(@types/react@19.2.6)(react@19.2.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + react-remove-scroll: 2.7.2(@types/react@19.3.0)(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-direction@1.1.1(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-direction@1.1.4(@types/react@19.3.0)(react@19.3.0)': dependencies: - react: 19.2.0 + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-dismissable-layer@1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-dropdown-menu@2.1.24(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-focus-guards@1.1.6(@types/react@19.3.0)(react@19.3.0)': dependencies: - react: 19.2.0 + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-focus-scope@1.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-form@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-form@0.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-label': 2.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-hover-card@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-hover-card@1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-id@1.1.1(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-id@1.1.4(@types/react@19.3.0)(react@19.3.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-label@2.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-label@2.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-menu@2.1.24(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-slot': 1.3.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) aria-hidden: 1.2.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-remove-scroll: 2.7.1(@types/react@19.2.6)(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-menubar@1.1.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-navigation-menu@1.2.14(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-one-time-password-field@0.1.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-password-toggle-field@0.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-popover@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + react-remove-scroll: 2.7.2(@types/react@19.3.0)(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-menubar@1.1.24(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-navigation-menu@1.2.22(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-previous': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-one-time-password-field@0.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/number': 1.1.3 + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-password-toggle-field@0.1.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-popover@1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-slot': 1.3.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) aria-hidden: 1.2.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-remove-scroll: 2.7.1(@types/react@19.2.6)(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/rect': 1.1.1 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-progress@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-radio-group@1.3.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-scroll-area@1.2.10(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + react-remove-scroll: 2.7.2(@types/react@19.3.0)(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-popper@1.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@floating-ui/react-dom': 2.1.9(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-arrow': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-rect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-size': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/rect': 1.1.3 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-portal@1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-presence@1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-primitive@2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/react-slot': 1.3.3(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-progress@1.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-radio-group@1.4.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-size': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-roving-focus@1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-scroll-area@1.2.18(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/number': 1.1.3 + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-select@2.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/number': 1.1.3 + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-slot': 1.3.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-previous': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) aria-hidden: 1.2.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-remove-scroll: 2.7.1(@types/react@19.2.6)(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-separator@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-separator@1.1.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-slot@1.2.3(@types/react@19.2.6)(react@19.2.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - optionalDependencies: - '@types/react': 19.2.6 - - '@radix-ui/react-slot@1.2.4(@types/react@19.2.6)(react@19.2.0)': - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - optionalDependencies: - '@types/react': 19.2.6 - - '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/react-toast@1.2.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + react-remove-scroll: 2.7.2(@types/react@19.3.0)(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-separator@1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-slider@1.4.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/number': 1.1.3 + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-previous': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-size': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-slot@1.3.3(@types/react@19.3.0)(react@19.3.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + optionalDependencies: + '@types/react': 19.3.0 + + '@radix-ui/react-switch@1.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-size': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-tabs@1.1.21(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@radix-ui/react-toast@1.2.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-toggle-group@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-toggle-group@1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-toggle': 1.1.18(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-toggle@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-toggle@1.1.18(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-toolbar@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-toolbar@1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-separator': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-toggle-group': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-tooltip@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-tooltip@1.2.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-slot': 1.3.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-use-callback-ref@1.1.4(@types/react@19.3.0)(react@19.3.0)': dependencies: - react: 19.2.0 + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-use-controllable-state@1.2.6(@types/react@19.3.0)(react@19.3.0)': dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-use-effect-event@0.0.5(@types/react@19.3.0)(react@19.3.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-use-escape-keydown@1.1.5(@types/react@19.3.0)(react@19.3.0)': dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-use-is-hydrated@0.1.0(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-use-is-hydrated@0.1.3(@types/react@19.3.0)(react@19.3.0)': dependencies: - react: 19.2.0 - use-sync-external-store: 1.6.0(react@19.2.0) + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-use-layout-effect@1.1.4(@types/react@19.3.0)(react@19.3.0)': dependencies: - react: 19.2.0 + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-use-previous@1.1.4(@types/react@19.3.0)(react@19.3.0)': dependencies: - react: 19.2.0 + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-use-rect@1.1.4(@types/react@19.3.0)(react@19.3.0)': dependencies: - '@radix-ui/rect': 1.1.1 - react: 19.2.0 + '@radix-ui/rect': 1.1.3 + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-use-size@1.1.1(@types/react@19.2.6)(react@19.2.0)': + '@radix-ui/react-use-size@1.1.4(@types/react@19.3.0)(react@19.3.0)': dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - react: 19.2.0 + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + react: 19.3.0 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@radix-ui/react-visually-hidden@1.2.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - '@radix-ui/rect@1.1.1': {} - - '@react-email/body@0.2.0(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/button@0.2.0(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/code-block@0.2.0(react@19.2.0)': - dependencies: - prismjs: 1.30.0 - react: 19.2.0 - - '@react-email/code-inline@0.0.5(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/column@0.0.13(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/components@1.0.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - '@react-email/body': 0.2.0(react@19.2.0) - '@react-email/button': 0.2.0(react@19.2.0) - '@react-email/code-block': 0.2.0(react@19.2.0) - '@react-email/code-inline': 0.0.5(react@19.2.0) - '@react-email/column': 0.0.13(react@19.2.0) - '@react-email/container': 0.0.15(react@19.2.0) - '@react-email/font': 0.0.9(react@19.2.0) - '@react-email/head': 0.0.12(react@19.2.0) - '@react-email/heading': 0.0.15(react@19.2.0) - '@react-email/hr': 0.0.11(react@19.2.0) - '@react-email/html': 0.0.11(react@19.2.0) - '@react-email/img': 0.0.11(react@19.2.0) - '@react-email/link': 0.0.12(react@19.2.0) - '@react-email/markdown': 0.0.17(react@19.2.0) - '@react-email/preview': 0.0.13(react@19.2.0) - '@react-email/render': 2.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@react-email/row': 0.0.12(react@19.2.0) - '@react-email/section': 0.0.16(react@19.2.0) - '@react-email/tailwind': 2.0.1(@react-email/body@0.2.0(react@19.2.0))(@react-email/button@0.2.0(react@19.2.0))(@react-email/code-block@0.2.0(react@19.2.0))(@react-email/code-inline@0.0.5(react@19.2.0))(@react-email/container@0.0.15(react@19.2.0))(@react-email/heading@0.0.15(react@19.2.0))(@react-email/hr@0.0.11(react@19.2.0))(@react-email/img@0.0.11(react@19.2.0))(@react-email/link@0.0.12(react@19.2.0))(@react-email/preview@0.0.13(react@19.2.0))(@react-email/text@0.1.5(react@19.2.0))(react@19.2.0) - '@react-email/text': 0.1.5(react@19.2.0) - react: 19.2.0 - transitivePeerDependencies: - - react-dom - - '@react-email/container@0.0.15(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/font@0.0.9(react@19.2.0)': - dependencies: - react: 19.2.0 + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) - '@react-email/head@0.0.12(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/heading@0.0.15(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/hr@0.0.11(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/html@0.0.11(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/img@0.0.11(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/link@0.0.12(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/markdown@0.0.17(react@19.2.0)': - dependencies: - marked: 15.0.12 - react: 19.2.0 - - '@react-email/preview-server@5.0.5(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': - dependencies: - next: 16.0.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - transitivePeerDependencies: - - '@babel/core' - - '@opentelemetry/api' - - '@playwright/test' - - babel-plugin-macros - - babel-plugin-react-compiler - - react - - react-dom - - sass + '@radix-ui/rect@1.1.3': {} - '@react-email/preview@0.0.13(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/render@2.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@react-email/render@2.1.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: + entities: 4.5.0 html-to-text: 9.0.5 - prettier: 3.6.2 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - - '@react-email/row@0.0.12(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/section@0.0.16(react@19.2.0)': - dependencies: - react: 19.2.0 - - '@react-email/tailwind@2.0.1(@react-email/body@0.2.0(react@19.2.0))(@react-email/button@0.2.0(react@19.2.0))(@react-email/code-block@0.2.0(react@19.2.0))(@react-email/code-inline@0.0.5(react@19.2.0))(@react-email/container@0.0.15(react@19.2.0))(@react-email/heading@0.0.15(react@19.2.0))(@react-email/hr@0.0.11(react@19.2.0))(@react-email/img@0.0.11(react@19.2.0))(@react-email/link@0.0.12(react@19.2.0))(@react-email/preview@0.0.13(react@19.2.0))(@react-email/text@0.1.5(react@19.2.0))(react@19.2.0)': - dependencies: - '@react-email/text': 0.1.5(react@19.2.0) - react: 19.2.0 - tailwindcss: 4.1.17 - optionalDependencies: - '@react-email/body': 0.2.0(react@19.2.0) - '@react-email/button': 0.2.0(react@19.2.0) - '@react-email/code-block': 0.2.0(react@19.2.0) - '@react-email/code-inline': 0.0.5(react@19.2.0) - '@react-email/container': 0.0.15(react@19.2.0) - '@react-email/heading': 0.0.15(react@19.2.0) - '@react-email/hr': 0.0.11(react@19.2.0) - '@react-email/img': 0.0.11(react@19.2.0) - '@react-email/link': 0.0.12(react@19.2.0) - '@react-email/preview': 0.0.13(react@19.2.0) - - '@react-email/text@0.1.5(react@19.2.0)': - dependencies: - react: 19.2.0 + html5parser: 3.0.0 + prettier: 3.9.8 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) - '@reduxjs/toolkit@2.10.1(react-redux@9.2.0(@types/react@19.2.6)(react@19.2.0)(redux@5.0.1))(react@19.2.0)': + '@reduxjs/toolkit@2.12.0(react-redux@9.3.0(@types/react@19.3.0)(react@19.3.0)(redux@5.0.1))(react@19.3.0)': dependencies: - '@standard-schema/spec': 1.0.0 + '@standard-schema/spec': 1.1.0 '@standard-schema/utils': 0.3.0 - immer: 10.2.0 + immer: 11.1.18 redux: 5.0.1 redux-thunk: 3.1.0(redux@5.0.1) - reselect: 5.1.1 + reselect: 5.2.0 optionalDependencies: - react: 19.2.0 - react-redux: 9.2.0(@types/react@19.2.6)(react@19.2.0)(redux@5.0.1) - - '@rolldown/binding-android-arm64@1.0.0-beta.41': - optional: true - - '@rolldown/binding-android-arm64@1.0.0-beta.51': - optional: true - - '@rolldown/binding-darwin-arm64@1.0.0-beta.41': - optional: true - - '@rolldown/binding-darwin-arm64@1.0.0-beta.51': - optional: true - - '@rolldown/binding-darwin-x64@1.0.0-beta.41': - optional: true - - '@rolldown/binding-darwin-x64@1.0.0-beta.51': - optional: true - - '@rolldown/binding-freebsd-x64@1.0.0-beta.41': - optional: true - - '@rolldown/binding-freebsd-x64@1.0.0-beta.51': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.41': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.0.0-beta.51': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.41': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.0.0-beta.51': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.41': - optional: true + react: 19.3.0 + react-redux: 9.3.0(@types/react@19.3.0)(react@19.3.0)(redux@5.0.1) - '@rolldown/binding-linux-arm64-musl@1.0.0-beta.51': + '@rolldown/binding-android-arm-eabi@1.2.9': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.41': + '@rolldown/binding-android-arm64@1.2.9': optional: true - '@rolldown/binding-linux-x64-gnu@1.0.0-beta.51': + '@rolldown/binding-darwin-arm64@1.2.9': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.41': + '@rolldown/binding-darwin-x64@1.2.9': optional: true - '@rolldown/binding-linux-x64-musl@1.0.0-beta.51': + '@rolldown/binding-freebsd-x64@1.2.9': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.41': + '@rolldown/binding-linux-arm-gnueabihf@1.2.9': optional: true - '@rolldown/binding-openharmony-arm64@1.0.0-beta.51': + '@rolldown/binding-linux-arm64-gnu@1.2.9': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.41': - dependencies: - '@napi-rs/wasm-runtime': 1.0.7 + '@rolldown/binding-linux-arm64-musl@1.2.9': optional: true - '@rolldown/binding-wasm32-wasi@1.0.0-beta.51': - dependencies: - '@napi-rs/wasm-runtime': 1.0.7 + '@rolldown/binding-linux-ppc64-gnu@1.2.9': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.41': + '@rolldown/binding-linux-s390x-gnu@1.2.9': optional: true - '@rolldown/binding-win32-arm64-msvc@1.0.0-beta.51': + '@rolldown/binding-linux-x64-gnu@1.2.9': optional: true - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.41': + '@rolldown/binding-linux-x64-musl@1.2.9': optional: true - '@rolldown/binding-win32-ia32-msvc@1.0.0-beta.51': + '@rolldown/binding-openharmony-arm64@1.2.9': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.41': + '@rolldown/binding-win32-arm64-msvc@1.2.9': optional: true - '@rolldown/binding-win32-x64-msvc@1.0.0-beta.51': + '@rolldown/binding-win32-x64-msvc@1.2.9': optional: true - '@rolldown/pluginutils@1.0.0-beta.41': {} - - '@rolldown/pluginutils@1.0.0-beta.47': {} + '@rolldown/pluginutils@1.0.1': {} - '@rolldown/pluginutils@1.0.0-beta.51': {} - - '@rollup/plugin-babel@5.3.1(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@2.79.2)': + '@rollup/plugin-babel@6.1.0(@babel/core@7.29.7(supports-color@10.2.2))(rollup@4.63.3)(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@rollup/pluginutils': 3.1.0(rollup@2.79.2) - rollup: 2.79.2 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-module-imports': 7.29.7(supports-color@10.2.2) + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) optionalDependencies: - '@types/babel__core': 7.20.5 + rollup: 4.63.3 transitivePeerDependencies: - supports-color - '@rollup/plugin-node-resolve@15.3.1(rollup@2.79.2)': + '@rollup/plugin-node-resolve@16.0.3(rollup@4.63.3)': dependencies: - '@rollup/pluginutils': 5.3.0(rollup@2.79.2) + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) '@types/resolve': 1.20.2 deepmerge: 4.3.1 is-module: 1.0.0 - resolve: 1.22.11 + resolve: 1.22.12 optionalDependencies: - rollup: 2.79.2 - - '@rollup/plugin-replace@2.4.2(rollup@2.79.2)': - dependencies: - '@rollup/pluginutils': 3.1.0(rollup@2.79.2) - magic-string: 0.25.9 - rollup: 2.79.2 + rollup: 4.63.3 - '@rollup/plugin-terser@0.4.4(rollup@2.79.2)': + '@rollup/plugin-replace@6.0.3(rollup@4.63.3)': dependencies: - serialize-javascript: 6.0.2 - smob: 1.5.0 - terser: 5.44.1 + '@rollup/pluginutils': 5.4.0(rollup@4.63.3) + magic-string: 0.30.21 optionalDependencies: - rollup: 2.79.2 + rollup: 4.63.3 - '@rollup/pluginutils@3.1.0(rollup@2.79.2)': + '@rollup/plugin-terser@1.0.0(rollup@4.63.3)': dependencies: - '@types/estree': 0.0.39 - estree-walker: 1.0.1 - picomatch: 2.3.1 - rollup: 2.79.2 + serialize-javascript: 7.1.1 + smob: 1.6.2 + terser: 5.51.2 + optionalDependencies: + rollup: 4.63.3 - '@rollup/pluginutils@5.3.0(rollup@2.79.2)': + '@rollup/pluginutils@5.4.0(rollup@4.63.3)': dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 estree-walker: 2.0.2 - picomatch: 4.0.3 + picomatch: 4.0.7 optionalDependencies: - rollup: 2.79.2 + rollup: 4.63.3 + + '@rollup/rollup-android-arm-eabi@4.63.3': + optional: true + + '@rollup/rollup-android-arm64@4.63.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.63.3': + optional: true - '@rollup/rollup-android-arm-eabi@4.53.3': + '@rollup/rollup-darwin-x64@4.63.3': optional: true - '@rollup/rollup-android-arm64@4.53.3': + '@rollup/rollup-freebsd-arm64@4.63.3': optional: true - '@rollup/rollup-darwin-arm64@4.53.3': + '@rollup/rollup-freebsd-x64@4.63.3': optional: true - '@rollup/rollup-darwin-x64@4.53.3': + '@rollup/rollup-linux-arm-gnueabihf@4.63.3': optional: true - '@rollup/rollup-freebsd-arm64@4.53.3': + '@rollup/rollup-linux-arm-musleabihf@4.63.3': optional: true - '@rollup/rollup-freebsd-x64@4.53.3': + '@rollup/rollup-linux-arm64-gnu@4.63.3': optional: true - '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + '@rollup/rollup-linux-arm64-musl@4.63.3': optional: true - '@rollup/rollup-linux-arm-musleabihf@4.53.3': + '@rollup/rollup-linux-loong64-gnu@4.63.3': optional: true - '@rollup/rollup-linux-arm64-gnu@4.53.3': + '@rollup/rollup-linux-loong64-musl@4.63.3': optional: true - '@rollup/rollup-linux-arm64-musl@4.53.3': + '@rollup/rollup-linux-ppc64-gnu@4.63.3': optional: true - '@rollup/rollup-linux-loong64-gnu@4.53.3': + '@rollup/rollup-linux-ppc64-musl@4.63.3': optional: true - '@rollup/rollup-linux-ppc64-gnu@4.53.3': + '@rollup/rollup-linux-riscv64-gnu@4.63.3': optional: true - '@rollup/rollup-linux-riscv64-gnu@4.53.3': + '@rollup/rollup-linux-riscv64-musl@4.63.3': optional: true - '@rollup/rollup-linux-riscv64-musl@4.53.3': + '@rollup/rollup-linux-s390x-gnu@4.63.3': optional: true - '@rollup/rollup-linux-s390x-gnu@4.53.3': + '@rollup/rollup-linux-x64-gnu@4.63.3': optional: true - '@rollup/rollup-linux-x64-gnu@4.53.3': + '@rollup/rollup-linux-x64-musl@4.63.3': optional: true - '@rollup/rollup-linux-x64-musl@4.53.3': + '@rollup/rollup-openbsd-x64@4.63.3': optional: true - '@rollup/rollup-openharmony-arm64@4.53.3': + '@rollup/rollup-openharmony-arm64@4.63.3': optional: true - '@rollup/rollup-win32-arm64-msvc@4.53.3': + '@rollup/rollup-win32-arm64-msvc@4.63.3': optional: true - '@rollup/rollup-win32-ia32-msvc@4.53.3': + '@rollup/rollup-win32-ia32-msvc@4.63.3': optional: true - '@rollup/rollup-win32-x64-gnu@4.53.3': + '@rollup/rollup-win32-x64-gnu@4.63.3': optional: true - '@rollup/rollup-win32-x64-msvc@4.53.3': + '@rollup/rollup-win32-x64-msvc@4.63.3': optional: true '@sec-ant/readable-stream@0.4.1': {} @@ -10802,322 +10217,295 @@ snapshots: domhandler: 5.0.3 selderee: 0.11.0 - '@sentry-internal/browser-utils@10.26.0': + '@sentry/browser-utils@10.75.0': dependencies: - '@sentry/core': 10.26.0 + '@sentry/conventions': 0.16.0 + '@sentry/core': 10.75.0 - '@sentry-internal/feedback@10.26.0': + '@sentry/browser@10.75.0': dependencies: - '@sentry/core': 10.26.0 + '@sentry/browser-utils': 10.75.0 + '@sentry/conventions': 0.16.0 + '@sentry/core': 10.75.0 + '@sentry/feedback': 10.75.0 + '@sentry/replay': 10.75.0 + '@sentry/replay-canvas': 10.75.0 - '@sentry-internal/replay-canvas@10.26.0': + '@sentry/cloudflare@10.75.0(@cloudflare/workers-types@5.20260918.1)(wrangler@4.135.0(@cloudflare/workers-types@5.20260918.1)(@types/node@24.13.5))': dependencies: - '@sentry-internal/replay': 10.26.0 - '@sentry/core': 10.26.0 + '@opentelemetry/api': 1.9.1 + '@sentry/core': 10.75.0 + '@sentry/server-utils': 10.75.0 + magic-string: 0.30.21 + optionalDependencies: + '@cloudflare/workers-types': 5.20260918.1 + wrangler: 4.135.0(@cloudflare/workers-types@5.20260918.1)(@types/node@24.13.5) + + '@sentry/conventions@0.16.0': {} - '@sentry-internal/replay@10.26.0': + '@sentry/core@10.75.0': dependencies: - '@sentry-internal/browser-utils': 10.26.0 - '@sentry/core': 10.26.0 + '@sentry/conventions': 0.16.0 - '@sentry/browser@10.26.0': + '@sentry/feedback@10.75.0': dependencies: - '@sentry-internal/browser-utils': 10.26.0 - '@sentry-internal/feedback': 10.26.0 - '@sentry-internal/replay': 10.26.0 - '@sentry-internal/replay-canvas': 10.26.0 - '@sentry/core': 10.26.0 + '@sentry/core': 10.75.0 - '@sentry/cloudflare@10.26.0(@cloudflare/workers-types@4.20251121.0)': + '@sentry/node-core@10.75.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.220.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/sdk-trace-base@2.11.0(@opentelemetry/api@1.9.1))': dependencies: - '@opentelemetry/api': 1.9.0 - '@sentry/core': 10.26.0 + '@sentry/conventions': 0.16.0 + '@sentry/core': 10.75.0 + '@sentry/opentelemetry': 10.75.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.11.0(@opentelemetry/api@1.9.1)) + import-in-the-middle: 3.5.1 optionalDependencies: - '@cloudflare/workers-types': 4.20251121.0 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/instrumentation': 0.220.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2) + '@opentelemetry/sdk-trace-base': 2.11.0(@opentelemetry/api@1.9.1) - '@sentry/core@10.26.0': {} - - '@sentry/node-core@10.26.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.204.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)': + '@sentry/node@10.75.0(@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1))(supports-color@10.2.2)': dependencies: - '@apm-js-collab/tracing-hooks': 0.3.1 - '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - '@sentry/core': 10.26.0 - '@sentry/opentelemetry': 10.26.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) - import-in-the-middle: 1.15.0 + '@opentelemetry/api': 1.9.1 + '@opentelemetry/instrumentation': 0.220.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2) + '@opentelemetry/sdk-trace-base': 2.11.0(@opentelemetry/api@1.9.1) + '@sentry/conventions': 0.16.0 + '@sentry/core': 10.75.0 + '@sentry/node-core': 10.75.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1))(@opentelemetry/instrumentation@0.220.0(@opentelemetry/api@1.9.1)(supports-color@10.2.2))(@opentelemetry/sdk-trace-base@2.11.0(@opentelemetry/api@1.9.1)) + '@sentry/opentelemetry': 10.75.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.11.0(@opentelemetry/api@1.9.1)) + '@sentry/server-utils': 10.75.0 + import-in-the-middle: 3.5.1 transitivePeerDependencies: + - '@opentelemetry/core' + - '@opentelemetry/exporter-trace-otlp-http' - supports-color - '@sentry/node@10.26.0': - dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-amqplib': 0.51.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-connect': 0.48.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-dataloader': 0.22.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-express': 0.53.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-fs': 0.24.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-generic-pool': 0.48.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-graphql': 0.52.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-hapi': 0.51.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-http': 0.204.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-ioredis': 0.52.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-kafkajs': 0.14.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-knex': 0.49.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-koa': 0.52.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-lru-memoizer': 0.49.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mongodb': 0.57.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mongoose': 0.51.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mysql': 0.50.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-mysql2': 0.51.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-pg': 0.57.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-redis': 0.53.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-tedious': 0.23.0(@opentelemetry/api@1.9.0) - '@opentelemetry/instrumentation-undici': 0.15.0(@opentelemetry/api@1.9.0) - '@opentelemetry/resources': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - '@prisma/instrumentation': 6.15.0(@opentelemetry/api@1.9.0) - '@sentry/core': 10.26.0 - '@sentry/node-core': 10.26.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/instrumentation@0.204.0(@opentelemetry/api@1.9.0))(@opentelemetry/resources@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) - '@sentry/opentelemetry': 10.26.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0) - import-in-the-middle: 1.15.0 - minimatch: 9.0.5 - transitivePeerDependencies: - - supports-color + '@sentry/opentelemetry@10.75.0(@opentelemetry/api@1.9.1)(@opentelemetry/core@2.11.0(@opentelemetry/api@1.9.1))(@opentelemetry/sdk-trace-base@2.11.0(@opentelemetry/api@1.9.1))': + dependencies: + '@opentelemetry/api': 1.9.1 + '@opentelemetry/core': 2.11.0(@opentelemetry/api@1.9.1) + '@opentelemetry/sdk-trace-base': 2.11.0(@opentelemetry/api@1.9.1) + '@sentry/conventions': 0.16.0 + '@sentry/core': 10.75.0 - '@sentry/opentelemetry@10.26.0(@opentelemetry/api@1.9.0)(@opentelemetry/context-async-hooks@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/core@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/sdk-trace-base@2.2.0(@opentelemetry/api@1.9.0))(@opentelemetry/semantic-conventions@1.38.0)': + '@sentry/react@10.75.0(react@19.3.0)': dependencies: - '@opentelemetry/api': 1.9.0 - '@opentelemetry/context-async-hooks': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/core': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/sdk-trace-base': 2.2.0(@opentelemetry/api@1.9.0) - '@opentelemetry/semantic-conventions': 1.38.0 - '@sentry/core': 10.26.0 + '@sentry/browser': 10.75.0 + '@sentry/conventions': 0.16.0 + '@sentry/core': 10.75.0 + react: 19.3.0 - '@sentry/react@10.26.0(react@19.2.0)': + '@sentry/replay-canvas@10.75.0': dependencies: - '@sentry/browser': 10.26.0 - '@sentry/core': 10.26.0 - hoist-non-react-statics: 3.3.2 - react: 19.2.0 + '@sentry/core': 10.75.0 + '@sentry/replay': 10.75.0 - '@sindresorhus/is@7.1.1': {} + '@sentry/replay@10.75.0': + dependencies: + '@sentry/browser-utils': 10.75.0 + '@sentry/core': 10.75.0 + + '@sentry/server-utils@10.75.0': + dependencies: + '@sentry/conventions': 0.16.0 + '@sentry/core': 10.75.0 + + '@sindresorhus/is@7.2.0': {} '@sindresorhus/merge-streams@4.0.0': {} '@socket.io/component-emitter@3.1.2': {} - '@speed-highlight/core@1.2.12': {} + '@speed-highlight/core@1.2.24': {} '@stablelib/base64@1.0.1': {} - '@standard-schema/spec@1.0.0': {} - '@standard-schema/spec@1.1.0': {} '@standard-schema/utils@0.3.0': {} - '@surma/rollup-plugin-off-main-thread@2.2.3': - dependencies: - ejs: 3.1.10 - json5: 2.2.3 - magic-string: 0.25.9 - string.prototype.matchall: 4.0.12 - - '@swc/helpers@0.5.15': - dependencies: - tslib: 2.8.1 - - '@tailwindcss/node@4.1.17': + '@tailwindcss/node@4.3.3': dependencies: '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.3 - jiti: 2.6.1 - lightningcss: 1.30.2 + enhanced-resolve: 5.25.1 + jiti: 2.7.0 + lightningcss: 1.32.0 magic-string: 0.30.21 source-map-js: 1.2.1 - tailwindcss: 4.1.17 + tailwindcss: 4.3.3 - '@tailwindcss/oxide-android-arm64@4.1.17': + '@tailwindcss/oxide-android-arm64@4.3.3': optional: true - '@tailwindcss/oxide-darwin-arm64@4.1.17': + '@tailwindcss/oxide-darwin-arm64@4.3.3': optional: true - '@tailwindcss/oxide-darwin-x64@4.1.17': + '@tailwindcss/oxide-darwin-x64@4.3.3': optional: true - '@tailwindcss/oxide-freebsd-x64@4.1.17': + '@tailwindcss/oxide-freebsd-x64@4.3.3': optional: true - '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.3': optional: true - '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': + '@tailwindcss/oxide-linux-arm64-gnu@4.3.3': optional: true - '@tailwindcss/oxide-linux-arm64-musl@4.1.17': + '@tailwindcss/oxide-linux-arm64-musl@4.3.3': optional: true - '@tailwindcss/oxide-linux-x64-gnu@4.1.17': + '@tailwindcss/oxide-linux-x64-gnu@4.3.3': optional: true - '@tailwindcss/oxide-linux-x64-musl@4.1.17': + '@tailwindcss/oxide-linux-x64-musl@4.3.3': optional: true - '@tailwindcss/oxide-wasm32-wasi@4.1.17': + '@tailwindcss/oxide-wasm32-wasi@4.3.3': optional: true - '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': + '@tailwindcss/oxide-win32-arm64-msvc@4.3.3': optional: true - '@tailwindcss/oxide-win32-x64-msvc@4.1.17': + '@tailwindcss/oxide-win32-x64-msvc@4.3.3': optional: true - '@tailwindcss/oxide@4.1.17': + '@tailwindcss/oxide@4.3.3': optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.17 - '@tailwindcss/oxide-darwin-arm64': 4.1.17 - '@tailwindcss/oxide-darwin-x64': 4.1.17 - '@tailwindcss/oxide-freebsd-x64': 4.1.17 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.17 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.17 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.17 - '@tailwindcss/oxide-linux-x64-musl': 4.1.17 - '@tailwindcss/oxide-wasm32-wasi': 4.1.17 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 + '@tailwindcss/oxide-android-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-arm64': 4.3.3 + '@tailwindcss/oxide-darwin-x64': 4.3.3 + '@tailwindcss/oxide-freebsd-x64': 4.3.3 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.3 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.3 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.3 + '@tailwindcss/oxide-linux-x64-musl': 4.3.3 + '@tailwindcss/oxide-wasm32-wasi': 4.3.3 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.3 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.3 - '@tailwindcss/typography@0.5.19(tailwindcss@4.1.17)': + '@tailwindcss/typography@0.5.20(tailwindcss@4.3.3)': dependencies: postcss-selector-parser: 6.0.10 - tailwindcss: 4.1.17 + tailwindcss: 4.3.3 - '@tailwindcss/vite@4.1.17(rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6))': + '@tailwindcss/vite@4.3.3(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1))': dependencies: - '@tailwindcss/node': 4.1.17 - '@tailwindcss/oxide': 4.1.17 - tailwindcss: 4.1.17 - vite: rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6) + '@tailwindcss/node': 4.3.3 + '@tailwindcss/oxide': 4.3.3 + tailwindcss: 4.3.3 + vite: 8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1) - '@tanstack/history@1.139.0': {} + '@tanstack/history@1.162.4': {} - '@tanstack/query-core@5.90.10': {} + '@tanstack/query-core@5.103.1': {} - '@tanstack/react-query@5.90.10(react@19.2.0)': + '@tanstack/react-query@5.103.1(react@19.3.0)': dependencies: - '@tanstack/query-core': 5.90.10 - react: 19.2.0 + '@tanstack/query-core': 5.103.1 + react: 19.3.0 - '@tanstack/react-router@1.139.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@tanstack/history': 1.139.0 - '@tanstack/react-store': 0.8.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@tanstack/router-core': 1.139.3 - isbot: 5.1.32 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 + '@tanstack/history': 1.162.4 + '@tanstack/react-store': 0.11.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@tanstack/router-core': 1.171.32 + isbot: 5.2.2 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) - '@tanstack/react-store@0.8.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@tanstack/react-store@0.11.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@tanstack/store': 0.8.0 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - use-sync-external-store: 1.6.0(react@19.2.0) + '@tanstack/store': 0.11.1 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + use-sync-external-store: 1.7.0(react@19.3.0) - '@tanstack/react-table@8.21.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@tanstack/react-table@9.2.4(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@tanstack/table-core': 8.21.3 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@tanstack/react-store': 0.11.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@tanstack/table-core': 9.2.4 + react: 19.3.0 + transitivePeerDependencies: + - react-dom - '@tanstack/router-cli@1.139.3': + '@tanstack/router-cli@1.167.38(supports-color@10.2.2)': dependencies: - '@tanstack/router-generator': 1.139.3 - chokidar: 3.6.0 - yargs: 17.7.2 + '@tanstack/router-generator': 1.167.38(supports-color@10.2.2) + chokidar: 5.0.0 + yargs: 17.7.3 transitivePeerDependencies: - supports-color - '@tanstack/router-core@1.139.3': + '@tanstack/router-core@1.171.32': dependencies: - '@tanstack/history': 1.139.0 - '@tanstack/store': 0.8.0 - cookie-es: 2.0.0 - seroval: 1.4.0 - seroval-plugins: 1.4.0(seroval@1.4.0) - tiny-invariant: 1.3.3 - tiny-warning: 1.0.3 + '@tanstack/history': 1.162.4 + cookie-es: 3.1.1 + seroval: 1.6.7 + seroval-plugins: 1.6.7(seroval@1.6.7) - '@tanstack/router-generator@1.139.3': + '@tanstack/router-generator@1.167.38(supports-color@10.2.2)': dependencies: - '@tanstack/router-core': 1.139.3 - '@tanstack/router-utils': 1.139.0 - '@tanstack/virtual-file-routes': 1.139.0 - prettier: 3.6.2 - recast: 0.23.11 - source-map: 0.7.6 - tsx: 4.20.6 - zod: 3.25.76 + '@babel/types': 7.29.8 + '@tanstack/router-core': 1.171.32 + '@tanstack/router-utils': 1.162.3(supports-color@10.2.2) + '@tanstack/virtual-file-routes': 1.162.0 + jiti: 2.7.0 + magic-string: 0.30.21 + prettier: 3.9.8 + zod: 4.6.5 transitivePeerDependencies: - supports-color - '@tanstack/router-plugin@1.139.3(@tanstack/react-router@1.139.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0))(rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6))': - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-syntax-jsx': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-syntax-typescript': 7.27.1(@babel/core@7.28.5) - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@tanstack/router-core': 1.139.3 - '@tanstack/router-generator': 1.139.3 - '@tanstack/router-utils': 1.139.0 - '@tanstack/virtual-file-routes': 1.139.0 - babel-dead-code-elimination: 1.0.10 - chokidar: 3.6.0 - unplugin: 2.3.11 - zod: 3.25.76 + '@tanstack/router-plugin@1.168.40(@tanstack/react-router@1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0))(esbuild@0.28.2)(rolldown@1.2.9)(rollup@4.63.3)(supports-color@10.2.2)(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1))': + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/template': 7.29.7 + '@babel/types': 7.29.8 + '@tanstack/router-core': 1.171.32 + '@tanstack/router-generator': 1.167.38(supports-color@10.2.2) + '@tanstack/router-utils': 1.162.3(supports-color@10.2.2) + chokidar: 5.0.0 + unplugin: 3.4.0(esbuild@0.28.2)(rolldown@1.2.9)(rollup@4.63.3)(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) + zod: 4.6.5 optionalDependencies: - '@tanstack/react-router': 1.139.3(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - vite: rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6) + '@tanstack/react-router': 1.170.38(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + vite: 8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1) transitivePeerDependencies: + - '@farmfe/core' + - '@rspack/core' + - bun-types-no-globals + - esbuild + - rolldown + - rollup - supports-color + - unloader - '@tanstack/router-utils@1.139.0': + '@tanstack/router-utils@1.162.3(supports-color@10.2.2)': dependencies: - '@babel/core': 7.28.5 - '@babel/generator': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) - ansis: 4.2.0 - diff: 8.0.2 + '@babel/generator': 7.29.8 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 + ansis: 4.4.0 + babel-dead-code-elimination: 1.0.12(supports-color@10.2.2) + diff: 8.0.4 pathe: 2.0.3 - tinyglobby: 0.2.15 + tinyglobby: 0.2.17 transitivePeerDependencies: - supports-color - '@tanstack/store@0.8.0': {} + '@tanstack/store@0.11.1': {} - '@tanstack/table-core@8.21.3': {} + '@tanstack/table-core@9.2.4': + dependencies: + '@tanstack/store': 0.11.1 - '@tanstack/virtual-file-routes@1.139.0': {} + '@tanstack/virtual-file-routes@1.162.0': {} - '@testing-library/dom@10.4.1': + '@testing-library/dom@10.4.2': dependencies: - '@babel/code-frame': 7.27.1 - '@babel/runtime': 7.28.4 + '@babel/code-frame': 7.29.7 + '@babel/runtime': 7.29.7 '@types/aria-query': 5.0.4 aria-query: 5.3.0 dom-accessibility-api: 0.5.16 @@ -11125,101 +10513,85 @@ snapshots: picocolors: 1.1.1 pretty-format: 27.5.1 - '@testing-library/jest-dom@6.9.1': + '@testing-library/jest-dom@7.0.1(@testing-library/dom@10.4.2)(vitest@5.0.1)': dependencies: - '@adobe/css-tools': 4.4.4 + '@adobe/css-tools': 4.5.0 + '@testing-library/dom': 10.4.2 aria-query: 5.3.2 css.escape: 1.5.1 dom-accessibility-api: 0.6.3 picocolors: 1.1.1 redent: 3.0.0 + optionalDependencies: + vitest: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@24.13.5)(@vitest/coverage-v8@5.0.1)(@vitest/ui@5.0.1)(jsdom@30.1.0(@noble/hashes@2.4.0))(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) - '@testing-library/react@16.3.0(@testing-library/dom@10.4.1)(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + '@testing-library/react@16.3.3(@testing-library/dom@10.4.2)(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0)': dependencies: - '@babel/runtime': 7.28.4 - '@testing-library/dom': 10.4.1 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@babel/runtime': 7.29.7 + '@testing-library/dom': 10.4.2 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + '@testing-library/user-event@14.6.7(@testing-library/dom@10.4.2)': + dependencies: + '@testing-library/dom': 10.4.2 - '@testing-library/user-event@14.6.1(@testing-library/dom@10.4.1)': + '@trickfilm400/rollup-plugin-off-main-thread@3.0.0-pre1': dependencies: - '@testing-library/dom': 10.4.1 + ejs: 3.1.10 + json5: 2.2.3 + magic-string: 0.30.21 + string.prototype.matchall: 4.1.0 - '@trpc/client@11.7.2(@trpc/server@11.7.2(typescript@5.9.3))(typescript@5.9.3)': + '@trpc/client@11.19.0(@trpc/server@11.19.0(typescript@6.0.3))(typescript@6.0.3)': dependencies: - '@trpc/server': 11.7.2(typescript@5.9.3) - typescript: 5.9.3 + '@trpc/server': 11.19.0(typescript@6.0.3) + typescript: 6.0.3 - '@trpc/react-query@11.7.2(@tanstack/react-query@5.90.10(react@19.2.0))(@trpc/client@11.7.2(@trpc/server@11.7.2(typescript@5.9.3))(typescript@5.9.3))(@trpc/server@11.7.2(typescript@5.9.3))(react-dom@19.2.0(react@19.2.0))(react@19.2.0)(typescript@5.9.3)': + '@trpc/react-query@11.19.0(@tanstack/react-query@5.103.1(react@19.3.0))(@trpc/client@11.19.0(@trpc/server@11.19.0(typescript@6.0.3))(typescript@6.0.3))(@trpc/server@11.19.0(typescript@6.0.3))(react@19.3.0)(typescript@6.0.3)': dependencies: - '@tanstack/react-query': 5.90.10(react@19.2.0) - '@trpc/client': 11.7.2(@trpc/server@11.7.2(typescript@5.9.3))(typescript@5.9.3) - '@trpc/server': 11.7.2(typescript@5.9.3) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - typescript: 5.9.3 + '@tanstack/react-query': 5.103.1(react@19.3.0) + '@trpc/client': 11.19.0(@trpc/server@11.19.0(typescript@6.0.3))(typescript@6.0.3) + '@trpc/server': 11.19.0(typescript@6.0.3) + react: 19.3.0 + typescript: 6.0.3 - '@trpc/server@11.7.2(typescript@5.9.3)': + '@trpc/server@11.19.0(typescript@6.0.3)': dependencies: - typescript: 5.9.3 + typescript: 6.0.3 '@ts-morph/common@0.27.0': dependencies: fast-glob: 3.3.3 - minimatch: 10.1.1 + minimatch: 10.2.6 path-browserify: 1.0.1 - '@tybys/wasm-util@0.10.1': + '@tybys/wasm-util@0.10.4': dependencies: tslib: 2.8.1 optional: true '@types/aria-query@5.0.4': {} - '@types/babel__core@7.20.5': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - - '@types/babel__generator@7.27.0': - dependencies: - '@babel/types': 7.28.5 - - '@types/babel__template@7.4.4': - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - - '@types/babel__traverse@7.28.0': - dependencies: - '@babel/types': 7.28.5 - '@types/bcrypt@6.0.0': dependencies: - '@types/node': 24.10.1 + '@types/node': 26.6.1 - '@types/better-sqlite3@7.6.13': + '@types/better-sqlite3@9.6.0': dependencies: - '@types/node': 24.10.1 + '@types/node': 26.6.1 '@types/chai@5.2.3': dependencies: '@types/deep-eql': 4.0.2 assertion-error: 2.0.1 - '@types/connect@3.4.38': - dependencies: - '@types/node': 24.10.1 - '@types/cors@2.8.19': dependencies: - '@types/node': 24.10.1 + '@types/node': 26.6.1 '@types/d3-array@3.2.2': {} @@ -11237,7 +10609,7 @@ snapshots: dependencies: '@types/d3-time': 3.0.4 - '@types/d3-shape@3.1.7': + '@types/d3-shape@3.2.0': dependencies: '@types/d3-path': 3.1.1 @@ -11247,236 +10619,265 @@ snapshots: '@types/deep-eql@4.0.2': {} - '@types/estree@0.0.39': {} + '@types/esrecurse@4.3.1': {} - '@types/estree@1.0.8': {} + '@types/estree@1.0.9': {} '@types/json-schema@7.0.15': {} - '@types/mysql@2.15.27': - dependencies: - '@types/node': 24.10.1 - '@types/node-cron@3.0.11': {} - '@types/node@22.19.1': - dependencies: - undici-types: 6.21.0 - - '@types/node@24.10.1': + '@types/node@24.13.5': dependencies: - undici-types: 7.16.0 + undici-types: 7.18.2 - '@types/pg-pool@2.0.6': + '@types/node@26.6.1': dependencies: - '@types/pg': 8.15.5 + undici-types: 8.9.0 - '@types/pg@8.15.5': + '@types/react-dom@19.3.0(@types/react@19.3.0)': dependencies: - '@types/node': 24.10.1 - pg-protocol: 1.10.3 - pg-types: 2.2.0 + '@types/react': 19.3.0 - '@types/react-dom@19.2.3(@types/react@19.2.6)': - dependencies: - '@types/react': 19.2.6 - - '@types/react@19.2.6': + '@types/react@19.3.0': dependencies: csstype: 3.2.3 '@types/resolve@1.20.2': {} - '@types/sanitize-html@2.16.0': - dependencies: - htmlparser2: 8.0.2 - - '@types/shimmer@1.2.0': {} - - '@types/statuses@2.0.6': {} - - '@types/tedious@4.0.14': + '@types/sanitize-html@2.16.1': dependencies: - '@types/node': 24.10.1 + htmlparser2: 10.1.0 '@types/trusted-types@2.0.7': {} '@types/use-sync-external-store@0.0.6': {} - '@typescript-eslint/eslint-plugin@8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@types/validate-npm-package-name@4.0.2': {} + + '@types/ws@8.18.1': + dependencies: + '@types/node': 26.6.1 + + '@typescript-eslint/eslint-plugin@8.70.0(@typescript-eslint/parser@8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.47.0 - '@typescript-eslint/type-utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.47.0 - eslint: 9.39.1(jiti@2.6.1) - graphemer: 1.4.0 - ignore: 7.0.5 + '@typescript-eslint/parser': 8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/scope-manager': 8.70.0 + '@typescript-eslint/type-utils': 8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/utils': 8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.70.0 + eslint: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) + ignore: 7.0.9 natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/parser@8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@typescript-eslint/scope-manager': 8.47.0 - '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.47.0 - debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) - typescript: 5.9.3 + '@typescript-eslint/scope-manager': 8.70.0 + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/typescript-estree': 8.70.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/visitor-keys': 8.70.0 + debug: 4.4.3(supports-color@10.2.2) + eslint: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/project-service@8.47.0(typescript@5.9.3)': + '@typescript-eslint/project-service@8.70.0(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3) - '@typescript-eslint/types': 8.47.0 - debug: 4.4.3 - typescript: 5.9.3 + '@typescript-eslint/tsconfig-utils': 8.70.0(typescript@6.0.3) + '@typescript-eslint/types': 8.70.0 + debug: 4.4.3(supports-color@10.2.2) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/scope-manager@8.47.0': + '@typescript-eslint/scope-manager@8.70.0': dependencies: - '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/visitor-keys': 8.47.0 + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/visitor-keys': 8.70.0 - '@typescript-eslint/tsconfig-utils@8.47.0(typescript@5.9.3)': + '@typescript-eslint/tsconfig-utils@8.70.0(typescript@6.0.3)': dependencies: - typescript: 5.9.3 + typescript: 6.0.3 - '@typescript-eslint/type-utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/type-utils@8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - debug: 4.4.3 - eslint: 9.39.1(jiti@2.6.1) - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/typescript-estree': 8.70.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/utils': 8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + debug: 4.4.3(supports-color@10.2.2) + eslint: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/types@8.47.0': {} + '@typescript-eslint/types@8.70.0': {} - '@typescript-eslint/typescript-estree@8.47.0(typescript@5.9.3)': + '@typescript-eslint/typescript-estree@8.70.0(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@typescript-eslint/project-service': 8.47.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.47.0(typescript@5.9.3) - '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/visitor-keys': 8.47.0 - debug: 4.4.3 - fast-glob: 3.3.3 - is-glob: 4.0.3 - minimatch: 9.0.5 - semver: 7.7.3 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 + '@typescript-eslint/project-service': 8.70.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/tsconfig-utils': 8.70.0(typescript@6.0.3) + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/visitor-keys': 8.70.0 + debug: 4.4.3(supports-color@10.2.2) + minimatch: 10.2.6 + semver: 7.8.5 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@6.0.3) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + '@typescript-eslint/utils@8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3)': dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) - '@typescript-eslint/scope-manager': 8.47.0 - '@typescript-eslint/types': 8.47.0 - '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) - eslint: 9.39.1(jiti@2.6.1) - typescript: 5.9.3 + '@eslint-community/eslint-utils': 4.10.1(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2)) + '@typescript-eslint/scope-manager': 8.70.0 + '@typescript-eslint/types': 8.70.0 + '@typescript-eslint/typescript-estree': 8.70.0(supports-color@10.2.2)(typescript@6.0.3) + eslint: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - '@typescript-eslint/visitor-keys@8.47.0': + '@typescript-eslint/visitor-keys@8.70.0': dependencies: - '@typescript-eslint/types': 8.47.0 - eslint-visitor-keys: 4.2.1 + '@typescript-eslint/types': 8.70.0 + eslint-visitor-keys: 5.0.1 + + '@typescript/typescript-aix-ppc64@7.0.2': + optional: true + + '@typescript/typescript-darwin-arm64@7.0.2': + optional: true + + '@typescript/typescript-darwin-x64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-freebsd-x64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm64@7.0.2': + optional: true + + '@typescript/typescript-linux-arm@7.0.2': + optional: true + + '@typescript/typescript-linux-loong64@7.0.2': + optional: true + + '@typescript/typescript-linux-mips64el@7.0.2': + optional: true + + '@typescript/typescript-linux-ppc64@7.0.2': + optional: true + + '@typescript/typescript-linux-riscv64@7.0.2': + optional: true + + '@typescript/typescript-linux-s390x@7.0.2': + optional: true - '@vercel/oidc@3.1.0': {} + '@typescript/typescript-linux-x64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-netbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-arm64@7.0.2': + optional: true + + '@typescript/typescript-openbsd-x64@7.0.2': + optional: true + + '@typescript/typescript-sunos-x64@7.0.2': + optional: true + + '@typescript/typescript-win32-arm64@7.0.2': + optional: true + + '@typescript/typescript-win32-x64@7.0.2': + optional: true + + '@vercel/oidc@3.2.0': {} - '@vitejs/plugin-react@5.1.1(rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6))': + '@vitejs/plugin-react@6.1.1(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1))': dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) - '@rolldown/pluginutils': 1.0.0-beta.47 - '@types/babel__core': 7.20.5 - react-refresh: 0.18.0 - vite: rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6) - transitivePeerDependencies: - - supports-color + '@rolldown/pluginutils': 1.0.1 + vite: 8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1) - '@vitest/coverage-v8@4.0.13(vitest@4.0.13)': + '@vitest/coverage-v8@5.0.1(vitest@5.0.1)': dependencies: '@bcoe/v8-coverage': 1.0.2 - '@vitest/utils': 4.0.13 - ast-v8-to-istanbul: 0.3.8 - debug: 4.4.3 - istanbul-lib-coverage: 3.2.2 - istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 5.0.6 - istanbul-reports: 3.2.0 - magicast: 0.5.1 - std-env: 3.10.0 - tinyrainbow: 3.0.3 - vitest: 4.0.13(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/ui@4.0.13)(esbuild@0.27.0)(jiti@2.6.1)(jsdom@27.2.0)(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6) - transitivePeerDependencies: - - supports-color + '@vitest/istanbul-lib-coverage': 1.0.1 + '@vitest/istanbul-lib-report': 1.0.1 + ast-v8-to-istanbul: 1.0.6 + magicast: 0.5.5 + obug: 2.2.1 + std-env: 4.2.0 + tinyrainbow: 3.1.1 + vitest: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@24.13.5)(@vitest/coverage-v8@5.0.1)(@vitest/ui@5.0.1)(jsdom@30.1.0(@noble/hashes@2.4.0))(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) + + '@vitest/istanbul-lib-coverage@1.0.1': {} - '@vitest/expect@4.0.13': + '@vitest/istanbul-lib-report@1.0.1': dependencies: - '@standard-schema/spec': 1.0.0 - '@types/chai': 5.2.3 - '@vitest/spy': 4.0.13 - '@vitest/utils': 4.0.13 - chai: 6.2.1 - tinyrainbow: 3.0.3 + '@vitest/istanbul-lib-coverage': 1.0.1 - '@vitest/mocker@4.0.13(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3))(rolldown-vite@7.1.14(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6))': + '@vitest/mocker@5.0.1(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1))': dependencies: - '@vitest/spy': 4.0.13 + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.1 estree-walker: 3.0.3 - magic-string: 0.30.21 + magic-string: 1.4.1 optionalDependencies: - msw: 2.12.4(@types/node@24.10.1)(typescript@5.9.3) - vite: rolldown-vite@7.1.14(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6) - - '@vitest/pretty-format@4.0.13': - dependencies: - tinyrainbow: 3.0.3 + vite: 8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1) - '@vitest/runner@4.0.13': + '@vitest/mocker@5.0.1(vite@8.3.0(@types/node@26.6.1)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1))': dependencies: - '@vitest/utils': 4.0.13 - pathe: 2.0.3 + '@jridgewell/trace-mapping': 0.3.31 + '@vitest/spy': 5.0.1 + estree-walker: 3.0.3 + magic-string: 1.4.1 + optionalDependencies: + vite: 8.3.0(@types/node@26.6.1)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1) - '@vitest/snapshot@4.0.13': + '@vitest/pretty-format@5.0.1': dependencies: - '@vitest/pretty-format': 4.0.13 - magic-string: 0.30.21 - pathe: 2.0.3 + tinyrainbow: 3.1.1 - '@vitest/spy@4.0.13': {} + '@vitest/spy@5.0.1': {} - '@vitest/ui@4.0.13(vitest@4.0.13)': + '@vitest/ui@5.0.1(vitest@5.0.1)': dependencies: - '@vitest/utils': 4.0.13 - fflate: 0.8.2 - flatted: 3.3.3 + '@vitest/utils': 5.0.1 + fflate: 0.8.3 + flatted: 3.4.4 pathe: 2.0.3 sirv: 3.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vitest: 4.0.13(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/ui@4.0.13)(esbuild@0.27.0)(jiti@2.6.1)(jsdom@27.2.0)(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6) + tinyrainbow: 3.1.1 + vitest: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@24.13.5)(@vitest/coverage-v8@5.0.1)(@vitest/ui@5.0.1)(jsdom@30.1.0(@noble/hashes@2.4.0))(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) - '@vitest/utils@4.0.13': + '@vitest/utils@5.0.1': dependencies: - '@vitest/pretty-format': 4.0.13 - tinyrainbow: 3.0.3 + '@vitest/pretty-format': 5.0.1 + convert-source-map: 2.0.0 + tinyrainbow: 3.1.1 + + '@workflow/serde@4.1.0': {} + + abbrev@5.0.0: {} accepts@1.3.8: dependencies: @@ -11486,58 +10887,53 @@ snapshots: accepts@2.0.0: dependencies: mime-types: 3.0.2 - negotiator: 1.0.0 - - acorn-import-attributes@1.9.5(acorn@8.15.0): - dependencies: - acorn: 8.15.0 + negotiator: 1.1.0 - acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2(acorn@8.18.0): dependencies: - acorn: 8.15.0 + acorn: 8.18.0 - acorn-walk@8.3.2: {} - - acorn@8.14.0: {} - - acorn@8.15.0: {} - - agent-base@7.1.4: {} + acorn@8.18.0: {} aggregate-error@3.1.0: dependencies: clean-stack: 2.2.0 indent-string: 4.0.0 - ai@6.0.19(zod@4.1.12): + ai@7.0.106(zod@4.6.5): dependencies: - '@ai-sdk/gateway': 3.0.10(zod@4.1.12) - '@ai-sdk/provider': 3.0.2 - '@ai-sdk/provider-utils': 4.0.4(zod@4.1.12) - '@opentelemetry/api': 1.9.0 - zod: 4.1.12 + '@ai-sdk/gateway': 4.0.86(zod@4.6.5) + '@ai-sdk/provider': 4.0.17 + '@ai-sdk/provider-utils': 5.0.44(zod@4.6.5) + zod: 4.6.5 + + ajv-formats@2.1.1(ajv@8.20.0): + optionalDependencies: + ajv: 8.20.0 - ajv-formats@3.0.1(ajv@8.17.1): + ajv-formats@3.0.1(ajv@8.20.0): optionalDependencies: - ajv: 8.17.1 + ajv: 8.20.0 - ajv@6.12.6: + ajv@6.15.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 - ajv@8.17.1: + ajv@8.20.0: dependencies: fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 + fast-uri: 3.1.8 json-schema-traverse: 1.0.0 require-from-string: 2.0.2 + ansi-colors@4.1.3: {} + ansi-regex@5.0.1: {} - ansi-regex@6.2.2: {} + ansi-regex@6.3.0: {} ansi-styles@4.3.0: dependencies: @@ -11547,14 +10943,11 @@ snapshots: ansi-styles@6.2.3: {} - ansis@4.2.0: {} + ansis@4.4.0: {} any-promise@1.3.0: {} - anymatch@3.1.3: - dependencies: - normalize-path: 3.0.0 - picomatch: 2.3.1 + anynum@1.0.1: {} append-transform@2.0.0: dependencies: @@ -11586,24 +10979,24 @@ snapshots: arraybuffer.prototype.slice@1.0.4: dependencies: array-buffer-byte-length: 1.0.2 - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-errors: 1.3.0 get-intrinsic: 1.3.0 is-array-buffer: 3.0.5 assertion-error@2.0.1: {} - ast-types@0.16.1: + ast-types@0.16.3: dependencies: tslib: 2.8.1 - ast-v8-to-istanbul@0.3.8: + ast-v8-to-istanbul@1.0.6: dependencies: '@jridgewell/trace-mapping': 0.3.31 estree-walker: 3.0.3 - js-tokens: 9.0.1 + js-tokens: 10.0.0 async-function@1.0.0: {} @@ -11611,7 +11004,9 @@ snapshots: at-least-node@1.0.0: {} - atomically@2.1.0: + atomically@1.7.0: {} + + atomically@2.1.1: dependencies: stubborn-fs: 2.0.0 when-exit: 2.1.5 @@ -11620,152 +11015,156 @@ snapshots: dependencies: possible-typed-array-names: 1.1.0 - babel-dead-code-elimination@1.0.10: + babel-dead-code-elimination@1.0.12(supports-color@10.2.2): dependencies: - '@babel/core': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/parser': 7.29.9 + '@babel/traverse': 7.29.8(supports-color@10.2.2) + '@babel/types': 7.29.8 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs2@0.4.14(@babel/core@7.28.5): + babel-plugin-polyfill-corejs2@0.4.17(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - '@babel/compat-data': 7.28.5 - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) + '@babel/compat-data': 7.29.7 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) semver: 6.3.1 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-corejs3@0.13.0(@babel/core@7.28.5): + babel-plugin-polyfill-corejs3@0.14.2(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) - core-js-compat: 3.47.0 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + core-js-compat: 3.50.0 transitivePeerDependencies: - supports-color - babel-plugin-polyfill-regenerator@0.6.5(@babel/core@7.28.5): + babel-plugin-polyfill-regenerator@0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - '@babel/core': 7.28.5 - '@babel/helper-define-polyfill-provider': 0.6.5(@babel/core@7.28.5) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/helper-define-polyfill-provider': 0.6.8(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) transitivePeerDependencies: - supports-color balanced-match@1.0.2: {} - base64-js@1.5.1: {} + balanced-match@4.0.4: {} base64id@2.0.0: {} - baseline-browser-mapping@2.9.2: {} + baseline-browser-mapping@2.11.25: {} bcrypt@6.0.0: dependencies: - node-addon-api: 8.5.0 + node-addon-api: 8.9.2 node-gyp-build: 4.8.4 - better-auth@1.4.1(react-dom@19.2.0(react@19.2.0))(react@19.2.0): - dependencies: - '@better-auth/core': 1.4.1(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.1.0)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.1.0) - '@better-auth/telemetry': 1.4.1(@better-auth/core@1.4.1(@better-auth/utils@0.3.0)(@better-fetch/fetch@1.1.18)(better-call@1.1.0)(jose@6.1.2)(kysely@0.28.8)(nanostores@1.1.0)) - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.18 - '@noble/ciphers': 2.0.1 - '@noble/hashes': 2.0.1 - '@standard-schema/spec': 1.0.0 - better-call: 1.1.0 - defu: 6.1.4 - jose: 6.1.2 - kysely: 0.28.8 - nanostores: 1.1.0 - zod: 4.1.12 - optionalDependencies: - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + better-auth@1.7.5(@opentelemetry/api@1.9.1)(drizzle-kit@0.31.10)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6))(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(vitest@5.0.1): + dependencies: + '@better-auth/core': 1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3) + '@better-auth/drizzle-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6)) + '@better-auth/kysely-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(kysely@0.29.6) + '@better-auth/memory-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2) + '@better-auth/mongo-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2) + '@better-auth/prisma-adapter': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2) + '@better-auth/telemetry': 1.7.5(@better-auth/core@1.7.5(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2)(@opentelemetry/api@1.9.1)(better-call@1.4.0(zod@4.6.5))(jose@6.2.12)(kysely@0.29.6)(nanostores@1.5.3))(@better-auth/utils@0.4.2)(@better-fetch/fetch@1.3.2) + '@better-auth/utils': 0.4.2 + '@better-fetch/fetch': 1.3.2 + '@noble/ciphers': 2.4.0 + '@noble/hashes': 2.4.0 + better-call: 1.4.0(zod@4.6.5) + defu: 6.1.7 + jose: 6.2.12 + kysely: 0.29.6 + nanostores: 1.5.3 + zod: 4.6.5 + optionalDependencies: + drizzle-kit: 0.31.10 + drizzle-orm: 0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + vitest: 5.0.1(@opentelemetry/api@1.9.1)(@types/node@24.13.5)(@vitest/coverage-v8@5.0.1)(@vitest/ui@5.0.1)(jsdom@30.1.0(@noble/hashes@2.4.0))(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) + transitivePeerDependencies: + - '@opentelemetry/api' - better-call@1.1.0: + better-call@1.4.0(zod@4.6.5): dependencies: - '@better-auth/utils': 0.3.0 - '@better-fetch/fetch': 1.1.18 - rou3: 0.5.1 - set-cookie-parser: 2.7.2 + '@better-auth/utils': 0.5.0 + '@better-fetch/fetch': 1.3.2 + rou3: 0.9.2 + set-cookie-parser: 3.1.2 + optionalDependencies: + zod: 4.6.5 - better-sqlite3@12.4.6: + better-sqlite3@13.0.3: dependencies: - bindings: 1.5.0 - prebuild-install: 7.1.3 + node-addon-api: 8.9.2 - bidi-js@1.0.3: + bidi-js@1.1.0: dependencies: require-from-string: 2.0.2 - binary-extensions@2.3.0: {} - - bindings@1.5.0: - dependencies: - file-uri-to-path: 1.0.0 - - bl@4.1.0: - dependencies: - buffer: 5.7.1 - inherits: 2.0.4 - readable-stream: 3.6.2 - blake3-wasm@2.1.5: {} - body-parser@2.2.1: + body-parser@2.3.0(supports-color@10.2.2): dependencies: bytes: 3.1.2 - content-type: 1.0.5 - debug: 4.4.3 + content-type: 2.1.0 + debug: 4.4.3(supports-color@10.2.2) http-errors: 2.0.1 - iconv-lite: 0.7.0 + iconv-lite: 0.7.3 on-finished: 2.4.1 - qs: 6.14.0 + qs: 6.16.0 raw-body: 3.0.2 - type-is: 2.0.1 + type-is: 2.1.0 transitivePeerDependencies: - supports-color - brace-expansion@1.1.12: + brace-expansion@2.1.7: dependencies: balanced-match: 1.0.2 - concat-map: 0.0.1 - brace-expansion@2.0.2: + brace-expansion@5.0.12: dependencies: - balanced-match: 1.0.2 + balanced-match: 4.0.4 braces@3.0.3: dependencies: fill-range: 7.1.1 - browserslist@4.28.1: + browserslist@4.29.0: dependencies: - baseline-browser-mapping: 2.9.2 - caniuse-lite: 1.0.30001759 - electron-to-chromium: 1.5.264 - node-releases: 2.0.27 - update-browserslist-db: 1.2.2(browserslist@4.28.1) + baseline-browser-mapping: 2.11.25 + caniuse-lite: 1.0.30001810 + electron-to-chromium: 1.5.432 + node-releases: 2.0.56 + update-browserslist-db: 1.3.3(browserslist@4.29.0) buffer-from@1.1.2: {} - buffer@5.7.1: + bundle-name@4.1.0: dependencies: - base64-js: 1.5.1 - ieee754: 1.2.1 + run-applescript: 7.1.0 - bundle-require@5.1.0(esbuild@0.27.0): + bundle-require@5.1.0(esbuild@0.28.2): dependencies: - esbuild: 0.27.0 + esbuild: 0.28.2 load-tsconfig: 0.2.5 bytes@3.1.2: {} cac@6.7.14: {} + cacheable@2.5.0: + dependencies: + '@cacheable/memory': 2.2.0 + '@cacheable/utils': 2.5.0 + hookified: 1.15.1 + keyv: 5.6.0 + qified: 0.10.1 + caching-transform@4.0.0: dependencies: hasha: 5.2.2 @@ -11778,7 +11177,7 @@ snapshots: es-errors: 1.3.0 function-bind: 1.1.2 - call-bind@1.0.8: + call-bind@1.0.9: dependencies: call-bind-apply-helpers: 1.0.2 es-define-property: 1.0.1 @@ -11794,42 +11193,25 @@ snapshots: camelcase@5.3.1: {} - caniuse-lite@1.0.30001756: {} + caniuse-lite@1.0.30001810: {} - caniuse-lite@1.0.30001759: {} - - chai@6.2.1: {} - - chalk@4.1.2: - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 + chai@6.2.2: {} chalk@5.6.2: {} - 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 - chownr@1.1.4: {} - - citty@0.1.6: + chokidar@5.0.0: dependencies: - consola: 3.4.2 + readdirp: 5.1.1 + + chownr@3.0.0: {} - cjs-module-lexer@1.4.3: {} + citty@0.2.2: {} + + cjs-module-lexer@2.2.1: {} class-variance-authority@0.7.1: dependencies: @@ -11843,10 +11225,6 @@ snapshots: cli-spinners@2.9.2: {} - cli-width@4.1.0: {} - - client-only@0.0.1: {} - cliui@6.0.0: dependencies: string-width: 4.2.3 @@ -11859,20 +11237,28 @@ snapshots: strip-ansi: 6.0.1 wrap-ansi: 7.0.0 + cliui@9.0.1: + dependencies: + string-width: 7.2.0 + strip-ansi: 7.2.0 + wrap-ansi: 9.0.2 + clsx@2.1.1: {} - cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + cmdk@1.1.1(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-id': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) transitivePeerDependencies: - '@types/react' - '@types/react-dom' + cn@0.2.6: {} + code-block-writer@13.0.3: {} color-convert@2.0.1: @@ -11881,21 +11267,11 @@ snapshots: color-name@1.1.4: {} - color-string@1.9.1: - dependencies: - color-name: 1.1.4 - simple-swizzle: 0.2.4 - - color@4.2.3: - dependencies: - color-convert: 2.0.1 - color-string: 1.9.1 - commander@11.1.0: {} commander@13.1.0: {} - commander@14.0.2: {} + commander@14.0.3: {} commander@2.20.3: {} @@ -11905,74 +11281,81 @@ snapshots: commondir@1.0.1: {} - concat-map@0.0.1: {} - - concurrently@9.2.1: + concurrently@10.0.5: dependencies: - chalk: 4.1.2 + chalk: 5.6.2 rxjs: 7.8.2 - shell-quote: 1.8.3 - supports-color: 8.1.1 + shell-quote: 1.9.0 + supports-color: 10.2.2 tree-kill: 1.2.2 - yargs: 17.7.2 + yargs: 18.0.0 - conf@15.0.2: + conf@10.2.0: dependencies: - ajv: 8.17.1 - ajv-formats: 3.0.1(ajv@8.17.1) - atomically: 2.1.0 + ajv: 8.20.0 + ajv-formats: 2.1.1(ajv@8.20.0) + atomically: 1.7.0 + debounce-fn: 4.0.0 + dot-prop: 6.0.1 + env-paths: 2.2.1 + json-schema-typed: 7.0.3 + onetime: 5.1.2 + pkg-up: 3.1.0 + semver: 7.8.5 + + conf@15.1.0: + dependencies: + ajv: 8.20.0 + ajv-formats: 3.0.1(ajv@8.20.0) + atomically: 2.1.1 debounce-fn: 6.0.0 - dot-prop: 10.1.0 + dot-prop: 10.2.0 env-paths: 3.0.0 json-schema-typed: 8.0.2 - semver: 7.7.3 + semver: 7.8.5 uint8array-extras: 1.5.0 confbox@0.1.8: {} - confbox@0.2.2: {} - consola@3.4.2: {} - content-disposition@1.0.1: {} + content-disposition@1.1.0: {} content-type@1.0.5: {} + content-type@2.1.0: {} + convert-source-map@1.9.0: {} convert-source-map@2.0.0: {} - cookie-es@2.0.0: {} + cookie-es@3.1.1: {} cookie-signature@1.2.2: {} cookie@0.7.2: {} - cookie@1.0.2: {} - cookie@1.1.1: {} - copy-anything@4.0.5: - dependencies: - is-what: 5.5.0 + copy-anything@4.1.0: {} - core-js-compat@3.47.0: + core-js-compat@3.50.0: dependencies: - browserslist: 4.28.1 + browserslist: 4.29.0 - cors@2.8.5: + cors@2.8.6: dependencies: object-assign: 4.1.1 vary: 1.1.2 - cosmiconfig@9.0.0(typescript@5.9.3): + cosmiconfig@9.0.2(typescript@7.0.2): dependencies: env-paths: 2.2.1 import-fresh: 3.3.1 - js-yaml: 4.1.1 + js-yaml: 4.3.2 parse-json: 5.2.0 optionalDependencies: - typescript: 5.9.3 + typescript: 7.0.2 cross-spawn@7.0.6: dependencies: @@ -11982,21 +11365,15 @@ snapshots: crypto-random-string@2.0.0: {} - css-tree@3.1.0: + css-tree@3.2.1: dependencies: - mdn-data: 2.12.2 + mdn-data: 2.27.1 source-map-js: 1.2.1 css.escape@1.5.1: {} cssesc@3.0.0: {} - cssstyle@5.3.3: - dependencies: - '@asamuzakjp/css-color': 4.1.0 - '@csstools/css-syntax-patches-for-csstree': 1.0.17 - css-tree: 3.1.0 - csstype@3.2.3: {} d3-array@3.2.4: @@ -12007,7 +11384,7 @@ snapshots: d3-ease@3.0.1: {} - d3-format@3.1.0: {} + d3-format@3.1.2: {} d3-interpolate@3.0.1: dependencies: @@ -12018,7 +11395,7 @@ snapshots: d3-scale@4.0.2: dependencies: d3-array: 3.2.4 - d3-format: 3.1.0 + d3-format: 3.1.2 d3-interpolate: 3.0.1 d3-time: 3.1.0 d3-time-format: 4.1.0 @@ -12037,12 +11414,12 @@ snapshots: d3-timer@3.0.1: {} - data-uri-to-buffer@4.0.1: {} - - data-urls@6.0.0: + data-urls@7.0.0(@noble/hashes@2.4.0): dependencies: - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 + whatwg-mimetype: 5.0.0 + whatwg-url: 16.0.1(@noble/hashes@2.4.0) + transitivePeerDependencies: + - '@noble/hashes' data-view-buffer@1.0.2: dependencies: @@ -12062,19 +11439,23 @@ snapshots: es-errors: 1.3.0 is-data-view: 1.0.2 + dayjs@1.11.23: {} + + debounce-fn@4.0.0: + dependencies: + mimic-fn: 3.1.0 + debounce-fn@6.0.0: dependencies: mimic-function: 5.0.1 debounce@2.2.0: {} - debug@4.3.7: - dependencies: - ms: 2.1.3 - - debug@4.4.3: + debug@4.4.3(supports-color@10.2.2): dependencies: ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 decamelize@1.2.0: {} @@ -12082,18 +11463,19 @@ snapshots: decimal.js@10.6.0: {} - decompress-response@6.0.0: - dependencies: - mimic-response: 3.1.0 - - dedent@1.7.0: {} - - deep-extend@0.6.0: {} + dedent@1.7.2: {} deep-is@0.1.4: {} deepmerge@4.3.1: {} + default-browser-id@5.0.1: {} + + default-browser@5.5.1: + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.1 + default-require-extensions@3.0.1: dependencies: strip-bom: 4.0.0 @@ -12104,13 +11486,17 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 + define-lazy-prop@2.0.0: {} + + define-lazy-prop@3.0.0: {} + define-properties@1.2.1: dependencies: define-data-property: 1.1.4 has-property-descriptors: 1.0.2 object-keys: 1.1.1 - defu@6.1.4: {} + defu@6.1.7: {} depd@2.0.0: {} @@ -12120,7 +11506,7 @@ snapshots: detect-node-es@1.1.0: {} - diff@8.0.2: {} + diff@8.0.4: {} dom-accessibility-api@0.5.16: {} @@ -12132,46 +11518,65 @@ snapshots: domhandler: 5.0.3 entities: 4.5.0 + dom-serializer@3.1.1: + dependencies: + domelementtype: 3.0.0 + domhandler: 6.0.1 + entities: 8.1.0 + domelementtype@2.3.0: {} + domelementtype@3.0.0: {} + domhandler@5.0.3: dependencies: domelementtype: 2.3.0 + domhandler@6.0.1: + dependencies: + domelementtype: 3.0.0 + domutils@3.2.2: dependencies: dom-serializer: 2.0.0 domelementtype: 2.3.0 domhandler: 5.0.3 - dot-prop@10.1.0: + domutils@4.0.2: + dependencies: + dom-serializer: 3.1.1 + domelementtype: 3.0.0 + domhandler: 6.0.1 + + dot-prop@10.2.0: dependencies: - type-fest: 5.2.0 + type-fest: 5.10.0 - dotenv@17.2.3: {} + dot-prop@6.0.1: + dependencies: + is-obj: 2.0.0 + + dotenv@17.4.2: {} - drizzle-kit@0.31.7: + drizzle-kit@0.31.10: dependencies: '@drizzle-team/brocli': 0.10.2 '@esbuild-kit/esm-loader': 2.6.5 - esbuild: 0.27.0 - esbuild-register: 3.6.0(esbuild@0.27.0) - transitivePeerDependencies: - - supports-color + esbuild: 0.28.2 + tsx: 4.23.13 - drizzle-orm@0.44.7(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.15.5)(better-sqlite3@12.4.6)(kysely@0.28.8): + drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6): optionalDependencies: - '@cloudflare/workers-types': 4.20251121.0 - '@opentelemetry/api': 1.9.0 - '@types/better-sqlite3': 7.6.13 - '@types/pg': 8.15.5 - better-sqlite3: 12.4.6 - kysely: 0.28.8 + '@cloudflare/workers-types': 5.20260918.1 + '@opentelemetry/api': 1.9.1 + '@types/better-sqlite3': 9.6.0 + better-sqlite3: 13.0.3 + kysely: 0.29.6 - drizzle-zod@0.8.3(drizzle-orm@0.44.7(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.15.5)(better-sqlite3@12.4.6)(kysely@0.28.8))(zod@4.1.12): + drizzle-zod@0.8.3(drizzle-orm@0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6))(zod@4.6.5): dependencies: - drizzle-orm: 0.44.7(@cloudflare/workers-types@4.20251121.0)(@opentelemetry/api@1.9.0)(@types/better-sqlite3@7.6.13)(@types/pg@8.15.5)(better-sqlite3@12.4.6)(kysely@0.28.8) - zod: 4.1.12 + drizzle-orm: 0.45.2(@cloudflare/workers-types@5.20260918.1)(@opentelemetry/api@1.9.1)(@types/better-sqlite3@9.6.0)(better-sqlite3@13.0.3)(kysely@0.29.6) + zod: 4.6.5 dunder-proto@1.0.1: dependencies: @@ -12179,63 +11584,53 @@ snapshots: es-errors: 1.3.0 gopd: 1.2.0 - eastasianwidth@0.2.0: {} - - eciesjs@0.4.16: - dependencies: - '@ecies/ciphers': 0.2.5(@noble/ciphers@1.3.0) - '@noble/ciphers': 1.3.0 - '@noble/curves': 1.9.7 - '@noble/hashes': 1.8.0 - ee-first@1.1.1: {} ejs@3.1.10: dependencies: jake: 10.9.4 - electron-to-chromium@1.5.264: {} + electron-to-chromium@1.5.432: {} emoji-regex@10.6.0: {} emoji-regex@8.0.0: {} - emoji-regex@9.2.2: {} - encodeurl@2.0.0: {} - end-of-stream@1.4.5: - dependencies: - once: 1.4.0 - engine.io-parser@5.2.3: {} - engine.io@6.6.4: + engine.io@6.6.10(supports-color@10.2.2): dependencies: '@types/cors': 2.8.19 - '@types/node': 24.10.1 + '@types/node': 26.6.1 + '@types/ws': 8.18.1 accepts: 1.3.8 - base64id: 2.0.0 cookie: 0.7.2 - cors: 2.8.5 - debug: 4.3.7 + cors: 2.8.6 + debug: 4.4.3(supports-color@10.2.2) engine.io-parser: 5.2.3 - ws: 8.17.1 + ws: 8.21.3 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - enhanced-resolve@5.18.3: + enhanced-resolve@5.25.1: dependencies: graceful-fs: 4.2.11 - tapable: 2.3.0 + tapable: 2.3.3 + + enquirer@2.4.1: + dependencies: + ansi-colors: 4.1.3 + strip-ansi: 6.0.1 entities@4.5.0: {} - entities@6.0.1: {} + entities@7.0.1: {} - entities@7.0.0: {} + entities@8.1.0: {} env-paths@2.2.1: {} @@ -12247,22 +11642,29 @@ snapshots: error-stack-parser-es@1.0.5: {} - es-abstract@1.24.0: + es-abstract-get@1.0.0: + dependencies: + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + is-callable: 1.2.7 + object-inspect: 1.13.4 + + es-abstract@1.24.2: dependencies: array-buffer-byte-length: 1.0.2 arraybuffer.prototype.slice: 1.0.4 available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 data-view-buffer: 1.0.2 data-view-byte-length: 1.0.2 data-view-byte-offset: 1.0.1 es-define-property: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 es-set-tostringtag: 2.1.0 - es-to-primitive: 1.3.0 - function.prototype.name: 1.1.8 + es-to-primitive: 1.3.4 + function.prototype.name: 1.2.0 get-intrinsic: 1.3.0 get-proto: 1.0.1 get-symbol-description: 1.1.0 @@ -12271,7 +11673,7 @@ snapshots: has-property-descriptors: 1.0.2 has-proto: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.4 internal-slot: 1.1.0 is-array-buffer: 3.0.5 is-callable: 1.2.7 @@ -12287,30 +11689,32 @@ snapshots: object-inspect: 1.13.4 object-keys: 1.1.1 object.assign: 4.1.7 - own-keys: 1.0.1 + own-keys: 1.0.2 regexp.prototype.flags: 1.5.4 - safe-array-concat: 1.1.3 + safe-array-concat: 1.1.4 safe-push-apply: 1.0.0 safe-regex-test: 1.1.0 set-proto: 1.0.0 stop-iteration-iterator: 1.1.0 - string.prototype.trim: 1.2.10 - string.prototype.trimend: 1.0.9 + string.prototype.trim: 1.2.11 + string.prototype.trimend: 1.0.10 string.prototype.trimstart: 1.0.8 typed-array-buffer: 1.0.3 typed-array-byte-length: 1.0.3 - typed-array-byte-offset: 1.0.4 - typed-array-length: 1.0.7 + typed-array-byte-offset: 1.0.5 + typed-array-length: 1.0.8 unbox-primitive: 1.1.0 - which-typed-array: 1.1.19 + which-typed-array: 1.1.23 es-define-property@1.0.1: {} es-errors@1.3.0: {} - es-module-lexer@1.7.0: {} + es-module-lexer@2.3.2: {} - es-object-atoms@1.1.1: + es-module-lexer@3.0.2: {} + + es-object-atoms@1.1.2: dependencies: es-errors: 1.3.0 @@ -12319,55 +11723,49 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.4 - es-to-primitive@1.3.0: + es-to-primitive@1.3.4: dependencies: + es-abstract-get: 1.0.0 + es-define-property: 1.0.1 + es-errors: 1.3.0 is-callable: 1.2.7 is-date-object: 1.1.0 is-symbol: 1.1.1 - es-toolkit@1.42.0: {} + es-toolkit@1.52.0: {} es6-error@4.1.1: {} - es6-promise@4.2.8: {} - - esbuild-register@3.6.0(esbuild@0.27.0): - dependencies: - debug: 4.4.3 - esbuild: 0.27.0 - transitivePeerDependencies: - - supports-color - - esbuild@0.27.0: - optionalDependencies: - '@esbuild/aix-ppc64': 0.27.0 - '@esbuild/android-arm': 0.27.0 - '@esbuild/android-arm64': 0.27.0 - '@esbuild/android-x64': 0.27.0 - '@esbuild/darwin-arm64': 0.27.0 - '@esbuild/darwin-x64': 0.27.0 - '@esbuild/freebsd-arm64': 0.27.0 - '@esbuild/freebsd-x64': 0.27.0 - '@esbuild/linux-arm': 0.27.0 - '@esbuild/linux-arm64': 0.27.0 - '@esbuild/linux-ia32': 0.27.0 - '@esbuild/linux-loong64': 0.27.0 - '@esbuild/linux-mips64el': 0.27.0 - '@esbuild/linux-ppc64': 0.27.0 - '@esbuild/linux-riscv64': 0.27.0 - '@esbuild/linux-s390x': 0.27.0 - '@esbuild/linux-x64': 0.27.0 - '@esbuild/netbsd-arm64': 0.27.0 - '@esbuild/netbsd-x64': 0.27.0 - '@esbuild/openbsd-arm64': 0.27.0 - '@esbuild/openbsd-x64': 0.27.0 - '@esbuild/openharmony-arm64': 0.27.0 - '@esbuild/sunos-x64': 0.27.0 - '@esbuild/win32-arm64': 0.27.0 - '@esbuild/win32-ia32': 0.27.0 - '@esbuild/win32-x64': 0.27.0 + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 escalade@3.2.0: {} @@ -12375,74 +11773,66 @@ snapshots: escape-string-regexp@4.0.0: {} - eslint-plugin-drizzle@0.2.3(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-drizzle@0.2.3(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2)): dependencies: - eslint: 9.39.1(jiti@2.6.1) + eslint: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) - eslint-plugin-no-relative-import-paths@1.6.1: {} - - eslint-plugin-react-hooks@7.0.1(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-react-hooks@7.1.1(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - '@babel/core': 7.28.5 - '@babel/parser': 7.28.5 - eslint: 9.39.1(jiti@2.6.1) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/parser': 7.29.9 + eslint: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) hermes-parser: 0.25.1 - zod: 4.1.12 - zod-validation-error: 4.0.2(zod@4.1.12) + zod: 4.6.5 + zod-validation-error: 4.0.2(zod@4.6.5) transitivePeerDependencies: - supports-color - eslint-plugin-react-perf@3.3.3(eslint@9.39.1(jiti@2.6.1)): - dependencies: - eslint: 9.39.1(jiti@2.6.1) - - eslint-plugin-react-refresh@0.4.24(eslint@9.39.1(jiti@2.6.1)): + eslint-plugin-react-refresh@0.5.7(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2)): dependencies: - eslint: 9.39.1(jiti@2.6.1) + eslint: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) - eslint-scope@8.4.0: + eslint-scope@9.1.2: dependencies: + '@types/esrecurse': 4.3.1 + '@types/estree': 1.0.9 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.1(jiti@2.6.1): + eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2): dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint-community/eslint-utils': 4.10.1(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2)) '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.39.1 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 + '@eslint/config-array': 0.23.5(supports-color@10.2.2) + '@eslint/config-helpers': 0.7.0 + '@eslint/core': 1.2.1 + '@eslint/plugin-kit': 0.7.3 + '@humanfs/node': 0.16.8 '@humanwhocodes/module-importer': 1.0.1 '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.12.6 - chalk: 4.1.2 + '@types/estree': 1.0.9 + ajv: 6.15.0 cross-spawn: 7.0.6 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 + eslint-scope: 9.1.2 + eslint-visitor-keys: 5.0.1 + espree: 11.2.0 + esquery: 1.7.0 esutils: 2.0.3 fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 + file-entry-cache: 11.1.5 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.2 + minimatch: 10.2.6 natural-compare: 1.4.0 optionator: 0.9.4 optionalDependencies: @@ -12450,15 +11840,15 @@ snapshots: transitivePeerDependencies: - supports-color - espree@10.4.0: + espree@11.2.0: dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 4.2.1 + acorn: 8.18.0 + acorn-jsx: 5.3.2(acorn@8.18.0) + eslint-visitor-keys: 5.0.1 esprima@4.0.1: {} - esquery@1.6.0: + esquery@1.7.0: dependencies: estraverse: 5.3.0 @@ -12468,25 +11858,25 @@ snapshots: estraverse@5.3.0: {} - estree-walker@1.0.1: {} - estree-walker@2.0.2: {} estree-walker@3.0.3: dependencies: - '@types/estree': 1.0.8 + '@types/estree': 1.0.9 esutils@2.0.3: {} + eta@4.6.0: {} + etag@1.8.1: {} - eventemitter3@5.0.1: {} + eventemitter3@5.0.4: {} - eventsource-parser@3.0.6: {} + eventsource-parser@3.1.1: {} eventsource@3.0.7: dependencies: - eventsource-parser: 3.0.6 + eventsource-parser: 3.1.1 execa@5.1.1: dependencies: @@ -12510,35 +11900,37 @@ snapshots: is-plain-obj: 4.1.0 is-stream: 4.0.1 npm-run-path: 6.0.0 - pretty-ms: 9.3.0 + pretty-ms: 9.3.1 signal-exit: 4.1.0 strip-final-newline: 4.0.0 - yoctocolors: 2.1.2 - - exit-hook@2.2.1: {} + yoctocolors: 2.2.0 - expand-template@2.0.3: {} + expect-type@1.4.0: {} - expect-type@1.2.2: {} + exponential-backoff@3.1.3: {} - express-rate-limit@7.5.1(express@5.2.1): + express-rate-limit@8.7.0(express@5.2.1(supports-color@10.2.2))(supports-color@10.2.2): dependencies: - express: 5.2.1 + debug: 4.4.3(supports-color@10.2.2) + express: 5.2.1(supports-color@10.2.2) + ip-address: 10.7.2 + transitivePeerDependencies: + - supports-color - express@5.2.1: + express@5.2.1(supports-color@10.2.2): dependencies: accepts: 2.0.0 - body-parser: 2.2.1 - content-disposition: 1.0.1 + body-parser: 2.3.0(supports-color@10.2.2) + content-disposition: 1.1.0 content-type: 1.0.5 cookie: 0.7.2 cookie-signature: 1.2.2 - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) depd: 2.0.0 encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 - finalhandler: 2.1.1 + finalhandler: 2.1.1(supports-color@10.2.2) fresh: 2.0.0 http-errors: 2.0.1 merge-descriptors: 2.0.0 @@ -12546,20 +11938,18 @@ snapshots: on-finished: 2.4.1 once: 1.4.0 parseurl: 1.3.3 - proxy-addr: 2.0.7 - qs: 6.14.0 - range-parser: 1.2.1 - router: 2.2.0 - send: 1.2.0 - serve-static: 2.2.0 + proxy-addr: 2.0.8 + qs: 6.16.0 + range-parser: 1.3.0 + router: 2.2.0(supports-color@10.2.2) + send: 1.2.1(supports-color@10.2.2) + serve-static: 2.2.1(supports-color@10.2.2) statuses: 2.0.2 - type-is: 2.0.1 + type-is: 2.1.0 vary: 1.1.2 transitivePeerDependencies: - supports-color - exsolve@1.0.8: {} - fast-deep-equal@3.1.3: {} fast-glob@3.3.3: @@ -12576,13 +11966,23 @@ snapshots: fast-sha256@1.3.0: {} - fast-uri@3.1.0: {} + fast-uri@3.1.8: {} + + fast-xml-builder@1.3.1: + dependencies: + path-expression-matcher: 1.6.2 + xml-naming: 0.3.0 - fast-xml-parser@5.3.2: + fast-xml-parser@5.11.1: dependencies: - strnum: 2.1.1 + '@nodable/entities': 3.0.0 + fast-xml-builder: 1.3.1 + is-unsafe: 2.0.2 + path-expression-matcher: 1.6.2 + strnum: 2.4.2 + xml-naming: 0.3.0 - fastq@1.19.1: + fastq@1.20.3: dependencies: reusify: 1.1.0 @@ -12590,43 +11990,36 @@ snapshots: dependencies: walk-up-path: 4.0.0 - fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0(picomatch@4.0.7): optionalDependencies: - picomatch: 4.0.3 + picomatch: 4.0.7 - feedsmith@2.6.0: + feedsmith@3.0.0: dependencies: - entities: 7.0.0 - fast-xml-parser: 5.3.2 + entities: 7.0.1 + fast-xml-parser: 5.11.1 - fetch-blob@3.2.0: - dependencies: - node-domexception: 1.0.0 - web-streams-polyfill: 3.3.3 - - fflate@0.8.2: {} + fflate@0.8.3: {} figures@6.1.0: dependencies: is-unicode-supported: 2.1.0 - file-entry-cache@8.0.0: + file-entry-cache@11.1.5: dependencies: - flat-cache: 4.0.1 + flat-cache: 6.1.23 - file-uri-to-path@1.0.0: {} - - filelist@1.0.4: + filelist@1.0.6: dependencies: - minimatch: 5.1.6 + minimatch: 5.1.9 fill-range@7.1.1: dependencies: to-regex-range: 5.0.1 - finalhandler@2.1.1: + finalhandler@2.1.1(supports-color@10.2.2): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) encodeurl: 2.0.0 escape-html: 1.0.3 on-finished: 2.4.1 @@ -12641,6 +12034,10 @@ snapshots: make-dir: 3.1.0 pkg-dir: 4.2.0 + find-up@3.0.0: + dependencies: + locate-path: 3.0.0 + find-up@4.1.0: dependencies: locate-path: 5.0.0 @@ -12654,15 +12051,16 @@ snapshots: fix-dts-default-cjs-exports@1.0.1: dependencies: magic-string: 0.30.21 - mlly: 1.8.0 - rollup: 4.53.3 + mlly: 1.8.2 + rollup: 4.63.3 - flat-cache@4.0.1: + flat-cache@6.1.23: dependencies: - flatted: 3.3.3 - keyv: 4.5.4 + cacheable: 2.5.0 + flatted: 3.4.4 + hookified: 1.15.1 - flatted@3.3.3: {} + flatted@3.4.4: {} for-each@0.3.5: dependencies: @@ -12678,87 +12076,79 @@ snapshots: cross-spawn: 7.0.6 signal-exit: 4.1.0 - formatly@0.3.0: + formatly@0.7.0: dependencies: fd-package-json: 2.0.0 - - formdata-polyfill@4.0.10: - dependencies: - fetch-blob: 3.2.0 - - forwarded-parse@2.1.2: {} + package-manager-detector: 1.8.0 forwarded@0.2.0: {} - framer-motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + framer-motion@13.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: - motion-dom: 12.23.23 - motion-utils: 12.23.6 + motion-dom: 13.3.0 + motion-utils: 13.3.0 tslib: 2.8.1 optionalDependencies: - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) fresh@2.0.0: {} fromentries@1.3.2: {} - fs-constants@1.0.0: {} - - fs-extra@11.3.2: + fs-extra@11.4.0: dependencies: graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.2.1 universalify: 2.0.1 fs-extra@9.1.0: dependencies: at-least-node: 1.0.0 graceful-fs: 4.2.11 - jsonfile: 6.2.0 + jsonfile: 6.2.1 universalify: 2.0.1 - fs.realpath@1.0.0: {} - fsevents@2.3.3: optional: true function-bind@1.1.2: {} - function.prototype.name@1.1.8: + function.prototype.name@1.2.0: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 - define-properties: 1.2.1 + es-define-property: 1.0.1 + es-errors: 1.3.0 functions-have-names: 1.2.3 - hasown: 2.0.2 + has-property-descriptors: 1.0.2 + hasown: 2.0.4 is-callable: 1.2.7 + is-document.all: 1.0.0 functions-have-names@1.2.3: {} fuzzysort@3.1.0: {} - fzf@0.5.2: {} - generator-function@2.0.1: {} gensync@1.0.0-beta.2: {} get-caller-file@2.0.5: {} - get-east-asian-width@1.4.0: {} + get-east-asian-width@1.7.0: {} 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 + es-object-atoms: 1.1.2 function-bind: 1.1.2 get-proto: 1.0.1 gopd: 1.2.0 has-symbols: 1.1.0 - hasown: 2.0.2 + hasown: 2.0.4 math-intrinsics: 1.1.0 get-nonce@1.0.1: {} @@ -12772,7 +12162,7 @@ snapshots: get-proto@1.0.1: dependencies: dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-stream@6.0.1: {} @@ -12787,12 +12177,10 @@ snapshots: es-errors: 1.3.0 get-intrinsic: 1.3.0 - get-tsconfig@4.13.0: + get-tsconfig@4.14.3: dependencies: resolve-pkg-maps: 1.0.0 - github-from-package@0.0.0: {} - glob-parent@5.1.2: dependencies: is-glob: 4.0.3 @@ -12801,29 +12189,22 @@ snapshots: dependencies: is-glob: 4.0.3 - glob-to-regexp@0.4.1: {} - glob@11.1.0: dependencies: foreground-child: 3.3.1 - jackspeak: 4.1.1 - minimatch: 10.1.1 - minipass: 7.1.2 + jackspeak: 4.2.3 + minimatch: 10.2.6 + minipass: 7.1.3 package-json-from-dist: 1.0.1 - path-scurry: 2.0.1 + path-scurry: 2.0.2 - glob@7.2.3: + glob@13.0.6: dependencies: - fs.realpath: 1.0.0 - inflight: 1.0.6 - inherits: 2.0.4 - minimatch: 3.1.2 - once: 1.4.0 - path-is-absolute: 1.0.1 + minimatch: 10.2.6 + minipass: 7.1.3 + path-scurry: 2.0.2 - globals@14.0.0: {} - - globals@16.5.0: {} + globals@17.12.0: {} globalthis@1.0.4: dependencies: @@ -12834,10 +12215,6 @@ snapshots: graceful-fs@4.2.11: {} - graphemer@1.4.0: {} - - graphql@16.12.0: {} - has-bigints@1.1.0: {} has-flag@4.0.0: {} @@ -12861,11 +12238,13 @@ snapshots: is-stream: 2.0.1 type-fest: 0.8.1 - hasown@2.0.2: + hashery@1.5.1: dependencies: - function-bind: 1.1.2 + hookified: 1.15.1 - headers-polyfill@4.0.3: {} + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 hermes-estree@0.25.1: {} @@ -12873,15 +12252,17 @@ snapshots: dependencies: hermes-estree: 0.25.1 - hoist-non-react-statics@3.3.2: - dependencies: - react-is: 16.13.1 + hono@4.13.8: {} + + hookified@1.15.1: {} - hono@4.10.6: {} + hookified@2.2.0: {} - html-encoding-sniffer@4.0.0: + html-encoding-sniffer@6.0.0(@noble/hashes@2.4.0): dependencies: - whatwg-encoding: 3.1.1 + '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) + transitivePeerDependencies: + - '@noble/hashes' html-escaper@2.0.2: {} @@ -12893,6 +12274,22 @@ snapshots: htmlparser2: 8.0.2 selderee: 0.11.0 + html5parser@3.0.0: {} + + htmlparser2@10.1.0: + dependencies: + domelementtype: 2.3.0 + domhandler: 5.0.3 + domutils: 3.2.2 + entities: 7.0.1 + + htmlparser2@12.0.0: + dependencies: + domelementtype: 3.0.0 + domhandler: 6.0.1 + domutils: 4.0.2 + entities: 8.1.0 + htmlparser2@8.0.2: dependencies: domelementtype: 2.3.0 @@ -12908,87 +12305,61 @@ snapshots: statuses: 2.0.2 toidentifier: 1.0.1 - http-proxy-agent@7.0.2: - dependencies: - agent-base: 7.1.4 - 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 - human-signals@2.1.0: {} human-signals@8.0.1: {} - iconv-lite@0.6.3: - dependencies: - safer-buffer: 2.1.2 - - iconv-lite@0.7.0: + iconv-lite@0.7.3: dependencies: safer-buffer: 2.1.2 idb@7.1.1: {} - ieee754@1.2.1: {} - ignore@5.3.2: {} - ignore@7.0.5: {} + ignore@7.0.9: {} - immer@10.2.0: {} + immer@11.1.18: {} import-fresh@3.3.1: dependencies: parent-module: 1.0.1 resolve-from: 4.0.0 - import-in-the-middle@1.15.0: + import-in-the-middle@3.5.1: dependencies: - acorn: 8.15.0 - acorn-import-attributes: 1.9.5(acorn@8.15.0) - cjs-module-lexer: 1.4.3 + cjs-module-lexer: 2.2.1 + es-module-lexer: 3.0.2 module-details-from-path: 1.0.4 imurmurhash@0.1.4: {} indent-string@4.0.0: {} - inflight@1.0.6: - dependencies: - once: 1.4.0 - wrappy: 1.0.2 - inherits@2.0.4: {} - ini@1.3.8: {} - internal-slot@1.1.0: dependencies: es-errors: 1.3.0 - hasown: 2.0.2 - side-channel: 1.1.0 + hasown: 2.0.4 + side-channel: 1.1.1 internmap@2.0.3: {} + ip-address@10.7.2: {} + ipaddr.js@1.9.1: {} + ipaddr.js@2.5.0: {} + is-array-buffer@3.0.5: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 is-arrayish@0.2.1: {} - is-arrayish@0.3.4: {} - is-async-function@2.1.1: dependencies: async-function: 1.0.0 @@ -13001,10 +12372,6 @@ snapshots: 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 @@ -13012,9 +12379,9 @@ snapshots: is-callable@1.2.7: {} - is-core-module@2.16.1: + is-core-module@2.17.0: dependencies: - hasown: 2.0.2 + hasown: 2.0.4 is-data-view@1.0.2: dependencies: @@ -13027,6 +12394,14 @@ snapshots: call-bound: 1.0.4 has-tostringtag: 1.0.2 + is-docker@2.2.1: {} + + is-docker@3.0.0: {} + + is-document.all@1.0.0: + dependencies: + call-bound: 1.0.4 + is-extglob@2.1.1: {} is-finalizationregistry@1.1.1: @@ -13047,6 +12422,12 @@ snapshots: dependencies: is-extglob: 2.1.1 + is-in-ssh@1.0.0: {} + + is-inside-container@1.0.0: + dependencies: + is-docker: 3.0.0 + is-interactive@2.0.0: {} is-map@2.0.3: {} @@ -13055,8 +12436,6 @@ snapshots: is-negative-zero@2.0.3: {} - is-node-process@1.2.0: {} - is-number-object@1.1.1: dependencies: call-bound: 1.0.4 @@ -13066,11 +12445,13 @@ snapshots: is-obj@1.0.1: {} + is-obj@2.0.0: {} + is-obj@3.0.0: {} is-plain-obj@4.1.0: {} - is-plain-object@5.0.0: {} + is-plain-object@5.1.0: {} is-potential-custom-element-name@1.0.1: {} @@ -13081,7 +12462,7 @@ snapshots: call-bound: 1.0.4 gopd: 1.2.0 has-tostringtag: 1.0.2 - hasown: 2.0.2 + hasown: 2.0.4 is-regexp@1.0.0: {} @@ -13110,7 +12491,7 @@ snapshots: is-typed-array@1.1.15: dependencies: - which-typed-array: 1.1.19 + which-typed-array: 1.1.23 is-typedarray@1.0.0: {} @@ -13118,6 +12499,8 @@ snapshots: is-unicode-supported@2.1.0: {} + is-unsafe@2.0.2: {} + is-weakmap@2.0.2: {} is-weakref@1.1.1: @@ -13129,17 +12512,25 @@ snapshots: call-bound: 1.0.4 get-intrinsic: 1.3.0 - is-what@5.5.0: {} - is-windows@1.0.2: {} + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + is-wsl@3.1.1: + dependencies: + is-inside-container: 1.0.0 + isarray@2.0.5: {} - isbot@5.1.32: {} + isbot@5.2.2: {} isexe@2.0.0: {} - isexe@3.1.1: {} + isexe@3.1.5: {} + + isexe@4.0.0: {} istanbul-lib-coverage@3.2.2: {} @@ -13147,24 +12538,23 @@ snapshots: dependencies: append-transform: 2.0.0 - istanbul-lib-instrument@6.0.3: + istanbul-lib-instrument@6.0.3(supports-color@10.2.2): dependencies: - '@babel/core': 7.28.5 - '@babel/parser': 7.28.5 - '@istanbuljs/schema': 0.1.3 + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/parser': 7.29.9 + '@istanbuljs/schema': 0.1.6 istanbul-lib-coverage: 3.2.2 - semver: 7.7.3 + semver: 7.8.5 transitivePeerDependencies: - supports-color - istanbul-lib-processinfo@2.0.3: + istanbul-lib-processinfo@3.0.1: dependencies: archy: 1.0.0 cross-spawn: 7.0.6 istanbul-lib-coverage: 3.2.2 p-map: 3.0.0 - rimraf: 3.0.2 - uuid: 8.3.2 + rimraf: 6.1.3 istanbul-lib-report@3.0.1: dependencies: @@ -13172,97 +12562,85 @@ snapshots: make-dir: 4.0.0 supports-color: 7.2.0 - istanbul-lib-source-maps@4.0.1: + istanbul-lib-source-maps@4.0.1(supports-color@10.2.2): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) istanbul-lib-coverage: 3.2.2 source-map: 0.6.1 transitivePeerDependencies: - supports-color - istanbul-lib-source-maps@5.0.6: - dependencies: - '@jridgewell/trace-mapping': 0.3.31 - debug: 4.4.3 - istanbul-lib-coverage: 3.2.2 - transitivePeerDependencies: - - supports-color - istanbul-reports@3.2.0: dependencies: html-escaper: 2.0.2 istanbul-lib-report: 3.0.1 - jackspeak@4.1.1: + jackspeak@4.2.3: dependencies: - '@isaacs/cliui': 8.0.2 + '@isaacs/cliui': 9.0.0 jake@10.9.4: dependencies: async: 3.2.6 - filelist: 1.0.4 + filelist: 1.0.6 picocolors: 1.1.1 - jiti@2.4.2: {} - jiti@2.6.1: {} - jose@6.1.2: {} + jiti@2.7.0: {} - jose@6.1.3: {} + jose@6.2.12: {} joycon@3.1.1: {} - js-tokens@4.0.0: {} + js-tokens@10.0.0: {} - js-tokens@9.0.1: {} + js-tokens@4.0.0: {} - js-yaml@3.14.2: + js-yaml@3.15.2: dependencies: argparse: 1.0.10 esprima: 4.0.1 - js-yaml@4.1.1: + js-yaml@4.3.2: dependencies: argparse: 2.0.1 - jsdom@27.2.0: + jsdom@30.1.0(@noble/hashes@2.4.0): dependencies: - '@acemir/cssom': 0.9.24 - '@asamuzakjp/dom-selector': 6.7.4 - cssstyle: 5.3.3 - data-urls: 6.0.0 + '@asamuzakjp/css-color': 7.0.0 + '@asamuzakjp/dom-selector': 9.2.0 + '@bramus/specificity': 2.4.2 + '@csstools/css-syntax-patches-for-csstree': 1.1.14(css-tree@3.2.1) + '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) + css-tree: 3.2.1 + data-urls: 7.0.0(@noble/hashes@2.4.0) decimal.js: 10.6.0 - html-encoding-sniffer: 4.0.0 - http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.6 + html-encoding-sniffer: 6.0.0(@noble/hashes@2.4.0) is-potential-custom-element-name: 1.0.1 - parse5: 8.0.0 + lru-cache: 11.5.2 + parse5: 8.0.1 saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 6.0.0 + tough-cookie: 6.0.2 + undici: 8.10.2 w3c-xmlserializer: 5.0.0 - webidl-conversions: 8.0.0 - whatwg-encoding: 3.1.1 - whatwg-mimetype: 4.0.0 - whatwg-url: 15.1.0 - ws: 8.18.3 + webidl-conversions: 8.0.1 + whatwg-mimetype: 5.0.0 + whatwg-url: 17.1.1(@noble/hashes@2.4.0) xml-name-validator: 5.0.0 transitivePeerDependencies: - - bufferutil - - supports-color - - utf-8-validate + - '@noble/hashes' jsesc@3.1.0: {} - json-buffer@3.0.1: {} - json-parse-even-better-errors@2.3.1: {} json-schema-traverse@0.4.1: {} json-schema-traverse@1.0.0: {} + json-schema-typed@7.0.3: {} + json-schema-typed@8.0.2: {} json-schema@0.4.0: {} @@ -13271,7 +12649,7 @@ snapshots: json5@2.2.3: {} - jsonfile@6.2.0: + jsonfile@6.2.1: dependencies: universalify: 2.0.1 optionalDependencies: @@ -13279,90 +12657,142 @@ snapshots: jsonpointer@5.0.1: {} - keyv@4.5.4: + keyv@5.6.0: dependencies: - json-buffer: 3.0.1 + '@keyv/serialize': 1.1.1 kleur@3.0.3: {} kleur@4.1.5: {} - knip@5.70.1(@types/node@24.10.1)(typescript@5.9.3): + knip@6.37.0: dependencies: - '@nodelib/fs.walk': 1.2.8 - '@types/node': 24.10.1 - fast-glob: 3.3.3 - formatly: 0.3.0 - jiti: 2.6.1 - js-yaml: 4.1.1 - minimist: 1.2.8 - oxc-resolver: 11.13.2 - picocolors: 1.1.1 - picomatch: 4.0.3 - smol-toml: 1.5.2 + fdir: 6.5.0(picomatch@4.0.7) + formatly: 0.7.0 + get-tsconfig: 4.14.3 + jiti: 2.7.0 + oxc-parser: 0.150.0 + oxc-resolver: 11.24.2 + picomatch: 4.0.7 + smol-toml: 1.8.0 strip-json-comments: 5.0.3 - typescript: 5.9.3 - zod: 4.1.12 + tinyglobby: 0.2.17 + unbash: 4.0.11 + yaml: 2.9.1 + zod: 4.6.5 + + kysely@0.29.6: {} + + launder@1.7.1: + dependencies: + dayjs: 1.11.23 + + leac@0.6.0: {} + + leven@3.1.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-android-arm64@1.33.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.33.0: + optional: true - kysely@0.28.8: {} + lightningcss-darwin-x64@1.32.0: + optional: true - leac@0.6.0: {} + lightningcss-darwin-x64@1.33.0: + optional: true - leven@3.1.0: {} + lightningcss-freebsd-x64@1.32.0: + optional: true - levn@0.4.1: - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 + lightningcss-freebsd-x64@1.33.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.33.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true - lightningcss-android-arm64@1.30.2: + lightningcss-linux-arm64-gnu@1.33.0: optional: true - lightningcss-darwin-arm64@1.30.2: + lightningcss-linux-arm64-musl@1.32.0: optional: true - lightningcss-darwin-x64@1.30.2: + lightningcss-linux-arm64-musl@1.33.0: optional: true - lightningcss-freebsd-x64@1.30.2: + lightningcss-linux-x64-gnu@1.32.0: optional: true - lightningcss-linux-arm-gnueabihf@1.30.2: + lightningcss-linux-x64-gnu@1.33.0: optional: true - lightningcss-linux-arm64-gnu@1.30.2: + lightningcss-linux-x64-musl@1.32.0: optional: true - lightningcss-linux-arm64-musl@1.30.2: + lightningcss-linux-x64-musl@1.33.0: optional: true - lightningcss-linux-x64-gnu@1.30.2: + lightningcss-win32-arm64-msvc@1.32.0: optional: true - lightningcss-linux-x64-musl@1.30.2: + lightningcss-win32-arm64-msvc@1.33.0: optional: true - lightningcss-win32-arm64-msvc@1.30.2: + lightningcss-win32-x64-msvc@1.32.0: optional: true - lightningcss-win32-x64-msvc@1.30.2: + lightningcss-win32-x64-msvc@1.33.0: optional: true - lightningcss@1.30.2: + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lightningcss@1.33.0: dependencies: detect-libc: 2.1.2 optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 + lightningcss-android-arm64: 1.33.0 + lightningcss-darwin-arm64: 1.33.0 + lightningcss-darwin-x64: 1.33.0 + lightningcss-freebsd-x64: 1.33.0 + lightningcss-linux-arm-gnueabihf: 1.33.0 + lightningcss-linux-arm64-gnu: 1.33.0 + lightningcss-linux-arm64-musl: 1.33.0 + lightningcss-linux-x64-gnu: 1.33.0 + lightningcss-linux-x64-musl: 1.33.0 + lightningcss-win32-arm64-msvc: 1.33.0 + lightningcss-win32-x64-msvc: 1.33.0 lilconfig@3.1.3: {} @@ -13370,6 +12800,11 @@ snapshots: load-tsconfig@0.2.5: {} + locate-path@3.0.0: + dependencies: + p-locate: 3.0.0 + path-exists: 3.0.0 + locate-path@5.0.0: dependencies: p-locate: 4.1.0 @@ -13382,12 +12817,6 @@ snapshots: lodash.flattendeep@4.4.0: {} - lodash.merge@4.6.2: {} - - lodash.sortby@4.7.0: {} - - lodash@4.17.21: {} - log-symbols@6.0.0: dependencies: chalk: 5.6.2 @@ -13396,32 +12825,32 @@ snapshots: log-symbols@7.0.1: dependencies: is-unicode-supported: 2.1.0 - yoctocolors: 2.1.2 + yoctocolors: 2.2.0 - lru-cache@11.2.2: {} + lru-cache@11.5.2: {} lru-cache@5.1.1: dependencies: yallist: 3.1.1 - lucide-react@0.554.0(react@19.2.0): + lucide-react@1.47.0(react@19.3.0): dependencies: - react: 19.2.0 + react: 19.3.0 lz-string@1.5.0: {} - magic-string@0.25.9: + magic-string@0.30.21: dependencies: - sourcemap-codec: 1.4.8 + '@jridgewell/sourcemap-codec': 1.6.0 - magic-string@0.30.21: + magic-string@1.4.1: dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/sourcemap-codec': 1.6.0 - magicast@0.5.1: + magicast@0.5.5: dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 + '@babel/parser': 7.29.9 + '@babel/types': 7.29.8 source-map-js: 1.2.1 make-dir@3.1.0: @@ -13430,15 +12859,15 @@ snapshots: make-dir@4.0.0: dependencies: - semver: 7.7.3 + semver: 7.8.5 marked@15.0.12: {} math-intrinsics@1.1.0: {} - mdn-data@2.12.2: {} + mdn-data@2.27.1: {} - media-typer@1.1.0: {} + media-typer@1.1.1: {} merge-descriptors@2.0.0: {} @@ -13449,7 +12878,7 @@ snapshots: micromatch@4.0.8: dependencies: braces: 3.0.3 - picomatch: 2.3.1 + picomatch: 2.3.2 mime-db@1.52.0: {} @@ -13463,175 +12892,116 @@ snapshots: dependencies: mime-db: 1.54.0 - mime@3.0.0: {} - mimic-fn@2.1.0: {} - mimic-function@5.0.1: {} + mimic-fn@3.1.0: {} - mimic-response@3.1.0: {} + mimic-function@5.0.1: {} min-indent@1.0.1: {} - miniflare@4.20251118.1: + miniflare@5.20260918.0-alpha(@types/node@24.13.5): dependencies: '@cspotcode/source-map-support': 0.8.1 - acorn: 8.14.0 - acorn-walk: 8.3.2 - exit-hook: 2.2.1 - glob-to-regexp: 0.4.1 - sharp: 0.33.5 - stoppable: 1.1.0 - undici: 7.14.0 - workerd: 1.20251118.0 - ws: 8.18.0 + sharp: 0.35.4(@types/node@24.13.5) + undici: 7.29.0 + workerd: 1.20260918.1 + ws: 8.21.0 youch: 4.1.0-beta.10 - zod: 3.22.3 transitivePeerDependencies: + - '@types/node' - bufferutil - utf-8-validate - minimatch@10.1.1: + minimatch@10.2.6: dependencies: - '@isaacs/brace-expansion': 5.0.0 + brace-expansion: 5.0.12 - minimatch@3.1.2: + minimatch@5.1.9: dependencies: - brace-expansion: 1.1.12 - - minimatch@5.1.6: - dependencies: - brace-expansion: 2.0.2 - - minimatch@9.0.5: - dependencies: - brace-expansion: 2.0.2 + brace-expansion: 2.1.7 minimist@1.2.8: {} - minipass@7.1.2: {} + minipass@7.1.3: {} - mkdirp-classic@0.5.3: {} + minizlib@3.1.0: + dependencies: + minipass: 7.1.3 - mlly@1.8.0: + mlly@1.8.2: dependencies: - acorn: 8.15.0 + acorn: 8.18.0 pathe: 2.0.3 pkg-types: 1.3.1 - ufo: 1.6.1 + ufo: 1.6.4 module-details-from-path@1.0.4: {} - motion-dom@12.23.23: + motion-dom@13.3.0: dependencies: - motion-utils: 12.23.6 + motion-utils: 13.3.0 - motion-utils@12.23.6: {} + motion-utils@13.3.0: {} - motion@12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + motion@13.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: - framer-motion: 12.23.24(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + framer-motion: 13.4.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) tslib: 2.8.1 optionalDependencies: - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) mrmime@2.0.1: {} ms@2.1.3: {} - msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3): - dependencies: - '@inquirer/confirm': 5.1.21(@types/node@24.10.1) - '@mswjs/interceptors': 0.40.0 - '@open-draft/deferred-promise': 2.2.0 - '@types/statuses': 2.0.6 - cookie: 1.1.1 - graphql: 16.12.0 - headers-polyfill: 4.0.3 - is-node-process: 1.2.0 - outvariant: 1.4.3 - path-to-regexp: 6.3.0 - picocolors: 1.1.1 - rettime: 0.7.0 - statuses: 2.0.2 - strict-event-emitter: 0.5.1 - tough-cookie: 6.0.0 - type-fest: 5.3.0 - until-async: 3.0.2 - yargs: 17.7.2 - optionalDependencies: - typescript: 5.9.3 - transitivePeerDependencies: - - '@types/node' - - mute-stream@2.0.0: {} - mz@2.7.0: dependencies: any-promise: 1.3.0 object-assign: 4.1.1 thenify-all: 1.6.0 - nanoid@3.3.11: {} - - nanostores@1.1.0: {} + nanoid@3.3.19: {} - napi-build-utils@2.0.0: {} + nanostores@1.5.3: {} natural-compare@1.4.0: {} negotiator@0.6.3: {} - negotiator@1.0.0: {} - - next@16.0.1(@babel/core@7.28.5)(@opentelemetry/api@1.9.0)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): - dependencies: - '@next/env': 16.0.1 - '@swc/helpers': 0.5.15 - caniuse-lite: 1.0.30001756 - postcss: 8.4.31 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - styled-jsx: 5.1.6(@babel/core@7.28.5)(react@19.2.0) - optionalDependencies: - '@next/swc-darwin-arm64': 16.0.1 - '@next/swc-darwin-x64': 16.0.1 - '@next/swc-linux-arm64-gnu': 16.0.1 - '@next/swc-linux-arm64-musl': 16.0.1 - '@next/swc-linux-x64-gnu': 16.0.1 - '@next/swc-linux-x64-musl': 16.0.1 - '@next/swc-win32-arm64-msvc': 16.0.1 - '@next/swc-win32-x64-msvc': 16.0.1 - '@opentelemetry/api': 1.9.0 - sharp: 0.34.5 - transitivePeerDependencies: - - '@babel/core' - - babel-plugin-macros - - node-abi@3.85.0: + negotiator@1.1.0: dependencies: - semver: 7.7.3 + content-type: 2.1.0 - node-addon-api@8.5.0: {} + node-addon-api@8.9.2: {} - node-cron@4.2.1: {} + node-cron@4.6.0: {} - node-domexception@1.0.0: {} + node-gyp-build@4.8.4: {} - node-fetch@3.3.2: + node-gyp@13.0.2: dependencies: - data-uri-to-buffer: 4.0.1 - fetch-blob: 3.2.0 - formdata-polyfill: 4.0.10 - - node-gyp-build@4.8.4: {} + env-paths: 2.2.1 + exponential-backoff: 3.1.3 + graceful-fs: 4.2.11 + nopt: 10.0.1 + proc-log: 7.0.0 + semver: 7.8.5 + tar: 7.5.22 + tinyglobby: 0.2.17 + undici: 8.10.2 + which: 7.0.0 node-preload@0.2.1: dependencies: process-on-spawn: 1.1.0 - node-releases@2.0.27: {} + node-releases@2.0.56: {} + + nopt@10.0.1: + dependencies: + abbrev: 5.0.0 normalize-path@3.0.0: {} @@ -13644,10 +13014,10 @@ snapshots: path-key: 4.0.0 unicorn-magic: 0.3.0 - nyc@17.1.0: + nyc@18.0.0(supports-color@10.2.2): dependencies: '@istanbuljs/load-nyc-config': 1.1.0 - '@istanbuljs/schema': 0.1.3 + '@istanbuljs/schema': 0.1.6 caching-transform: 4.0.0 convert-source-map: 1.9.0 decamelize: 1.2.0 @@ -13655,34 +13025,32 @@ snapshots: find-up: 4.1.0 foreground-child: 3.3.1 get-package-type: 0.1.0 - glob: 7.2.3 + glob: 13.0.6 istanbul-lib-coverage: 3.2.2 istanbul-lib-hook: 3.0.0 - istanbul-lib-instrument: 6.0.3 - istanbul-lib-processinfo: 2.0.3 + istanbul-lib-instrument: 6.0.3(supports-color@10.2.2) + istanbul-lib-processinfo: 3.0.1 istanbul-lib-report: 3.0.1 - istanbul-lib-source-maps: 4.0.1 + istanbul-lib-source-maps: 4.0.1(supports-color@10.2.2) istanbul-reports: 3.2.0 make-dir: 3.1.0 node-preload: 0.2.1 p-map: 3.0.0 process-on-spawn: 1.1.0 resolve-from: 5.0.0 - rimraf: 3.0.2 + rimraf: 6.1.3 signal-exit: 3.0.7 - spawn-wrap: 2.0.0 - test-exclude: 6.0.0 + spawn-wrap: 3.0.0 + test-exclude: 8.0.0 yargs: 15.4.1 transitivePeerDependencies: - supports-color - nypm@0.6.0: + nypm@0.6.6: dependencies: - citty: 0.1.6 - consola: 3.4.2 + citty: 0.2.2 pathe: 2.0.3 - pkg-types: 2.3.0 - tinyexec: 0.3.2 + tinyexec: 1.3.1 object-assign@4.1.1: {} @@ -13694,13 +13062,15 @@ snapshots: object.assign@4.1.7: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 has-symbols: 1.1.0 object-keys: 1.1.1 + obug@2.2.1: {} + on-finished@2.4.1: dependencies: ee-first: 1.1.1 @@ -13717,6 +13087,21 @@ snapshots: dependencies: mimic-function: 5.0.1 + open@11.0.4: + dependencies: + default-browser: 5.5.1 + define-lazy-prop: 3.0.0 + is-in-ssh: 1.0.0 + is-inside-container: 1.0.0 + powershell-utils: 0.2.1 + wsl-utils: 1.0.0 + + open@8.4.2: + dependencies: + define-lazy-prop: 2.0.0 + is-docker: 2.2.1 + is-wsl: 2.2.0 + optionator@0.9.4: dependencies: deep-is: 0.1.4 @@ -13736,37 +13121,60 @@ snapshots: log-symbols: 6.0.0 stdin-discarder: 0.2.2 string-width: 7.2.0 - strip-ansi: 7.1.2 - - outvariant@1.4.3: {} + strip-ansi: 7.2.0 - own-keys@1.0.1: + own-keys@1.0.2: dependencies: + call-bound: 1.0.4 get-intrinsic: 1.3.0 object-keys: 1.1.1 safe-push-apply: 1.0.0 - oxc-resolver@11.13.2: - optionalDependencies: - '@oxc-resolver/binding-android-arm-eabi': 11.13.2 - '@oxc-resolver/binding-android-arm64': 11.13.2 - '@oxc-resolver/binding-darwin-arm64': 11.13.2 - '@oxc-resolver/binding-darwin-x64': 11.13.2 - '@oxc-resolver/binding-freebsd-x64': 11.13.2 - '@oxc-resolver/binding-linux-arm-gnueabihf': 11.13.2 - '@oxc-resolver/binding-linux-arm-musleabihf': 11.13.2 - '@oxc-resolver/binding-linux-arm64-gnu': 11.13.2 - '@oxc-resolver/binding-linux-arm64-musl': 11.13.2 - '@oxc-resolver/binding-linux-ppc64-gnu': 11.13.2 - '@oxc-resolver/binding-linux-riscv64-gnu': 11.13.2 - '@oxc-resolver/binding-linux-riscv64-musl': 11.13.2 - '@oxc-resolver/binding-linux-s390x-gnu': 11.13.2 - '@oxc-resolver/binding-linux-x64-gnu': 11.13.2 - '@oxc-resolver/binding-linux-x64-musl': 11.13.2 - '@oxc-resolver/binding-wasm32-wasi': 11.13.2 - '@oxc-resolver/binding-win32-arm64-msvc': 11.13.2 - '@oxc-resolver/binding-win32-ia32-msvc': 11.13.2 - '@oxc-resolver/binding-win32-x64-msvc': 11.13.2 + oxc-parser@0.150.0: + dependencies: + '@oxc-project/types': 0.150.0 + optionalDependencies: + '@oxc-parser/binding-android-arm-eabi': 0.150.0 + '@oxc-parser/binding-android-arm64': 0.150.0 + '@oxc-parser/binding-darwin-arm64': 0.150.0 + '@oxc-parser/binding-darwin-x64': 0.150.0 + '@oxc-parser/binding-freebsd-x64': 0.150.0 + '@oxc-parser/binding-linux-arm-gnueabihf': 0.150.0 + '@oxc-parser/binding-linux-arm-musleabihf': 0.150.0 + '@oxc-parser/binding-linux-arm64-gnu': 0.150.0 + '@oxc-parser/binding-linux-arm64-musl': 0.150.0 + '@oxc-parser/binding-linux-ppc64-gnu': 0.150.0 + '@oxc-parser/binding-linux-riscv64-gnu': 0.150.0 + '@oxc-parser/binding-linux-riscv64-musl': 0.150.0 + '@oxc-parser/binding-linux-s390x-gnu': 0.150.0 + '@oxc-parser/binding-linux-x64-gnu': 0.150.0 + '@oxc-parser/binding-linux-x64-musl': 0.150.0 + '@oxc-parser/binding-openharmony-arm64': 0.150.0 + '@oxc-parser/binding-win32-arm64-msvc': 0.150.0 + '@oxc-parser/binding-win32-ia32-msvc': 0.150.0 + '@oxc-parser/binding-win32-x64-msvc': 0.150.0 + + oxc-resolver@11.24.2: + optionalDependencies: + '@oxc-resolver/binding-android-arm-eabi': 11.24.2 + '@oxc-resolver/binding-android-arm64': 11.24.2 + '@oxc-resolver/binding-darwin-arm64': 11.24.2 + '@oxc-resolver/binding-darwin-x64': 11.24.2 + '@oxc-resolver/binding-freebsd-x64': 11.24.2 + '@oxc-resolver/binding-linux-arm-gnueabihf': 11.24.2 + '@oxc-resolver/binding-linux-arm-musleabihf': 11.24.2 + '@oxc-resolver/binding-linux-arm64-gnu': 11.24.2 + '@oxc-resolver/binding-linux-arm64-musl': 11.24.2 + '@oxc-resolver/binding-linux-ppc64-gnu': 11.24.2 + '@oxc-resolver/binding-linux-riscv64-gnu': 11.24.2 + '@oxc-resolver/binding-linux-riscv64-musl': 11.24.2 + '@oxc-resolver/binding-linux-s390x-gnu': 11.24.2 + '@oxc-resolver/binding-linux-x64-gnu': 11.24.2 + '@oxc-resolver/binding-linux-x64-musl': 11.24.2 + '@oxc-resolver/binding-openharmony-arm64': 11.24.2 + '@oxc-resolver/binding-wasm32-wasi': 11.24.2 + '@oxc-resolver/binding-win32-arm64-msvc': 11.24.2 + '@oxc-resolver/binding-win32-x64-msvc': 11.24.2 p-limit@2.3.0: dependencies: @@ -13776,6 +13184,10 @@ snapshots: dependencies: yocto-queue: 0.1.0 + p-locate@3.0.0: + dependencies: + p-limit: 2.3.0 + p-locate@4.1.0: dependencies: p-limit: 2.3.0 @@ -13799,7 +13211,7 @@ snapshots: package-json-from-dist@1.0.1: {} - package-manager-detector@1.6.0: {} + package-manager-detector@1.8.0: {} parent-module@1.0.1: dependencies: @@ -13807,7 +13219,7 @@ snapshots: parse-json@5.2.0: dependencies: - '@babel/code-frame': 7.27.1 + '@babel/code-frame': 7.29.7 error-ex: 1.3.4 json-parse-even-better-errors: 2.3.1 lines-and-columns: 1.2.4 @@ -13816,9 +13228,9 @@ snapshots: parse-srcset@1.0.2: {} - parse5@8.0.0: + parse5@8.0.1: dependencies: - entities: 6.0.1 + entities: 8.1.0 parseley@0.12.1: dependencies: @@ -13829,9 +13241,11 @@ snapshots: path-browserify@1.0.1: {} + path-exists@3.0.0: {} + path-exists@4.0.0: {} - path-is-absolute@1.0.1: {} + path-expression-matcher@1.6.2: {} path-key@3.1.1: {} @@ -13839,36 +13253,26 @@ snapshots: path-parse@1.0.7: {} - path-scurry@2.0.1: + path-scurry@2.0.2: dependencies: - lru-cache: 11.2.2 - minipass: 7.1.2 + lru-cache: 11.5.2 + minipass: 7.1.3 path-to-regexp@6.3.0: {} - path-to-regexp@8.3.0: {} + path-to-regexp@8.4.2: {} pathe@2.0.3: {} peberminta@0.9.0: {} - pg-int8@1.0.1: {} - - pg-protocol@1.10.3: {} - - pg-types@2.2.0: - dependencies: - pg-int8: 1.0.1 - postgres-array: 2.0.0 - postgres-bytea: 1.0.0 - postgres-date: 1.0.7 - postgres-interval: 1.2.0 - picocolors@1.1.1: {} - picomatch@2.3.1: {} + picomatch@2.3.2: {} + + picomatch@4.0.7: {} - picomatch@4.0.3: {} + picospinner@3.1.2: {} pirates@4.0.7: {} @@ -13881,72 +13285,49 @@ snapshots: pkg-types@1.3.1: dependencies: confbox: 0.1.8 - mlly: 1.8.0 + mlly: 1.8.2 pathe: 2.0.3 - pkg-types@2.3.0: + pkg-up@3.1.0: dependencies: - confbox: 0.2.2 - exsolve: 1.0.8 - pathe: 2.0.3 + find-up: 3.0.0 possible-typed-array-names@1.1.0: {} - postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.6): + postal-mime@2.7.6: {} + + postcss-load-config@6.0.1(jiti@2.6.1)(postcss@8.5.28)(tsx@4.23.13)(yaml@2.9.1): dependencies: lilconfig: 3.1.3 optionalDependencies: jiti: 2.6.1 - postcss: 8.5.6 - tsx: 4.20.6 + postcss: 8.5.28 + tsx: 4.23.13 + yaml: 2.9.1 postcss-selector-parser@6.0.10: dependencies: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss@8.4.31: + postcss-selector-parser@7.1.6: dependencies: - nanoid: 3.3.11 - picocolors: 1.1.1 - source-map-js: 1.2.1 + cssesc: 3.0.0 + util-deprecate: 1.0.2 - postcss@8.5.6: + postcss@8.5.28: dependencies: - nanoid: 3.3.11 + nanoid: 3.3.19 picocolors: 1.1.1 source-map-js: 1.2.1 - postgres-array@2.0.0: {} - - postgres-bytea@1.0.0: {} - - postgres-date@1.0.7: {} + powershell-utils@0.1.0: {} - postgres-interval@1.2.0: - dependencies: - xtend: 4.0.2 - - prebuild-install@7.1.3: - dependencies: - detect-libc: 2.1.2 - expand-template: 2.0.3 - github-from-package: 0.0.0 - minimist: 1.2.8 - mkdirp-classic: 0.5.3 - napi-build-utils: 2.0.0 - node-abi: 3.85.0 - pump: 3.0.3 - rc: 1.2.8 - simple-get: 4.0.1 - tar-fs: 2.1.4 - tunnel-agent: 0.6.0 + powershell-utils@0.2.1: {} prelude-ls@1.2.1: {} - prettier@3.6.2: {} - - prettier@3.7.4: {} + prettier@3.9.8: {} pretty-bytes@5.6.0: {} @@ -13958,12 +13339,14 @@ snapshots: ansi-styles: 5.2.0 react-is: 17.0.2 - pretty-ms@9.3.0: + pretty-ms@9.3.1: dependencies: parse-ms: 4.0.0 prismjs@1.30.0: {} + proc-log@7.0.0: {} + process-on-spawn@1.1.0: dependencies: fromentries: 1.3.2 @@ -13973,234 +13356,214 @@ snapshots: kleur: 3.0.3 sisteransi: 1.0.5 - proxy-addr@2.0.7: + proxy-addr@2.0.8: dependencies: forwarded: 0.2.0 ipaddr.js: 1.9.1 - pump@3.0.3: - dependencies: - end-of-stream: 1.4.5 - once: 1.4.0 - punycode@2.3.1: {} - qs@6.14.0: + qified@0.10.1: dependencies: - side-channel: 1.1.0 + hookified: 2.2.0 - querystringify@2.2.0: {} + qs@6.16.0: + dependencies: + es-define-property: 1.0.1 + side-channel: 1.1.1 queue-microtask@1.2.3: {} - radix-ui@1.4.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-accessible-icon': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-accordion': 1.2.12(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-alert-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-aspect-ratio': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-avatar': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-checkbox': 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-collapsible': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-context-menu': 2.2.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-dropdown-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-form': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-hover-card': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-label': 2.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-menubar': 1.1.16(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-navigation-menu': 1.2.14(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-one-time-password-field': 0.1.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-password-toggle-field': 0.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-popover': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-progress': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-radio-group': 1.3.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-scroll-area': 1.2.10(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-select': 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-separator': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slider': 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-switch': 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-tabs': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-toast': 1.2.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-toggle': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-toggle-group': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-toolbar': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-tooltip': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-is-hydrated': 0.1.0(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.6)(react@19.2.0) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - optionalDependencies: - '@types/react': 19.2.6 - '@types/react-dom': 19.2.3(@types/react@19.2.6) - - randombytes@2.1.0: - dependencies: - safe-buffer: 5.2.1 - - range-parser@1.2.1: {} + radix-ui@1.6.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + dependencies: + '@radix-ui/primitive': 1.1.7 + '@radix-ui/react-accessible-icon': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-accordion': 1.2.20(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-alert-dialog': 1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-arrow': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-aspect-ratio': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-avatar': 1.2.6(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-checkbox': 1.3.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-collapsible': 1.1.20(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-collection': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-compose-refs': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context': 1.2.2(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-context-menu': 2.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-direction': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-dismissable-layer': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-dropdown-menu': 2.1.24(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-focus-guards': 1.1.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-focus-scope': 1.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-form': 0.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-hover-card': 1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-label': 2.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-menu': 2.1.24(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-menubar': 1.1.24(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-navigation-menu': 1.2.22(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-one-time-password-field': 0.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-password-toggle-field': 0.1.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-popover': 1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-popper': 1.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-portal': 1.1.17(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-presence': 1.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-primitive': 2.1.10(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-progress': 1.1.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-radio-group': 1.4.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-roving-focus': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-scroll-area': 1.2.18(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-select': 2.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-separator': 1.1.15(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-slider': 1.4.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-slot': 1.3.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-switch': 1.3.7(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-tabs': 1.1.21(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-toast': 1.2.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-toggle': 1.1.18(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-toggle-group': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-toolbar': 1.1.19(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-tooltip': 1.2.16(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + '@radix-ui/react-use-callback-ref': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-controllable-state': 1.2.6(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-effect-event': 0.0.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-escape-keydown': 1.1.5(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-is-hydrated': 0.1.3(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-layout-effect': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-use-size': 1.1.4(@types/react@19.3.0)(react@19.3.0) + '@radix-ui/react-visually-hidden': 1.2.11(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 + '@types/react-dom': 19.3.0(@types/react@19.3.0) + + range-parser@1.3.0: {} raw-body@3.0.2: dependencies: bytes: 3.1.2 http-errors: 2.0.1 - iconv-lite: 0.7.0 + iconv-lite: 0.7.3 unpipe: 1.0.0 - rc@1.2.8: + react-dom@19.3.0(react@19.3.0): dependencies: - deep-extend: 0.6.0 - ini: 1.3.8 - minimist: 1.2.8 - strip-json-comments: 2.0.1 - - react-dom@19.2.0(react@19.2.0): - dependencies: - react: 19.2.0 - scheduler: 0.27.0 + react: 19.3.0 + scheduler: 0.28.0 - react-email@5.0.5: + react-email@6.9.5(react-dom@19.3.0(react@19.3.0))(react@19.3.0)(supports-color@10.2.2): dependencies: - '@babel/parser': 7.28.5 - '@babel/traverse': 7.28.5 + '@babel/parser': 7.29.2 + '@babel/traverse': 7.29.0(supports-color@10.2.2) + '@react-email/render': 2.1.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) chokidar: 4.0.3 commander: 13.1.0 - conf: 15.0.2 + conf: 15.1.0 + css-tree: 3.2.1 debounce: 2.2.0 - esbuild: 0.27.0 - glob: 11.1.0 - jiti: 2.4.2 + esbuild: 0.28.2 + glob: 13.0.6 + jiti: 2.6.1 log-symbols: 7.0.1 + marked: 15.0.12 mime-types: 3.0.2 normalize-path: 3.0.0 - nypm: 0.6.0 - ora: 8.2.0 + nypm: 0.6.6 + picospinner: 3.1.2 + prismjs: 1.30.0 prompts: 2.4.2 - socket.io: 4.8.1 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + socket.io: 4.8.3(supports-color@10.2.2) + tailwindcss: 4.3.3 tsconfig-paths: 4.2.0 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - react-hook-form@7.66.1(react@19.2.0): + react-hook-form@7.88.0(react@19.3.0): dependencies: - react: 19.2.0 + react: 19.3.0 - react-intersection-observer@10.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + react-intersection-observer@11.0.1(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: - react: 19.2.0 + react: 19.3.0 optionalDependencies: - react-dom: 19.2.0(react@19.2.0) - - react-is@16.13.1: {} + react-dom: 19.3.0(react@19.3.0) react-is@17.0.2: {} - react-is@18.3.1: {} + react-is@19.3.0: {} - react-redux@9.2.0(@types/react@19.2.6)(react@19.2.0)(redux@5.0.1): + react-redux@9.3.0(@types/react@19.3.0)(react@19.3.0)(redux@5.0.1): dependencies: '@types/use-sync-external-store': 0.0.6 - react: 19.2.0 - use-sync-external-store: 1.6.0(react@19.2.0) + react: 19.3.0 + use-sync-external-store: 1.7.0(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 redux: 5.0.1 - react-refresh@0.18.0: {} - - react-remove-scroll-bar@2.3.8(@types/react@19.2.6)(react@19.2.0): + react-remove-scroll-bar@2.3.8(@types/react@19.3.0)(react@19.3.0): dependencies: - react: 19.2.0 - react-style-singleton: 2.2.3(@types/react@19.2.6)(react@19.2.0) + react: 19.3.0 + react-style-singleton: 2.2.3(@types/react@19.3.0)(react@19.3.0) tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - react-remove-scroll@2.7.1(@types/react@19.2.6)(react@19.2.0): + react-remove-scroll@2.7.2(@types/react@19.3.0)(react@19.3.0): dependencies: - react: 19.2.0 - react-remove-scroll-bar: 2.3.8(@types/react@19.2.6)(react@19.2.0) - react-style-singleton: 2.2.3(@types/react@19.2.6)(react@19.2.0) + react: 19.3.0 + react-remove-scroll-bar: 2.3.8(@types/react@19.3.0)(react@19.3.0) + react-style-singleton: 2.2.3(@types/react@19.3.0)(react@19.3.0) tslib: 2.8.1 - use-callback-ref: 1.3.3(@types/react@19.2.6)(react@19.2.0) - use-sidecar: 1.1.3(@types/react@19.2.6)(react@19.2.0) + use-callback-ref: 1.3.3(@types/react@19.3.0)(react@19.3.0) + use-sidecar: 1.1.3(@types/react@19.3.0)(react@19.3.0) optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - react-style-singleton@2.2.3(@types/react@19.2.6)(react@19.2.0): + react-style-singleton@2.2.3(@types/react@19.3.0)(react@19.3.0): dependencies: get-nonce: 1.0.1 - react: 19.2.0 + react: 19.3.0 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.6 - - react@19.2.0: {} - - readable-stream@3.6.2: - dependencies: - inherits: 2.0.4 - string_decoder: 1.3.0 - util-deprecate: 1.0.2 + '@types/react': 19.3.0 - readdirp@3.6.0: - dependencies: - picomatch: 2.3.1 + react@19.3.0: {} readdirp@4.1.2: {} - recast@0.23.11: + readdirp@5.1.1: {} + + recast@0.23.21: dependencies: - ast-types: 0.16.1 + ast-types: 0.16.3 esprima: 4.0.1 source-map: 0.6.1 tiny-invariant: 1.3.3 tslib: 2.8.1 - recharts@3.5.0(@types/react@19.2.6)(eslint@9.39.1(jiti@2.6.1))(react-dom@19.2.0(react@19.2.0))(react-is@18.3.1)(react@19.2.0)(redux@5.0.1): + recharts@3.10.1(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react-is@19.3.0)(react@19.3.0)(redux@5.0.1): dependencies: - '@reduxjs/toolkit': 2.10.1(react-redux@9.2.0(@types/react@19.2.6)(react@19.2.0)(redux@5.0.1))(react@19.2.0) + '@reduxjs/toolkit': 2.12.0(react-redux@9.3.0(@types/react@19.3.0)(react@19.3.0)(redux@5.0.1))(react@19.3.0) clsx: 2.1.1 decimal.js-light: 2.5.1 - es-toolkit: 1.42.0 - eslint-plugin-react-perf: 3.3.3(eslint@9.39.1(jiti@2.6.1)) - eventemitter3: 5.0.1 - immer: 10.2.0 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-is: 18.3.1 - react-redux: 9.2.0(@types/react@19.2.6)(react@19.2.0)(redux@5.0.1) - reselect: 5.1.1 + es-toolkit: 1.52.0 + eventemitter3: 5.0.4 + immer: 11.1.18 + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + react-is: 19.3.0 + react-redux: 9.3.0(@types/react@19.3.0)(react@19.3.0)(redux@5.0.1) + reselect: 5.2.0 tiny-invariant: 1.3.3 - use-sync-external-store: 1.6.0(react@19.2.0) + use-sync-external-store: 1.7.0(react@19.3.0) victory-vendor: 37.3.6 transitivePeerDependencies: - '@types/react' - - eslint - redux redent@3.0.0: @@ -14216,11 +13579,11 @@ snapshots: reflect.getprototypeof@1.0.10: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-intrinsic: 1.3.0 get-proto: 1.0.1 which-builtin-type: 1.2.1 @@ -14233,7 +13596,7 @@ snapshots: regexp.prototype.flags@1.5.4: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 es-errors: 1.3.0 get-proto: 1.0.1 @@ -14245,13 +13608,13 @@ snapshots: regenerate: 1.4.2 regenerate-unicode-properties: 10.2.2 regjsgen: 0.8.0 - regjsparser: 0.13.0 + regjsparser: 0.13.3 unicode-match-property-ecmascript: 2.0.0 unicode-match-property-value-ecmascript: 2.2.1 regjsgen@0.8.0: {} - regjsparser@0.13.0: + regjsparser@0.13.3: dependencies: jsesc: 3.1.0 @@ -14263,25 +13626,23 @@ snapshots: require-from-string@2.0.2: {} - require-in-the-middle@7.5.2: + require-in-the-middle@8.0.1(supports-color@10.2.2): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) module-details-from-path: 1.0.4 - resolve: 1.22.11 transitivePeerDependencies: - supports-color require-main-filename@2.0.0: {} - requires-port@1.0.0: {} - - reselect@5.1.1: {} + reselect@5.2.0: {} - resend@6.5.2(@react-email/render@2.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0)): + resend@6.28.1(@react-email/render@2.1.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0)): dependencies: - svix: 1.76.1 + postal-mime: 2.7.6 + standardwebhooks: 1.1.1 optionalDependencies: - '@react-email/render': 2.0.0(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@react-email/render': 2.1.0(react-dom@19.3.0(react@19.3.0))(react@19.3.0) resolve-from@4.0.0: {} @@ -14289,9 +13650,10 @@ snapshots: resolve-pkg-maps@1.0.0: {} - resolve@1.22.11: + resolve@1.22.12: dependencies: - is-core-module: 2.16.1 + es-errors: 1.3.0 + is-core-module: 2.17.0 path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 @@ -14300,133 +13662,80 @@ snapshots: onetime: 7.0.0 signal-exit: 4.1.0 - rettime@0.7.0: {} - reusify@1.1.0: {} - rimraf@3.0.2: - dependencies: - glob: 7.2.3 - - rolldown-vite@7.1.14(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6): - dependencies: - '@oxc-project/runtime': 0.92.0 - fdir: 6.5.0(picomatch@4.0.3) - lightningcss: 1.30.2 - picomatch: 4.0.3 - postcss: 8.5.6 - rolldown: 1.0.0-beta.41 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 24.10.1 - esbuild: 0.27.0 - fsevents: 2.3.3 - jiti: 2.6.1 - terser: 5.44.1 - tsx: 4.20.6 - - rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6): + rimraf@6.1.3: dependencies: - '@oxc-project/runtime': 0.98.0 - fdir: 6.5.0(picomatch@4.0.3) - lightningcss: 1.30.2 - picomatch: 4.0.3 - postcss: 8.5.6 - rolldown: 1.0.0-beta.51 - tinyglobby: 0.2.15 - optionalDependencies: - '@types/node': 24.10.1 - esbuild: 0.27.0 - fsevents: 2.3.3 - jiti: 2.6.1 - terser: 5.44.1 - tsx: 4.20.6 - - rolldown@1.0.0-beta.41: - dependencies: - '@oxc-project/types': 0.93.0 - '@rolldown/pluginutils': 1.0.0-beta.41 - ansis: 4.2.0 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.41 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.41 - '@rolldown/binding-darwin-x64': 1.0.0-beta.41 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.41 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.41 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.41 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.41 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.41 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.41 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.41 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.41 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.41 - '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.41 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.41 - - rolldown@1.0.0-beta.51: - dependencies: - '@oxc-project/types': 0.98.0 - '@rolldown/pluginutils': 1.0.0-beta.51 - optionalDependencies: - '@rolldown/binding-android-arm64': 1.0.0-beta.51 - '@rolldown/binding-darwin-arm64': 1.0.0-beta.51 - '@rolldown/binding-darwin-x64': 1.0.0-beta.51 - '@rolldown/binding-freebsd-x64': 1.0.0-beta.51 - '@rolldown/binding-linux-arm-gnueabihf': 1.0.0-beta.51 - '@rolldown/binding-linux-arm64-gnu': 1.0.0-beta.51 - '@rolldown/binding-linux-arm64-musl': 1.0.0-beta.51 - '@rolldown/binding-linux-x64-gnu': 1.0.0-beta.51 - '@rolldown/binding-linux-x64-musl': 1.0.0-beta.51 - '@rolldown/binding-openharmony-arm64': 1.0.0-beta.51 - '@rolldown/binding-wasm32-wasi': 1.0.0-beta.51 - '@rolldown/binding-win32-arm64-msvc': 1.0.0-beta.51 - '@rolldown/binding-win32-ia32-msvc': 1.0.0-beta.51 - '@rolldown/binding-win32-x64-msvc': 1.0.0-beta.51 - - rollup@2.79.2: - optionalDependencies: - fsevents: 2.3.3 + glob: 13.0.6 + package-json-from-dist: 1.0.1 - rollup@4.53.3: - dependencies: - '@types/estree': 1.0.8 - optionalDependencies: - '@rollup/rollup-android-arm-eabi': 4.53.3 - '@rollup/rollup-android-arm64': 4.53.3 - '@rollup/rollup-darwin-arm64': 4.53.3 - '@rollup/rollup-darwin-x64': 4.53.3 - '@rollup/rollup-freebsd-arm64': 4.53.3 - '@rollup/rollup-freebsd-x64': 4.53.3 - '@rollup/rollup-linux-arm-gnueabihf': 4.53.3 - '@rollup/rollup-linux-arm-musleabihf': 4.53.3 - '@rollup/rollup-linux-arm64-gnu': 4.53.3 - '@rollup/rollup-linux-arm64-musl': 4.53.3 - '@rollup/rollup-linux-loong64-gnu': 4.53.3 - '@rollup/rollup-linux-ppc64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-gnu': 4.53.3 - '@rollup/rollup-linux-riscv64-musl': 4.53.3 - '@rollup/rollup-linux-s390x-gnu': 4.53.3 - '@rollup/rollup-linux-x64-gnu': 4.53.3 - '@rollup/rollup-linux-x64-musl': 4.53.3 - '@rollup/rollup-openharmony-arm64': 4.53.3 - '@rollup/rollup-win32-arm64-msvc': 4.53.3 - '@rollup/rollup-win32-ia32-msvc': 4.53.3 - '@rollup/rollup-win32-x64-gnu': 4.53.3 - '@rollup/rollup-win32-x64-msvc': 4.53.3 + rolldown@1.2.9: + dependencies: + '@oxc-project/types': 0.150.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm-eabi': 1.2.9 + '@rolldown/binding-android-arm64': 1.2.9 + '@rolldown/binding-darwin-arm64': 1.2.9 + '@rolldown/binding-darwin-x64': 1.2.9 + '@rolldown/binding-freebsd-x64': 1.2.9 + '@rolldown/binding-linux-arm-gnueabihf': 1.2.9 + '@rolldown/binding-linux-arm64-gnu': 1.2.9 + '@rolldown/binding-linux-arm64-musl': 1.2.9 + '@rolldown/binding-linux-ppc64-gnu': 1.2.9 + '@rolldown/binding-linux-s390x-gnu': 1.2.9 + '@rolldown/binding-linux-x64-gnu': 1.2.9 + '@rolldown/binding-linux-x64-musl': 1.2.9 + '@rolldown/binding-openharmony-arm64': 1.2.9 + '@rolldown/binding-win32-arm64-msvc': 1.2.9 + '@rolldown/binding-win32-x64-msvc': 1.2.9 + + rollup@4.63.3: + dependencies: + '@types/estree': 1.0.9 + optionalDependencies: + '@napi-rs/lzma-linux-x64-gnu': 1.5.1 + '@rollup/rollup-android-arm-eabi': 4.63.3 + '@rollup/rollup-android-arm64': 4.63.3 + '@rollup/rollup-darwin-arm64': 4.63.3 + '@rollup/rollup-darwin-x64': 4.63.3 + '@rollup/rollup-freebsd-arm64': 4.63.3 + '@rollup/rollup-freebsd-x64': 4.63.3 + '@rollup/rollup-linux-arm-gnueabihf': 4.63.3 + '@rollup/rollup-linux-arm-musleabihf': 4.63.3 + '@rollup/rollup-linux-arm64-gnu': 4.63.3 + '@rollup/rollup-linux-arm64-musl': 4.63.3 + '@rollup/rollup-linux-loong64-gnu': 4.63.3 + '@rollup/rollup-linux-loong64-musl': 4.63.3 + '@rollup/rollup-linux-ppc64-gnu': 4.63.3 + '@rollup/rollup-linux-ppc64-musl': 4.63.3 + '@rollup/rollup-linux-riscv64-gnu': 4.63.3 + '@rollup/rollup-linux-riscv64-musl': 4.63.3 + '@rollup/rollup-linux-s390x-gnu': 4.63.3 + '@rollup/rollup-linux-x64-gnu': 4.63.3 + '@rollup/rollup-linux-x64-musl': 4.63.3 + '@rollup/rollup-openbsd-x64': 4.63.3 + '@rollup/rollup-openharmony-arm64': 4.63.3 + '@rollup/rollup-win32-arm64-msvc': 4.63.3 + '@rollup/rollup-win32-ia32-msvc': 4.63.3 + '@rollup/rollup-win32-x64-gnu': 4.63.3 + '@rollup/rollup-win32-x64-msvc': 4.63.3 fsevents: 2.3.3 - rou3@0.5.1: {} + rou3@0.9.2: {} - router@2.2.0: + router@2.2.0(supports-color@10.2.2): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) depd: 2.0.0 is-promise: 4.0.0 parseurl: 1.3.3 - path-to-regexp: 8.3.0 + path-to-regexp: 8.4.2 transitivePeerDependencies: - supports-color + run-applescript@7.1.0: {} + run-parallel@1.2.0: dependencies: queue-microtask: 1.2.3 @@ -14435,16 +13744,14 @@ snapshots: dependencies: tslib: 2.8.1 - safe-array-concat@1.1.3: + safe-array-concat@1.1.4: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 get-intrinsic: 1.3.0 has-symbols: 1.1.0 isarray: 2.0.5 - safe-buffer@5.2.1: {} - safe-push-apply@1.0.0: dependencies: es-errors: 1.3.0 @@ -14458,20 +13765,21 @@ snapshots: safer-buffer@2.1.2: {} - sanitize-html@2.17.0: + sanitize-html@2.17.7: dependencies: deepmerge: 4.3.1 escape-string-regexp: 4.0.0 - htmlparser2: 8.0.2 - is-plain-object: 5.0.0 + htmlparser2: 12.0.0 + is-plain-object: 5.1.0 + launder: 1.7.1 parse-srcset: 1.0.2 - postcss: 8.5.6 + postcss: 8.5.28 saxes@6.0.0: dependencies: xmlchars: 2.2.0 - scheduler@0.27.0: {} + scheduler@0.28.0: {} selderee@0.11.0: dependencies: @@ -14479,11 +13787,11 @@ snapshots: semver@6.3.1: {} - semver@7.7.3: {} + semver@7.8.5: {} - send@1.2.0: + send@1.2.1(supports-color@10.2.2): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) encodeurl: 2.0.0 escape-html: 1.0.3 etag: 1.8.1 @@ -14492,33 +13800,31 @@ snapshots: mime-types: 3.0.2 ms: 2.1.3 on-finished: 2.4.1 - range-parser: 1.2.1 + range-parser: 1.3.0 statuses: 2.0.2 transitivePeerDependencies: - supports-color - serialize-javascript@6.0.2: - dependencies: - randombytes: 2.1.0 + serialize-javascript@7.1.1: {} - seroval-plugins@1.4.0(seroval@1.4.0): + seroval-plugins@1.6.7(seroval@1.6.7): dependencies: - seroval: 1.4.0 + seroval: 1.6.7 - seroval@1.4.0: {} + seroval@1.6.7: {} - serve-static@2.2.0: + serve-static@2.2.1(supports-color@10.2.2): dependencies: encodeurl: 2.0.0 escape-html: 1.0.3 parseurl: 1.3.3 - send: 1.2.0 + send: 1.2.1(supports-color@10.2.2) transitivePeerDependencies: - supports-color set-blocking@2.0.0: {} - set-cookie-parser@2.7.2: {} + set-cookie-parser@3.1.2: {} set-function-length@1.2.2: dependencies: @@ -14540,105 +13846,83 @@ snapshots: dependencies: dunder-proto: 1.0.1 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 setprototypeof@1.2.0: {} - shadcn@3.5.1(@types/node@24.10.1)(typescript@5.9.3): - dependencies: - '@antfu/ni': 25.0.0 - '@babel/core': 7.28.5 - '@babel/parser': 7.28.5 - '@babel/plugin-transform-typescript': 7.28.5(@babel/core@7.28.5) - '@babel/preset-typescript': 7.28.5(@babel/core@7.28.5) - '@dotenvx/dotenvx': 1.51.1 - '@modelcontextprotocol/sdk': 1.24.3(zod@3.25.76) - browserslist: 4.28.1 - commander: 14.0.2 - cosmiconfig: 9.0.0(typescript@5.9.3) - dedent: 1.7.0 + shadcn@4.21.0(supports-color@10.2.2)(typescript@7.0.2): + dependencies: + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/parser': 7.29.9 + '@babel/plugin-transform-typescript': 7.29.9(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/preset-typescript': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@dotenvx/dotenvx': 1.75.1 + '@modelcontextprotocol/sdk': 1.30.0(supports-color@10.2.2)(zod@3.25.76) + '@types/validate-npm-package-name': 4.0.2 + browserslist: 4.29.0 + cn: 0.2.6 + commander: 14.0.3 + cosmiconfig: 9.0.2(typescript@7.0.2) + dedent: 1.7.2 deepmerge: 4.3.1 - diff: 8.0.2 + diff: 8.0.4 execa: 9.6.1 fast-glob: 3.3.3 - fs-extra: 11.3.2 + fs-extra: 11.4.0 fuzzysort: 3.1.0 - https-proxy-agent: 7.0.6 kleur: 4.1.5 - msw: 2.12.4(@types/node@24.10.1)(typescript@5.9.3) - node-fetch: 3.3.2 + open: 11.0.4 ora: 8.2.0 - postcss: 8.5.6 + postcss: 8.5.28 + postcss-selector-parser: 7.1.6 prompts: 2.4.2 - recast: 0.23.11 + recast: 0.23.21 + socks: 2.8.10 stringify-object: 5.0.0 ts-morph: 26.0.0 tsconfig-paths: 4.2.0 + undici: 7.29.1 + validate-npm-package-name: 7.0.2 zod: 3.25.76 - zod-to-json-schema: 3.25.0(zod@3.25.76) + zod-to-json-schema: 3.25.2(zod@3.25.76) transitivePeerDependencies: - '@cfworker/json-schema' - - '@types/node' - babel-plugin-macros - supports-color - typescript - sharp@0.33.5: + sharp@0.35.4(@types/node@24.13.5): dependencies: - color: 4.2.3 - detect-libc: 2.1.2 - semver: 7.7.3 - optionalDependencies: - '@img/sharp-darwin-arm64': 0.33.5 - '@img/sharp-darwin-x64': 0.33.5 - '@img/sharp-libvips-darwin-arm64': 1.0.4 - '@img/sharp-libvips-darwin-x64': 1.0.4 - '@img/sharp-libvips-linux-arm': 1.0.5 - '@img/sharp-libvips-linux-arm64': 1.0.4 - '@img/sharp-libvips-linux-s390x': 1.0.4 - '@img/sharp-libvips-linux-x64': 1.0.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.0.4 - '@img/sharp-libvips-linuxmusl-x64': 1.0.4 - '@img/sharp-linux-arm': 0.33.5 - '@img/sharp-linux-arm64': 0.33.5 - '@img/sharp-linux-s390x': 0.33.5 - '@img/sharp-linux-x64': 0.33.5 - '@img/sharp-linuxmusl-arm64': 0.33.5 - '@img/sharp-linuxmusl-x64': 0.33.5 - '@img/sharp-wasm32': 0.33.5 - '@img/sharp-win32-ia32': 0.33.5 - '@img/sharp-win32-x64': 0.33.5 - - sharp@0.34.5: - dependencies: - '@img/colour': 1.0.0 + '@img/colour': 1.1.0 detect-libc: 2.1.2 - semver: 7.7.3 - optionalDependencies: - '@img/sharp-darwin-arm64': 0.34.5 - '@img/sharp-darwin-x64': 0.34.5 - '@img/sharp-libvips-darwin-arm64': 1.2.4 - '@img/sharp-libvips-darwin-x64': 1.2.4 - '@img/sharp-libvips-linux-arm': 1.2.4 - '@img/sharp-libvips-linux-arm64': 1.2.4 - '@img/sharp-libvips-linux-ppc64': 1.2.4 - '@img/sharp-libvips-linux-riscv64': 1.2.4 - '@img/sharp-libvips-linux-s390x': 1.2.4 - '@img/sharp-libvips-linux-x64': 1.2.4 - '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 - '@img/sharp-libvips-linuxmusl-x64': 1.2.4 - '@img/sharp-linux-arm': 0.34.5 - '@img/sharp-linux-arm64': 0.34.5 - '@img/sharp-linux-ppc64': 0.34.5 - '@img/sharp-linux-riscv64': 0.34.5 - '@img/sharp-linux-s390x': 0.34.5 - '@img/sharp-linux-x64': 0.34.5 - '@img/sharp-linuxmusl-arm64': 0.34.5 - '@img/sharp-linuxmusl-x64': 0.34.5 - '@img/sharp-wasm32': 0.34.5 - '@img/sharp-win32-arm64': 0.34.5 - '@img/sharp-win32-ia32': 0.34.5 - '@img/sharp-win32-x64': 0.34.5 + semver: 7.8.5 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.35.4 + '@img/sharp-darwin-x64': 0.35.4 + '@img/sharp-freebsd-wasm32': 0.35.4 + '@img/sharp-libvips-darwin-arm64': 1.3.3 + '@img/sharp-libvips-darwin-x64': 1.3.3 + '@img/sharp-libvips-linux-arm': 1.3.3 + '@img/sharp-libvips-linux-arm64': 1.3.3 + '@img/sharp-libvips-linux-ppc64': 1.3.3 + '@img/sharp-libvips-linux-riscv64': 1.3.3 + '@img/sharp-libvips-linux-s390x': 1.3.3 + '@img/sharp-libvips-linux-x64': 1.3.3 + '@img/sharp-libvips-linuxmusl-arm64': 1.3.3 + '@img/sharp-libvips-linuxmusl-x64': 1.3.3 + '@img/sharp-linux-arm': 0.35.4 + '@img/sharp-linux-arm64': 0.35.4 + '@img/sharp-linux-ppc64': 0.35.4 + '@img/sharp-linux-riscv64': 0.35.4 + '@img/sharp-linux-s390x': 0.35.4 + '@img/sharp-linux-x64': 0.35.4 + '@img/sharp-linuxmusl-arm64': 0.35.4 + '@img/sharp-linuxmusl-x64': 0.35.4 + '@img/sharp-webcontainers-wasm32': 0.35.4 + '@img/sharp-win32-arm64': 0.35.4 + '@img/sharp-win32-ia32': 0.35.4 + '@img/sharp-win32-x64': 0.35.4 + '@types/node': 24.13.5 shebang-command@2.0.0: dependencies: @@ -14646,11 +13930,9 @@ snapshots: shebang-regex@3.0.0: {} - shell-quote@1.8.3: {} + shell-quote@1.9.0: {} - shimmer@1.2.1: {} - - side-channel-list@1.0.0: + side-channel-list@1.0.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 @@ -14670,11 +13952,11 @@ snapshots: object-inspect: 1.13.4 side-channel-map: 1.0.1 - side-channel@1.1.0: + side-channel@1.1.1: dependencies: es-errors: 1.3.0 object-inspect: 1.13.4 - side-channel-list: 1.0.0 + side-channel-list: 1.0.1 side-channel-map: 1.0.1 side-channel-weakmap: 1.0.2 @@ -14684,18 +13966,6 @@ snapshots: signal-exit@4.1.0: {} - simple-concat@1.0.1: {} - - simple-get@4.0.1: - dependencies: - decompress-response: 6.0.0 - once: 1.4.0 - simple-concat: 1.0.1 - - simple-swizzle@0.2.4: - dependencies: - is-arrayish: 0.3.4 - sirv@3.0.2: dependencies: '@polka/url': 1.0.0-next.29 @@ -14704,44 +13974,53 @@ snapshots: sisteransi@1.0.5: {} - smob@1.5.0: {} + smart-buffer@4.2.0: {} + + smob@1.6.2: {} - smol-toml@1.5.2: {} + smol-toml@1.8.0: {} - socket.io-adapter@2.5.5: + socket.io-adapter@2.5.8(supports-color@10.2.2): dependencies: - debug: 4.3.7 - ws: 8.17.1 + debug: 4.4.3(supports-color@10.2.2) + ws: 8.21.3 transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - socket.io-parser@4.2.4: + socket.io-parser@4.2.7(supports-color@10.2.2): dependencies: '@socket.io/component-emitter': 3.1.2 - debug: 4.3.7 + debug: 4.4.3(supports-color@10.2.2) transitivePeerDependencies: - supports-color - socket.io@4.8.1: + socket.io@4.8.3(supports-color@10.2.2): dependencies: accepts: 1.3.8 base64id: 2.0.0 - cors: 2.8.5 - debug: 4.3.7 - engine.io: 6.6.4 - socket.io-adapter: 2.5.5 - socket.io-parser: 4.2.4 + cors: 2.8.6 + debug: 4.4.3(supports-color@10.2.2) + engine.io: 6.6.10(supports-color@10.2.2) + socket.io-adapter: 2.5.8(supports-color@10.2.2) + socket.io-parser: 4.2.7(supports-color@10.2.2) transitivePeerDependencies: - bufferutil - supports-color - utf-8-validate - sonner@2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + socks@2.8.10: dependencies: - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + ip-address: 10.7.2 + smart-buffer: 4.2.0 + + sonner@2.0.8(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): + dependencies: + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) + optionalDependencies: + '@types/react': 19.3.0 source-map-js@1.2.1: {} @@ -14754,18 +14033,15 @@ snapshots: source-map@0.7.6: {} - source-map@0.8.0-beta.0: - dependencies: - whatwg-url: 7.1.0 - - sourcemap-codec@1.4.8: {} + source-map@0.8.0: {} - spawn-wrap@2.0.0: + spawn-wrap@3.0.0: dependencies: + cross-spawn: 7.0.6 foreground-child: 2.0.0 is-windows: 1.0.2 make-dir: 3.1.0 - rimraf: 3.0.2 + rimraf: 6.1.3 signal-exit: 3.0.7 which: 2.0.2 @@ -14773,9 +14049,14 @@ snapshots: stackback@0.0.2: {} + standardwebhooks@1.1.1: + dependencies: + '@stablelib/base64': 1.0.1 + fast-sha256: 1.3.0 + statuses@2.0.2: {} - std-env@3.10.0: {} + std-env@4.2.0: {} stdin-discarder@0.2.2: {} @@ -14784,70 +14065,57 @@ snapshots: es-errors: 1.3.0 internal-slot: 1.1.0 - stoppable@1.1.0: {} - - strict-event-emitter@0.5.1: {} - string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - string-width@5.1.2: - dependencies: - eastasianwidth: 0.2.0 - emoji-regex: 9.2.2 - strip-ansi: 7.1.2 - string-width@7.2.0: dependencies: emoji-regex: 10.6.0 - get-east-asian-width: 1.4.0 - strip-ansi: 7.1.2 + get-east-asian-width: 1.7.0 + strip-ansi: 7.2.0 - string.prototype.matchall@4.0.12: + string.prototype.matchall@4.1.0: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-abstract: 1.24.0 + es-abstract: 1.24.2 es-errors: 1.3.0 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 get-intrinsic: 1.3.0 gopd: 1.2.0 has-symbols: 1.1.0 internal-slot: 1.1.0 regexp.prototype.flags: 1.5.4 set-function-name: 2.0.2 - side-channel: 1.1.0 + side-channel: 1.1.1 - string.prototype.trim@1.2.10: + string.prototype.trim@1.2.11: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-data-property: 1.1.4 define-properties: 1.2.1 - es-abstract: 1.24.0 - es-object-atoms: 1.1.1 + es-abstract: 1.24.2 + es-object-atoms: 1.1.2 has-property-descriptors: 1.0.2 + safe-regex-test: 1.1.0 - string.prototype.trimend@1.0.9: + string.prototype.trimend@1.0.10: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 define-properties: 1.2.1 - es-object-atoms: 1.1.1 + es-object-atoms: 1.1.2 string.prototype.trimstart@1.0.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 define-properties: 1.2.1 - es-object-atoms: 1.1.1 - - string_decoder@1.3.0: - dependencies: - safe-buffer: 5.2.1 + es-object-atoms: 1.1.2 stringify-object@3.3.0: dependencies: @@ -14865,9 +14133,9 @@ snapshots: dependencies: ansi-regex: 5.0.1 - strip-ansi@7.1.2: + strip-ansi@7.2.0: dependencies: - ansi-regex: 6.2.2 + ansi-regex: 6.3.0 strip-bom@3.0.0: {} @@ -14883,13 +14151,11 @@ snapshots: dependencies: min-indent: 1.0.1 - strip-json-comments@2.0.1: {} - - strip-json-comments@3.1.1: {} - strip-json-comments@5.0.3: {} - strnum@2.1.1: {} + strnum@2.4.2: + dependencies: + anynum: 1.0.1 stubborn-fs@2.0.0: dependencies: @@ -14897,13 +14163,6 @@ snapshots: stubborn-utils@1.0.2: {} - styled-jsx@5.1.6(@babel/core@7.28.5)(react@19.2.0): - dependencies: - client-only: 0.0.1 - react: 19.2.0 - optionalDependencies: - '@babel/core': 7.28.5 - sucrase@3.35.1: dependencies: '@jridgewell/gen-mapping': 0.3.13 @@ -14911,12 +14170,12 @@ snapshots: lines-and-columns: 1.2.4 mz: 2.7.0 pirates: 4.0.7 - tinyglobby: 0.2.15 + tinyglobby: 0.2.17 ts-interface-checker: 0.1.13 superjson@2.2.6: dependencies: - copy-anything: 4.0.5 + copy-anything: 4.1.0 supports-color@10.2.2: {} @@ -14924,47 +14183,27 @@ snapshots: dependencies: has-flag: 4.0.0 - supports-color@8.1.1: - dependencies: - has-flag: 4.0.0 - supports-preserve-symlinks-flag@1.0.0: {} - svix@1.76.1: - dependencies: - '@stablelib/base64': 1.0.1 - '@types/node': 22.19.1 - es6-promise: 4.2.8 - fast-sha256: 1.3.0 - url-parse: 1.5.10 - uuid: 10.0.0 - - symbol-tree@3.2.4: {} + systeminformation@5.33.12: {} - tabbable@6.3.0: {} + tabbable@6.5.0: {} tagged-tag@1.0.0: {} - tailwind-merge@3.4.0: {} + tailwind-merge@3.7.0: {} - tailwindcss@4.1.17: {} + tailwindcss@4.3.3: {} - tapable@2.3.0: {} - - tar-fs@2.1.4: - dependencies: - chownr: 1.1.4 - mkdirp-classic: 0.5.3 - pump: 3.0.3 - tar-stream: 2.2.0 + tapable@2.3.3: {} - tar-stream@2.2.0: + tar@7.5.22: dependencies: - bl: 4.1.0 - end-of-stream: 1.4.5 - fs-constants: 1.0.0 - inherits: 2.0.4 - readable-stream: 3.6.2 + '@isaacs/fs-minipass': 4.0.1 + chownr: 3.0.0 + minipass: 7.1.3 + minizlib: 3.1.0 + yallist: 5.0.0 temp-dir@2.0.0: {} @@ -14975,18 +14214,18 @@ snapshots: type-fest: 0.16.0 unique-string: 2.0.0 - terser@5.44.1: + terser@5.51.2: dependencies: '@jridgewell/source-map': 0.3.11 - acorn: 8.15.0 + acorn: 8.18.0 commander: 2.20.3 source-map-support: 0.5.21 - test-exclude@6.0.0: + test-exclude@8.0.0: dependencies: - '@istanbuljs/schema': 0.1.3 - glob: 7.2.3 - minimatch: 3.1.2 + '@istanbuljs/schema': 0.1.6 + glob: 13.0.6 + minimatch: 10.2.6 thenify-all@1.6.0: dependencies: @@ -14998,26 +14237,26 @@ snapshots: tiny-invariant@1.3.3: {} - tiny-warning@1.0.3: {} - - tinybench@2.9.0: {} + tinybench@6.1.4: {} tinyexec@0.3.2: {} - tinyexec@1.0.2: {} + tinyexec@1.3.0: {} - tinyglobby@0.2.15: + tinyexec@1.3.1: {} + + tinyglobby@0.2.17: dependencies: - fdir: 6.5.0(picomatch@4.0.3) - picomatch: 4.0.3 + fdir: 6.5.0(picomatch@4.0.7) + picomatch: 4.0.7 - tinyrainbow@3.0.3: {} + tinyrainbow@3.1.1: {} - tldts-core@7.0.19: {} + tldts-core@7.4.13: {} - tldts@7.0.19: + tldts@7.4.13: dependencies: - tldts-core: 7.0.19 + tldts-core: 7.4.13 to-regex-range@5.0.1: dependencies: @@ -15027,13 +14266,9 @@ snapshots: totalist@3.0.1: {} - tough-cookie@6.0.0: - dependencies: - tldts: 7.0.19 - - tr46@1.0.1: + tough-cookie@6.0.2: dependencies: - punycode: 2.3.1 + tldts: 7.4.13 tr46@6.0.0: dependencies: @@ -15041,9 +14276,9 @@ snapshots: tree-kill@1.2.2: {} - ts-api-utils@2.1.0(typescript@5.9.3): + ts-api-utils@2.5.0(typescript@6.0.3): dependencies: - typescript: 5.9.3 + typescript: 6.0.3 ts-interface-checker@0.1.13: {} @@ -15060,45 +14295,40 @@ snapshots: tslib@2.8.1: {} - tsup@8.5.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.6)(typescript@5.9.3): + tsup@8.5.1(jiti@2.6.1)(postcss@8.5.28)(supports-color@10.2.2)(tsx@4.23.13)(typescript@6.0.3)(yaml@2.9.1): dependencies: - bundle-require: 5.1.0(esbuild@0.27.0) + bundle-require: 5.1.0(esbuild@0.28.2) cac: 6.7.14 chokidar: 4.0.3 consola: 3.4.2 - debug: 4.4.3 - esbuild: 0.27.0 + debug: 4.4.3(supports-color@10.2.2) + esbuild: 0.28.2 fix-dts-default-cjs-exports: 1.0.1 joycon: 3.1.1 picocolors: 1.1.1 - postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.6)(tsx@4.20.6) + postcss-load-config: 6.0.1(jiti@2.6.1)(postcss@8.5.28)(tsx@4.23.13)(yaml@2.9.1) resolve-from: 5.0.0 - rollup: 4.53.3 + rollup: 4.63.3 source-map: 0.7.6 sucrase: 3.35.1 tinyexec: 0.3.2 - tinyglobby: 0.2.15 + tinyglobby: 0.2.17 tree-kill: 1.2.2 optionalDependencies: - postcss: 8.5.6 - typescript: 5.9.3 + postcss: 8.5.28 + typescript: 6.0.3 transitivePeerDependencies: - jiti - supports-color - tsx - yaml - tsx@4.20.6: + tsx@4.23.13: dependencies: - esbuild: 0.27.0 - get-tsconfig: 4.13.0 + esbuild: 0.28.2 optionalDependencies: fsevents: 2.3.3 - tunnel-agent@0.6.0: - dependencies: - safe-buffer: 5.2.1 - tw-animate-css@1.4.0: {} type-check@0.4.0: @@ -15109,18 +14339,14 @@ snapshots: type-fest@0.8.1: {} - type-fest@5.2.0: + type-fest@5.10.0: dependencies: tagged-tag: 1.0.0 - type-fest@5.3.0: + type-is@2.1.0: dependencies: - tagged-tag: 1.0.0 - - type-is@2.0.1: - dependencies: - content-type: 1.0.5 - media-typer: 1.1.0 + content-type: 2.1.0 + media-typer: 1.1.1 mime-types: 3.0.2 typed-array-buffer@1.0.3: @@ -15131,25 +14357,24 @@ snapshots: typed-array-byte-length@1.0.3: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 has-proto: 1.2.0 is-typed-array: 1.1.15 - typed-array-byte-offset@1.0.4: + typed-array-byte-offset@1.0.5: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 - has-proto: 1.2.0 is-typed-array: 1.1.15 reflect.getprototypeof: 1.0.10 - typed-array-length@1.0.7: + typed-array-length@1.0.8: dependencies: - call-bind: 1.0.8 + call-bind: 1.0.9 for-each: 0.3.5 gopd: 1.2.0 is-typed-array: 1.1.15 @@ -15160,23 +14385,49 @@ snapshots: dependencies: is-typedarray: 1.0.0 - typescript-eslint@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): + typescript-eslint@8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.47.0(@typescript-eslint/parser@8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/parser': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - '@typescript-eslint/typescript-estree': 8.47.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.47.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) - eslint: 9.39.1(jiti@2.6.1) - typescript: 5.9.3 + '@typescript-eslint/eslint-plugin': 8.70.0(@typescript-eslint/parser@8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3))(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/parser': 8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/typescript-estree': 8.70.0(supports-color@10.2.2)(typescript@6.0.3) + '@typescript-eslint/utils': 8.70.0(eslint@10.10.0(jiti@2.6.1)(supports-color@10.2.2))(supports-color@10.2.2)(typescript@6.0.3) + eslint: 10.10.0(jiti@2.6.1)(supports-color@10.2.2) + typescript: 6.0.3 transitivePeerDependencies: - supports-color - typescript@5.9.3: {} - - ufo@1.6.1: {} + typescript@6.0.3: {} + + typescript@7.0.2: + optionalDependencies: + '@typescript/typescript-aix-ppc64': 7.0.2 + '@typescript/typescript-darwin-arm64': 7.0.2 + '@typescript/typescript-darwin-x64': 7.0.2 + '@typescript/typescript-freebsd-arm64': 7.0.2 + '@typescript/typescript-freebsd-x64': 7.0.2 + '@typescript/typescript-linux-arm': 7.0.2 + '@typescript/typescript-linux-arm64': 7.0.2 + '@typescript/typescript-linux-loong64': 7.0.2 + '@typescript/typescript-linux-mips64el': 7.0.2 + '@typescript/typescript-linux-ppc64': 7.0.2 + '@typescript/typescript-linux-riscv64': 7.0.2 + '@typescript/typescript-linux-s390x': 7.0.2 + '@typescript/typescript-linux-x64': 7.0.2 + '@typescript/typescript-netbsd-arm64': 7.0.2 + '@typescript/typescript-netbsd-x64': 7.0.2 + '@typescript/typescript-openbsd-arm64': 7.0.2 + '@typescript/typescript-openbsd-x64': 7.0.2 + '@typescript/typescript-sunos-x64': 7.0.2 + '@typescript/typescript-win32-arm64': 7.0.2 + '@typescript/typescript-win32-x64': 7.0.2 + optional: true + + ufo@1.6.4: {} uint8array-extras@1.5.0: {} + unbash@4.0.11: {} + unbox-primitive@1.1.0: dependencies: call-bound: 1.0.4 @@ -15184,11 +14435,15 @@ snapshots: has-symbols: 1.1.0 which-boxed-primitive: 1.1.1 - undici-types@6.21.0: {} + undici-types@7.18.2: {} + + undici-types@8.9.0: {} - undici-types@7.16.0: {} + undici@7.29.0: {} - undici@7.14.0: {} + undici@7.29.1: {} + + undici@8.10.2: {} unenv@2.0.0-rc.24: dependencies: @@ -15215,20 +14470,22 @@ snapshots: unpipe@1.0.0: {} - unplugin@2.3.11: + unplugin@3.4.0(esbuild@0.28.2)(rolldown@1.2.9)(rollup@4.63.3)(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)): dependencies: '@jridgewell/remapping': 2.3.5 - acorn: 8.15.0 - picomatch: 4.0.3 + picomatch: 4.0.7 webpack-virtual-modules: 0.6.2 - - until-async@3.0.2: {} + optionalDependencies: + esbuild: 0.28.2 + rolldown: 1.2.9 + rollup: 4.63.3 + vite: 8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1) upath@1.2.0: {} - update-browserslist-db@1.2.2(browserslist@4.28.1): + update-browserslist-db@1.3.3(browserslist@4.29.0): dependencies: - browserslist: 4.28.1 + browserslist: 4.29.0 escalade: 3.2.0 picocolors: 1.1.1 @@ -15236,43 +14493,36 @@ snapshots: dependencies: punycode: 2.3.1 - url-parse@1.5.10: - dependencies: - querystringify: 2.2.0 - requires-port: 1.0.0 - - use-callback-ref@1.3.3(@types/react@19.2.6)(react@19.2.0): + use-callback-ref@1.3.3(@types/react@19.3.0)(react@19.3.0): dependencies: - react: 19.2.0 + react: 19.3.0 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - use-sidecar@1.1.3(@types/react@19.2.6)(react@19.2.0): + use-sidecar@1.1.3(@types/react@19.3.0)(react@19.3.0): dependencies: detect-node-es: 1.1.0 - react: 19.2.0 + react: 19.3.0 tslib: 2.8.1 optionalDependencies: - '@types/react': 19.2.6 + '@types/react': 19.3.0 - use-sync-external-store@1.6.0(react@19.2.0): + use-sync-external-store@1.7.0(react@19.3.0): dependencies: - react: 19.2.0 + react: 19.3.0 util-deprecate@1.0.2: {} - uuid@10.0.0: {} - - uuid@8.3.2: {} + validate-npm-package-name@7.0.2: {} vary@1.1.2: {} - vaul@1.1.2(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + vaul@1.1.2(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0): dependencies: - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.6))(@types/react@19.2.6)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) + '@radix-ui/react-dialog': 1.1.23(@types/react-dom@19.3.0(@types/react@19.3.0))(@types/react@19.3.0)(react-dom@19.3.0(react@19.3.0))(react@19.3.0) + react: 19.3.0 + react-dom: 19.3.0(react@19.3.0) transitivePeerDependencies: - '@types/react' - '@types/react-dom' @@ -15283,7 +14533,7 @@ snapshots: '@types/d3-ease': 3.0.2 '@types/d3-interpolate': 3.0.4 '@types/d3-scale': 4.0.9 - '@types/d3-shape': 3.1.7 + '@types/d3-shape': 3.2.0 '@types/d3-time': 3.0.4 '@types/d3-timer': 3.0.2 d3-array: 3.2.4 @@ -15294,57 +14544,98 @@ snapshots: d3-time: 3.1.0 d3-timer: 3.0.1 - vite-plugin-pwa@1.1.0(rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6))(workbox-build@7.3.0(@types/babel__core@7.20.5))(workbox-window@7.4.0): + vite-plugin-pwa@1.3.0(supports-color@10.2.2)(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1))(workbox-build@7.4.1(supports-color@10.2.2))(workbox-window@7.4.1): dependencies: - debug: 4.4.3 + debug: 4.4.3(supports-color@10.2.2) pretty-bytes: 6.1.1 - tinyglobby: 0.2.15 - vite: rolldown-vite@7.2.7(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6) - workbox-build: 7.3.0(@types/babel__core@7.20.5) - workbox-window: 7.4.0 + tinyglobby: 0.2.17 + vite: 8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1) + workbox-build: 7.4.1(supports-color@10.2.2) + workbox-window: 7.4.1 transitivePeerDependencies: - supports-color - vitest@4.0.13(@opentelemetry/api@1.9.0)(@types/node@24.10.1)(@vitest/ui@4.0.13)(esbuild@0.27.0)(jiti@2.6.1)(jsdom@27.2.0)(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3))(terser@5.44.1)(tsx@4.20.6): - dependencies: - '@vitest/expect': 4.0.13 - '@vitest/mocker': 4.0.13(msw@2.12.4(@types/node@24.10.1)(typescript@5.9.3))(rolldown-vite@7.1.14(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6)) - '@vitest/pretty-format': 4.0.13 - '@vitest/runner': 4.0.13 - '@vitest/snapshot': 4.0.13 - '@vitest/spy': 4.0.13 - '@vitest/utils': 4.0.13 - debug: 4.4.3 - es-module-lexer: 1.7.0 - expect-type: 1.2.2 - magic-string: 0.30.21 - pathe: 2.0.3 - picomatch: 4.0.3 - std-env: 3.10.0 - tinybench: 2.9.0 - tinyexec: 0.3.2 - tinyglobby: 0.2.15 - tinyrainbow: 3.0.3 - vite: rolldown-vite@7.1.14(@types/node@24.10.1)(esbuild@0.27.0)(jiti@2.6.1)(terser@5.44.1)(tsx@4.20.6) + vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.28 + rolldown: 1.2.9 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 24.13.5 + esbuild: 0.28.2 + fsevents: 2.3.3 + jiti: 2.6.1 + terser: 5.51.2 + tsx: 4.23.13 + yaml: 2.9.1 + + vite@8.3.0(@types/node@26.6.1)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1): + dependencies: + lightningcss: 1.33.0 + picomatch: 4.0.7 + postcss: 8.5.28 + rolldown: 1.2.9 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 26.6.1 + esbuild: 0.28.2 + fsevents: 2.3.3 + jiti: 2.6.1 + terser: 5.51.2 + tsx: 4.23.13 + yaml: 2.9.1 + + vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@24.13.5)(@vitest/coverage-v8@5.0.1)(@vitest/ui@5.0.1)(jsdom@30.1.0(@noble/hashes@2.4.0))(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)): + dependencies: + '@types/chai': 5.2.3 + '@vitest/mocker': 5.0.1(vite@8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) + chai: 6.2.2 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 + magic-string: 1.4.1 + obug: 2.2.1 + picomatch: 4.0.7 + std-env: 4.2.0 + tinybench: 6.1.4 + tinyexec: 1.3.0 + tinyglobby: 0.2.17 + vite: 8.3.0(@types/node@24.13.5)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1) why-is-node-running: 2.3.0 optionalDependencies: - '@opentelemetry/api': 1.9.0 - '@types/node': 24.10.1 - '@vitest/ui': 4.0.13(vitest@4.0.13) - jsdom: 27.2.0 + '@opentelemetry/api': 1.9.1 + '@types/node': 24.13.5 + '@vitest/coverage-v8': 5.0.1(vitest@5.0.1) + '@vitest/ui': 5.0.1(vitest@5.0.1) + jsdom: 30.1.0(@noble/hashes@2.4.0) + transitivePeerDependencies: + - msw + + vitest@5.0.1(@opentelemetry/api@1.9.1)(@types/node@26.6.1)(@vitest/coverage-v8@5.0.1)(@vitest/ui@5.0.1)(jsdom@30.1.0(@noble/hashes@2.4.0))(vite@8.3.0(@types/node@26.6.1)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)): + dependencies: + '@types/chai': 5.2.3 + '@vitest/mocker': 5.0.1(vite@8.3.0(@types/node@26.6.1)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1)) + chai: 6.2.2 + es-module-lexer: 2.3.2 + expect-type: 1.4.0 + magic-string: 1.4.1 + obug: 2.2.1 + picomatch: 4.0.7 + std-env: 4.2.0 + tinybench: 6.1.4 + tinyexec: 1.3.0 + tinyglobby: 0.2.17 + vite: 8.3.0(@types/node@26.6.1)(esbuild@0.28.2)(jiti@2.6.1)(terser@5.51.2)(tsx@4.23.13)(yaml@2.9.1) + why-is-node-running: 2.3.0 + optionalDependencies: + '@opentelemetry/api': 1.9.1 + '@types/node': 26.6.1 + '@vitest/coverage-v8': 5.0.1(vitest@5.0.1) + '@vitest/ui': 5.0.1(vitest@5.0.1) + jsdom: 30.1.0(@noble/hashes@2.4.0) transitivePeerDependencies: - - esbuild - - jiti - - less - msw - - sass - - sass-embedded - - stylus - - sugarss - - supports-color - - terser - - tsx - - yaml w3c-xmlserializer@5.0.0: dependencies: @@ -15352,30 +14643,27 @@ snapshots: walk-up-path@4.0.0: {} - web-streams-polyfill@3.3.3: {} - - webidl-conversions@4.0.2: {} - - webidl-conversions@8.0.0: {} + webidl-conversions@8.0.1: {} webpack-virtual-modules@0.6.2: {} - whatwg-encoding@3.1.1: - dependencies: - iconv-lite: 0.6.3 - - whatwg-mimetype@4.0.0: {} + whatwg-mimetype@5.0.0: {} - whatwg-url@15.1.0: + whatwg-url@16.0.1(@noble/hashes@2.4.0): dependencies: + '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) tr46: 6.0.0 - webidl-conversions: 8.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' - whatwg-url@7.1.0: + whatwg-url@17.1.1(@noble/hashes@2.4.0): dependencies: - lodash.sortby: 4.7.0 - tr46: 1.0.1 - webidl-conversions: 4.0.2 + '@exodus/bytes': 1.15.1(@noble/hashes@2.4.0) + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' when-exit@2.1.5: {} @@ -15390,7 +14678,7 @@ snapshots: which-builtin-type@1.2.1: dependencies: call-bound: 1.0.4 - function.prototype.name: 1.1.8 + function.prototype.name: 1.2.0 has-tostringtag: 1.0.2 is-async-function: 2.1.1 is-date-object: 1.1.0 @@ -15401,7 +14689,7 @@ snapshots: isarray: 2.0.5 which-boxed-primitive: 1.1.1 which-collection: 1.0.2 - which-typed-array: 1.1.19 + which-typed-array: 1.1.23 which-collection@1.0.2: dependencies: @@ -15412,10 +14700,10 @@ snapshots: which-module@2.0.1: {} - which-typed-array@1.1.19: + which-typed-array@1.1.23: dependencies: available-typed-arrays: 1.0.7 - call-bind: 1.0.8 + call-bind: 1.0.9 call-bound: 1.0.4 for-each: 0.3.5 get-proto: 1.0.1 @@ -15428,7 +14716,11 @@ snapshots: which@4.0.0: dependencies: - isexe: 3.1.1 + isexe: 3.1.5 + + which@7.0.0: + dependencies: + isexe: 4.0.0 why-is-node-running@2.3.0: dependencies: @@ -15437,148 +14729,142 @@ snapshots: word-wrap@1.2.5: {} - workbox-background-sync@7.3.0: + workbox-background-sync@7.4.1: dependencies: idb: 7.1.1 - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-broadcast-update@7.3.0: + workbox-broadcast-update@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-build@7.3.0(@types/babel__core@7.20.5): + workbox-build@7.4.1(supports-color@10.2.2): dependencies: - '@apideck/better-ajv-errors': 0.3.6(ajv@8.17.1) - '@babel/core': 7.28.5 - '@babel/preset-env': 7.28.5(@babel/core@7.28.5) - '@babel/runtime': 7.28.4 - '@rollup/plugin-babel': 5.3.1(@babel/core@7.28.5)(@types/babel__core@7.20.5)(rollup@2.79.2) - '@rollup/plugin-node-resolve': 15.3.1(rollup@2.79.2) - '@rollup/plugin-replace': 2.4.2(rollup@2.79.2) - '@rollup/plugin-terser': 0.4.4(rollup@2.79.2) - '@surma/rollup-plugin-off-main-thread': 2.2.3 - ajv: 8.17.1 + '@apideck/better-ajv-errors': 0.3.7(ajv@8.20.0) + '@babel/core': 7.29.7(supports-color@10.2.2) + '@babel/preset-env': 7.29.7(@babel/core@7.29.7(supports-color@10.2.2))(supports-color@10.2.2) + '@babel/runtime': 7.29.7 + '@rollup/plugin-babel': 6.1.0(@babel/core@7.29.7(supports-color@10.2.2))(rollup@4.63.3)(supports-color@10.2.2) + '@rollup/plugin-node-resolve': 16.0.3(rollup@4.63.3) + '@rollup/plugin-replace': 6.0.3(rollup@4.63.3) + '@rollup/plugin-terser': 1.0.0(rollup@4.63.3) + '@trickfilm400/rollup-plugin-off-main-thread': 3.0.0-pre1 + ajv: 8.20.0 common-tags: 1.8.2 + eta: 4.6.0 fast-json-stable-stringify: 2.1.0 fs-extra: 9.1.0 - glob: 7.2.3 - lodash: 4.17.21 + glob: 11.1.0 pretty-bytes: 5.6.0 - rollup: 2.79.2 - source-map: 0.8.0-beta.0 + rollup: 4.63.3 + source-map: 0.8.0 stringify-object: 3.3.0 strip-comments: 2.0.1 tempy: 0.6.0 upath: 1.2.0 - workbox-background-sync: 7.3.0 - workbox-broadcast-update: 7.3.0 - workbox-cacheable-response: 7.3.0 - workbox-core: 7.3.0 - workbox-expiration: 7.3.0 - workbox-google-analytics: 7.3.0 - workbox-navigation-preload: 7.3.0 - workbox-precaching: 7.3.0 - workbox-range-requests: 7.3.0 - workbox-recipes: 7.3.0 - workbox-routing: 7.3.0 - workbox-strategies: 7.3.0 - workbox-streams: 7.3.0 - workbox-sw: 7.3.0 - workbox-window: 7.3.0 + workbox-background-sync: 7.4.1 + workbox-broadcast-update: 7.4.1 + workbox-cacheable-response: 7.4.1 + workbox-core: 7.4.1 + workbox-expiration: 7.4.1 + workbox-google-analytics: 7.4.1 + workbox-navigation-preload: 7.4.1 + workbox-precaching: 7.4.1 + workbox-range-requests: 7.4.1 + workbox-recipes: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 + workbox-streams: 7.4.1 + workbox-sw: 7.4.1 + workbox-window: 7.4.1 transitivePeerDependencies: - '@types/babel__core' - supports-color - workbox-cacheable-response@7.3.0: + workbox-cacheable-response@7.4.1: dependencies: - workbox-core: 7.3.0 - - workbox-core@7.3.0: {} + workbox-core: 7.4.1 - workbox-core@7.4.0: {} + workbox-core@7.4.1: {} - workbox-expiration@7.3.0: + workbox-expiration@7.4.1: dependencies: idb: 7.1.1 - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-google-analytics@7.3.0: + workbox-google-analytics@7.4.1: dependencies: - workbox-background-sync: 7.3.0 - workbox-core: 7.3.0 - workbox-routing: 7.3.0 - workbox-strategies: 7.3.0 + workbox-background-sync: 7.4.1 + workbox-core: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 - workbox-navigation-preload@7.3.0: + workbox-navigation-preload@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-precaching@7.3.0: + workbox-precaching@7.4.1: dependencies: - workbox-core: 7.3.0 - workbox-routing: 7.3.0 - workbox-strategies: 7.3.0 + workbox-core: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 - workbox-range-requests@7.3.0: + workbox-range-requests@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-recipes@7.3.0: + workbox-recipes@7.4.1: dependencies: - workbox-cacheable-response: 7.3.0 - workbox-core: 7.3.0 - workbox-expiration: 7.3.0 - workbox-precaching: 7.3.0 - workbox-routing: 7.3.0 - workbox-strategies: 7.3.0 + workbox-cacheable-response: 7.4.1 + workbox-core: 7.4.1 + workbox-expiration: 7.4.1 + workbox-precaching: 7.4.1 + workbox-routing: 7.4.1 + workbox-strategies: 7.4.1 - workbox-routing@7.3.0: + workbox-routing@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-strategies@7.3.0: + workbox-strategies@7.4.1: dependencies: - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-streams@7.3.0: + workbox-streams@7.4.1: dependencies: - workbox-core: 7.3.0 - workbox-routing: 7.3.0 + workbox-core: 7.4.1 + workbox-routing: 7.4.1 - workbox-sw@7.3.0: {} + workbox-sw@7.4.1: {} - workbox-window@7.3.0: + workbox-window@7.4.1: dependencies: '@types/trusted-types': 2.0.7 - workbox-core: 7.3.0 + workbox-core: 7.4.1 - workbox-window@7.4.0: - dependencies: - '@types/trusted-types': 2.0.7 - workbox-core: 7.4.0 - - workerd@1.20251118.0: + workerd@1.20260918.1: optionalDependencies: - '@cloudflare/workerd-darwin-64': 1.20251118.0 - '@cloudflare/workerd-darwin-arm64': 1.20251118.0 - '@cloudflare/workerd-linux-64': 1.20251118.0 - '@cloudflare/workerd-linux-arm64': 1.20251118.0 - '@cloudflare/workerd-windows-64': 1.20251118.0 + '@cloudflare/workerd-darwin-64': 1.20260918.1 + '@cloudflare/workerd-darwin-arm64': 1.20260918.1 + '@cloudflare/workerd-linux-64': 1.20260918.1 + '@cloudflare/workerd-linux-arm64': 1.20260918.1 + '@cloudflare/workerd-windows-64': 1.20260918.1 - wrangler@4.50.0(@cloudflare/workers-types@4.20251121.0): + wrangler@4.135.0(@cloudflare/workers-types@5.20260918.1)(@types/node@24.13.5): dependencies: - '@cloudflare/kv-asset-handler': 0.4.0 - '@cloudflare/unenv-preset': 2.7.11(unenv@2.0.0-rc.24)(workerd@1.20251118.0) + '@cloudflare/kv-asset-handler': 0.5.0 + '@cloudflare/unenv-preset': 2.16.1(unenv@2.0.0-rc.24)(workerd@1.20260918.1) blake3-wasm: 2.1.5 - esbuild: 0.27.0 - miniflare: 4.20251118.1 + esbuild: 0.28.2 + miniflare: 5.20260918.0-alpha(@types/node@24.13.5) path-to-regexp: 6.3.0 unenv: 2.0.0-rc.24 - workerd: 1.20251118.0 + workerd: 1.20260918.1 optionalDependencies: - '@cloudflare/workers-types': 4.20251121.0 + '@cloudflare/workers-types': 5.20260918.1 fsevents: 2.3.3 transitivePeerDependencies: + - '@types/node' - bufferutil - utf-8-validate @@ -15594,11 +14880,11 @@ snapshots: string-width: 4.2.3 strip-ansi: 6.0.1 - wrap-ansi@8.1.0: + wrap-ansi@9.0.2: dependencies: ansi-styles: 6.2.3 - string-width: 5.1.2 - strip-ansi: 7.1.2 + string-width: 7.2.0 + strip-ansi: 7.2.0 wrappy@1.0.2: {} @@ -15609,17 +14895,20 @@ snapshots: signal-exit: 3.0.7 typedarray-to-buffer: 3.1.5 - ws@8.17.1: {} + ws@8.21.0: {} - ws@8.18.0: {} + ws@8.21.3: {} - ws@8.18.3: {} + wsl-utils@1.0.0: + dependencies: + is-wsl: 3.1.1 + powershell-utils: 0.1.0 xml-name-validator@5.0.0: {} - xmlchars@2.2.0: {} + xml-naming@0.3.0: {} - xtend@4.0.2: {} + xmlchars@2.2.0: {} y18n@4.0.3: {} @@ -15627,6 +14916,10 @@ snapshots: yallist@3.1.1: {} + yallist@5.0.0: {} + + yaml@2.9.1: {} + yargs-parser@18.1.3: dependencies: camelcase: 5.3.1 @@ -15634,6 +14927,8 @@ snapshots: yargs-parser@21.1.1: {} + yargs-parser@22.0.0: {} + yargs@15.4.1: dependencies: cliui: 6.0.0 @@ -15648,7 +14943,7 @@ snapshots: y18n: 4.0.3 yargs-parser: 18.1.3 - yargs@17.7.2: + yargs@17.7.3: dependencies: cliui: 8.0.1 escalade: 3.2.0 @@ -15658,35 +14953,44 @@ snapshots: y18n: 5.0.8 yargs-parser: 21.1.1 + yargs@18.0.0: + dependencies: + cliui: 9.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + string-width: 7.2.0 + y18n: 5.0.8 + yargs-parser: 22.0.0 + yocto-queue@0.1.0: {} - yoctocolors-cjs@2.1.3: {} + yocto-spinner@1.2.2: + dependencies: + yoctocolors: 2.2.0 - yoctocolors@2.1.2: {} + yoctocolors@2.2.0: {} youch-core@0.3.3: dependencies: - '@poppinss/exception': 1.2.2 + '@poppinss/exception': 1.2.3 error-stack-parser-es: 1.0.5 youch@4.1.0-beta.10: dependencies: - '@poppinss/colors': 4.1.5 + '@poppinss/colors': 4.1.6 '@poppinss/dumper': 0.6.5 - '@speed-highlight/core': 1.2.12 - cookie: 1.0.2 + '@speed-highlight/core': 1.2.24 + cookie: 1.1.1 youch-core: 0.3.3 - zod-to-json-schema@3.25.0(zod@3.25.76): + zod-to-json-schema@3.25.2(zod@3.25.76): dependencies: zod: 3.25.76 - zod-validation-error@4.0.2(zod@4.1.12): + zod-validation-error@4.0.2(zod@4.6.5): dependencies: - zod: 4.1.12 - - zod@3.22.3: {} + zod: 4.6.5 zod@3.25.76: {} - zod@4.1.12: {} + zod@4.6.5: {} diff --git a/pnpm-workspace.yaml b/pnpm-workspace.yaml index dee51e92..7a2a180b 100644 --- a/pnpm-workspace.yaml +++ b/pnpm-workspace.yaml @@ -1,2 +1,15 @@ packages: - "packages/*" + +# Build only the native dependencies used by this workspace. +allowBuilds: + "@swc/core": true + "bcrypt": true + "better-sqlite3": true + "esbuild": true + "msw": true + "sharp": true + "workerd": true + +overrides: + esbuild: ">=0.28.1" From 2498efab6f57b95689ea6d015378433a0852a6ef Mon Sep 17 00:00:00 2001 From: KyleTryon Date: Sat, 19 Sep 2026 20:33:57 -0400 Subject: [PATCH 2/2] fix: restore clean builds and accurate ingestion alerts --- docs/release-checklist.md | 2 +- .../__tests__/feed-reliability.test.ts | 18 +++++++++++++ packages/api/src/services/feed-health.ts | 3 ++- packages/app/package.json | 2 +- .../app/src/lib/api/generated/client/index.ts | 26 ------------------- packages/app/src/lib/api/generated/index.ts | 4 --- 6 files changed, 22 insertions(+), 33 deletions(-) delete mode 100644 packages/app/src/lib/api/generated/client/index.ts delete mode 100644 packages/app/src/lib/api/generated/index.ts diff --git a/docs/release-checklist.md b/docs/release-checklist.md index 729daeb0..54b3b99a 100644 --- a/docs/release-checklist.md +++ b/docs/release-checklist.md @@ -13,7 +13,7 @@ This release fixes feed starvation, hardens ingestion and authentication, update ## 1. Review and validate the PR - [ ] Review the dependency changes, security changes, migration SQL, and API response changes. -- [ ] Run `pnpm install --frozen-lockfile`, `pnpm pre-check`, and `pnpm test` with the supported toolchain. +- [ ] Run `pnpm install --frozen-lockfile`, `pnpm build:tricorder`, `pnpm pre-check`, and `pnpm test` with the supported toolchain. Build Tricorder first on a clean checkout, as CI does, so its workspace exports are available. - [ ] Require CI success, including Docker validation. Local verification passed 1,584 tests across 108 files, with five existing skips; lint, formatting, types, builds, Worker dry-run, and desktop/mobile smoke checks passed. Docker validation remains pending because the local daemon was unavailable. - [ ] Rehearse an upgrade on a disposable database with existing sources, articles, subscriptions, and read/saved state. Record row counts and representative timestamps before and after. Also verify a fresh installation. - [ ] Check staging login/logout, article filters and pagination, read/saved state, feed refresh, error/retry display, and a healthy feed recovering after an induced failure. diff --git a/packages/api/src/services/__tests__/feed-reliability.test.ts b/packages/api/src/services/__tests__/feed-reliability.test.ts index bd35ac6c..14d59d75 100644 --- a/packages/api/src/services/__tests__/feed-reliability.test.ts +++ b/packages/api/src/services/__tests__/feed-reliability.test.ts @@ -146,4 +146,22 @@ describe("feed reliability", () => { } expect(alert).toHaveBeenCalledTimes(1); }); + + it("treats unchanged successful feeds as recovery despite other failures", async () => { + const alert = vi.spyOn(Sentry, "captureMessage"); + const failed = { backlog: 50, errors: 20, added: 0, processed: 20 }; + await recordFeedBatchHealth(db, failed); + await recordFeedBatchHealth(db, failed); + for (let batch = 0; batch < 3; batch++) { + await recordFeedBatchHealth(db, { ...failed, errors: 1 }); + } + const [health] = await db.select().from(schema.feedFetchHealth); + expect(health?.failingBatches).toBe(0); + expect(alert).not.toHaveBeenCalled(); + await recordFeedBatchHealth(db, failed); + await recordFeedBatchHealth(db, failed); + expect(alert).not.toHaveBeenCalled(); + await recordFeedBatchHealth(db, failed); + expect(alert).toHaveBeenCalledTimes(1); + }); }); diff --git a/packages/api/src/services/feed-health.ts b/packages/api/src/services/feed-health.ts index 0ff4033b..dec7c871 100644 --- a/packages/api/src/services/feed-health.ts +++ b/packages/api/src/services/feed-health.ts @@ -14,7 +14,8 @@ export async function recordFeedBatchHealth( } ): Promise { if (batch.processed === 0) return; - const stalled = batch.errors > 0 && batch.added === 0; + // A successful fetch is progress even when the publisher has no new articles. + const stalled = batch.errors === batch.processed; const [health] = await db .insert(feedFetchHealth) .values({ diff --git a/packages/app/package.json b/packages/app/package.json index 4b6c2746..154525e8 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -10,7 +10,7 @@ "preview": "vite preview", "generate:routes": "tsr generate", "generate:icons": "node scripts/generate-icons.mjs", - "type-check": "tsc --noEmit -p tsconfig.app.json && tsc --noEmit -p tsconfig.node.json", + "type-check": "pnpm run generate:routes && tsc --noEmit -p tsconfig.app.json && tsc --noEmit -p tsconfig.node.json", "knip": "knip", "format": "prettier --write .", "format:check": "prettier --check .", diff --git a/packages/app/src/lib/api/generated/client/index.ts b/packages/app/src/lib/api/generated/client/index.ts deleted file mode 100644 index 6dd96c7e..00000000 --- a/packages/app/src/lib/api/generated/client/index.ts +++ /dev/null @@ -1,26 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type { Auth } from "../core/auth.gen"; -export type { QuerySerializerOptions } from "../core/bodySerializer.gen"; -export { - formDataBodySerializer, - jsonBodySerializer, - urlSearchParamsBodySerializer, -} from "../core/bodySerializer.gen"; -export { buildClientParams } from "../core/params.gen"; -export { serializeQueryKeyValue } from "../core/queryKeySerializer.gen"; -export { createClient } from "./client.gen"; -export type { - Client, - ClientOptions, - Config, - CreateClientConfig, - Options, - OptionsLegacyParser, - RequestOptions, - RequestResult, - ResolvedRequestOptions, - ResponseStyle, - TDataShape, -} from "./types.gen"; -export { createConfig, mergeHeaders } from "./utils.gen"; diff --git a/packages/app/src/lib/api/generated/index.ts b/packages/app/src/lib/api/generated/index.ts deleted file mode 100644 index 7a716924..00000000 --- a/packages/app/src/lib/api/generated/index.ts +++ /dev/null @@ -1,4 +0,0 @@ -// This file is auto-generated by @hey-api/openapi-ts - -export type * from "./types.gen"; -export * from "./sdk.gen";