From ba6e06a9a3b31124d6c37475b5667dd70ab42379 Mon Sep 17 00:00:00 2001 From: Jake Wang Date: Mon, 7 Sep 2026 03:56:54 -0400 Subject: [PATCH] Harden capture, transactional history and release workflows for 2.1.0 --- .github/workflows/ci.yml | 77 +++- .github/workflows/publish-mcp.yml | 70 ++-- .github/workflows/release.yml | 166 +++++--- .gitignore | 1 + README.md | 44 ++- VERSION | 2 +- api/go.mod | 18 +- api/go.sum | 45 +-- api/main.go | 32 +- api/server/api_test.go | 4 +- api/server/console.go | 68 +++- api/server/demo.go | 130 ++++--- api/server/demo_test.go | 30 +- api/server/events.go | 35 ++ api/server/router.go | 155 ++++++-- api/server/security_test.go | 101 +++++ api/server/ui/dist/.source | 3 +- api/server/ui/dist/assets/index-3FWB-cCO.js | 51 +++ api/server/ui/dist/assets/index-B-ZQhslv.css | 1 - api/server/ui/dist/assets/index-Cpj3B2v5.css | 1 + api/server/ui/dist/assets/index-roLBxi3d.js | 67 ---- api/server/ui/dist/index.html | 4 +- cli/cmd/branches.go | 33 +- cli/cmd/checkout.go | 19 +- cli/cmd/cli_test.go | 196 ++++++++++ cli/cmd/collections.go | 40 ++ cli/cmd/console.go | 25 +- cli/cmd/doctor.go | 222 +++++++++++ cli/cmd/gc.go | 3 +- cli/cmd/import.go | 44 +-- cli/cmd/mcp.go | 3 +- cli/cmd/merge.go | 37 +- cli/cmd/metrics.go | 3 +- cli/cmd/migrate.go | 3 +- cli/cmd/output.go | 31 ++ cli/cmd/pin.go | 33 +- cli/cmd/projects.go | 18 +- cli/cmd/proxy.go | 3 +- cli/cmd/restore.go | 21 +- cli/cmd/root.go | 90 ++--- cli/cmd/sandbox.go | 29 +- cli/cmd/services.go | 66 ++++ cli/cmd/snapshot.go | 18 +- cli/cmd/status.go | 52 +-- cli/cmd/timetravel.go | 61 +-- cli/cmd/undo.go | 46 ++- cli/cmd/watch.go | 14 +- cli/go.mod | 26 +- cli/go.sum | 48 +-- compat/mongoose/compat.test.mjs | 4 + compat/pymongo/test_compat.py | 4 + docs/AGENTS.md | 47 ++- docs/ARCHITECTURE.md | 100 +++-- docs/CLI.md | 40 +- docs/OPERATIONS.md | 91 ++++- docs/PERFORMANCE.md | 17 +- docs/QUICK_START.md | 127 +++--- docs/RELEASE_2_1.md | 71 ++++ examples/pinned_agents.py | 83 ++++ go.mod | 20 +- go.sum | 38 +- internal/branch/wal/capture.go | 23 ++ internal/branch/wal/service.go | 164 ++++++-- internal/checkout/service.go | 107 +++++- internal/ingest/errors_test.go | 65 ++++ internal/ingest/lifecycle.go | 382 +++++++++++++++++++ internal/ingest/service.go | 370 ++++++++++++++---- internal/materializer/keys_test.go | 34 ++ internal/materializer/service.go | 65 +++- internal/merge/keys_test.go | 17 + internal/merge/service.go | 246 ++++++++---- internal/restore/service.go | 30 +- internal/sandbox/service.go | 5 +- internal/snapshot/auto.go | 71 +++- internal/snapshot/codec.go | 21 +- internal/snapshot/gc.go | 14 +- internal/snapshot/locking.go | 51 +++ internal/snapshot/service.go | 46 ++- internal/undo/service.go | 210 +++++++--- internal/wal/docid.go | 146 ++++++- internal/wal/docid_test.go | 48 +++ internal/wal/models.go | 44 ++- internal/wal/service.go | 68 +++- internal/walwriter/writer.go | 133 +++++-- npm/README.md | 33 +- npm/package.json | 13 +- npm/scripts/install.js | 141 +++---- npm/scripts/install.test.js | 60 +++ pkg/mcpserver/server.go | 90 +++-- pkg/mcpserver/tools.go | 42 +- pkg/version/version.go | 20 + pkg/walcli/services.go | 131 ++++++- scripts/publish-npm.sh | 73 ++-- scripts/release-version.js | 56 +++ scripts/release-version.test.js | 26 ++ scripts/sync-ui.sh | 12 +- server.json | 4 +- tests/wal/capture_hardening_test.go | 283 ++++++++++++++ tests/wal/checkout_test.go | 2 + tests/wal/hardening_core_test.go | 286 ++++++++++++++ tests/wal/ingest_test.go | 7 +- tests/wal/performance_checks_test.go | 52 +++ tests/wal/snapshot_shutdown_test.go | 127 ++++++ tests/wal/timetravel_performance_test.go | 10 +- tests/wal/timetravel_test.go | 13 +- tests/wal/undo_hardening_test.go | 131 +++++++ tests/wal/wal_stress_test.go | 43 ++- tests/wal/write_performance_test.go | 22 +- version.go | 9 + 109 files changed, 5553 insertions(+), 1424 deletions(-) create mode 100644 api/server/events.go create mode 100644 api/server/security_test.go create mode 100644 api/server/ui/dist/assets/index-3FWB-cCO.js delete mode 100644 api/server/ui/dist/assets/index-B-ZQhslv.css create mode 100644 api/server/ui/dist/assets/index-Cpj3B2v5.css delete mode 100644 api/server/ui/dist/assets/index-roLBxi3d.js create mode 100644 cli/cmd/cli_test.go create mode 100644 cli/cmd/collections.go create mode 100644 cli/cmd/doctor.go create mode 100644 cli/cmd/output.go create mode 100644 cli/cmd/services.go create mode 100644 docs/RELEASE_2_1.md create mode 100644 examples/pinned_agents.py create mode 100644 internal/branch/wal/capture.go create mode 100644 internal/ingest/errors_test.go create mode 100644 internal/ingest/lifecycle.go create mode 100644 internal/materializer/keys_test.go create mode 100644 internal/merge/keys_test.go create mode 100644 internal/snapshot/locking.go create mode 100644 internal/wal/docid_test.go create mode 100644 npm/scripts/install.test.js create mode 100644 pkg/version/version.go create mode 100644 scripts/release-version.js create mode 100644 scripts/release-version.test.js create mode 100644 tests/wal/capture_hardening_test.go create mode 100644 tests/wal/hardening_core_test.go create mode 100644 tests/wal/performance_checks_test.go create mode 100644 tests/wal/snapshot_shutdown_test.go create mode 100644 tests/wal/undo_hardening_test.go create mode 100644 version.go diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b0ad3f4..00224b7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,16 +23,18 @@ jobs: docker exec ci-mongo mongosh --quiet --eval 'db.runCommand({ping: 1})' && break sleep 1 done + docker exec ci-mongo mongosh --quiet --eval 'db.runCommand({ping: 1})' docker exec ci-mongo mongosh --quiet --eval 'rs.initiate({_id: "rs0", members: [{_id: 0, host: "localhost:27017"}]})' for i in $(seq 1 30); do [ "$(docker exec ci-mongo mongosh --quiet --eval 'db.hello().isWritablePrimary')" = "true" ] && break sleep 1 done + test "$(docker exec ci-mongo mongosh --quiet --eval 'db.hello().isWritablePrimary')" = true - name: Set up Go uses: actions/setup-go@v5 with: - go-version: '1.21' + go-version-file: go.mod - name: Cache Go modules uses: actions/cache@v4 @@ -45,6 +47,16 @@ jobs: - name: Download dependencies run: go mod download + - uses: actions/setup-node@v4 + with: + node-version: '22' + + - name: Validate release metadata and installer + run: | + node scripts/release-version.js --check + node --test scripts/release-version.test.js npm/scripts/install.test.js + npm pack --dry-run ./npm + - name: Start MinIO (S3 chunk store backend) run: | docker run -d --name ci-minio -p 9010:9000 \ @@ -54,6 +66,7 @@ jobs: curl -sf http://localhost:9010/minio/health/live && break sleep 1 done + curl -fsS http://localhost:9010/minio/health/live - name: Run tests env: @@ -64,9 +77,13 @@ jobs: AWS_REGION: us-east-1 run: go test -v ./... - - name: Build CLI + - name: Test and build CLI working-directory: ./cli - run: go build -v . + env: + ARGON_TEST_MONGODB_URI: mongodb://localhost:27017/?replicaSet=rs0 + run: | + go test ./... + go build -v . - name: Test API working-directory: ./api @@ -82,7 +99,7 @@ jobs: - name: Set up Go uses: actions/setup-go@v5 with: - go-version: '1.24' + go-version-file: go.mod - name: Set up Python uses: actions/setup-python@v5 @@ -101,11 +118,13 @@ jobs: docker exec compat-mongo mongosh --quiet --eval 'db.runCommand({ping: 1})' && break sleep 1 done + docker exec compat-mongo mongosh --quiet --eval 'db.runCommand({ping: 1})' docker exec compat-mongo mongosh --quiet --eval 'rs.initiate({_id: "rs0", members: [{_id: 0, host: "localhost:27017"}]})' for i in $(seq 1 30); do [ "$(docker exec compat-mongo mongosh --quiet --eval 'db.hello().isWritablePrimary')" = "true" ] && break sleep 1 done + test "$(docker exec compat-mongo mongosh --quiet --eval 'db.hello().isWritablePrimary')" = true - name: Install Python driver run: pip install pymongo pytest @@ -114,19 +133,41 @@ jobs: run: bash compat/run.sh lint: - name: Lint + name: Vet (${{ matrix.module }}) runs-on: ubuntu-latest - + strategy: + matrix: + module: ['.', cli, api] steps: - - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v5 - with: - go-version: '1.21' - - - name: golangci-lint - uses: golangci/golangci-lint-action@v6 - with: - version: latest - args: --timeout=5m \ No newline at end of file + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache-dependency-path: | + go.sum + cli/go.sum + api/go.sum + - name: Go vet + working-directory: ${{ matrix.module }} + run: go vet ./... + + vulnerabilities: + name: Reachable Go vulnerabilities (${{ matrix.module }}) + runs-on: ubuntu-latest + strategy: + matrix: + module: ['.', cli, api] + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache-dependency-path: | + go.sum + cli/go.sum + api/go.sum + - name: Install official vulnerability scanner + run: go install golang.org/x/vuln/cmd/govulncheck@v1.7.0 + - name: Scan reachable dependencies against the current database + working-directory: ${{ matrix.module }} + run: govulncheck ./... diff --git a/.github/workflows/publish-mcp.yml b/.github/workflows/publish-mcp.yml index f3d6e53..1bf6a95 100644 --- a/.github/workflows/publish-mcp.yml +++ b/.github/workflows/publish-mcp.yml @@ -1,53 +1,57 @@ name: Publish to MCP Registry -# Registers io.github.argon-lab/argon in the official MCP Registry. -# Auth is GitHub OIDC (no tokens): the registry trusts that this workflow runs -# in the argon-lab org, which grants the io.github.argon-lab/* namespace. -# -# Prerequisite each publish: argonctl must already be on npm at the target -# version WITH the "mcpName" field (npm publish is manual — see runbook), because -# the registry verifies the published package's mcpName matches server.json. - +# Called explicitly after npm succeeds: release events created with GITHUB_TOKEN +# do not start another workflow. Manual dispatch is available for recovery. on: - release: - types: [published] + workflow_call: + inputs: + version: + description: Published npm version + required: true + type: string workflow_dispatch: inputs: version: - description: "Version to publish, e.g. 2.0.1 (defaults to the release tag)" - required: false + description: Published npm version, for example 2.0.1 + required: true + type: string permissions: contents: read - id-token: write # required for github-oidc login to the registry + id-token: write jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - - - name: Resolve version - id: ver + - uses: actions/setup-node@v4 + with: + node-version: '22' + - name: Validate and stamp the requested version + id: version + env: + RELEASE_VERSION: ${{ inputs.version }} run: | - v="${{ github.event.inputs.version }}" - [ -z "$v" ] && v="${GITHUB_REF_NAME#v}" - echo "version=$v" >> "$GITHUB_OUTPUT" - - - name: Stamp version into server.json + version=$(node scripts/release-version.js "$RELEASE_VERSION") + echo "version=$version" >> "$GITHUB_OUTPUT" + - name: Verify npm publication is visible + env: + RELEASE_VERSION: ${{ steps.version.outputs.version }} run: | - v="${{ steps.ver.outputs.version }}" - tmp=$(mktemp) - jq --arg v "$v" '.version=$v | .packages[0].version=$v' server.json > "$tmp" && mv "$tmp" server.json - cat server.json - + for attempt in $(seq 1 12); do + if [ "$(npm view "argonctl@$RELEASE_VERSION" mcpName 2>/dev/null)" = io.github.argon-lab/argon ]; then + exit 0 + fi + sleep 5 + done + echo 'The matching argonctl package with mcpName is not visible on npm.' >&2 + exit 1 - name: Install mcp-publisher run: | - curl -L "https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_$(uname -s | tr '[:upper:]' '[:lower:]')_$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/').tar.gz" | tar xz mcp-publisher - sudo mv mcp-publisher /usr/local/bin/ - - - name: Authenticate (GitHub OIDC) - run: mcp-publisher login github-oidc - + curl --fail --location --retry 3 --output mcp-publisher.tar.gz https://github.com/modelcontextprotocol/registry/releases/latest/download/mcp-publisher_linux_amd64.tar.gz + tar -xzf mcp-publisher.tar.gz mcp-publisher + - name: Authenticate with GitHub OIDC + run: ./mcp-publisher login github-oidc - name: Publish - run: mcp-publisher publish + run: ./mcp-publisher publish diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 1aade67..242c795 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -2,15 +2,40 @@ name: Release on: push: - tags: - - 'v*' + tags: ['v*'] permissions: - contents: write + contents: read + +concurrency: + group: release-${{ github.ref }} + cancel-in-progress: false jobs: + prepare: + name: Validate release version + runs-on: ubuntu-latest + outputs: + version: ${{ steps.version.outputs.version }} + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + - name: Resolve the authoritative tag + id: version + env: + RELEASE_TAG: ${{ github.ref_name }} + run: | + version=$(node scripts/release-version.js "$RELEASE_TAG") + echo "version=$version" >> "$GITHUB_OUTPUT" + node scripts/release-version.js --check + - name: Check release tooling + run: node --test scripts/release-version.test.js npm/scripts/install.test.js + build: name: Build binaries + needs: prepare runs-on: ubuntu-latest strategy: matrix: @@ -19,75 +44,90 @@ jobs: exclude: - goos: windows goarch: arm64 - steps: - - uses: actions/checkout@v4 - - - name: Set up Go - uses: actions/setup-go@v4 - with: - go-version: '1.21' - - - name: Build binary - working-directory: ./cli - env: - GOOS: ${{ matrix.goos }} - GOARCH: ${{ matrix.goarch }} - run: | - mkdir -p ../dist - if [ "$GOOS" = "windows" ]; then - go build -ldflags="-s -w" -o ../dist/argon-${{ matrix.goos }}-${{ matrix.goarch }}.exe . - else - go build -ldflags="-s -w" -o ../dist/argon-${{ matrix.goos }}-${{ matrix.goarch }} . - fi - - - name: Upload artifacts - uses: actions/upload-artifact@v4 - with: - name: binaries-${{ matrix.goos }}-${{ matrix.goarch }} - path: dist/ + - uses: actions/checkout@v4 + - name: Set up Go + uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache-dependency-path: | + go.sum + cli/go.sum + api/go.sum + - name: Build binary + working-directory: cli + env: + GOOS: ${{ matrix.goos }} + GOARCH: ${{ matrix.goarch }} + CGO_ENABLED: '0' + RELEASE_VERSION: ${{ needs.prepare.outputs.version }} + run: | + mkdir -p ../dist + asset="argon-${GOOS}-${GOARCH}" + if [ "$GOOS" = windows ]; then asset="$asset.exe"; fi + go build -trimpath -ldflags="-s -w -X github.com/argon-lab/argon/pkg/version.Build=$RELEASE_VERSION" -o "../dist/$asset" . + - uses: actions/upload-artifact@v4 + with: + name: binaries-${{ matrix.goos }}-${{ matrix.goarch }} + path: dist/ + if-no-files-found: error release: name: Create release - needs: build + needs: [prepare, build] runs-on: ubuntu-latest + permissions: + contents: write steps: - - uses: actions/checkout@v4 - - - name: Download artifacts - uses: actions/download-artifact@v4 - with: - pattern: binaries-* - path: dist/ - merge-multiple: true - - - name: Create release - uses: softprops/action-gh-release@v1 - with: - files: dist/* - generate_release_notes: true - draft: false - prerelease: false - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + - uses: actions/download-artifact@v4 + with: + pattern: binaries-* + path: dist/ + merge-multiple: true + - name: Generate checksums + working-directory: dist + run: sha256sum argon-* > SHA256SUMS + - name: Create release + uses: softprops/action-gh-release@v2 + with: + files: dist/* + fail_on_unmatched_files: true + generate_release_notes: true + prerelease: ${{ contains(needs.prepare.outputs.version, '-') }} publish-npm: name: Publish to npm - needs: release + needs: [prepare, release] runs-on: ubuntu-latest - # Requires an NPM_TOKEN repo secret — an npm "Automation" (or granular, - # 2FA-bypass) token that owns argonctl, so CI can publish without an OTP. steps: - - uses: actions/checkout@v4 - - - name: Setup Node.js - uses: actions/setup-node@v3 - with: - node-version: '18' - registry-url: 'https://registry.npmjs.org' + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '22' + registry-url: https://registry.npmjs.org + - name: Stamp package from release tag + env: + RELEASE_VERSION: ${{ needs.prepare.outputs.version }} + run: node scripts/release-version.js "$RELEASE_VERSION" + - name: Check package contents + working-directory: npm + run: npm pack --dry-run + - name: Publish to npm + working-directory: npm + env: + NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} + RELEASE_VERSION: ${{ needs.prepare.outputs.version }} + run: | + dist_tag=latest + if [[ "$RELEASE_VERSION" == *-* ]]; then dist_tag=next; fi + npm publish --access public --tag "$dist_tag" - - name: Publish to npm - working-directory: ./npm - run: npm publish --access public - env: - NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }} \ No newline at end of file + publish-mcp: + name: Publish to MCP Registry + needs: [prepare, publish-npm] + permissions: + contents: read + id-token: write + uses: ./.github/workflows/publish-mcp.yml + with: + version: ${{ needs.prepare.outputs.version }} diff --git a/.gitignore b/.gitignore index 4b432bd..b60480d 100644 --- a/.gitignore +++ b/.gitignore @@ -143,6 +143,7 @@ argon_projects.db # Local testing test_dump.archive +.review-artifacts/ # Claude AI assistant files CLAUDE.md diff --git a/README.md b/README.md index 435c1db..4bdc4a9 100644 --- a/README.md +++ b/README.md @@ -18,13 +18,12 @@ versioned history underneath. Built for AI agents.** Three ideas, thirty seconds: -1. **A branch is a pointer, not a copy** — created in milliseconds at any - data size. +1. **A branch is a pointer, not a copy** — created with a metadata write. Checkout separately materializes the data. 2. **`checkout` turns a branch into a real MongoDB database** — pymongo, mongoose, mongosh, indexes, aggregation, transactions: all real, and - every write becomes versioned history. -3. **Nothing is ever lost** — diff it, merge it, undo it, rewind it, or pin - it forever. + supported document writes become history while capture is healthy. +3. **Review and recover changes** — diff, merge, undo and pin states within + the configured retention and capture guarantees. ## Install @@ -33,16 +32,20 @@ brew install argon-lab/tap/argonctl # macOS npm install -g argonctl # cross-platform # MongoDB must run as a replica set (one-node is fine): -docker run -d --name argon-mongo -p 27017:27017 mongo:7 --replSet rs0 -docker exec argon-mongo mongosh --quiet --eval 'rs.initiate()' +docker run -d --name argon-mongo -p 127.0.0.1:27017:27017 mongo:7 --replSet rs0 +docker exec argon-mongo mongosh --quiet --eval 'rs.initiate({_id:"rs0",members:[{_id:0,host:"localhost:27017"}]})' +argon doctor ``` +Use a current supported MongoDB patch release in production. Source builds use +Go 1.26.6 or newer, as declared in `go.mod`. + ## The flow ``` main ──branch──▶ experiment ──checkout──▶ mongodb://… ← any driver │ - ┌── argon diff ──────────┤ every write captured + ┌── argon diff ──────────┤ document history ▼ ▼ merge (a data PR) or undo / discard / rewind ``` @@ -54,9 +57,11 @@ argon import database --uri mongodb://localhost:27017 --database myapp --project # 1 · Branch — instant, no copy argon branches create experiment -p myapp -# 2 · Get a real database for it, capture writes +# 2 · In terminal A, capture writes with a branch actor label argon checkout -p myapp -b experiment # prints a connection string -argon watch -p myapp -b experiment # keep running while you write +argon watch -p myapp -b experiment --actor agent:experiment + +# In terminal B, write through the printed URI. Then: # 3 · Review and merge back — a data pull request argon diff -p myapp -b experiment @@ -67,8 +72,9 @@ argon merge apply argon restore reset -p myapp -b main --time 2026-07-07T09:00:00Z --backup pre-incident ``` -Prefer clicking? `argon console` serves a local web console (UI + REST API) -and opens your browser. +Prefer clicking? `argon console` serves a local web console (UI + REST API), +supervises capture, reaps expired sandboxes every minute, and opens your browser. +For a complete managed workflow, run [the two-agent pinned dataset example](examples/pinned_agents.py). ## What you get @@ -76,16 +82,22 @@ and opens your browser. |---|---|---| | **Branching** | `argon branches create` | a metadata write — instant, zero copy | | **Real databases** | `argon checkout` / `argon proxy` | any driver, real mongod; proxy serves stable `mongodb://host/~` URIs | -| **Write capture** | `argon watch` | change-stream → versioned history, per-actor attribution | +| **Write capture** | `argon watch` | exact change-stream images → history, one actor label per branch | | **Time travel** | `argon time-travel query` | any historical state, by LSN or timestamp | -| **Undo** | `argon undo --actor ` | revert a range or one writer's changes; append-only, conflict-aware | -| **Restore** | `argon restore preview/reset/branch` | rewind a branch or fork history; recorded, never destructive | +| **Undo** | `argon undo --actor ` | revert a range or actor label; append-only, conflict-aware | +| **Restore** | `argon restore preview/reset/branch` | rewind a released branch or fork retained history | | **Data PRs** | `argon merge preview/apply` | three-way merges as reviewable plans; conflicts never silent | | **Sandboxes** | `argon sandbox create --ttl 1h` | fork + checkout + TTL in one step — disposable agent workspaces | | **Dataset pins** | `argon pin create` / `pin sandbox` | immutable named states that survive GC and resets — reproducible evals | | **Web console** | `argon console` | local UI + REST API in one command | -Storage stays bounded: snapshots + retention-window GC keep state plus a +Data history covers document inserts, updates, replacements and deletes. Collection +drop/rename produces degraded capture; indexes and collection options are not +versioned. Native writes are asynchronous; control operations drain capture. +Stop writers before release. Pins preserve states, while GC can expire audit +and undo history. See [operations](docs/OPERATIONS.md) for recovery and credentials. + +Storage retention uses snapshots + retention-window GC keep state plus a window of history, not every write forever. Details and the consistency model, stated honestly: [ARCHITECTURE.md](docs/ARCHITECTURE.md). diff --git a/VERSION b/VERSION index 10bf840..7ec1d6d 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.0.1 \ No newline at end of file +2.1.0 diff --git a/api/go.mod b/api/go.mod index c26967e..0e89aa3 100644 --- a/api/go.mod +++ b/api/go.mod @@ -1,14 +1,12 @@ module github.com/argon-lab/argon/api -go 1.24 - -toolchain go1.24.5 +go 1.26.6 require ( github.com/argon-lab/argon v0.0.0 github.com/gin-gonic/gin v1.9.1 github.com/stretchr/testify v1.9.0 - go.mongodb.org/mongo-driver v1.13.1 + go.mongodb.org/mongo-driver v1.17.7 ) replace github.com/argon-lab/argon => ../ @@ -59,13 +57,13 @@ require ( github.com/xdg-go/pbkdf2 v1.0.0 // indirect github.com/xdg-go/scram v1.1.2 // indirect github.com/xdg-go/stringprep v1.0.4 // indirect - github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a // indirect + github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 // indirect golang.org/x/arch v0.3.0 // indirect - golang.org/x/crypto v0.14.0 // indirect - golang.org/x/net v0.10.0 // indirect - golang.org/x/sync v0.4.0 // indirect - golang.org/x/sys v0.13.0 // indirect - golang.org/x/text v0.13.0 // indirect + golang.org/x/crypto v0.51.0 // indirect + golang.org/x/net v0.55.0 // indirect + golang.org/x/sync v0.21.0 // indirect + golang.org/x/sys v0.45.0 // indirect + golang.org/x/text v0.39.0 // indirect google.golang.org/protobuf v1.30.0 // indirect gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/api/go.sum b/api/go.sum index e984e3d..5434b71 100644 --- a/api/go.sum +++ b/api/go.sum @@ -61,16 +61,14 @@ github.com/go-playground/validator/v10 v10.14.0/go.mod h1:9iXMNT7sEkjXb0I+enO7QX github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU= github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/golang/snappy v0.0.4 h1:yAGX7huGHXlcLOEtBnF4w7FQwA26wojNCwOYAEhLjQM= github.com/golang/snappy v0.0.4/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= +github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= -github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk= github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM= github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= @@ -93,7 +91,6 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd h1:TRLaZ9cD/w github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= -github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= github.com/montanaflynn/stats v0.7.1 h1:etflOAAHORrCC44V+aR6Ftzort912ZU+YLiSTuV8eaE= github.com/montanaflynn/stats v0.7.1/go.mod h1:etXPPgVO6n31NxCd9KQUMvCM+ve0ruNzt6R8Bnaayow= github.com/pelletier/go-toml/v2 v2.0.8 h1:0ctb6s9mE31h0/lhu+J6OPmVeDxJn+kYnJc2jZR9tGQ= @@ -126,59 +123,49 @@ github.com/xdg-go/scram v1.1.2 h1:FHX5I5B4i4hKRVRBCFRxq1iQRej7WO3hhBuJf+UUySY= github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= github.com/xdg-go/stringprep v1.0.4 h1:XLI/Ng3O1Atzq0oBs3TWm+5ZVgkq2aqdlvP9JtoZ6c8= github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= -github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= -github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a h1:fZHgsYlfvtyqToslyjUt3VOPF4J7aK/3MPcK7xp3PDk= -github.com/youmark/pkcs8 v0.0.0-20201027041543-1326539a0a0a/go.mod h1:ul22v+Nro/R083muKhosV54bj5niojjWZvU8xrevuH4= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78 h1:ilQV1hzziu+LLM3zUTJ0trRztfwgjqKnBWNtSRkbmwM= +github.com/youmark/pkcs8 v0.0.0-20240726163527-a2c0da244d78/go.mod h1:aL8wCCfTfSfmXjznFBSZNN13rSJjlIOI1fUNAtF7rmI= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= -go.mongodb.org/mongo-driver v1.13.1 h1:YIc7HTYsKndGK4RFzJ3covLz1byri52x0IoMB0Pt/vk= -go.mongodb.org/mongo-driver v1.13.1/go.mod h1:wcDf1JBCXy2mOW0bWHwO/IOYqdca1MPCwDtFu/Z9+eo= +go.mongodb.org/mongo-driver v1.17.7 h1:a9w+U3Vt67eYzcfq3k/OAv284/uUUkL0uP75VE5rCOU= +go.mongodb.org/mongo-driver v1.17.7/go.mod h1:Hy04i7O2kC4RS06ZrhPRqj/u4DTYkFDAAccj+rVKqgQ= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.3.0 h1:02VY4/ZcO/gBOH6PUaoiptASxtXU10jazRCP865E97k= golang.org/x/arch v0.3.0/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200302210943-78000ba7a073/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/crypto v0.14.0 h1:wBqGXzWJW6m1XrIKlAH0Hs1JJ7+9KBwnIO8v66Q9cHc= -golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4= +golang.org/x/crypto v0.51.0 h1:IBPXwPfKxY7cWQZ38ZCIRPI50YLeevDLlLnyC5wRGTI= +golang.org/x/crypto v0.51.0/go.mod h1:8AdwkbraGNABw2kOX6YFPs3WM22XqI4EXEd8g+x7Oc8= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= -golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M= -golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= +golang.org/x/net v0.55.0 h1:bcvxaJn3e1U6InsFWt1JUq1aSjnRxLzT2rtD2KfkDF8= +golang.org/x/net v0.55.0/go.mod h1:L5U2KuzuOe1lY7Z+aWVIKK6qEeJXnXV9yzGA+WCHJww= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.4.0 h1:zxkM55ReGkDlKSM+Fu41A+zmbZuaPVbGMzvvdUPznYQ= -golang.org/x/sync v0.4.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y= +golang.org/x/sync v0.21.0 h1:HLII4xRRTtCRkxYp4HNFF0Js/Og6q2i++KXbg0gHCwM= +golang.org/x/sync v0.21.0/go.mod h1:9xrNwdLfx4jkKbNva9FpL6vEN7evnE43NNNJQ2LF3+0= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220704084225-05e143d24a9e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.13.0 h1:Af8nKPmuFypiUBjVoU9V20FiaFXOcuZI21p0ycVYYGE= -golang.org/x/sys v0.13.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.45.0 h1:dO4czNzziLiiXplLQgBCEpCvXQ3dnkn0SdaZSYdQ+FY= +golang.org/x/sys v0.45.0/go.mod h1:4GL1E5IUh+htKOUEOaiffhrAeqysfVGipDYzABqnCmw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= golang.org/x/text v0.3.8/go.mod h1:E6s5w1FMmriuDzIBO73fBruAKo1PCIq6d2Q6DHfQ8WQ= -golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= -golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k= -golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE= +golang.org/x/text v0.39.0 h1:UbZz4pLOvn600D6Oh6GGEI6VAmndrEBLv8/6BEXzyus= +golang.org/x/text v0.39.0/go.mod h1:3UwRclnC2g0TU9x8PZiyfOajCd1zaUNHF9cvqcQZ+ZM= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng= diff --git a/api/main.go b/api/main.go index 49f335f..6356bea 100644 --- a/api/main.go +++ b/api/main.go @@ -12,6 +12,7 @@ package main import ( "context" "log" + "net" "net/http" "os" "os/signal" @@ -23,20 +24,28 @@ import ( ) func main() { - services, err := walcli.NewServices() - if err != nil { - log.Fatalf("failed to initialize services: %v", err) - } - - router := server.NewRouter(services) port := os.Getenv("PORT") if port == "" { port = "8080" } + host := os.Getenv("ARGON_API_HOST") + if host == "" { + host = "127.0.0.1" + } + addr := net.JoinHostPort(host, port) + opts := server.OptionsFromEnv() + if err := server.ValidateListenAddress(addr, opts); err != nil { + log.Fatal(err) + } + services, err := walcli.NewServices() + if err != nil { + log.Fatalf("failed to initialize services: %v", err) + } - srv := &http.Server{Addr: ":" + port, Handler: router} + router := server.NewRouterWith(services, opts) + srv := &http.Server{Addr: addr, Handler: router, ReadHeaderTimeout: 10 * time.Second} go func() { - log.Printf("Argon API listening on :%s", port) + log.Printf("Argon API listening on %s", addr) if err := srv.ListenAndServe(); err != nil && err != http.ErrServerClosed { log.Fatalf("server error: %v", err) } @@ -47,8 +56,11 @@ func main() { <-quit log.Println("shutting down...") - router.Shutdown() // stop supervised ingesters first ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() - _ = srv.Shutdown(ctx) + if err := srv.Shutdown(ctx); err != nil { + log.Printf("api: HTTP shutdown: %v", err) + _ = srv.Close() + } + router.Shutdown() // producers have stopped; drain capture and snapshots last } diff --git a/api/server/api_test.go b/api/server/api_test.go index fa29fe9..2457640 100644 --- a/api/server/api_test.go +++ b/api/server/api_test.go @@ -222,7 +222,7 @@ func TestAPI_ConsoleReadSurface(t *testing.T) { // Meta and status come up before any data exists. code, resp := do(t, router, "GET", "/api/v1/meta", nil) require.Equal(t, http.StatusOK, code) - assert.Equal(t, "dev", resp["version"]) + assert.Equal(t, Version, resp["version"]) assert.Equal(t, false, resp["read_only"]) code, resp = do(t, router, "GET", "/api/v1/status/ingesters", nil) require.Equal(t, http.StatusOK, code) @@ -362,7 +362,7 @@ func TestAPI_TokenReadOnlyAndCORS(t *testing.T) { _ = services.Client.Database(dbName).Drop(context.Background()) }) - router := NewRouterWith(services, Options{Token: "sesame", ReadOnly: true, Version: "test"}) + router := NewRouterWith(services, Options{Token: "sesame", ReadOnly: true, Version: "test", CORSOrigins: "http://localhost:5173"}) t.Cleanup(router.Shutdown) // Meta stays open so a client can discover it needs a token. diff --git a/api/server/console.go b/api/server/console.go index 9527d07..3e2b13c 100644 --- a/api/server/console.go +++ b/api/server/console.go @@ -8,7 +8,10 @@ package server import ( "crypto/subtle" "fmt" + "github.com/argon-lab/argon/pkg/version" + "net" "net/http" + "net/url" "os" "sort" "strconv" @@ -21,16 +24,15 @@ import ( "go.mongodb.org/mongo-driver/mongo/options" ) -// Version is stamped at build time via -ldflags -// "-X github.com/argon-lab/argon/api/server.Version=...". It is what -// /api/v1/meta reports. -var Version = "dev" +// Version shares the embedded release metadata with the CLI. Release builds +// override github.com/argon-lab/argon/pkg/version.Build via -ldflags. +var Version = version.String() // Options are the cross-cutting server settings. The zero value is an open -// local control plane: any origin, no token, writes allowed. +// local control plane: same origin, no token, writes allowed. type Options struct { // CORSOrigins is a comma-separated allowlist of browser origins; - // empty or "*" allows any origin. + // empty permits same-origin requests; "*" explicitly allows any origin. CORSOrigins string // Token, when set, requires "Authorization: Bearer " on every // endpoint except /health and /api/v1/meta. @@ -80,7 +82,7 @@ func OptionsFromEnv() Options { // --- middleware --- func corsMiddleware(origins string) gin.HandlerFunc { - allowAll := origins == "" || origins == "*" + allowAll := origins == "*" allowed := make(map[string]bool) for _, o := range strings.Split(origins, ",") { if o = strings.TrimSpace(o); o != "" { @@ -88,7 +90,13 @@ func corsMiddleware(origins string) gin.HandlerFunc { } } return func(c *gin.Context) { - if origin := c.GetHeader("Origin"); origin != "" && (allowAll || allowed[origin]) { + if origin := c.GetHeader("Origin"); origin != "" { + u, err := url.Parse(origin) + sameOrigin := err == nil && (u.Scheme == "http" || u.Scheme == "https") && u.User == nil && u.Host == c.Request.Host && u.Path == "" && u.RawQuery == "" && u.Fragment == "" + if !allowAll && !allowed[origin] && !sameOrigin { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "origin is not allowed"}) + return + } c.Header("Access-Control-Allow-Origin", origin) c.Header("Vary", "Origin") c.Header("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS") @@ -103,6 +111,21 @@ func corsMiddleware(origins string) gin.HandlerFunc { } } +// ValidateListenAddress prevents accidentally exposing an unauthenticated +// control plane. Anonymous demo is deliberately limited to its HTTP sandbox. +func ValidateListenAddress(addr string, opts Options) error { + host, _, err := net.SplitHostPort(addr) + if err != nil { + return fmt.Errorf("invalid listen address: %w", err) + } + ip := net.ParseIP(host) + local := host == "localhost" || (ip != nil && ip.IsLoopback()) + if !local && opts.Token == "" && !opts.DemoMode { + return fmt.Errorf("public API binding requires ARGON_API_TOKEN (or explicit ARGON_DEMO_MODE); use 127.0.0.1 for local access") + } + return nil +} + func authMiddleware(token string) gin.HandlerFunc { want := []byte("Bearer " + token) return func(c *gin.Context) { @@ -151,8 +174,11 @@ func intQuery(c *gin.Context, name string, def int64) (int64, error) { func (r *Router) meta(c *gin.Context) { resp := gin.H{ - "version": r.opts.Version, - "read_only": r.opts.ReadOnly, + "version": r.opts.Version, + "read_only": r.opts.ReadOnly, + "native_connections": !r.opts.DemoMode, + "actor_scope": "branch", + "ddl_capture": false, } if r.opts.DemoMode { resp["demo"] = true @@ -162,14 +188,15 @@ func (r *Router) meta(c *gin.Context) { } func (r *Router) ingesterStatus(c *gin.Context) { - r.ingestMu.Lock() - ids := make([]string, 0, len(r.ingest)) - for id := range r.ingest { - ids = append(ids, id) + statuses := r.services.Ingest.Statuses() + ids := make([]string, 0, len(statuses)) + for _, status := range statuses { + if status.State == "running" { + ids = append(ids, status.BranchID) + } } - r.ingestMu.Unlock() sort.Strings(ids) - c.JSON(http.StatusOK, gin.H{"ingesters": ids, "count": len(ids)}) + c.JSON(http.StatusOK, gin.H{"ingesters": ids, "count": len(ids), "capture": statuses}) } // --- history --- @@ -367,7 +394,11 @@ func (r *Router) listSandboxes(c *gin.Context) { items := make([]gin.H, 0, len(boxes)) for _, b := range boxes { item := gin.H{"branch": b} - if b.IsLive() { + if b.IsLive() && !r.opts.DemoMode { + if err := r.startIngester(b.ID); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } item["connection_string"] = r.services.BranchConnectionString(b.PhysicalDB) } items = append(items, item) @@ -380,7 +411,6 @@ func (r *Router) discardSandbox(c *gin.Context) { if !ok { return } - r.stopIngester(branchID) if err := r.services.Sandbox.Discard(c.Request.Context(), branchID); err != nil { abortErr(c, http.StatusConflict, err) return @@ -400,7 +430,7 @@ func (r *Router) extendSandbox(c *gin.Context) { abortErr(c, http.StatusBadRequest, err) return } - expires, err := r.services.Sandbox.Extend(c.Request.Context(), branchID, time.Duration(body.TTLMinutes)*time.Minute) + expires, err := r.services.Sandbox.Extend(c.Request.Context(), branchID, time.Duration(body.TTLMinutes*float64(time.Minute))) if err != nil { abortErr(c, http.StatusConflict, err) return diff --git a/api/server/demo.go b/api/server/demo.go index b75f984..58643c3 100644 --- a/api/server/demo.go +++ b/api/server/demo.go @@ -118,6 +118,12 @@ func (r *Router) demoGuard() gin.HandlerFunc { gin.H{"error": "no demo session; POST /api/v1/demo/session first"}) return } + // Anonymous visitors use only metadata/WAL workflows. Native Mongo + // access would bypass HTTP project isolation and expose service credentials. + if c.Request.Method == http.MethodPost && (strings.HasSuffix(p, "/checkout") || strings.HasSuffix(p, "/sandboxes")) { + c.AbortWithStatusJSON(http.StatusForbidden, gin.H{"error": "native database connections are disabled in the hosted demo; run Argon locally for driver access"}) + return + } switch { // The project list is the visitor's project, nothing else. @@ -248,7 +254,8 @@ func (r *Router) demoSession(c *gin.Context) { maxAge := int(r.opts.DemoTTL / time.Second) c.SetSameSite(http.SameSiteLaxMode) - c.SetCookie(demoCookie, name, maxAge, "/", "", false, true) + c.SetSameSite(http.SameSiteLaxMode) + c.SetCookie(demoCookie, name, maxAge, "/", "", c.Request.TLS != nil || c.GetHeader("X-Forwarded-Proto") == "https", true) c.JSON(http.StatusCreated, gin.H{ "project": name, "expires_at": project.CreatedAt.Add(r.opts.DemoTTL), @@ -270,7 +277,7 @@ func (r *Router) seedDemo(ctx context.Context, project string) error { {"products", bson.M{"_id": "keyboard", "name": "Keyboard MX", "price": 89, "stock": 40}}, {"products", bson.M{"_id": "mouse", "name": "Mouse S1", "price": 49, "stock": 65}}, {"products", bson.M{"_id": "monitor", "name": "Monitor 27q", "price": 329, "stock": 12}}, - {"orders", bson.M{"_id": "o1", "product": "keyboard", "qty": 2, "status": "pending"}}, + {"orders", bson.M{"_id": "o1", "product": "keyboard", "qty": 2, "price": 49, "status": "pending"}}, {"orders", bson.M{"_id": "o2", "product": "monitor", "qty": 1, "status": "paid"}}, {"orders", bson.M{"_id": "o3", "product": "mouse", "qty": 3, "status": "shipped"}}, } @@ -295,24 +302,23 @@ func (r *Router) seedDemo(ctx context.Context, project string) error { // --- the scripted agent session --- -// demoScenario plays a short two-actor agent session on a fresh branch -// and a conflicting human edit on main — one click, and diff, merge -// conflicts and per-actor undo all have something real to show. +// demoScenario runs two scripted proposals from the exact same pinned input. +// It adopts the planner's reviewed proposal; the executor remains a conflicting +// branch visitors can inspect, undo or discard. All data is this session's own. func (r *Router) demoScenario(c *gin.Context) { project := r.demoProject(c) if project == "" { - c.AbortWithStatusJSON(http.StatusUnauthorized, - gin.H{"error": "no demo session; POST /api/v1/demo/session first"}) + c.AbortWithStatusJSON(http.StatusUnauthorized, gin.H{"error": "no demo session"}) return } proj, err := r.services.Projects.GetProjectByName(project) if err != nil { - abortErr(c, http.StatusNotFound, err) + abortErr(c, 404, err) return } branches, err := r.services.Branches.ListBranches(proj.ID) if err != nil { - abortErr(c, http.StatusInternalServerError, err) + abortErr(c, 500, err) return } runs := 0 @@ -321,74 +327,90 @@ func (r *Router) demoScenario(c *gin.Context) { runs++ } } - name := fmt.Sprintf("agent-run-%d", runs+1) - + // A random suffix avoids name reuse after visitors discard previous runs. + suffix := make([]byte, 4) + if _, err = rand.Read(suffix); err != nil { + abortErr(c, 500, err) + return + } + run := fmt.Sprintf("%d-%s", runs+1, hex.EncodeToString(suffix)) + plannerName, executorName, pinName := "planner-"+run, "agent-run-"+run, "run-input-"+run main, err := r.services.Branches.GetBranch(proj.ID, "main") if err != nil { - abortErr(c, http.StatusInternalServerError, err) + abortErr(c, 500, err) return } - if _, err := r.services.Branches.CreateBranch(proj.ID, name, main.ID); err != nil { - abortErr(c, http.StatusConflict, err) + // Each scripted run starts from the advertised $49 input, including + // repeated runs after a visitor has merged or undone an earlier proposal. + // This setup write is retained in this visitor's private demo history. + ctx := c.Request.Context() + setup, err := r.services.WriterFor(project, "main") + if err != nil { + abortErr(c, 500, err) return } - - ctx := c.Request.Context() - agent, err := r.services.WriterFor(project, name) + setup.SetActor("demo:setup") + inputLSN, err := setup.Put(ctx, "orders", bson.M{"_id": "o1", "product": "keyboard", "qty": 2, "price": 49, "status": "pending"}) if err != nil { - abortErr(c, http.StatusInternalServerError, err) + abortErr(c, 500, err) return } - // The planner drafts new work… - agent.SetActor("agent:planner") - steps := []struct { - collection string - doc bson.M - }{ - {"orders", bson.M{"_id": "o4", "product": "monitor", "qty": 2, "status": "draft"}}, - {"notes", bson.M{"_id": "plan-1", "text": "restock monitors before the o4 order ships", "order": "o4"}}, + input, err := r.services.Pins.Create(proj.ID, main.ID, pinName, inputLSN, "Identical $49 input for two scripted agent proposals") + if err != nil { + abortErr(c, 500, err) + return + } + for _, name := range []string{plannerName, executorName} { + if _, err = r.services.Restore.CreateBranchFromPin(proj.ID, input.BranchID, name, input.LSN); err != nil { + abortErr(c, 500, err) + return + } + } + planner, err := r.services.WriterFor(project, plannerName) + if err != nil { + abortErr(c, 500, err) + return + } + planner.SetActor("agent:planner") + if _, err = planner.Put(ctx, "orders", bson.M{"_id": "o1", "product": "keyboard", "qty": 2, "price": 44, "status": "approved", "run": run}); err != nil { + abortErr(c, 500, err) + return } - // …and the executor updates existing state, touching o1. - execSteps := []struct { + executor, err := r.services.WriterFor(project, executorName) + if err != nil { + abortErr(c, 500, err) + return + } + executor.SetActor("agent:executor") + for _, step := range []struct { collection string doc bson.M }{ - {"orders", bson.M{"_id": "o1", "product": "keyboard", "qty": 2, "status": "refunded"}}, + {"orders", bson.M{"_id": "o1", "product": "keyboard", "qty": 2, "price": 1, "status": "refunded", "run": run}}, + {"orders", bson.M{"_id": "o4", "product": "monitor", "qty": 2, "status": "draft"}}, + {"notes", bson.M{"_id": "plan-1", "text": "Review this proposal before accepting", "order": "o4"}}, {"products", bson.M{"_id": "monitor", "name": "Monitor 27q", "price": 329, "stock": 10}}, - } - for _, s := range steps { - if _, err := agent.Put(ctx, s.collection, s.doc); err != nil { - abortErr(c, http.StatusInternalServerError, err) + } { + if _, err = executor.Put(ctx, step.collection, step.doc); err != nil { + abortErr(c, 500, err) return } } - agent.SetActor("agent:executor") - for _, s := range execSteps { - if _, err := agent.Put(ctx, s.collection, s.doc); err != nil { - abortErr(c, http.StatusInternalServerError, err) - return - } + plannerBranch, err := r.services.Branches.GetBranch(proj.ID, plannerName) + if err != nil { + abortErr(c, 500, err) + return } - - // Meanwhile a human touches the same order on main — the merge - // preview will surface this as a conflict, never silently. - human, err := r.services.WriterFor(project, "main") + plan, err := r.services.Merge.Preview(ctx, plannerBranch.ID) if err != nil { - abortErr(c, http.StatusInternalServerError, err) + abortErr(c, 500, err) return } - human.SetActor("user:demo") - if _, err := human.Put(ctx, "orders", - bson.M{"_id": "o1", "product": "keyboard", "qty": 2, "status": "expedited"}); err != nil { - abortErr(c, http.StatusInternalServerError, err) + if _, err = r.services.Merge.Apply(ctx, plan.ID, ""); err != nil { + abortErr(c, 500, err) return } - - c.JSON(http.StatusCreated, gin.H{ - "branch": name, - "actors": []string{"agent:planner", "agent:executor"}, - "hint": "diff the branch, preview the merge (one conflict on orders/o1), or undo a single actor", - }) + c.JSON(http.StatusCreated, gin.H{"branch": executorName, "branches": []string{plannerName, executorName}, "accepted_branch": plannerName, "accepted_plan": plan.ID.Hex(), "pin": pinName, "actors": []string{"agent:planner", "agent:executor"}, "hint": "Both proposals started at the same pin. The planner was adopted; inspect the executor conflict, discard it, or undo the adopted merge on main."}) } // --- sweeping --- diff --git a/api/server/demo_test.go b/api/server/demo_test.go index 6272bfd..86d2808 100644 --- a/api/server/demo_test.go +++ b/api/server/demo_test.go @@ -110,10 +110,21 @@ func TestAPI_DemoGateway(t *testing.T) { code, resp, _ = doDemo(t, router, "POST", "/api/v1/demo/scenario", session1, nil) require.Equal(t, http.StatusCreated, code, "%v", resp) runBranch := resp["branch"].(string) - assert.Equal(t, "agent-run-1", runBranch) + assert.Contains(t, runBranch, "agent-run-1-") + acceptedBranch := resp["accepted_branch"].(string) + require.Len(t, resp["branches"], 2) + projectRecord, err := services.Projects.GetProjectByName(project1) + require.NoError(t, err) + input, err := services.Pins.Get(projectRecord.ID, resp["pin"].(string)) + require.NoError(t, err) + for _, name := range []string{runBranch, acceptedBranch} { + b, e := services.Branches.GetBranch(input.ProjectID, name) + require.NoError(t, e) + require.Equal(t, input.LSN, b.BaseLSN) + } code, resp, _ = doDemo(t, router, "GET", - "/api/v1/projects/"+project1+"/branches/"+runBranch+"/entries?actor=agent:planner", session1, nil) + "/api/v1/projects/"+project1+"/branches/"+acceptedBranch+"/entries?actor=agent:planner", session1, nil) require.Equal(t, http.StatusOK, code) require.NotEmpty(t, resp["entries"]) @@ -121,13 +132,26 @@ func TestAPI_DemoGateway(t *testing.T) { "/api/v1/projects/"+project1+"/branches/"+runBranch+"/merge-preview", session1, nil) require.Equal(t, http.StatusCreated, code, "%v", resp) planID := resp["id"].(string) - require.Len(t, resp["conflicts"], 1, "the human edit on main must surface as a conflict") + require.Len(t, resp["conflicts"], 1, "the adopted planner proposal must surface as a conflict") // Plans are reachable by their owner and invisible across sessions. code, _, _ = doDemo(t, router, "GET", "/api/v1/merge-plans/"+planID, session1, nil) require.Equal(t, http.StatusOK, code) code, _, _ = doDemo(t, router, "GET", "/api/v1/merge-plans/"+planID, session2, nil) require.Equal(t, http.StatusNotFound, code) + + // Repeating the walkthrough must still start both agents at $49. + code, resp, _ = doDemo(t, router, "POST", "/api/v1/demo/scenario", session1, nil) + require.Equal(t, http.StatusCreated, code, "%v", resp) + input, err = services.Pins.Get(projectRecord.ID, resp["pin"].(string)) + require.NoError(t, err) + for _, name := range []string{resp["branch"].(string), resp["accepted_branch"].(string)} { + b, err := services.Branches.GetBranch(projectRecord.ID, name) + require.NoError(t, err) + before, err := services.Materializer.MaterializeDocumentAtLSN(b, "orders", "o1", input.LSN) + require.NoError(t, err) + require.EqualValues(t, 49, before["price"]) + } } func TestAPI_DemoWriteBudgetAndSweep(t *testing.T) { diff --git a/api/server/events.go b/api/server/events.go new file mode 100644 index 0000000..61f5a81 --- /dev/null +++ b/api/server/events.go @@ -0,0 +1,35 @@ +package server + +import ( + "encoding/json" + "io" + "log" + "net/http" + + "github.com/gin-gonic/gin" +) + +// Client consent is opt-in; the server accepts only this fixed vocabulary, +// never identifiers, documents, URLs or free-form properties. +func (r *Router) recordEvent(c *gin.Context) { + var body struct { + Event string `json:"event"` + } + decoder := json.NewDecoder(http.MaxBytesReader(c.Writer, c.Request.Body, 256)) + decoder.DisallowUnknownFields() + if err := decoder.Decode(&body); err != nil { + c.JSON(400, gin.H{"error": "invalid event"}) + return + } + if err := decoder.Decode(&struct{}{}); err != io.EOF { + c.JSON(400, gin.H{"error": "invalid event"}) + return + } + switch body.Event { + case "demo_entered", "first_diff", "first_merge", "first_undo", "quickstart_opened": + log.Printf("argon_funnel event=%s", body.Event) + c.Status(http.StatusNoContent) + default: + c.JSON(400, gin.H{"error": "unknown event"}) + } +} diff --git a/api/server/router.go b/api/server/router.go index 1eed817..ce56005 100644 --- a/api/server/router.go +++ b/api/server/router.go @@ -29,8 +29,9 @@ type Router struct { opts Options demo *demoState - ingestMu sync.Mutex - ingest map[string]context.CancelFunc + ingestMu sync.Mutex + ingest map[string]context.CancelFunc + sweepCancel context.CancelFunc } // NewRouter builds the API over the given services, configured from the @@ -85,6 +86,7 @@ func NewRouterWith(services *walcli.Services, opts Options) *Router { v1 := r.Group("/api/v1") { v1.GET("/meta", r.meta) + v1.POST("/events", r.recordEvent) v1.GET("/status/ingesters", r.ingesterStatus) if opts.DemoMode { @@ -129,6 +131,11 @@ func NewRouterWith(services *walcli.Services, opts Options) *Router { } r.mountUI() r.superviseLiveBranches() + sweepCtx, sweepCancel := context.WithCancel(context.Background()) + r.sweepCancel = sweepCancel + if !opts.ReadOnly && !opts.DemoMode { + go services.RunSandboxSweeper(sweepCtx) + } if opts.DemoMode { r.startDemoSweeper() } @@ -154,47 +161,69 @@ func (r *Router) superviseLiveBranches() { } for _, b := range branches { if b.IsLive() { - r.startIngester(b.ID) + if err := r.startIngester(b.ID); err != nil { + log.Printf("api: capture for %s unavailable: %v", b.ID, err) + } } } } } -// Shutdown stops every supervised ingester and the demo sweeper. +// Shutdown stops every supervised ingester and the demo sweeper, then waits +// for automatic snapshots. Stop/drain HTTP requests before calling it. func (r *Router) Shutdown() { + if r.sweepCancel != nil { + r.sweepCancel() + } if r.demo != nil && r.demo.cancel != nil { r.demo.cancel() } - r.ingestMu.Lock() - defer r.ingestMu.Unlock() - for id, cancel := range r.ingest { - cancel() - delete(r.ingest, id) + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + if err := r.services.Ingest.Shutdown(ctx); err != nil { + log.Printf("api: capture shutdown: %v", err) + } + snapshotCtx, snapshotCancel := context.WithTimeout(context.Background(), 30*time.Second) + defer snapshotCancel() + if err := r.services.WaitAuto(snapshotCtx); err != nil { + log.Printf("api: snapshot shutdown: %v", err) + // Cancellation interrupts cooperative storage I/O; give its independent + // deferred publication-lock cleanup a short grace before process exit. + cleanupCtx, cleanupCancel := context.WithTimeout(context.Background(), 5*time.Second) + defer cleanupCancel() + if cleanupErr := r.services.WaitAuto(cleanupCtx); cleanupErr != nil { + log.Printf("api: snapshot cleanup still incomplete: %v", cleanupErr) + } } + } -func (r *Router) startIngester(branchID string) { - r.ingestMu.Lock() - defer r.ingestMu.Unlock() - if _, running := r.ingest[branchID]; running { - return +func (r *Router) startIngester(branchID string, actors ...string) error { + actor := "" + if len(actors) > 0 { + actor = actors[0] } - ctx, cancel := context.WithCancel(context.Background()) - r.ingest[branchID] = cancel - go func() { - if err := r.services.Ingest.Run(ctx, branchID); err != nil && ctx.Err() == nil { - log.Printf("api: ingester for branch %s stopped: %v", branchID, err) - } - }() + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + if err := r.services.StartCapture(ctx, branchID, actor); err != nil { + return err + } + r.ingestMu.Lock() + r.ingest[branchID] = func() { _ = r.stopIngester(branchID) } + r.ingestMu.Unlock() + return nil } -func (r *Router) stopIngester(branchID string) { +func (r *Router) stopIngester(branchID string) error { + ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second) + defer cancel() + if err := r.services.Ingest.Stop(ctx, branchID); err != nil { + return err + } r.ingestMu.Lock() defer r.ingestMu.Unlock() - if cancel, ok := r.ingest[branchID]; ok { - cancel() - delete(r.ingest, branchID) - } + delete(r.ingest, branchID) + return nil } // --- helpers --- @@ -304,24 +333,24 @@ func (r *Router) getBranch(c *gin.Context) { return } resp := gin.H{"branch": branch} - if branch.IsLive() { + if branch.IsLive() && !r.opts.DemoMode { + if err := r.startIngester(branchID); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } resp["connection_string"] = r.services.BranchConnectionString(branch.PhysicalDB) } c.JSON(http.StatusOK, resp) } func (r *Router) deleteBranch(c *gin.Context) { - projectID, branchID, ok := r.resolve(c) + _, branchID, ok := r.resolve(c) if !ok { return } - r.stopIngester(branchID) if err := r.services.Sandbox.Discard(c.Request.Context(), branchID); err != nil { - // Fall back for non-sandbox branches that are not checked out. - if err2 := r.services.Branches.DeleteBranch(projectID, c.Param("branch")); err2 != nil { - abortErr(c, http.StatusConflict, err2) - return - } + abortErr(c, http.StatusConflict, err) + return } c.JSON(http.StatusOK, gin.H{"deleted": true}) } @@ -338,7 +367,17 @@ func (r *Router) checkoutBranch(c *gin.Context) { abortErr(c, http.StatusInternalServerError, err) return } - r.startIngester(branchID) + var capture struct { + Actor string `json:"actor"` + } + if err := c.ShouldBindJSON(&capture); err != nil && err.Error() != "EOF" { + abortErr(c, http.StatusBadRequest, err) + return + } + if err := r.startIngester(branchID, capture.Actor); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } c.JSON(http.StatusOK, gin.H{ "connection_string": r.services.BranchConnectionString(info.PhysicalDB), "physical_db": info.PhysicalDB, @@ -353,7 +392,6 @@ func (r *Router) releaseBranch(c *gin.Context) { if !ok { return } - r.stopIngester(branchID) if err := r.services.Checkout.Release(c.Request.Context(), branchID); err != nil { abortErr(c, http.StatusInternalServerError, err) return @@ -372,6 +410,7 @@ func (r *Router) createSandbox(c *gin.Context) { From string `json:"from"` Name string `json:"name"` TTLMinutes float64 `json:"ttl_minutes"` + Actor string `json:"actor"` } if err := c.ShouldBindJSON(&body); err != nil && err.Error() != "EOF" { abortErr(c, http.StatusBadRequest, err) @@ -386,13 +425,20 @@ func (r *Router) createSandbox(c *gin.Context) { abortErr(c, http.StatusNotFound, fmt.Errorf("parent branch %q not found", from)) return } - ttl := time.Duration(body.TTLMinutes) * time.Minute + if err := r.services.SyncBranch(c.Request.Context(), parent.ID); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } + ttl := time.Duration(body.TTLMinutes * float64(time.Minute)) info, err := r.services.Sandbox.Create(c.Request.Context(), projectID, parent.ID, body.Name, ttl) if err != nil { abortErr(c, http.StatusInternalServerError, err) return } - r.startIngester(info.BranchID) + if err := r.startIngester(info.BranchID, body.Actor); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } c.JSON(http.StatusCreated, gin.H{ "branch": info.BranchName, "connection_string": r.services.BranchConnectionString(info.PhysicalDB), @@ -441,6 +487,10 @@ func (r *Router) createPin(c *gin.Context) { abortErr(c, http.StatusNotFound, fmt.Errorf("branch %q not found", branchName)) return } + if err := r.services.SyncBranch(c.Request.Context(), branch.ID); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } pin, err := r.services.Pins.Create(projectID, branch.ID, body.Name, body.LSN, body.Note) if err != nil { abortErr(c, http.StatusConflict, err) @@ -494,6 +544,7 @@ func (r *Router) sandboxFromPin(c *gin.Context) { var body struct { Name string `json:"name"` TTLMinutes float64 `json:"ttl_minutes"` + Actor string `json:"actor"` } if err := c.ShouldBindJSON(&body); err != nil && err.Error() != "EOF" { abortErr(c, http.StatusBadRequest, err) @@ -518,13 +569,16 @@ func (r *Router) sandboxFromPin(c *gin.Context) { abortErr(c, http.StatusConflict, err) return } - ttl := time.Duration(body.TTLMinutes) * time.Minute + ttl := time.Duration(body.TTLMinutes * float64(time.Minute)) info, err := r.services.Sandbox.Adopt(c.Request.Context(), branch.ID, ttl) if err != nil { abortErr(c, http.StatusInternalServerError, err) return } - r.startIngester(info.BranchID) + if err := r.startIngester(info.BranchID, body.Actor); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } c.JSON(http.StatusCreated, gin.H{ "branch": info.BranchName, "connection_string": r.services.BranchConnectionString(info.PhysicalDB), @@ -542,6 +596,10 @@ func (r *Router) diffBranch(c *gin.Context) { if !ok { return } + if err := r.services.SyncBranch(c.Request.Context(), branchID); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } plan, err := r.services.Merge.Compute(branchID) if err != nil { abortErr(c, http.StatusBadRequest, err) @@ -555,6 +613,10 @@ func (r *Router) mergePreview(c *gin.Context) { if !ok { return } + if err := r.services.SyncBranch(c.Request.Context(), branchID); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } plan, err := r.services.Merge.Preview(c.Request.Context(), branchID) if err != nil { abortErr(c, http.StatusBadRequest, err) @@ -576,6 +638,15 @@ func (r *Router) mergeApply(c *gin.Context) { abortErr(c, http.StatusBadRequest, err) return } + plan, err := r.services.Merge.GetPlan(c.Request.Context(), planID) + if err != nil { + abortErr(c, http.StatusNotFound, err) + return + } + if err := r.services.SyncBranch(c.Request.Context(), plan.SourceBranchID); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } result, err := r.services.Merge.Apply(c.Request.Context(), planID, body.Strategy) if err != nil { abortErr(c, http.StatusConflict, err) @@ -649,6 +720,10 @@ func (r *Router) createSnapshot(c *gin.Context) { if !ok { return } + if err := r.services.SyncBranch(c.Request.Context(), branchID); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return + } branch, err := r.services.Branches.GetBranchByID(branchID) if err != nil { abortErr(c, http.StatusNotFound, err) diff --git a/api/server/security_test.go b/api/server/security_test.go new file mode 100644 index 0000000..ed4c841 --- /dev/null +++ b/api/server/security_test.go @@ -0,0 +1,101 @@ +package server + +import ( + "context" + "fmt" + "net/http" + "net/http/httptest" + "strings" + "testing" + "time" + + "github.com/argon-lab/argon/pkg/walcli" + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/require" +) + +func TestFunnelAcceptsOnlyAnonymousVocabulary(t *testing.T) { + router := gin.New() + router.POST("/events", (&Router{}).recordEvent) + for _, tc := range []struct { + body string + code int + }{ + {`{"event":"first_diff"}`, 204}, + {`{"event":"first_diff","project":"private"}`, 400}, + {`{"event":"not-allowed"}`, 400}, + {`{"event":"first_diff"} {}`, 400}, + {strings.Repeat("x", 257), 400}, + } { + req := httptest.NewRequest("POST", "/events", strings.NewReader(tc.body)) + rec := httptest.NewRecorder() + router.ServeHTTP(rec, req) + require.Equal(t, tc.code, rec.Code) + } +} + +func TestListenAddressRequiresExplicitPublicAccess(t *testing.T) { + for _, addr := range []string{"127.0.0.1:8080", "[::1]:8080", "localhost:8080"} { + require.NoError(t, ValidateListenAddress(addr, Options{})) + } + for _, addr := range []string{":8080", "0.0.0.0:8080", "[::]:8080", "192.168.1.2:8080"} { + require.Error(t, ValidateListenAddress(addr, Options{})) + require.NoError(t, ValidateListenAddress(addr, Options{Token: "test"})) + require.NoError(t, ValidateListenAddress(addr, Options{DemoMode: true})) + } +} + +func TestOriginGuardRejectsCrossOriginWrites(t *testing.T) { + for _, tc := range []struct { + origin, allow string + want int + }{ + {"", "", 200}, {"http://localhost:8080", "", 200}, + {"https://untrusted.example", "", 403}, {"null", "", 403}, + {"https://console.example", "https://console.example", 200}, + } { + r := gin.New() + r.Use(corsMiddleware(tc.allow)) + r.POST("/api/v1/projects", func(c *gin.Context) { c.Status(200) }) + req := httptest.NewRequest("POST", "http://localhost:8080/api/v1/projects", nil) + req.Header.Set("Origin", tc.origin) + rec := httptest.NewRecorder() + r.ServeHTTP(rec, req) + require.Equal(t, tc.want, rec.Code, tc.origin) + } +} + +func TestDemoNeverReturnsNativeServiceCredentials(t *testing.T) { + name := fmt.Sprintf("argon_api_security_test_%d", time.Now().UnixNano()) + services, err := walcli.NewServicesAt("mongodb://localhost:27017", name) + require.NoError(t, err) + defer services.Client.Database(name).Drop(context.Background()) + services.MongoURI = "mongodb://service:secret@localhost:27017/?authSource=admin" + r := NewRouterWith(services, Options{DemoMode: true, DemoWriteLimit: 100}) + defer r.Shutdown() + code, body, cookie := doDemo(t, r, "POST", "/api/v1/demo/session", "", nil) + require.Equal(t, http.StatusCreated, code) + p := body["project"].(string) + for _, path := range []string{ + "/api/v1/projects/" + p + "/branches/main/checkout", + "/api/v1/projects/" + p + "/sandboxes", + "/api/v1/projects/" + p + "/pins/baseline/sandboxes", + } { + code, body, _ = doDemo(t, r, "POST", path, cookie, nil) + require.Equal(t, http.StatusForbidden, code) + require.NotContains(t, fmt.Sprint(body), "service:secret") + } + project, err := services.Projects.GetProjectByName(p) + require.NoError(t, err) + main, err := services.Branches.GetBranch(project.ID, "main") + require.NoError(t, err) + box, err := services.Sandbox.Create(context.Background(), project.ID, main.ID, "internal-box", time.Hour) + require.NoError(t, err) + defer services.Sandbox.Discard(context.Background(), box.BranchID) + for _, path := range []string{"/api/v1/projects/" + p + "/branches/internal-box", "/api/v1/projects/" + p + "/sandboxes"} { + code, body, _ = doDemo(t, r, "GET", path, cookie, nil) + require.Equal(t, http.StatusOK, code) + require.NotContains(t, fmt.Sprint(body), "connection_string") + require.NotContains(t, fmt.Sprint(body), "service:secret") + } +} diff --git a/api/server/ui/dist/.source b/api/server/ui/dist/.source index 72b2692..a823c63 100644 --- a/api/server/ui/dist/.source +++ b/api/server/ui/dist/.source @@ -1 +1,2 @@ -a3dd08c +0304e68 +source-diff-sha256=e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855 diff --git a/api/server/ui/dist/assets/index-3FWB-cCO.js b/api/server/ui/dist/assets/index-3FWB-cCO.js new file mode 100644 index 0000000..6311d5f --- /dev/null +++ b/api/server/ui/dist/assets/index-3FWB-cCO.js @@ -0,0 +1,51 @@ +var Iu=e=>{throw TypeError(e)};var Il=(e,t,n)=>t.has(e)||Iu("Cannot "+n);var v=(e,t,n)=>(Il(e,t,"read from private field"),n?n.call(e):t.get(e)),F=(e,t,n)=>t.has(e)?Iu("Cannot add the same private member more than once"):t instanceof WeakSet?t.add(e):t.set(e,n),_=(e,t,n,r)=>(Il(e,t,"write to private field"),r?r.call(e,n):t.set(e,n),n),I=(e,t,n)=>(Il(e,t,"access private method"),n);var si=(e,t,n,r)=>({set _(s){_(e,t,s,n)},get _(){return v(e,t,r)}});(function(){const t=document.createElement("link").relList;if(t&&t.supports&&t.supports("modulepreload"))return;for(const s of document.querySelectorAll('link[rel="modulepreload"]'))r(s);new MutationObserver(s=>{for(const i of s)if(i.type==="childList")for(const l of i.addedNodes)l.tagName==="LINK"&&l.rel==="modulepreload"&&r(l)}).observe(document,{childList:!0,subtree:!0});function n(s){const i={};return s.integrity&&(i.integrity=s.integrity),s.referrerPolicy&&(i.referrerPolicy=s.referrerPolicy),s.crossOrigin==="use-credentials"?i.credentials="include":s.crossOrigin==="anonymous"?i.credentials="omit":i.credentials="same-origin",i}function r(s){if(s.ep)return;s.ep=!0;const i=n(s);fetch(s.href,i)}})();function Ep(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}var Cd={exports:{}},fl={},jd={exports:{}},U={};/** + * @license React + * react.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Ks=Symbol.for("react.element"),Cp=Symbol.for("react.portal"),jp=Symbol.for("react.fragment"),Np=Symbol.for("react.strict_mode"),Pp=Symbol.for("react.profiler"),Rp=Symbol.for("react.provider"),_p=Symbol.for("react.context"),Lp=Symbol.for("react.forward_ref"),Tp=Symbol.for("react.suspense"),Fp=Symbol.for("react.memo"),Op=Symbol.for("react.lazy"),$u=Symbol.iterator;function bp(e){return e===null||typeof e!="object"?null:(e=$u&&e[$u]||e["@@iterator"],typeof e=="function"?e:null)}var Nd={isMounted:function(){return!1},enqueueForceUpdate:function(){},enqueueReplaceState:function(){},enqueueSetState:function(){}},Pd=Object.assign,Rd={};function Qr(e,t,n){this.props=e,this.context=t,this.refs=Rd,this.updater=n||Nd}Qr.prototype.isReactComponent={};Qr.prototype.setState=function(e,t){if(typeof e!="object"&&typeof e!="function"&&e!=null)throw Error("setState(...): takes an object of state variables to update or a function which returns an object of state variables.");this.updater.enqueueSetState(this,e,t,"setState")};Qr.prototype.forceUpdate=function(e){this.updater.enqueueForceUpdate(this,e,"forceUpdate")};function _d(){}_d.prototype=Qr.prototype;function _o(e,t,n){this.props=e,this.context=t,this.refs=Rd,this.updater=n||Nd}var Lo=_o.prototype=new _d;Lo.constructor=_o;Pd(Lo,Qr.prototype);Lo.isPureReactComponent=!0;var zu=Array.isArray,Ld=Object.prototype.hasOwnProperty,To={current:null},Td={key:!0,ref:!0,__self:!0,__source:!0};function Fd(e,t,n){var r,s={},i=null,l=null;if(t!=null)for(r in t.ref!==void 0&&(l=t.ref),t.key!==void 0&&(i=""+t.key),t)Ld.call(t,r)&&!Td.hasOwnProperty(r)&&(s[r]=t[r]);var a=arguments.length-2;if(a===1)s.children=n;else if(1>>1,de=T[se];if(0>>1;ses(Dl,$))Pns(ri,Dl)?(T[se]=ri,T[Pn]=$,se=Pn):(T[se]=Dl,T[Nn]=$,se=Nn);else if(Pns(ri,$))T[se]=ri,T[Pn]=$,se=Pn;else break e}}return D}function s(T,D){var $=T.sortIndex-D.sortIndex;return $!==0?$:T.id-D.id}if(typeof performance=="object"&&typeof performance.now=="function"){var i=performance;e.unstable_now=function(){return i.now()}}else{var l=Date,a=l.now();e.unstable_now=function(){return l.now()-a}}var u=[],c=[],p=1,d=null,m=3,x=!1,g=!1,S=!1,E=typeof setTimeout=="function"?setTimeout:null,f=typeof clearTimeout=="function"?clearTimeout:null,h=typeof setImmediate<"u"?setImmediate:null;typeof navigator<"u"&&navigator.scheduling!==void 0&&navigator.scheduling.isInputPending!==void 0&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function y(T){for(var D=n(c);D!==null;){if(D.callback===null)r(c);else if(D.startTime<=T)r(c),D.sortIndex=D.expirationTime,t(u,D);else break;D=n(c)}}function k(T){if(S=!1,y(T),!g)if(n(u)!==null)g=!0,bl(C);else{var D=n(c);D!==null&&Ml(k,D.startTime-T)}}function C(T,D){g=!1,S&&(S=!1,f(N),N=-1),x=!0;var $=m;try{for(y(D),d=n(u);d!==null&&(!(d.expirationTime>D)||T&&!te());){var se=d.callback;if(typeof se=="function"){d.callback=null,m=d.priorityLevel;var de=se(d.expirationTime<=D);D=e.unstable_now(),typeof de=="function"?d.callback=de:d===n(u)&&r(u),y(D)}else r(u);d=n(u)}if(d!==null)var ni=!0;else{var Nn=n(c);Nn!==null&&Ml(k,Nn.startTime-D),ni=!1}return ni}finally{d=null,m=$,x=!1}}var P=!1,R=null,N=-1,b=5,O=-1;function te(){return!(e.unstable_now()-OT||125se?(T.sortIndex=$,t(c,T),n(u)===null&&T===n(c)&&(S?(f(N),N=-1):S=!0,Ml(k,$-se))):(T.sortIndex=de,t(u,T),g||x||(g=!0,bl(C))),T},e.unstable_shouldYield=te,e.unstable_wrapCallback=function(T){var D=m;return function(){var $=m;m=D;try{return T.apply(this,arguments)}finally{m=$}}}})(Id);Dd.exports=Id;var Wp=Dd.exports;/** + * @license React + * react-dom.production.min.js + * + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */var Vp=w,Ge=Wp;function j(e){for(var t="https://reactjs.org/docs/error-decoder.html?invariant="+e,n=1;n"u"||typeof window.document>"u"||typeof window.document.createElement>"u"),ya=Object.prototype.hasOwnProperty,qp=/^[:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD][:A-Z_a-z\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u02FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FEF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD\-.0-9\u00B7\u0300-\u036F\u203F-\u2040]*$/,Au={},Qu={};function Gp(e){return ya.call(Qu,e)?!0:ya.call(Au,e)?!1:qp.test(e)?Qu[e]=!0:(Au[e]=!0,!1)}function Yp(e,t,n,r){if(n!==null&&n.type===0)return!1;switch(typeof t){case"function":case"symbol":return!0;case"boolean":return r?!1:n!==null?!n.acceptsBooleans:(e=e.toLowerCase().slice(0,5),e!=="data-"&&e!=="aria-");default:return!1}}function Xp(e,t,n,r){if(t===null||typeof t>"u"||Yp(e,t,n,r))return!0;if(r)return!1;if(n!==null)switch(n.type){case 3:return!t;case 4:return t===!1;case 5:return isNaN(t);case 6:return isNaN(t)||1>t}return!1}function be(e,t,n,r,s,i,l){this.acceptsBooleans=t===2||t===3||t===4,this.attributeName=r,this.attributeNamespace=s,this.mustUseProperty=n,this.propertyName=e,this.type=t,this.sanitizeURL=i,this.removeEmptyString=l}var xe={};"children dangerouslySetInnerHTML defaultValue defaultChecked innerHTML suppressContentEditableWarning suppressHydrationWarning style".split(" ").forEach(function(e){xe[e]=new be(e,0,!1,e,null,!1,!1)});[["acceptCharset","accept-charset"],["className","class"],["htmlFor","for"],["httpEquiv","http-equiv"]].forEach(function(e){var t=e[0];xe[t]=new be(t,1,!1,e[1],null,!1,!1)});["contentEditable","draggable","spellCheck","value"].forEach(function(e){xe[e]=new be(e,2,!1,e.toLowerCase(),null,!1,!1)});["autoReverse","externalResourcesRequired","focusable","preserveAlpha"].forEach(function(e){xe[e]=new be(e,2,!1,e,null,!1,!1)});"allowFullScreen async autoFocus autoPlay controls default defer disabled disablePictureInPicture disableRemotePlayback formNoValidate hidden loop noModule noValidate open playsInline readOnly required reversed scoped seamless itemScope".split(" ").forEach(function(e){xe[e]=new be(e,3,!1,e.toLowerCase(),null,!1,!1)});["checked","multiple","muted","selected"].forEach(function(e){xe[e]=new be(e,3,!0,e,null,!1,!1)});["capture","download"].forEach(function(e){xe[e]=new be(e,4,!1,e,null,!1,!1)});["cols","rows","size","span"].forEach(function(e){xe[e]=new be(e,6,!1,e,null,!1,!1)});["rowSpan","start"].forEach(function(e){xe[e]=new be(e,5,!1,e.toLowerCase(),null,!1,!1)});var Oo=/[\-:]([a-z])/g;function bo(e){return e[1].toUpperCase()}"accent-height alignment-baseline arabic-form baseline-shift cap-height clip-path clip-rule color-interpolation color-interpolation-filters color-profile color-rendering dominant-baseline enable-background fill-opacity fill-rule flood-color flood-opacity font-family font-size font-size-adjust font-stretch font-style font-variant font-weight glyph-name glyph-orientation-horizontal glyph-orientation-vertical horiz-adv-x horiz-origin-x image-rendering letter-spacing lighting-color marker-end marker-mid marker-start overline-position overline-thickness paint-order panose-1 pointer-events rendering-intent shape-rendering stop-color stop-opacity strikethrough-position strikethrough-thickness stroke-dasharray stroke-dashoffset stroke-linecap stroke-linejoin stroke-miterlimit stroke-opacity stroke-width text-anchor text-decoration text-rendering underline-position underline-thickness unicode-bidi unicode-range units-per-em v-alphabetic v-hanging v-ideographic v-mathematical vector-effect vert-adv-y vert-origin-x vert-origin-y word-spacing writing-mode xmlns:xlink x-height".split(" ").forEach(function(e){var t=e.replace(Oo,bo);xe[t]=new be(t,1,!1,e,null,!1,!1)});"xlink:actuate xlink:arcrole xlink:role xlink:show xlink:title xlink:type".split(" ").forEach(function(e){var t=e.replace(Oo,bo);xe[t]=new be(t,1,!1,e,"http://www.w3.org/1999/xlink",!1,!1)});["xml:base","xml:lang","xml:space"].forEach(function(e){var t=e.replace(Oo,bo);xe[t]=new be(t,1,!1,e,"http://www.w3.org/XML/1998/namespace",!1,!1)});["tabIndex","crossOrigin"].forEach(function(e){xe[e]=new be(e,1,!1,e.toLowerCase(),null,!1,!1)});xe.xlinkHref=new be("xlinkHref",1,!1,"xlink:href","http://www.w3.org/1999/xlink",!0,!1);["src","href","action","formAction"].forEach(function(e){xe[e]=new be(e,1,!1,e.toLowerCase(),null,!0,!0)});function Mo(e,t,n,r){var s=xe.hasOwnProperty(t)?xe[t]:null;(s!==null?s.type!==0:r||!(2a||s[l]!==i[a]){var u=` +`+s[l].replace(" at new "," at ");return e.displayName&&u.includes("")&&(u=u.replace("",e.displayName)),u}while(1<=l&&0<=a);break}}}finally{Ul=!1,Error.prepareStackTrace=n}return(e=e?e.displayName||e.name:"")?ls(e):""}function Jp(e){switch(e.tag){case 5:return ls(e.type);case 16:return ls("Lazy");case 13:return ls("Suspense");case 19:return ls("SuspenseList");case 0:case 2:case 15:return e=Al(e.type,!1),e;case 11:return e=Al(e.type.render,!1),e;case 1:return e=Al(e.type,!0),e;default:return""}}function wa(e){if(e==null)return null;if(typeof e=="function")return e.displayName||e.name||null;if(typeof e=="string")return e;switch(e){case rr:return"Fragment";case nr:return"Portal";case va:return"Profiler";case Do:return"StrictMode";case ga:return"Suspense";case xa:return"SuspenseList"}if(typeof e=="object")switch(e.$$typeof){case Ud:return(e.displayName||"Context")+".Consumer";case zd:return(e._context.displayName||"Context")+".Provider";case Io:var t=e.render;return e=e.displayName,e||(e=t.displayName||t.name||"",e=e!==""?"ForwardRef("+e+")":"ForwardRef"),e;case $o:return t=e.displayName||null,t!==null?t:wa(e.type)||"Memo";case Yt:t=e._payload,e=e._init;try{return wa(e(t))}catch{}}return null}function Zp(e){var t=e.type;switch(e.tag){case 24:return"Cache";case 9:return(t.displayName||"Context")+".Consumer";case 10:return(t._context.displayName||"Context")+".Provider";case 18:return"DehydratedFragment";case 11:return e=t.render,e=e.displayName||e.name||"",t.displayName||(e!==""?"ForwardRef("+e+")":"ForwardRef");case 7:return"Fragment";case 5:return t;case 4:return"Portal";case 3:return"Root";case 6:return"Text";case 16:return wa(t);case 8:return t===Do?"StrictMode":"Mode";case 22:return"Offscreen";case 12:return"Profiler";case 21:return"Scope";case 13:return"Suspense";case 19:return"SuspenseList";case 25:return"TracingMarker";case 1:case 0:case 17:case 2:case 14:case 15:if(typeof t=="function")return t.displayName||t.name||null;if(typeof t=="string")return t}return null}function Sn(e){switch(typeof e){case"boolean":case"number":case"string":case"undefined":return e;case"object":return e;default:return""}}function Qd(e){var t=e.type;return(e=e.nodeName)&&e.toLowerCase()==="input"&&(t==="checkbox"||t==="radio")}function em(e){var t=Qd(e)?"checked":"value",n=Object.getOwnPropertyDescriptor(e.constructor.prototype,t),r=""+e[t];if(!e.hasOwnProperty(t)&&typeof n<"u"&&typeof n.get=="function"&&typeof n.set=="function"){var s=n.get,i=n.set;return Object.defineProperty(e,t,{configurable:!0,get:function(){return s.call(this)},set:function(l){r=""+l,i.call(this,l)}}),Object.defineProperty(e,t,{enumerable:n.enumerable}),{getValue:function(){return r},setValue:function(l){r=""+l},stopTracking:function(){e._valueTracker=null,delete e[t]}}}}function ai(e){e._valueTracker||(e._valueTracker=em(e))}function Bd(e){if(!e)return!1;var t=e._valueTracker;if(!t)return!0;var n=t.getValue(),r="";return e&&(r=Qd(e)?e.checked?"true":"false":e.value),e=r,e!==n?(t.setValue(e),!0):!1}function zi(e){if(e=e||(typeof document<"u"?document:void 0),typeof e>"u")return null;try{return e.activeElement||e.body}catch{return e.body}}function Sa(e,t){var n=t.checked;return ee({},t,{defaultChecked:void 0,defaultValue:void 0,value:void 0,checked:n??e._wrapperState.initialChecked})}function Hu(e,t){var n=t.defaultValue==null?"":t.defaultValue,r=t.checked!=null?t.checked:t.defaultChecked;n=Sn(t.value!=null?t.value:n),e._wrapperState={initialChecked:r,initialValue:n,controlled:t.type==="checkbox"||t.type==="radio"?t.checked!=null:t.value!=null}}function Hd(e,t){t=t.checked,t!=null&&Mo(e,"checked",t,!1)}function ka(e,t){Hd(e,t);var n=Sn(t.value),r=t.type;if(n!=null)r==="number"?(n===0&&e.value===""||e.value!=n)&&(e.value=""+n):e.value!==""+n&&(e.value=""+n);else if(r==="submit"||r==="reset"){e.removeAttribute("value");return}t.hasOwnProperty("value")?Ea(e,t.type,n):t.hasOwnProperty("defaultValue")&&Ea(e,t.type,Sn(t.defaultValue)),t.checked==null&&t.defaultChecked!=null&&(e.defaultChecked=!!t.defaultChecked)}function Ku(e,t,n){if(t.hasOwnProperty("value")||t.hasOwnProperty("defaultValue")){var r=t.type;if(!(r!=="submit"&&r!=="reset"||t.value!==void 0&&t.value!==null))return;t=""+e._wrapperState.initialValue,n||t===e.value||(e.value=t),e.defaultValue=t}n=e.name,n!==""&&(e.name=""),e.defaultChecked=!!e._wrapperState.initialChecked,n!==""&&(e.name=n)}function Ea(e,t,n){(t!=="number"||zi(e.ownerDocument)!==e)&&(n==null?e.defaultValue=""+e._wrapperState.initialValue:e.defaultValue!==""+n&&(e.defaultValue=""+n))}var as=Array.isArray;function pr(e,t,n,r){if(e=e.options,t){t={};for(var s=0;s"+t.valueOf().toString()+"",t=oi.firstChild;e.firstChild;)e.removeChild(e.firstChild);for(;t.firstChild;)e.appendChild(t.firstChild)}});function ks(e,t){if(t){var n=e.firstChild;if(n&&n===e.lastChild&&n.nodeType===3){n.nodeValue=t;return}}e.textContent=t}var fs={animationIterationCount:!0,aspectRatio:!0,borderImageOutset:!0,borderImageSlice:!0,borderImageWidth:!0,boxFlex:!0,boxFlexGroup:!0,boxOrdinalGroup:!0,columnCount:!0,columns:!0,flex:!0,flexGrow:!0,flexPositive:!0,flexShrink:!0,flexNegative:!0,flexOrder:!0,gridArea:!0,gridRow:!0,gridRowEnd:!0,gridRowSpan:!0,gridRowStart:!0,gridColumn:!0,gridColumnEnd:!0,gridColumnSpan:!0,gridColumnStart:!0,fontWeight:!0,lineClamp:!0,lineHeight:!0,opacity:!0,order:!0,orphans:!0,tabSize:!0,widows:!0,zIndex:!0,zoom:!0,fillOpacity:!0,floodOpacity:!0,stopOpacity:!0,strokeDasharray:!0,strokeDashoffset:!0,strokeMiterlimit:!0,strokeOpacity:!0,strokeWidth:!0},tm=["Webkit","ms","Moz","O"];Object.keys(fs).forEach(function(e){tm.forEach(function(t){t=t+e.charAt(0).toUpperCase()+e.substring(1),fs[t]=fs[e]})});function qd(e,t,n){return t==null||typeof t=="boolean"||t===""?"":n||typeof t!="number"||t===0||fs.hasOwnProperty(e)&&fs[e]?(""+t).trim():t+"px"}function Gd(e,t){e=e.style;for(var n in t)if(t.hasOwnProperty(n)){var r=n.indexOf("--")===0,s=qd(n,t[n],r);n==="float"&&(n="cssFloat"),r?e.setProperty(n,s):e[n]=s}}var nm=ee({menuitem:!0},{area:!0,base:!0,br:!0,col:!0,embed:!0,hr:!0,img:!0,input:!0,keygen:!0,link:!0,meta:!0,param:!0,source:!0,track:!0,wbr:!0});function Na(e,t){if(t){if(nm[e]&&(t.children!=null||t.dangerouslySetInnerHTML!=null))throw Error(j(137,e));if(t.dangerouslySetInnerHTML!=null){if(t.children!=null)throw Error(j(60));if(typeof t.dangerouslySetInnerHTML!="object"||!("__html"in t.dangerouslySetInnerHTML))throw Error(j(61))}if(t.style!=null&&typeof t.style!="object")throw Error(j(62))}}function Pa(e,t){if(e.indexOf("-")===-1)return typeof t.is=="string";switch(e){case"annotation-xml":case"color-profile":case"font-face":case"font-face-src":case"font-face-uri":case"font-face-format":case"font-face-name":case"missing-glyph":return!1;default:return!0}}var Ra=null;function zo(e){return e=e.target||e.srcElement||window,e.correspondingUseElement&&(e=e.correspondingUseElement),e.nodeType===3?e.parentNode:e}var _a=null,mr=null,yr=null;function qu(e){if(e=qs(e)){if(typeof _a!="function")throw Error(j(280));var t=e.stateNode;t&&(t=vl(t),_a(e.stateNode,e.type,t))}}function Yd(e){mr?yr?yr.push(e):yr=[e]:mr=e}function Xd(){if(mr){var e=mr,t=yr;if(yr=mr=null,qu(e),t)for(e=0;e>>=0,e===0?32:31-(hm(e)/pm|0)|0}var ui=64,ci=4194304;function os(e){switch(e&-e){case 1:return 1;case 2:return 2;case 4:return 4;case 8:return 8;case 16:return 16;case 32:return 32;case 64:case 128:case 256:case 512:case 1024:case 2048:case 4096:case 8192:case 16384:case 32768:case 65536:case 131072:case 262144:case 524288:case 1048576:case 2097152:return e&4194240;case 4194304:case 8388608:case 16777216:case 33554432:case 67108864:return e&130023424;case 134217728:return 134217728;case 268435456:return 268435456;case 536870912:return 536870912;case 1073741824:return 1073741824;default:return e}}function Bi(e,t){var n=e.pendingLanes;if(n===0)return 0;var r=0,s=e.suspendedLanes,i=e.pingedLanes,l=n&268435455;if(l!==0){var a=l&~s;a!==0?r=os(a):(i&=l,i!==0&&(r=os(i)))}else l=n&~s,l!==0?r=os(l):i!==0&&(r=os(i));if(r===0)return 0;if(t!==0&&t!==r&&!(t&s)&&(s=r&-r,i=t&-t,s>=i||s===16&&(i&4194240)!==0))return t;if(r&4&&(r|=n&16),t=e.entangledLanes,t!==0)for(e=e.entanglements,t&=r;0n;n++)t.push(e);return t}function Ws(e,t,n){e.pendingLanes|=t,t!==536870912&&(e.suspendedLanes=0,e.pingedLanes=0),e=e.eventTimes,t=31-ht(t),e[t]=n}function gm(e,t){var n=e.pendingLanes&~t;e.pendingLanes=t,e.suspendedLanes=0,e.pingedLanes=0,e.expiredLanes&=t,e.mutableReadLanes&=t,e.entangledLanes&=t,t=e.entanglements;var r=e.eventTimes;for(e=e.expirationTimes;0=ps),rc=" ",sc=!1;function gf(e,t){switch(e){case"keyup":return Wm.indexOf(t.keyCode)!==-1;case"keydown":return t.keyCode!==229;case"keypress":case"mousedown":case"focusout":return!0;default:return!1}}function xf(e){return e=e.detail,typeof e=="object"&&"data"in e?e.data:null}var sr=!1;function qm(e,t){switch(e){case"compositionend":return xf(t);case"keypress":return t.which!==32?null:(sc=!0,rc);case"textInput":return e=t.data,e===rc&&sc?null:e;default:return null}}function Gm(e,t){if(sr)return e==="compositionend"||!Vo&&gf(e,t)?(e=yf(),Pi=Ho=cn=null,sr=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1=t)return{node:n,offset:t-e};e=r}e:{for(;n;){if(n.nextSibling){n=n.nextSibling;break e}n=n.parentNode}n=void 0}n=oc(n)}}function Ef(e,t){return e&&t?e===t?!0:e&&e.nodeType===3?!1:t&&t.nodeType===3?Ef(e,t.parentNode):"contains"in e?e.contains(t):e.compareDocumentPosition?!!(e.compareDocumentPosition(t)&16):!1:!1}function Cf(){for(var e=window,t=zi();t instanceof e.HTMLIFrameElement;){try{var n=typeof t.contentWindow.location.href=="string"}catch{n=!1}if(n)e=t.contentWindow;else break;t=zi(e.document)}return t}function qo(e){var t=e&&e.nodeName&&e.nodeName.toLowerCase();return t&&(t==="input"&&(e.type==="text"||e.type==="search"||e.type==="tel"||e.type==="url"||e.type==="password")||t==="textarea"||e.contentEditable==="true")}function sy(e){var t=Cf(),n=e.focusedElem,r=e.selectionRange;if(t!==n&&n&&n.ownerDocument&&Ef(n.ownerDocument.documentElement,n)){if(r!==null&&qo(n)){if(t=r.start,e=r.end,e===void 0&&(e=t),"selectionStart"in n)n.selectionStart=t,n.selectionEnd=Math.min(e,n.value.length);else if(e=(t=n.ownerDocument||document)&&t.defaultView||window,e.getSelection){e=e.getSelection();var s=n.textContent.length,i=Math.min(r.start,s);r=r.end===void 0?i:Math.min(r.end,s),!e.extend&&i>r&&(s=r,r=i,i=s),s=uc(n,i);var l=uc(n,r);s&&l&&(e.rangeCount!==1||e.anchorNode!==s.node||e.anchorOffset!==s.offset||e.focusNode!==l.node||e.focusOffset!==l.offset)&&(t=t.createRange(),t.setStart(s.node,s.offset),e.removeAllRanges(),i>r?(e.addRange(t),e.extend(l.node,l.offset)):(t.setEnd(l.node,l.offset),e.addRange(t)))}}for(t=[],e=n;e=e.parentNode;)e.nodeType===1&&t.push({element:e,left:e.scrollLeft,top:e.scrollTop});for(typeof n.focus=="function"&&n.focus(),n=0;n=document.documentMode,ir=null,Ma=null,ys=null,Da=!1;function cc(e,t,n){var r=n.window===n?n.document:n.nodeType===9?n:n.ownerDocument;Da||ir==null||ir!==zi(r)||(r=ir,"selectionStart"in r&&qo(r)?r={start:r.selectionStart,end:r.selectionEnd}:(r=(r.ownerDocument&&r.ownerDocument.defaultView||window).getSelection(),r={anchorNode:r.anchorNode,anchorOffset:r.anchorOffset,focusNode:r.focusNode,focusOffset:r.focusOffset}),ys&&Rs(ys,r)||(ys=r,r=Wi(Ma,"onSelect"),0or||(e.current=Qa[or],Qa[or]=null,or--)}function W(e,t){or++,Qa[or]=e.current,e.current=t}var kn={},Pe=Cn(kn),ze=Cn(!1),Wn=kn;function br(e,t){var n=e.type.contextTypes;if(!n)return kn;var r=e.stateNode;if(r&&r.__reactInternalMemoizedUnmaskedChildContext===t)return r.__reactInternalMemoizedMaskedChildContext;var s={},i;for(i in n)s[i]=t[i];return r&&(e=e.stateNode,e.__reactInternalMemoizedUnmaskedChildContext=t,e.__reactInternalMemoizedMaskedChildContext=s),s}function Ue(e){return e=e.childContextTypes,e!=null}function qi(){G(ze),G(Pe)}function vc(e,t,n){if(Pe.current!==kn)throw Error(j(168));W(Pe,t),W(ze,n)}function Of(e,t,n){var r=e.stateNode;if(t=t.childContextTypes,typeof r.getChildContext!="function")return n;r=r.getChildContext();for(var s in r)if(!(s in t))throw Error(j(108,Zp(e)||"Unknown",s));return ee({},n,r)}function Gi(e){return e=(e=e.stateNode)&&e.__reactInternalMemoizedMergedChildContext||kn,Wn=Pe.current,W(Pe,e),W(ze,ze.current),!0}function gc(e,t,n){var r=e.stateNode;if(!r)throw Error(j(169));n?(e=Of(e,t,Wn),r.__reactInternalMemoizedMergedChildContext=e,G(ze),G(Pe),W(Pe,e)):G(ze),W(ze,n)}var Ft=null,gl=!1,ta=!1;function bf(e){Ft===null?Ft=[e]:Ft.push(e)}function yy(e){gl=!0,bf(e)}function jn(){if(!ta&&Ft!==null){ta=!0;var e=0,t=H;try{var n=Ft;for(H=1;e>=l,s-=l,It=1<<32-ht(t)+s|n<N?(b=R,R=null):b=R.sibling;var O=m(f,R,y[N],k);if(O===null){R===null&&(R=b);break}e&&R&&O.alternate===null&&t(f,R),h=i(O,h,N),P===null?C=O:P.sibling=O,P=O,R=b}if(N===y.length)return n(f,R),Y&&Rn(f,N),C;if(R===null){for(;NN?(b=R,R=null):b=R.sibling;var te=m(f,R,O.value,k);if(te===null){R===null&&(R=b);break}e&&R&&te.alternate===null&&t(f,R),h=i(te,h,N),P===null?C=te:P.sibling=te,P=te,R=b}if(O.done)return n(f,R),Y&&Rn(f,N),C;if(R===null){for(;!O.done;N++,O=y.next())O=d(f,O.value,k),O!==null&&(h=i(O,h,N),P===null?C=O:P.sibling=O,P=O);return Y&&Rn(f,N),C}for(R=r(f,R);!O.done;N++,O=y.next())O=x(R,f,N,O.value,k),O!==null&&(e&&O.alternate!==null&&R.delete(O.key===null?N:O.key),h=i(O,h,N),P===null?C=O:P.sibling=O,P=O);return e&&R.forEach(function(Je){return t(f,Je)}),Y&&Rn(f,N),C}function E(f,h,y,k){if(typeof y=="object"&&y!==null&&y.type===rr&&y.key===null&&(y=y.props.children),typeof y=="object"&&y!==null){switch(y.$$typeof){case li:e:{for(var C=y.key,P=h;P!==null;){if(P.key===C){if(C=y.type,C===rr){if(P.tag===7){n(f,P.sibling),h=s(P,y.props.children),h.return=f,f=h;break e}}else if(P.elementType===C||typeof C=="object"&&C!==null&&C.$$typeof===Yt&&Sc(C)===P.type){n(f,P.sibling),h=s(P,y.props),h.ref=ts(f,P,y),h.return=f,f=h;break e}n(f,P);break}else t(f,P);P=P.sibling}y.type===rr?(h=Kn(y.props.children,f.mode,k,y.key),h.return=f,f=h):(k=Mi(y.type,y.key,y.props,null,f.mode,k),k.ref=ts(f,h,y),k.return=f,f=k)}return l(f);case nr:e:{for(P=y.key;h!==null;){if(h.key===P)if(h.tag===4&&h.stateNode.containerInfo===y.containerInfo&&h.stateNode.implementation===y.implementation){n(f,h.sibling),h=s(h,y.children||[]),h.return=f,f=h;break e}else{n(f,h);break}else t(f,h);h=h.sibling}h=ua(y,f.mode,k),h.return=f,f=h}return l(f);case Yt:return P=y._init,E(f,h,P(y._payload),k)}if(as(y))return g(f,h,y,k);if(Yr(y))return S(f,h,y,k);vi(f,y)}return typeof y=="string"&&y!==""||typeof y=="number"?(y=""+y,h!==null&&h.tag===6?(n(f,h.sibling),h=s(h,y),h.return=f,f=h):(n(f,h),h=oa(y,f.mode,k),h.return=f,f=h),l(f)):n(f,h)}return E}var Dr=$f(!0),zf=$f(!1),Ji=Cn(null),Zi=null,dr=null,Jo=null;function Zo(){Jo=dr=Zi=null}function eu(e){var t=Ji.current;G(Ji),e._currentValue=t}function Ka(e,t,n){for(;e!==null;){var r=e.alternate;if((e.childLanes&t)!==t?(e.childLanes|=t,r!==null&&(r.childLanes|=t)):r!==null&&(r.childLanes&t)!==t&&(r.childLanes|=t),e===n)break;e=e.return}}function gr(e,t){Zi=e,Jo=dr=null,e=e.dependencies,e!==null&&e.firstContext!==null&&(e.lanes&t&&($e=!0),e.firstContext=null)}function st(e){var t=e._currentValue;if(Jo!==e)if(e={context:e,memoizedValue:t,next:null},dr===null){if(Zi===null)throw Error(j(308));dr=e,Zi.dependencies={lanes:0,firstContext:e}}else dr=dr.next=e;return t}var Fn=null;function tu(e){Fn===null?Fn=[e]:Fn.push(e)}function Uf(e,t,n,r){var s=t.interleaved;return s===null?(n.next=n,tu(t)):(n.next=s.next,s.next=n),t.interleaved=n,Bt(e,r)}function Bt(e,t){e.lanes|=t;var n=e.alternate;for(n!==null&&(n.lanes|=t),n=e,e=e.return;e!==null;)e.childLanes|=t,n=e.alternate,n!==null&&(n.childLanes|=t),n=e,e=e.return;return n.tag===3?n.stateNode:null}var Xt=!1;function nu(e){e.updateQueue={baseState:e.memoizedState,firstBaseUpdate:null,lastBaseUpdate:null,shared:{pending:null,interleaved:null,lanes:0},effects:null}}function Af(e,t){e=e.updateQueue,t.updateQueue===e&&(t.updateQueue={baseState:e.baseState,firstBaseUpdate:e.firstBaseUpdate,lastBaseUpdate:e.lastBaseUpdate,shared:e.shared,effects:e.effects})}function zt(e,t){return{eventTime:e,lane:t,tag:0,payload:null,callback:null,next:null}}function yn(e,t,n){var r=e.updateQueue;if(r===null)return null;if(r=r.shared,Q&2){var s=r.pending;return s===null?t.next=t:(t.next=s.next,s.next=t),r.pending=t,Bt(e,n)}return s=r.interleaved,s===null?(t.next=t,tu(r)):(t.next=s.next,s.next=t),r.interleaved=t,Bt(e,n)}function _i(e,t,n){if(t=t.updateQueue,t!==null&&(t=t.shared,(n&4194240)!==0)){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Ao(e,n)}}function kc(e,t){var n=e.updateQueue,r=e.alternate;if(r!==null&&(r=r.updateQueue,n===r)){var s=null,i=null;if(n=n.firstBaseUpdate,n!==null){do{var l={eventTime:n.eventTime,lane:n.lane,tag:n.tag,payload:n.payload,callback:n.callback,next:null};i===null?s=i=l:i=i.next=l,n=n.next}while(n!==null);i===null?s=i=t:i=i.next=t}else s=i=t;n={baseState:r.baseState,firstBaseUpdate:s,lastBaseUpdate:i,shared:r.shared,effects:r.effects},e.updateQueue=n;return}e=n.lastBaseUpdate,e===null?n.firstBaseUpdate=t:e.next=t,n.lastBaseUpdate=t}function el(e,t,n,r){var s=e.updateQueue;Xt=!1;var i=s.firstBaseUpdate,l=s.lastBaseUpdate,a=s.shared.pending;if(a!==null){s.shared.pending=null;var u=a,c=u.next;u.next=null,l===null?i=c:l.next=c,l=u;var p=e.alternate;p!==null&&(p=p.updateQueue,a=p.lastBaseUpdate,a!==l&&(a===null?p.firstBaseUpdate=c:a.next=c,p.lastBaseUpdate=u))}if(i!==null){var d=s.baseState;l=0,p=c=u=null,a=i;do{var m=a.lane,x=a.eventTime;if((r&m)===m){p!==null&&(p=p.next={eventTime:x,lane:0,tag:a.tag,payload:a.payload,callback:a.callback,next:null});e:{var g=e,S=a;switch(m=t,x=n,S.tag){case 1:if(g=S.payload,typeof g=="function"){d=g.call(x,d,m);break e}d=g;break e;case 3:g.flags=g.flags&-65537|128;case 0:if(g=S.payload,m=typeof g=="function"?g.call(x,d,m):g,m==null)break e;d=ee({},d,m);break e;case 2:Xt=!0}}a.callback!==null&&a.lane!==0&&(e.flags|=64,m=s.effects,m===null?s.effects=[a]:m.push(a))}else x={eventTime:x,lane:m,tag:a.tag,payload:a.payload,callback:a.callback,next:null},p===null?(c=p=x,u=d):p=p.next=x,l|=m;if(a=a.next,a===null){if(a=s.shared.pending,a===null)break;m=a,a=m.next,m.next=null,s.lastBaseUpdate=m,s.shared.pending=null}}while(!0);if(p===null&&(u=d),s.baseState=u,s.firstBaseUpdate=c,s.lastBaseUpdate=p,t=s.shared.interleaved,t!==null){s=t;do l|=s.lane,s=s.next;while(s!==t)}else i===null&&(s.shared.lanes=0);Gn|=l,e.lanes=l,e.memoizedState=d}}function Ec(e,t,n){if(e=t.effects,t.effects=null,e!==null)for(t=0;tn?n:4,e(!0);var r=ra.transition;ra.transition={};try{e(!1),t()}finally{H=n,ra.transition=r}}function sh(){return it().memoizedState}function wy(e,t,n){var r=gn(e);if(n={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null},ih(e))lh(t,n);else if(n=Uf(e,t,n,r),n!==null){var s=Fe();pt(n,e,r,s),ah(n,t,r)}}function Sy(e,t,n){var r=gn(e),s={lane:r,action:n,hasEagerState:!1,eagerState:null,next:null};if(ih(e))lh(t,s);else{var i=e.alternate;if(e.lanes===0&&(i===null||i.lanes===0)&&(i=t.lastRenderedReducer,i!==null))try{var l=t.lastRenderedState,a=i(l,n);if(s.hasEagerState=!0,s.eagerState=a,yt(a,l)){var u=t.interleaved;u===null?(s.next=s,tu(t)):(s.next=u.next,u.next=s),t.interleaved=s;return}}catch{}finally{}n=Uf(e,t,s,r),n!==null&&(s=Fe(),pt(n,e,r,s),ah(n,t,r))}}function ih(e){var t=e.alternate;return e===J||t!==null&&t===J}function lh(e,t){vs=nl=!0;var n=e.pending;n===null?t.next=t:(t.next=n.next,n.next=t),e.pending=t}function ah(e,t,n){if(n&4194240){var r=t.lanes;r&=e.pendingLanes,n|=r,t.lanes=n,Ao(e,n)}}var rl={readContext:st,useCallback:we,useContext:we,useEffect:we,useImperativeHandle:we,useInsertionEffect:we,useLayoutEffect:we,useMemo:we,useReducer:we,useRef:we,useState:we,useDebugValue:we,useDeferredValue:we,useTransition:we,useMutableSource:we,useSyncExternalStore:we,useId:we,unstable_isNewReconciler:!1},ky={readContext:st,useCallback:function(e,t){return wt().memoizedState=[e,t===void 0?null:t],e},useContext:st,useEffect:jc,useImperativeHandle:function(e,t,n){return n=n!=null?n.concat([e]):null,Ti(4194308,4,Zf.bind(null,t,e),n)},useLayoutEffect:function(e,t){return Ti(4194308,4,e,t)},useInsertionEffect:function(e,t){return Ti(4,2,e,t)},useMemo:function(e,t){var n=wt();return t=t===void 0?null:t,e=e(),n.memoizedState=[e,t],e},useReducer:function(e,t,n){var r=wt();return t=n!==void 0?n(t):t,r.memoizedState=r.baseState=t,e={pending:null,interleaved:null,lanes:0,dispatch:null,lastRenderedReducer:e,lastRenderedState:t},r.queue=e,e=e.dispatch=wy.bind(null,J,e),[r.memoizedState,e]},useRef:function(e){var t=wt();return e={current:e},t.memoizedState=e},useState:Cc,useDebugValue:cu,useDeferredValue:function(e){return wt().memoizedState=e},useTransition:function(){var e=Cc(!1),t=e[0];return e=xy.bind(null,e[1]),wt().memoizedState=e,[t,e]},useMutableSource:function(){},useSyncExternalStore:function(e,t,n){var r=J,s=wt();if(Y){if(n===void 0)throw Error(j(407));n=n()}else{if(n=t(),pe===null)throw Error(j(349));qn&30||Kf(r,t,n)}s.memoizedState=n;var i={value:n,getSnapshot:t};return s.queue=i,jc(Vf.bind(null,r,i,e),[e]),r.flags|=2048,Ds(9,Wf.bind(null,r,i,n,t),void 0,null),n},useId:function(){var e=wt(),t=pe.identifierPrefix;if(Y){var n=$t,r=It;n=(r&~(1<<32-ht(r)-1)).toString(32)+n,t=":"+t+"R"+n,n=bs++,0<\/script>",e=e.removeChild(e.firstChild)):typeof r.is=="string"?e=l.createElement(n,{is:r.is}):(e=l.createElement(n),n==="select"&&(l=e,r.multiple?l.multiple=!0:r.size&&(l.size=r.size))):e=l.createElementNS(e,n),e[Ct]=t,e[Ts]=r,vh(e,t,!1,!1),t.stateNode=e;e:{switch(l=Pa(n,r),n){case"dialog":q("cancel",e),q("close",e),s=r;break;case"iframe":case"object":case"embed":q("load",e),s=r;break;case"video":case"audio":for(s=0;szr&&(t.flags|=128,r=!0,ns(i,!1),t.lanes=4194304)}else{if(!r)if(e=tl(l),e!==null){if(t.flags|=128,r=!0,n=e.updateQueue,n!==null&&(t.updateQueue=n,t.flags|=4),ns(i,!0),i.tail===null&&i.tailMode==="hidden"&&!l.alternate&&!Y)return Se(t),null}else 2*ie()-i.renderingStartTime>zr&&n!==1073741824&&(t.flags|=128,r=!0,ns(i,!1),t.lanes=4194304);i.isBackwards?(l.sibling=t.child,t.child=l):(n=i.last,n!==null?n.sibling=l:t.child=l,i.last=l)}return i.tail!==null?(t=i.tail,i.rendering=t,i.tail=t.sibling,i.renderingStartTime=ie(),t.sibling=null,n=X.current,W(X,r?n&1|2:n&1),t):(Se(t),null);case 22:case 23:return yu(),r=t.memoizedState!==null,e!==null&&e.memoizedState!==null!==r&&(t.flags|=8192),r&&t.mode&1?Be&1073741824&&(Se(t),t.subtreeFlags&6&&(t.flags|=8192)):Se(t),null;case 24:return null;case 25:return null}throw Error(j(156,t.tag))}function Ly(e,t){switch(Yo(t),t.tag){case 1:return Ue(t.type)&&qi(),e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 3:return Ir(),G(ze),G(Pe),iu(),e=t.flags,e&65536&&!(e&128)?(t.flags=e&-65537|128,t):null;case 5:return su(t),null;case 13:if(G(X),e=t.memoizedState,e!==null&&e.dehydrated!==null){if(t.alternate===null)throw Error(j(340));Mr()}return e=t.flags,e&65536?(t.flags=e&-65537|128,t):null;case 19:return G(X),null;case 4:return Ir(),null;case 10:return eu(t.type._context),null;case 22:case 23:return yu(),null;case 24:return null;default:return null}}var xi=!1,je=!1,Ty=typeof WeakSet=="function"?WeakSet:Set,L=null;function fr(e,t){var n=e.ref;if(n!==null)if(typeof n=="function")try{n(null)}catch(r){re(e,t,r)}else n.current=null}function eo(e,t,n){try{n()}catch(r){re(e,t,r)}}var Dc=!1;function Fy(e,t){if(Ia=Hi,e=Cf(),qo(e)){if("selectionStart"in e)var n={start:e.selectionStart,end:e.selectionEnd};else e:{n=(n=e.ownerDocument)&&n.defaultView||window;var r=n.getSelection&&n.getSelection();if(r&&r.rangeCount!==0){n=r.anchorNode;var s=r.anchorOffset,i=r.focusNode;r=r.focusOffset;try{n.nodeType,i.nodeType}catch{n=null;break e}var l=0,a=-1,u=-1,c=0,p=0,d=e,m=null;t:for(;;){for(var x;d!==n||s!==0&&d.nodeType!==3||(a=l+s),d!==i||r!==0&&d.nodeType!==3||(u=l+r),d.nodeType===3&&(l+=d.nodeValue.length),(x=d.firstChild)!==null;)m=d,d=x;for(;;){if(d===e)break t;if(m===n&&++c===s&&(a=l),m===i&&++p===r&&(u=l),(x=d.nextSibling)!==null)break;d=m,m=d.parentNode}d=x}n=a===-1||u===-1?null:{start:a,end:u}}else n=null}n=n||{start:0,end:0}}else n=null;for($a={focusedElem:e,selectionRange:n},Hi=!1,L=t;L!==null;)if(t=L,e=t.child,(t.subtreeFlags&1028)!==0&&e!==null)e.return=t,L=e;else for(;L!==null;){t=L;try{var g=t.alternate;if(t.flags&1024)switch(t.tag){case 0:case 11:case 15:break;case 1:if(g!==null){var S=g.memoizedProps,E=g.memoizedState,f=t.stateNode,h=f.getSnapshotBeforeUpdate(t.elementType===t.type?S:ut(t.type,S),E);f.__reactInternalSnapshotBeforeUpdate=h}break;case 3:var y=t.stateNode.containerInfo;y.nodeType===1?y.textContent="":y.nodeType===9&&y.documentElement&&y.removeChild(y.documentElement);break;case 5:case 6:case 4:case 17:break;default:throw Error(j(163))}}catch(k){re(t,t.return,k)}if(e=t.sibling,e!==null){e.return=t.return,L=e;break}L=t.return}return g=Dc,Dc=!1,g}function gs(e,t,n){var r=t.updateQueue;if(r=r!==null?r.lastEffect:null,r!==null){var s=r=r.next;do{if((s.tag&e)===e){var i=s.destroy;s.destroy=void 0,i!==void 0&&eo(t,n,i)}s=s.next}while(s!==r)}}function Sl(e,t){if(t=t.updateQueue,t=t!==null?t.lastEffect:null,t!==null){var n=t=t.next;do{if((n.tag&e)===e){var r=n.create;n.destroy=r()}n=n.next}while(n!==t)}}function to(e){var t=e.ref;if(t!==null){var n=e.stateNode;switch(e.tag){case 5:e=n;break;default:e=n}typeof t=="function"?t(e):t.current=e}}function wh(e){var t=e.alternate;t!==null&&(e.alternate=null,wh(t)),e.child=null,e.deletions=null,e.sibling=null,e.tag===5&&(t=e.stateNode,t!==null&&(delete t[Ct],delete t[Ts],delete t[Aa],delete t[py],delete t[my])),e.stateNode=null,e.return=null,e.dependencies=null,e.memoizedProps=null,e.memoizedState=null,e.pendingProps=null,e.stateNode=null,e.updateQueue=null}function Sh(e){return e.tag===5||e.tag===3||e.tag===4}function Ic(e){e:for(;;){for(;e.sibling===null;){if(e.return===null||Sh(e.return))return null;e=e.return}for(e.sibling.return=e.return,e=e.sibling;e.tag!==5&&e.tag!==6&&e.tag!==18;){if(e.flags&2||e.child===null||e.tag===4)continue e;e.child.return=e,e=e.child}if(!(e.flags&2))return e.stateNode}}function no(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.nodeType===8?n.parentNode.insertBefore(e,t):n.insertBefore(e,t):(n.nodeType===8?(t=n.parentNode,t.insertBefore(e,n)):(t=n,t.appendChild(e)),n=n._reactRootContainer,n!=null||t.onclick!==null||(t.onclick=Vi));else if(r!==4&&(e=e.child,e!==null))for(no(e,t,n),e=e.sibling;e!==null;)no(e,t,n),e=e.sibling}function ro(e,t,n){var r=e.tag;if(r===5||r===6)e=e.stateNode,t?n.insertBefore(e,t):n.appendChild(e);else if(r!==4&&(e=e.child,e!==null))for(ro(e,t,n),e=e.sibling;e!==null;)ro(e,t,n),e=e.sibling}var ve=null,dt=!1;function qt(e,t,n){for(n=n.child;n!==null;)kh(e,t,n),n=n.sibling}function kh(e,t,n){if(jt&&typeof jt.onCommitFiberUnmount=="function")try{jt.onCommitFiberUnmount(hl,n)}catch{}switch(n.tag){case 5:je||fr(n,t);case 6:var r=ve,s=dt;ve=null,qt(e,t,n),ve=r,dt=s,ve!==null&&(dt?(e=ve,n=n.stateNode,e.nodeType===8?e.parentNode.removeChild(n):e.removeChild(n)):ve.removeChild(n.stateNode));break;case 18:ve!==null&&(dt?(e=ve,n=n.stateNode,e.nodeType===8?ea(e.parentNode,n):e.nodeType===1&&ea(e,n),Ns(e)):ea(ve,n.stateNode));break;case 4:r=ve,s=dt,ve=n.stateNode.containerInfo,dt=!0,qt(e,t,n),ve=r,dt=s;break;case 0:case 11:case 14:case 15:if(!je&&(r=n.updateQueue,r!==null&&(r=r.lastEffect,r!==null))){s=r=r.next;do{var i=s,l=i.destroy;i=i.tag,l!==void 0&&(i&2||i&4)&&eo(n,t,l),s=s.next}while(s!==r)}qt(e,t,n);break;case 1:if(!je&&(fr(n,t),r=n.stateNode,typeof r.componentWillUnmount=="function"))try{r.props=n.memoizedProps,r.state=n.memoizedState,r.componentWillUnmount()}catch(a){re(n,t,a)}qt(e,t,n);break;case 21:qt(e,t,n);break;case 22:n.mode&1?(je=(r=je)||n.memoizedState!==null,qt(e,t,n),je=r):qt(e,t,n);break;default:qt(e,t,n)}}function $c(e){var t=e.updateQueue;if(t!==null){e.updateQueue=null;var n=e.stateNode;n===null&&(n=e.stateNode=new Ty),t.forEach(function(r){var s=Ay.bind(null,e,r);n.has(r)||(n.add(r),r.then(s,s))})}}function ot(e,t){var n=t.deletions;if(n!==null)for(var r=0;rs&&(s=l),r&=~i}if(r=s,r=ie()-r,r=(120>r?120:480>r?480:1080>r?1080:1920>r?1920:3e3>r?3e3:4320>r?4320:1960*by(r/1960))-r,10e?16:e,dn===null)var r=!1;else{if(e=dn,dn=null,ll=0,Q&6)throw Error(j(331));var s=Q;for(Q|=4,L=e.current;L!==null;){var i=L,l=i.child;if(L.flags&16){var a=i.deletions;if(a!==null){for(var u=0;uie()-pu?Hn(e,0):hu|=n),Ae(e,t)}function Lh(e,t){t===0&&(e.mode&1?(t=ci,ci<<=1,!(ci&130023424)&&(ci=4194304)):t=1);var n=Fe();e=Bt(e,t),e!==null&&(Ws(e,t,n),Ae(e,n))}function Uy(e){var t=e.memoizedState,n=0;t!==null&&(n=t.retryLane),Lh(e,n)}function Ay(e,t){var n=0;switch(e.tag){case 13:var r=e.stateNode,s=e.memoizedState;s!==null&&(n=s.retryLane);break;case 19:r=e.stateNode;break;default:throw Error(j(314))}r!==null&&r.delete(t),Lh(e,n)}var Th;Th=function(e,t,n){if(e!==null)if(e.memoizedProps!==t.pendingProps||ze.current)$e=!0;else{if(!(e.lanes&n)&&!(t.flags&128))return $e=!1,Ry(e,t,n);$e=!!(e.flags&131072)}else $e=!1,Y&&t.flags&1048576&&Mf(t,Xi,t.index);switch(t.lanes=0,t.tag){case 2:var r=t.type;Fi(e,t),e=t.pendingProps;var s=br(t,Pe.current);gr(t,n),s=au(null,t,r,e,s,n);var i=ou();return t.flags|=1,typeof s=="object"&&s!==null&&typeof s.render=="function"&&s.$$typeof===void 0?(t.tag=1,t.memoizedState=null,t.updateQueue=null,Ue(r)?(i=!0,Gi(t)):i=!1,t.memoizedState=s.state!==null&&s.state!==void 0?s.state:null,nu(t),s.updater=wl,t.stateNode=s,s._reactInternals=t,Va(t,r,e,n),t=Ya(null,t,r,!0,i,n)):(t.tag=0,Y&&i&&Go(t),Le(null,t,s,n),t=t.child),t;case 16:r=t.elementType;e:{switch(Fi(e,t),e=t.pendingProps,s=r._init,r=s(r._payload),t.type=r,s=t.tag=By(r),e=ut(r,e),s){case 0:t=Ga(null,t,r,e,n);break e;case 1:t=Oc(null,t,r,e,n);break e;case 11:t=Tc(null,t,r,e,n);break e;case 14:t=Fc(null,t,r,ut(r.type,e),n);break e}throw Error(j(306,r,""))}return t;case 0:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ut(r,s),Ga(e,t,r,s,n);case 1:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ut(r,s),Oc(e,t,r,s,n);case 3:e:{if(ph(t),e===null)throw Error(j(387));r=t.pendingProps,i=t.memoizedState,s=i.element,Af(e,t),el(t,r,null,n);var l=t.memoizedState;if(r=l.element,i.isDehydrated)if(i={element:r,isDehydrated:!1,cache:l.cache,pendingSuspenseBoundaries:l.pendingSuspenseBoundaries,transitions:l.transitions},t.updateQueue.baseState=i,t.memoizedState=i,t.flags&256){s=$r(Error(j(423)),t),t=bc(e,t,r,n,s);break e}else if(r!==s){s=$r(Error(j(424)),t),t=bc(e,t,r,n,s);break e}else for(We=mn(t.stateNode.containerInfo.firstChild),qe=t,Y=!0,ft=null,n=zf(t,null,r,n),t.child=n;n;)n.flags=n.flags&-3|4096,n=n.sibling;else{if(Mr(),r===s){t=Ht(e,t,n);break e}Le(e,t,r,n)}t=t.child}return t;case 5:return Qf(t),e===null&&Ha(t),r=t.type,s=t.pendingProps,i=e!==null?e.memoizedProps:null,l=s.children,za(r,s)?l=null:i!==null&&za(r,i)&&(t.flags|=32),hh(e,t),Le(e,t,l,n),t.child;case 6:return e===null&&Ha(t),null;case 13:return mh(e,t,n);case 4:return ru(t,t.stateNode.containerInfo),r=t.pendingProps,e===null?t.child=Dr(t,null,r,n):Le(e,t,r,n),t.child;case 11:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ut(r,s),Tc(e,t,r,s,n);case 7:return Le(e,t,t.pendingProps,n),t.child;case 8:return Le(e,t,t.pendingProps.children,n),t.child;case 12:return Le(e,t,t.pendingProps.children,n),t.child;case 10:e:{if(r=t.type._context,s=t.pendingProps,i=t.memoizedProps,l=s.value,W(Ji,r._currentValue),r._currentValue=l,i!==null)if(yt(i.value,l)){if(i.children===s.children&&!ze.current){t=Ht(e,t,n);break e}}else for(i=t.child,i!==null&&(i.return=t);i!==null;){var a=i.dependencies;if(a!==null){l=i.child;for(var u=a.firstContext;u!==null;){if(u.context===r){if(i.tag===1){u=zt(-1,n&-n),u.tag=2;var c=i.updateQueue;if(c!==null){c=c.shared;var p=c.pending;p===null?u.next=u:(u.next=p.next,p.next=u),c.pending=u}}i.lanes|=n,u=i.alternate,u!==null&&(u.lanes|=n),Ka(i.return,n,t),a.lanes|=n;break}u=u.next}}else if(i.tag===10)l=i.type===t.type?null:i.child;else if(i.tag===18){if(l=i.return,l===null)throw Error(j(341));l.lanes|=n,a=l.alternate,a!==null&&(a.lanes|=n),Ka(l,n,t),l=i.sibling}else l=i.child;if(l!==null)l.return=i;else for(l=i;l!==null;){if(l===t){l=null;break}if(i=l.sibling,i!==null){i.return=l.return,l=i;break}l=l.return}i=l}Le(e,t,s.children,n),t=t.child}return t;case 9:return s=t.type,r=t.pendingProps.children,gr(t,n),s=st(s),r=r(s),t.flags|=1,Le(e,t,r,n),t.child;case 14:return r=t.type,s=ut(r,t.pendingProps),s=ut(r.type,s),Fc(e,t,r,s,n);case 15:return dh(e,t,t.type,t.pendingProps,n);case 17:return r=t.type,s=t.pendingProps,s=t.elementType===r?s:ut(r,s),Fi(e,t),t.tag=1,Ue(r)?(e=!0,Gi(t)):e=!1,gr(t,n),oh(t,r,s),Va(t,r,s,n),Ya(null,t,r,!0,e,n);case 19:return yh(e,t,n);case 22:return fh(e,t,n)}throw Error(j(156,t.tag))};function Fh(e,t){return sf(e,t)}function Qy(e,t,n,r){this.tag=e,this.key=n,this.sibling=this.child=this.return=this.stateNode=this.type=this.elementType=null,this.index=0,this.ref=null,this.pendingProps=t,this.dependencies=this.memoizedState=this.updateQueue=this.memoizedProps=null,this.mode=r,this.subtreeFlags=this.flags=0,this.deletions=null,this.childLanes=this.lanes=0,this.alternate=null}function nt(e,t,n,r){return new Qy(e,t,n,r)}function gu(e){return e=e.prototype,!(!e||!e.isReactComponent)}function By(e){if(typeof e=="function")return gu(e)?1:0;if(e!=null){if(e=e.$$typeof,e===Io)return 11;if(e===$o)return 14}return 2}function xn(e,t){var n=e.alternate;return n===null?(n=nt(e.tag,t,e.key,e.mode),n.elementType=e.elementType,n.type=e.type,n.stateNode=e.stateNode,n.alternate=e,e.alternate=n):(n.pendingProps=t,n.type=e.type,n.flags=0,n.subtreeFlags=0,n.deletions=null),n.flags=e.flags&14680064,n.childLanes=e.childLanes,n.lanes=e.lanes,n.child=e.child,n.memoizedProps=e.memoizedProps,n.memoizedState=e.memoizedState,n.updateQueue=e.updateQueue,t=e.dependencies,n.dependencies=t===null?null:{lanes:t.lanes,firstContext:t.firstContext},n.sibling=e.sibling,n.index=e.index,n.ref=e.ref,n}function Mi(e,t,n,r,s,i){var l=2;if(r=e,typeof e=="function")gu(e)&&(l=1);else if(typeof e=="string")l=5;else e:switch(e){case rr:return Kn(n.children,s,i,t);case Do:l=8,s|=8;break;case va:return e=nt(12,n,t,s|2),e.elementType=va,e.lanes=i,e;case ga:return e=nt(13,n,t,s),e.elementType=ga,e.lanes=i,e;case xa:return e=nt(19,n,t,s),e.elementType=xa,e.lanes=i,e;case Ad:return El(n,s,i,t);default:if(typeof e=="object"&&e!==null)switch(e.$$typeof){case zd:l=10;break e;case Ud:l=9;break e;case Io:l=11;break e;case $o:l=14;break e;case Yt:l=16,r=null;break e}throw Error(j(130,e==null?e:typeof e,""))}return t=nt(l,n,t,s),t.elementType=e,t.type=r,t.lanes=i,t}function Kn(e,t,n,r){return e=nt(7,e,r,t),e.lanes=n,e}function El(e,t,n,r){return e=nt(22,e,r,t),e.elementType=Ad,e.lanes=n,e.stateNode={isHidden:!1},e}function oa(e,t,n){return e=nt(6,e,null,t),e.lanes=n,e}function ua(e,t,n){return t=nt(4,e.children!==null?e.children:[],e.key,t),t.lanes=n,t.stateNode={containerInfo:e.containerInfo,pendingChildren:null,implementation:e.implementation},t}function Hy(e,t,n,r,s){this.tag=t,this.containerInfo=e,this.finishedWork=this.pingCache=this.current=this.pendingChildren=null,this.timeoutHandle=-1,this.callbackNode=this.pendingContext=this.context=null,this.callbackPriority=0,this.eventTimes=Bl(0),this.expirationTimes=Bl(-1),this.entangledLanes=this.finishedLanes=this.mutableReadLanes=this.expiredLanes=this.pingedLanes=this.suspendedLanes=this.pendingLanes=0,this.entanglements=Bl(0),this.identifierPrefix=r,this.onRecoverableError=s,this.mutableSourceEagerHydrationData=null}function xu(e,t,n,r,s,i,l,a,u){return e=new Hy(e,t,n,a,u),t===1?(t=1,i===!0&&(t|=8)):t=0,i=nt(3,null,null,t),e.current=i,i.stateNode=e,i.memoizedState={element:r,isDehydrated:n,cache:null,transitions:null,pendingSuspenseBoundaries:null},nu(i),e}function Ky(e,t,n){var r=3"u"||typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE!="function"))try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(Dh)}catch(e){console.error(e)}}Dh(),Md.exports=Ye;var Yy=Md.exports,Wc=Yy;ma.createRoot=Wc.createRoot,ma.hydrateRoot=Wc.hydrateRoot;var Kr=class{constructor(){this.listeners=new Set,this.subscribe=this.subscribe.bind(this)}subscribe(e){return this.listeners.add(e),this.onSubscribe(),()=>{this.listeners.delete(e),this.onUnsubscribe()}}hasListeners(){return this.listeners.size>0}onSubscribe(){}onUnsubscribe(){}},Mn,en,wr,hd,Xy=(hd=class extends Kr{constructor(){super();F(this,Mn);F(this,en);F(this,wr);_(this,wr,t=>{if(typeof window<"u"&&window.addEventListener){const n=()=>t();return window.addEventListener("visibilitychange",n,!1),()=>{window.removeEventListener("visibilitychange",n)}}})}onSubscribe(){v(this,en)||this.setEventListener(v(this,wr))}onUnsubscribe(){var t;this.hasListeners()||((t=v(this,en))==null||t.call(this),_(this,en,void 0))}setEventListener(t){var n;_(this,wr,t),(n=v(this,en))==null||n.call(this),_(this,en,t(r=>{typeof r=="boolean"?this.setFocused(r):this.onFocus()}))}setFocused(t){v(this,Mn)!==t&&(_(this,Mn,t),this.onFocus())}onFocus(){const t=this.isFocused();this.listeners.forEach(n=>{n(t)})}isFocused(){var t;return typeof v(this,Mn)=="boolean"?v(this,Mn):((t=globalThis.document)==null?void 0:t.visibilityState)!=="hidden"}},Mn=new WeakMap,en=new WeakMap,wr=new WeakMap,hd),Eu=new Xy,Jy={setTimeout:(e,t)=>setTimeout(e,t),clearTimeout:e=>clearTimeout(e),setInterval:(e,t)=>setInterval(e,t),clearInterval:e=>clearInterval(e)},tn,Ro,pd,Zy=(pd=class{constructor(){F(this,tn,Jy);F(this,Ro,!1)}setTimeoutProvider(e){_(this,tn,e)}setTimeout(e,t){return v(this,tn).setTimeout(e,t)}clearTimeout(e){v(this,tn).clearTimeout(e)}setInterval(e,t){return v(this,tn).setInterval(e,t)}clearInterval(e){v(this,tn).clearInterval(e)}},tn=new WeakMap,Ro=new WeakMap,pd),bn=new Zy;function ev(e){setTimeout(e,0)}var tv=typeof window>"u"||"Deno"in globalThis;function Te(){}function nv(e,t){return typeof e=="function"?e(t):e}function oo(e){return typeof e=="number"&&e>=0&&e!==1/0}function Ih(e,t){return Math.max(e+(t||0)-Date.now(),0)}function wn(e,t){return typeof e=="function"?e(t):e}function Ke(e,t){return typeof e=="function"?e(t):e}function Vc(e,t){const{type:n="all",exact:r,fetchStatus:s,predicate:i,queryKey:l,stale:a}=e;if(l){if(r){if(t.queryHash!==Cu(l,t.options))return!1}else if(!$s(t.queryKey,l))return!1}if(n!=="all"){const u=t.isActive();if(n==="active"&&!u||n==="inactive"&&u)return!1}return!(typeof a=="boolean"&&t.isStale()!==a||s&&s!==t.state.fetchStatus||i&&!i(t))}function qc(e,t){const{exact:n,status:r,predicate:s,mutationKey:i}=e;if(i){if(!t.options.mutationKey)return!1;if(n){if(Xn(t.options.mutationKey)!==Xn(i))return!1}else if(!$s(t.options.mutationKey,i))return!1}return!(r&&t.state.status!==r||s&&!s(t))}function Cu(e,t){return((t==null?void 0:t.queryKeyHashFn)||Xn)(e)}function Xn(e){return JSON.stringify(e,(t,n)=>uo(n)?Object.keys(n).sort().reduce((r,s)=>(r[s]=n[s],r),{}):n)}function $s(e,t){return e===t?!0:typeof e!=typeof t?!1:e&&t&&typeof e=="object"&&typeof t=="object"?Object.keys(t).every(n=>$s(e[n],t[n])):!1}var rv=Object.prototype.hasOwnProperty;function $h(e,t,n=0){if(e===t)return e;if(n>500)return t;const r=Gc(e)&&Gc(t);if(!r&&!(uo(e)&&uo(t)))return t;const i=(r?e:Object.keys(e)).length,l=r?t:Object.keys(t),a=l.length,u=r?new Array(a):{};let c=0;for(let p=0;p{bn.setTimeout(t,e)})}function co(e,t,n){return typeof n.structuralSharing=="function"?n.structuralSharing(e,t):n.structuralSharing!==!1?$h(e,t):t}function iv(e,t,n=0){const r=[...e,t];return n&&r.length>n?r.slice(1):r}function lv(e,t,n=0){const r=[t,...e];return n&&r.length>n?r.slice(0,-1):r}var ju=Symbol();function zh(e,t){return!e.queryFn&&(t!=null&&t.initialPromise)?()=>t.initialPromise:!e.queryFn||e.queryFn===ju?()=>Promise.reject(new Error(`Missing queryFn: '${e.queryHash}'`)):e.queryFn}function Nu(e,t){return typeof e=="function"?e(...t):!!e}function av(e,t,n){let r=!1,s;return Object.defineProperty(e,"signal",{enumerable:!0,get:()=>(s??(s=t()),r||(r=!0,s.aborted?n():s.addEventListener("abort",n,{once:!0})),s)}),e}var zs=(()=>{let e=()=>tv;return{isServer(){return e()},setIsServer(t){e=t}}})();function fo(){let e,t;const n=new Promise((s,i)=>{e=s,t=i});n.status="pending",n.catch(()=>{});function r(s){Object.assign(n,s),delete n.resolve,delete n.reject}return n.resolve=s=>{r({status:"fulfilled",value:s}),e(s)},n.reject=s=>{r({status:"rejected",reason:s}),t(s)},n}var ov=ev;function uv(){let e=[],t=0,n=a=>{a()},r=a=>{a()},s=ov;const i=a=>{t?e.push(a):s(()=>{n(a)})},l=()=>{const a=e;e=[],a.length&&s(()=>{r(()=>{a.forEach(u=>{n(u)})})})};return{batch:a=>{let u;t++;try{u=a()}finally{t--,t||l()}return u},batchCalls:a=>(...u)=>{i(()=>{a(...u)})},schedule:i,setNotifyFunction:a=>{n=a},setBatchNotifyFunction:a=>{r=a},setScheduler:a=>{s=a}}}var ue=uv(),Sr,nn,kr,md,cv=(md=class extends Kr{constructor(){super();F(this,Sr,!0);F(this,nn);F(this,kr);_(this,kr,t=>{if(typeof window<"u"&&window.addEventListener){const n=()=>t(!0),r=()=>t(!1);return window.addEventListener("online",n,!1),window.addEventListener("offline",r,!1),()=>{window.removeEventListener("online",n),window.removeEventListener("offline",r)}}})}onSubscribe(){v(this,nn)||this.setEventListener(v(this,kr))}onUnsubscribe(){var t;this.hasListeners()||((t=v(this,nn))==null||t.call(this),_(this,nn,void 0))}setEventListener(t){var n;_(this,kr,t),(n=v(this,nn))==null||n.call(this),_(this,nn,t(this.setOnline.bind(this)))}setOnline(t){v(this,Sr)!==t&&(_(this,Sr,t),this.listeners.forEach(r=>{r(t)}))}isOnline(){return v(this,Sr)}},Sr=new WeakMap,nn=new WeakMap,kr=new WeakMap,md),cl=new cv;function dv(e){return Math.min(1e3*2**e,3e4)}function Uh(e){return(e??"online")==="online"?cl.isOnline():!0}var ho=class extends Error{constructor(e){super("CancelledError"),this.revert=e==null?void 0:e.revert,this.silent=e==null?void 0:e.silent}};function Ah(e){let t=!1,n=0,r;const s=fo(),i=()=>s.status!=="pending",l=S=>{var E;if(!i()){const f=new ho(S);m(f),(E=e.onCancel)==null||E.call(e,f)}},a=()=>{t=!0},u=()=>{t=!1},c=()=>Eu.isFocused()&&(e.networkMode==="always"||cl.isOnline())&&e.canRun(),p=()=>Uh(e.networkMode)&&e.canRun(),d=S=>{i()||(r==null||r(),s.resolve(S))},m=S=>{i()||(r==null||r(),s.reject(S))},x=()=>new Promise(S=>{var E;r=f=>{(i()||c())&&S(f)},(E=e.onPause)==null||E.call(e)}).then(()=>{var S;r=void 0,i()||(S=e.onContinue)==null||S.call(e)}),g=()=>{if(i())return;let S;const E=n===0?e.initialPromise:void 0;try{S=E??e.fn()}catch(f){S=Promise.reject(f)}Promise.resolve(S).then(d).catch(f=>{var P;if(i())return;const h=e.retry??(zs.isServer()?0:3),y=e.retryDelay??dv,k=typeof y=="function"?y(n,f):y,C=h===!0||typeof h=="number"&&nc()?void 0:x()).then(()=>{t?m(f):g()})})};return{promise:s,status:()=>s.status,cancel:l,continue:()=>(r==null||r(),s),cancelRetry:a,continueRetry:u,canStart:p,start:()=>(p()?g():x().then(g),s)}}var Dn,yd,Qh=(yd=class{constructor(){F(this,Dn)}destroy(){this.clearGcTimeout()}scheduleGc(){this.clearGcTimeout(),oo(this.gcTime)&&_(this,Dn,bn.setTimeout(()=>{this.optionalRemove()},this.gcTime))}updateGcTime(e){this.gcTime=Math.max(this.gcTime||0,e??(zs.isServer()?1/0:5*60*1e3))}clearGcTimeout(){v(this,Dn)!==void 0&&(bn.clearTimeout(v(this,Dn)),_(this,Dn,void 0))}},Dn=new WeakMap,yd);function fv(e){return{onFetch:(t,n)=>{var p,d,m,x,g;const r=t.options,s=(m=(d=(p=t.fetchOptions)==null?void 0:p.meta)==null?void 0:d.fetchMore)==null?void 0:m.direction,i=((x=t.state.data)==null?void 0:x.pages)||[],l=((g=t.state.data)==null?void 0:g.pageParams)||[];let a={pages:[],pageParams:[]},u=0;const c=async()=>{let S=!1;const E=y=>{av(y,()=>t.signal,()=>S=!0)},f=zh(t.options,t.fetchOptions),h=async(y,k,C)=>{if(S)return Promise.reject(t.signal.reason);if(k==null&&y.pages.length)return Promise.resolve(y);const R=(()=>{const te={client:t.client,queryKey:t.queryKey,pageParam:k,direction:C?"backward":"forward",meta:t.options.meta};return E(te),te})(),N=await f(R),{maxPages:b}=t.options,O=C?lv:iv;return{pages:O(y.pages,N,b),pageParams:O(y.pageParams,k,b)}};if(s&&i.length){const y=s==="backward",k=y?hv:Xc,C={pages:i,pageParams:l},P=k(r,C);a=await h(C,P,y)}else{const y=e??i.length;do{const k=u===0?l[0]??r.initialPageParam:Xc(r,a);if(u>0&&k==null)break;a=await h(a,k),u++}while(u{var S,E;return(E=(S=t.options).persister)==null?void 0:E.call(S,c,{client:t.client,queryKey:t.queryKey,meta:t.options.meta,signal:t.signal},n)}:t.fetchFn=c}}}function Xc(e,{pages:t,pageParams:n}){const r=t.length-1;return t.length>0?e.getNextPageParam(t[r],t,n[r],n):void 0}function hv(e,{pages:t,pageParams:n}){var r;return t.length>0?(r=e.getPreviousPageParam)==null?void 0:r.call(e,t[0],t,n[0],n):void 0}var Er,In,Cr,Ze,$n,fe,Us,zn,He,Bh,Lt,vd,pv=(vd=class extends Qh{constructor(t){super();F(this,He);F(this,Er);F(this,In);F(this,Cr);F(this,Ze);F(this,$n);F(this,fe);F(this,Us);F(this,zn);_(this,zn,!1),_(this,Us,t.defaultOptions),this.setOptions(t.options),this.observers=[],_(this,$n,t.client),_(this,Ze,v(this,$n).getQueryCache()),this.queryKey=t.queryKey,this.queryHash=t.queryHash,_(this,In,Zc(this.options)),this.state=t.state??v(this,In),this.scheduleGc()}get meta(){return this.options.meta}get queryType(){return v(this,Er)}get promise(){var t;return(t=v(this,fe))==null?void 0:t.promise}setOptions(t){if(this.options={...v(this,Us),...t},t!=null&&t._type&&_(this,Er,t._type),this.updateGcTime(this.options.gcTime),this.state&&this.state.data===void 0){const n=Zc(this.options);n.data!==void 0&&(this.setState(Jc(n.data,n.dataUpdatedAt)),_(this,In,n))}}optionalRemove(){!this.observers.length&&this.state.fetchStatus==="idle"&&v(this,Ze).remove(this)}setData(t,n){const r=co(this.state.data,t,this.options);return I(this,He,Lt).call(this,{data:r,type:"success",dataUpdatedAt:n==null?void 0:n.updatedAt,manual:n==null?void 0:n.manual}),r}setState(t){I(this,He,Lt).call(this,{type:"setState",state:t})}cancel(t){var r,s;const n=(r=v(this,fe))==null?void 0:r.promise;return(s=v(this,fe))==null||s.cancel(t),n?n.then(Te).catch(Te):Promise.resolve()}destroy(){super.destroy(),this.cancel({silent:!0})}get resetState(){return v(this,In)}reset(){this.destroy(),this.setState(this.resetState)}isActive(){return this.observers.some(t=>Ke(t.options.enabled,this)!==!1)}isDisabled(){return this.getObserversCount()>0?!this.isActive():this.options.queryFn===ju||!this.isFetched()}isFetched(){return this.state.dataUpdateCount+this.state.errorUpdateCount>0}isStatic(){return this.getObserversCount()>0?this.observers.some(t=>wn(t.options.staleTime,this)==="static"):!1}isStale(){return this.getObserversCount()>0?this.observers.some(t=>t.getCurrentResult().isStale):this.state.data===void 0||this.state.isInvalidated}isStaleByTime(t=0){return this.state.data===void 0?!0:t==="static"?!1:this.state.isInvalidated?!0:!Ih(this.state.dataUpdatedAt,t)}onFocus(){var n;const t=this.observers.find(r=>r.shouldFetchOnWindowFocus());t==null||t.refetch({cancelRefetch:!1}),(n=v(this,fe))==null||n.continue()}onOnline(){var n;const t=this.observers.find(r=>r.shouldFetchOnReconnect());t==null||t.refetch({cancelRefetch:!1}),(n=v(this,fe))==null||n.continue()}addObserver(t){this.observers.includes(t)||(this.observers.push(t),this.clearGcTimeout(),v(this,Ze).notify({type:"observerAdded",query:this,observer:t}))}removeObserver(t){this.observers.includes(t)&&(this.observers=this.observers.filter(n=>n!==t),this.observers.length||(v(this,fe)&&(v(this,zn)||I(this,He,Bh).call(this)?v(this,fe).cancel({revert:!0}):v(this,fe).cancelRetry()),this.scheduleGc()),v(this,Ze).notify({type:"observerRemoved",query:this,observer:t}))}getObserversCount(){return this.observers.length}invalidate(){this.state.isInvalidated||I(this,He,Lt).call(this,{type:"invalidate"})}async fetch(t,n){var c,p,d,m,x,g,S,E,f,h,y;if(this.state.fetchStatus!=="idle"&&((c=v(this,fe))==null?void 0:c.status())!=="rejected"){if(this.state.data!==void 0&&(n!=null&&n.cancelRefetch))this.cancel({silent:!0});else if(v(this,fe))return v(this,fe).continueRetry(),v(this,fe).promise}if(t&&this.setOptions(t),!this.options.queryFn){const k=this.observers.find(C=>C.options.queryFn);k&&this.setOptions(k.options)}const r=new AbortController,s=k=>{Object.defineProperty(k,"signal",{enumerable:!0,get:()=>(_(this,zn,!0),r.signal)})},i=()=>{const k=zh(this.options,n),P=(()=>{const R={client:v(this,$n),queryKey:this.queryKey,meta:this.meta};return s(R),R})();return _(this,zn,!1),this.options.persister?this.options.persister(k,P,this):k(P)},a=(()=>{const k={fetchOptions:n,options:this.options,queryKey:this.queryKey,client:v(this,$n),state:this.state,fetchFn:i};return s(k),k})(),u=v(this,Er)==="infinite"?fv(this.options.pages):this.options.behavior;u==null||u.onFetch(a,this),_(this,Cr,this.state),(this.state.fetchStatus==="idle"||this.state.fetchMeta!==((p=a.fetchOptions)==null?void 0:p.meta))&&I(this,He,Lt).call(this,{type:"fetch",meta:(d=a.fetchOptions)==null?void 0:d.meta}),_(this,fe,Ah({initialPromise:n==null?void 0:n.initialPromise,fn:a.fetchFn,onCancel:k=>{k instanceof ho&&k.revert&&this.setState({...v(this,Cr),fetchStatus:"idle"}),r.abort()},onFail:(k,C)=>{I(this,He,Lt).call(this,{type:"failed",failureCount:k,error:C})},onPause:()=>{I(this,He,Lt).call(this,{type:"pause"})},onContinue:()=>{I(this,He,Lt).call(this,{type:"continue"})},retry:a.options.retry,retryDelay:a.options.retryDelay,networkMode:a.options.networkMode,canRun:()=>!0}));try{const k=await v(this,fe).start();if(k===void 0)throw new Error(`${this.queryHash} data is undefined`);return this.setData(k),(x=(m=v(this,Ze).config).onSuccess)==null||x.call(m,k,this),(S=(g=v(this,Ze).config).onSettled)==null||S.call(g,k,this.state.error,this),k}catch(k){if(k instanceof ho){if(k.silent)return v(this,fe).promise;if(k.revert){if(this.state.data===void 0)throw k;return this.state.data}}throw I(this,He,Lt).call(this,{type:"error",error:k}),(f=(E=v(this,Ze).config).onError)==null||f.call(E,k,this),(y=(h=v(this,Ze).config).onSettled)==null||y.call(h,this.state.data,k,this),k}finally{this.scheduleGc()}}},Er=new WeakMap,In=new WeakMap,Cr=new WeakMap,Ze=new WeakMap,$n=new WeakMap,fe=new WeakMap,Us=new WeakMap,zn=new WeakMap,He=new WeakSet,Bh=function(){return this.state.fetchStatus==="paused"&&this.state.status==="pending"},Lt=function(t){const n=r=>{switch(t.type){case"failed":return{...r,fetchFailureCount:t.failureCount,fetchFailureReason:t.error};case"pause":return{...r,fetchStatus:"paused"};case"continue":return{...r,fetchStatus:"fetching"};case"fetch":return{...r,...Hh(r.data,this.options),fetchMeta:t.meta??null};case"success":const s={...r,...Jc(t.data,t.dataUpdatedAt),dataUpdateCount:r.dataUpdateCount+1,...!t.manual&&{fetchStatus:"idle",fetchFailureCount:0,fetchFailureReason:null}};return _(this,Cr,t.manual?s:void 0),s;case"error":const i=t.error;return{...r,error:i,errorUpdateCount:r.errorUpdateCount+1,errorUpdatedAt:Date.now(),fetchFailureCount:r.fetchFailureCount+1,fetchFailureReason:i,fetchStatus:"idle",status:"error",isInvalidated:!0};case"invalidate":return{...r,isInvalidated:!0};case"setState":return{...r,...t.state}}};this.state=n(this.state),ue.batch(()=>{this.observers.forEach(r=>{r.onQueryUpdate()}),v(this,Ze).notify({query:this,type:"updated",action:t})})},vd);function Hh(e,t){return{fetchFailureCount:0,fetchFailureReason:null,fetchStatus:Uh(t.networkMode)?"fetching":"paused",...e===void 0&&{error:null,status:"pending"}}}function Jc(e,t){return{data:e,dataUpdatedAt:t??Date.now(),error:null,isInvalidated:!1,status:"success"}}function Zc(e){const t=typeof e.initialData=="function"?e.initialData():e.initialData,n=t!==void 0,r=n?typeof e.initialDataUpdatedAt=="function"?e.initialDataUpdatedAt():e.initialDataUpdatedAt:0;return{data:t,dataUpdateCount:0,dataUpdatedAt:n?r??Date.now():0,error:null,errorUpdateCount:0,errorUpdatedAt:0,fetchFailureCount:0,fetchFailureReason:null,fetchMeta:null,isInvalidated:!1,status:n?"success":"pending",fetchStatus:"idle"}}var Me,A,As,_e,Un,jr,Ot,rn,Qs,Nr,Pr,An,Qn,sn,Rr,B,cs,po,mo,yo,vo,go,xo,wo,Kh,gd,mv=(gd=class extends Kr{constructor(t,n){super();F(this,B);F(this,Me);F(this,A);F(this,As);F(this,_e);F(this,Un);F(this,jr);F(this,Ot);F(this,rn);F(this,Qs);F(this,Nr);F(this,Pr);F(this,An);F(this,Qn);F(this,sn);F(this,Rr,new Set);this.options=n,_(this,Me,t),_(this,rn,null),_(this,Ot,fo()),this.bindMethods(),this.setOptions(n)}bindMethods(){this.refetch=this.refetch.bind(this)}onSubscribe(){this.listeners.size===1&&(v(this,A).addObserver(this),ed(v(this,A),this.options)?I(this,B,cs).call(this):this.updateResult(),I(this,B,vo).call(this))}onUnsubscribe(){this.hasListeners()||this.destroy()}shouldFetchOnReconnect(){return So(v(this,A),this.options,this.options.refetchOnReconnect)}shouldFetchOnWindowFocus(){return So(v(this,A),this.options,this.options.refetchOnWindowFocus)}destroy(){this.listeners=new Set,I(this,B,go).call(this),I(this,B,xo).call(this),v(this,A).removeObserver(this)}setOptions(t){const n=this.options,r=v(this,A);if(this.options=v(this,Me).defaultQueryOptions(t),this.options.enabled!==void 0&&typeof this.options.enabled!="boolean"&&typeof this.options.enabled!="function"&&typeof Ke(this.options.enabled,v(this,A))!="boolean")throw new Error("Expected enabled to be a boolean or a callback that returns a boolean");I(this,B,wo).call(this),v(this,A).setOptions(this.options),n._defaulted&&!ul(this.options,n)&&v(this,Me).getQueryCache().notify({type:"observerOptionsUpdated",query:v(this,A),observer:this});const s=this.hasListeners();s&&td(v(this,A),r,this.options,n)&&I(this,B,cs).call(this),this.updateResult(),s&&(v(this,A)!==r||Ke(this.options.enabled,v(this,A))!==Ke(n.enabled,v(this,A))||wn(this.options.staleTime,v(this,A))!==wn(n.staleTime,v(this,A)))&&I(this,B,po).call(this);const i=I(this,B,mo).call(this);s&&(v(this,A)!==r||Ke(this.options.enabled,v(this,A))!==Ke(n.enabled,v(this,A))||i!==v(this,sn))&&I(this,B,yo).call(this,i)}getOptimisticResult(t){const n=v(this,Me).getQueryCache().build(v(this,Me),t),r=this.createResult(n,t);return vv(this,r)&&(_(this,_e,r),_(this,jr,this.options),_(this,Un,v(this,A).state)),r}getCurrentResult(){return v(this,_e)}trackResult(t,n){return new Proxy(t,{get:(r,s)=>(this.trackProp(s),n==null||n(s),s==="promise"&&(this.trackProp("data"),!this.options.experimental_prefetchInRender&&v(this,Ot).status==="pending"&&v(this,Ot).reject(new Error("experimental_prefetchInRender feature flag is not enabled"))),Reflect.get(r,s))})}trackProp(t){v(this,Rr).add(t)}getCurrentQuery(){return v(this,A)}refetch({...t}={}){return this.fetch({...t})}fetchOptimistic(t){const n=v(this,Me).defaultQueryOptions(t),r=v(this,Me).getQueryCache().build(v(this,Me),n);return r.fetch().then(()=>this.createResult(r,n))}fetch(t){return I(this,B,cs).call(this,{...t,cancelRefetch:t.cancelRefetch??!0}).then(()=>(this.updateResult(),v(this,_e)))}createResult(t,n){var b;const r=v(this,A),s=this.options,i=v(this,_e),l=v(this,Un),a=v(this,jr),c=t!==r?t.state:v(this,As),{state:p}=t;let d={...p},m=!1,x;if(n._optimisticResults){const O=this.hasListeners(),te=!O&&ed(t,n),Je=O&&td(t,r,n,s);(te||Je)&&(d={...d,...Hh(p.data,t.options)}),n._optimisticResults==="isRestoring"&&(d.fetchStatus="idle")}let{error:g,errorUpdatedAt:S,status:E}=d;x=d.data;let f=!1;if(n.placeholderData!==void 0&&x===void 0&&E==="pending"){let O;i!=null&&i.isPlaceholderData&&n.placeholderData===(a==null?void 0:a.placeholderData)?(O=i.data,f=!0):O=typeof n.placeholderData=="function"?n.placeholderData((b=v(this,Pr))==null?void 0:b.state.data,v(this,Pr)):n.placeholderData,O!==void 0&&(E="success",x=co(i==null?void 0:i.data,O,n),m=!0)}if(n.select&&x!==void 0&&!f)if(i&&x===(l==null?void 0:l.data)&&n.select===v(this,Qs))x=v(this,Nr);else try{_(this,Qs,n.select),x=n.select(x),x=co(i==null?void 0:i.data,x,n),_(this,Nr,x),_(this,rn,null)}catch(O){_(this,rn,O)}v(this,rn)&&(g=v(this,rn),x=v(this,Nr),S=Date.now(),E="error");const h=d.fetchStatus==="fetching",y=E==="pending",k=E==="error",C=y&&h,P=x!==void 0,N={status:E,fetchStatus:d.fetchStatus,isPending:y,isSuccess:E==="success",isError:k,isInitialLoading:C,isLoading:C,data:x,dataUpdatedAt:d.dataUpdatedAt,error:g,errorUpdatedAt:S,failureCount:d.fetchFailureCount,failureReason:d.fetchFailureReason,errorUpdateCount:d.errorUpdateCount,isFetched:t.isFetched(),isFetchedAfterMount:d.dataUpdateCount>c.dataUpdateCount||d.errorUpdateCount>c.errorUpdateCount,isFetching:h,isRefetching:h&&!y,isLoadingError:k&&!P,isPaused:d.fetchStatus==="paused",isPlaceholderData:m,isRefetchError:k&&P,isStale:Pu(t,n),refetch:this.refetch,promise:v(this,Ot),isEnabled:Ke(n.enabled,t)!==!1};if(this.options.experimental_prefetchInRender){const O=N.data!==void 0,te=N.status==="error"&&!O,Je=Re=>{te?Re.reject(N.error):O&&Re.resolve(N.data)},at=()=>{const Re=_(this,Ot,N.promise=fo());Je(Re)},gt=v(this,Ot);switch(gt.status){case"pending":t.queryHash===r.queryHash&&Je(gt);break;case"fulfilled":(te||N.data!==gt.value)&&at();break;case"rejected":(!te||N.error!==gt.reason)&&at();break}}return N}updateResult(){const t=v(this,_e),n=this.createResult(v(this,A),this.options);if(_(this,Un,v(this,A).state),_(this,jr,this.options),v(this,Un).data!==void 0&&_(this,Pr,v(this,A)),ul(n,t))return;_(this,_e,n);const r=()=>{if(!t)return!0;const{notifyOnChangeProps:s}=this.options,i=typeof s=="function"?s():s;if(i==="all"||!i&&!v(this,Rr).size)return!0;const l=new Set(i??v(this,Rr));return this.options.throwOnError&&l.add("error"),Object.keys(v(this,_e)).some(a=>{const u=a;return v(this,_e)[u]!==t[u]&&l.has(u)})};I(this,B,Kh).call(this,{listeners:r()})}onQueryUpdate(){this.updateResult(),this.hasListeners()&&I(this,B,vo).call(this)}},Me=new WeakMap,A=new WeakMap,As=new WeakMap,_e=new WeakMap,Un=new WeakMap,jr=new WeakMap,Ot=new WeakMap,rn=new WeakMap,Qs=new WeakMap,Nr=new WeakMap,Pr=new WeakMap,An=new WeakMap,Qn=new WeakMap,sn=new WeakMap,Rr=new WeakMap,B=new WeakSet,cs=function(t){I(this,B,wo).call(this);let n=v(this,A).fetch(this.options,t);return t!=null&&t.throwOnError||(n=n.catch(Te)),n},po=function(){I(this,B,go).call(this);const t=wn(this.options.staleTime,v(this,A));if(zs.isServer()||v(this,_e).isStale||!oo(t))return;const r=Ih(v(this,_e).dataUpdatedAt,t)+1;_(this,An,bn.setTimeout(()=>{v(this,_e).isStale||this.updateResult()},r))},mo=function(){return(typeof this.options.refetchInterval=="function"?this.options.refetchInterval(v(this,A)):this.options.refetchInterval)??!1},yo=function(t){I(this,B,xo).call(this),_(this,sn,t),!(zs.isServer()||Ke(this.options.enabled,v(this,A))===!1||!oo(v(this,sn))||v(this,sn)===0)&&_(this,Qn,bn.setInterval(()=>{(this.options.refetchIntervalInBackground||Eu.isFocused())&&I(this,B,cs).call(this)},v(this,sn)))},vo=function(){I(this,B,po).call(this),I(this,B,yo).call(this,I(this,B,mo).call(this))},go=function(){v(this,An)!==void 0&&(bn.clearTimeout(v(this,An)),_(this,An,void 0))},xo=function(){v(this,Qn)!==void 0&&(bn.clearInterval(v(this,Qn)),_(this,Qn,void 0))},wo=function(){const t=v(this,Me).getQueryCache().build(v(this,Me),this.options);if(t===v(this,A))return;const n=v(this,A);_(this,A,t),_(this,As,t.state),this.hasListeners()&&(n==null||n.removeObserver(this),t.addObserver(this))},Kh=function(t){ue.batch(()=>{t.listeners&&this.listeners.forEach(n=>{n(v(this,_e))}),v(this,Me).getQueryCache().notify({query:v(this,A),type:"observerResultsUpdated"})})},gd);function yv(e,t){return Ke(t.enabled,e)!==!1&&e.state.data===void 0&&!(e.state.status==="error"&&Ke(t.retryOnMount,e)===!1)}function ed(e,t){return yv(e,t)||e.state.data!==void 0&&So(e,t,t.refetchOnMount)}function So(e,t,n){if(Ke(t.enabled,e)!==!1&&wn(t.staleTime,e)!=="static"){const r=typeof n=="function"?n(e):n;return r==="always"||r!==!1&&Pu(e,t)}return!1}function td(e,t,n,r){return(e!==t||Ke(r.enabled,e)===!1)&&(!n.suspense||e.state.status!=="error")&&Pu(e,n)}function Pu(e,t){return Ke(t.enabled,e)!==!1&&e.isStaleByTime(wn(t.staleTime,e))}function vv(e,t){return!ul(e.getCurrentResult(),t)}var Bs,St,Ce,Bn,kt,Gt,xd,gv=(xd=class extends Qh{constructor(t){super();F(this,kt);F(this,Bs);F(this,St);F(this,Ce);F(this,Bn);_(this,Bs,t.client),this.mutationId=t.mutationId,_(this,Ce,t.mutationCache),_(this,St,[]),this.state=t.state||Wh(),this.setOptions(t.options),this.scheduleGc()}setOptions(t){this.options=t,this.updateGcTime(this.options.gcTime)}get meta(){return this.options.meta}addObserver(t){v(this,St).includes(t)||(v(this,St).push(t),this.clearGcTimeout(),v(this,Ce).notify({type:"observerAdded",mutation:this,observer:t}))}removeObserver(t){_(this,St,v(this,St).filter(n=>n!==t)),this.scheduleGc(),v(this,Ce).notify({type:"observerRemoved",mutation:this,observer:t})}optionalRemove(){v(this,St).length||(this.state.status==="pending"?this.scheduleGc():v(this,Ce).remove(this))}continue(){var t;return((t=v(this,Bn))==null?void 0:t.continue())??this.execute(this.state.variables)}async execute(t){var l,a,u,c,p,d,m,x,g,S,E,f,h,y,k,C,P,R;const n=()=>{I(this,kt,Gt).call(this,{type:"continue"})},r={client:v(this,Bs),meta:this.options.meta,mutationKey:this.options.mutationKey};_(this,Bn,Ah({fn:()=>this.options.mutationFn?this.options.mutationFn(t,r):Promise.reject(new Error("No mutationFn found")),onFail:(N,b)=>{I(this,kt,Gt).call(this,{type:"failed",failureCount:N,error:b})},onPause:()=>{I(this,kt,Gt).call(this,{type:"pause"})},onContinue:n,retry:this.options.retry??0,retryDelay:this.options.retryDelay,networkMode:this.options.networkMode,canRun:()=>v(this,Ce).canRun(this)}));const s=this.state.status==="pending",i=!v(this,Bn).canStart();try{if(s)n();else{I(this,kt,Gt).call(this,{type:"pending",variables:t,isPaused:i}),v(this,Ce).config.onMutate&&await v(this,Ce).config.onMutate(t,this,r);const b=await((a=(l=this.options).onMutate)==null?void 0:a.call(l,t,r));b!==this.state.context&&I(this,kt,Gt).call(this,{type:"pending",context:b,variables:t,isPaused:i})}const N=await v(this,Bn).start();return await((c=(u=v(this,Ce).config).onSuccess)==null?void 0:c.call(u,N,t,this.state.context,this,r)),await((d=(p=this.options).onSuccess)==null?void 0:d.call(p,N,t,this.state.context,r)),await((x=(m=v(this,Ce).config).onSettled)==null?void 0:x.call(m,N,null,this.state.variables,this.state.context,this,r)),await((S=(g=this.options).onSettled)==null?void 0:S.call(g,N,null,t,this.state.context,r)),I(this,kt,Gt).call(this,{type:"success",data:N}),N}catch(N){try{await((f=(E=v(this,Ce).config).onError)==null?void 0:f.call(E,N,t,this.state.context,this,r))}catch(b){Promise.reject(b)}try{await((y=(h=this.options).onError)==null?void 0:y.call(h,N,t,this.state.context,r))}catch(b){Promise.reject(b)}try{await((C=(k=v(this,Ce).config).onSettled)==null?void 0:C.call(k,void 0,N,this.state.variables,this.state.context,this,r))}catch(b){Promise.reject(b)}try{await((R=(P=this.options).onSettled)==null?void 0:R.call(P,void 0,N,t,this.state.context,r))}catch(b){Promise.reject(b)}throw I(this,kt,Gt).call(this,{type:"error",error:N}),N}finally{v(this,Ce).runNext(this)}}},Bs=new WeakMap,St=new WeakMap,Ce=new WeakMap,Bn=new WeakMap,kt=new WeakSet,Gt=function(t){const n=r=>{switch(t.type){case"failed":return{...r,failureCount:t.failureCount,failureReason:t.error};case"pause":return{...r,isPaused:!0};case"continue":return{...r,isPaused:!1};case"pending":return{...r,context:t.context,data:void 0,failureCount:0,failureReason:null,error:null,isPaused:t.isPaused,status:"pending",variables:t.variables,submittedAt:Date.now()};case"success":return{...r,data:t.data,failureCount:0,failureReason:null,error:null,status:"success",isPaused:!1};case"error":return{...r,data:void 0,error:t.error,failureCount:r.failureCount+1,failureReason:t.error,isPaused:!1,status:"error"}}};this.state=n(this.state),ue.batch(()=>{v(this,St).forEach(r=>{r.onMutationUpdate(t)}),v(this,Ce).notify({mutation:this,type:"updated",action:t})})},xd);function Wh(){return{context:void 0,data:void 0,error:null,failureCount:0,failureReason:null,isPaused:!1,status:"idle",variables:void 0,submittedAt:0}}var bt,ct,Hs,wd,xv=(wd=class extends Kr{constructor(t={}){super();F(this,bt);F(this,ct);F(this,Hs);this.config=t,_(this,bt,new Set),_(this,ct,new Map),_(this,Hs,0)}build(t,n,r){const s=new gv({client:t,mutationCache:this,mutationId:++si(this,Hs)._,options:t.defaultMutationOptions(n),state:r});return this.add(s),s}add(t){v(this,bt).add(t);const n=ki(t);if(typeof n=="string"){const r=v(this,ct).get(n);r?r.push(t):v(this,ct).set(n,[t])}this.notify({type:"added",mutation:t})}remove(t){if(v(this,bt).delete(t)){const n=ki(t);if(typeof n=="string"){const r=v(this,ct).get(n);if(r)if(r.length>1){const s=r.indexOf(t);s!==-1&&r.splice(s,1)}else r[0]===t&&v(this,ct).delete(n)}}this.notify({type:"removed",mutation:t})}canRun(t){const n=ki(t);if(typeof n=="string"){const r=v(this,ct).get(n),s=r==null?void 0:r.find(i=>i.state.status==="pending");return!s||s===t}else return!0}runNext(t){var r;const n=ki(t);if(typeof n=="string"){const s=(r=v(this,ct).get(n))==null?void 0:r.find(i=>i!==t&&i.state.isPaused);return(s==null?void 0:s.continue())??Promise.resolve()}else return Promise.resolve()}clear(){ue.batch(()=>{v(this,bt).forEach(t=>{this.notify({type:"removed",mutation:t})}),v(this,bt).clear(),v(this,ct).clear()})}getAll(){return Array.from(v(this,bt))}find(t){const n={exact:!0,...t};return this.getAll().find(r=>qc(n,r))}findAll(t={}){return this.getAll().filter(n=>qc(t,n))}notify(t){ue.batch(()=>{this.listeners.forEach(n=>{n(t)})})}resumePausedMutations(){const t=this.getAll().filter(n=>n.state.isPaused);return ue.batch(()=>Promise.all(t.map(n=>n.continue().catch(Te))))}},bt=new WeakMap,ct=new WeakMap,Hs=new WeakMap,wd);function ki(e){var t;return(t=e.options.scope)==null?void 0:t.id}var Mt,ln,De,Dt,Ut,Di,ko,Sd,wv=(Sd=class extends Kr{constructor(n,r){super();F(this,Ut);F(this,Mt);F(this,ln);F(this,De);F(this,Dt);_(this,Mt,n),this.setOptions(r),this.bindMethods(),I(this,Ut,Di).call(this)}bindMethods(){this.mutate=this.mutate.bind(this),this.reset=this.reset.bind(this)}setOptions(n){var s;const r=this.options;this.options=v(this,Mt).defaultMutationOptions(n),ul(this.options,r)||v(this,Mt).getMutationCache().notify({type:"observerOptionsUpdated",mutation:v(this,De),observer:this}),r!=null&&r.mutationKey&&this.options.mutationKey&&Xn(r.mutationKey)!==Xn(this.options.mutationKey)?this.reset():((s=v(this,De))==null?void 0:s.state.status)==="pending"&&v(this,De).setOptions(this.options)}onUnsubscribe(){var n;this.hasListeners()||(n=v(this,De))==null||n.removeObserver(this)}onMutationUpdate(n){I(this,Ut,Di).call(this),I(this,Ut,ko).call(this,n)}getCurrentResult(){return v(this,ln)}reset(){var n;(n=v(this,De))==null||n.removeObserver(this),_(this,De,void 0),I(this,Ut,Di).call(this),I(this,Ut,ko).call(this)}mutate(n,r){var s;return _(this,Dt,r),(s=v(this,De))==null||s.removeObserver(this),_(this,De,v(this,Mt).getMutationCache().build(v(this,Mt),this.options)),v(this,De).addObserver(this),v(this,De).execute(n)}},Mt=new WeakMap,ln=new WeakMap,De=new WeakMap,Dt=new WeakMap,Ut=new WeakSet,Di=function(){var r;const n=((r=v(this,De))==null?void 0:r.state)??Wh();_(this,ln,{...n,isPending:n.status==="pending",isSuccess:n.status==="success",isError:n.status==="error",isIdle:n.status==="idle",mutate:this.mutate,reset:this.reset})},ko=function(n){ue.batch(()=>{var r,s,i,l,a,u,c,p;if(v(this,Dt)&&this.hasListeners()){const d=v(this,ln).variables,m=v(this,ln).context,x={client:v(this,Mt),meta:this.options.meta,mutationKey:this.options.mutationKey};if((n==null?void 0:n.type)==="success"){try{(s=(r=v(this,Dt)).onSuccess)==null||s.call(r,n.data,d,m,x)}catch(g){Promise.reject(g)}try{(l=(i=v(this,Dt)).onSettled)==null||l.call(i,n.data,null,d,m,x)}catch(g){Promise.reject(g)}}else if((n==null?void 0:n.type)==="error"){try{(u=(a=v(this,Dt)).onError)==null||u.call(a,n.error,d,m,x)}catch(g){Promise.reject(g)}try{(p=(c=v(this,Dt)).onSettled)==null||p.call(c,void 0,n.error,d,m,x)}catch(g){Promise.reject(g)}}}this.listeners.forEach(d=>{d(v(this,ln))})})},Sd),Et,kd,Sv=(kd=class extends Kr{constructor(t={}){super();F(this,Et);this.config=t,_(this,Et,new Map)}build(t,n,r){const s=n.queryKey,i=n.queryHash??Cu(s,n);let l=this.get(i);return l||(l=new pv({client:t,queryKey:s,queryHash:i,options:t.defaultQueryOptions(n),state:r,defaultOptions:t.getQueryDefaults(s)}),this.add(l)),l}add(t){v(this,Et).has(t.queryHash)||(v(this,Et).set(t.queryHash,t),this.notify({type:"added",query:t}))}remove(t){const n=v(this,Et).get(t.queryHash);n&&(t.destroy(),n===t&&v(this,Et).delete(t.queryHash),this.notify({type:"removed",query:t}))}clear(){ue.batch(()=>{this.getAll().forEach(t=>{this.remove(t)})})}get(t){return v(this,Et).get(t)}getAll(){return[...v(this,Et).values()]}find(t){const n={exact:!0,...t};return this.getAll().find(r=>Vc(n,r))}findAll(t={}){const n=this.getAll();return Object.keys(t).length>0?n.filter(r=>Vc(t,r)):n}notify(t){ue.batch(()=>{this.listeners.forEach(n=>{n(t)})})}onFocus(){ue.batch(()=>{this.getAll().forEach(t=>{t.onFocus()})})}onOnline(){ue.batch(()=>{this.getAll().forEach(t=>{t.onOnline()})})}},Et=new WeakMap,kd),ne,an,on,_r,Lr,un,Tr,Fr,Ed,kv=(Ed=class{constructor(e={}){F(this,ne);F(this,an);F(this,on);F(this,_r);F(this,Lr);F(this,un);F(this,Tr);F(this,Fr);_(this,ne,e.queryCache||new Sv),_(this,an,e.mutationCache||new xv),_(this,on,e.defaultOptions||{}),_(this,_r,new Map),_(this,Lr,new Map),_(this,un,0)}mount(){si(this,un)._++,v(this,un)===1&&(_(this,Tr,Eu.subscribe(async e=>{e&&(await this.resumePausedMutations(),v(this,ne).onFocus())})),_(this,Fr,cl.subscribe(async e=>{e&&(await this.resumePausedMutations(),v(this,ne).onOnline())})))}unmount(){var e,t;si(this,un)._--,v(this,un)===0&&((e=v(this,Tr))==null||e.call(this),_(this,Tr,void 0),(t=v(this,Fr))==null||t.call(this),_(this,Fr,void 0))}isFetching(e){return v(this,ne).findAll({...e,fetchStatus:"fetching"}).length}isMutating(e){return v(this,an).findAll({...e,status:"pending"}).length}getQueryData(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=v(this,ne).get(t.queryHash))==null?void 0:n.state.data}ensureQueryData(e){const t=this.defaultQueryOptions(e),n=v(this,ne).build(this,t),r=n.state.data;return r===void 0?this.fetchQuery(e):(e.revalidateIfStale&&n.isStaleByTime(wn(t.staleTime,n))&&this.prefetchQuery(t),Promise.resolve(r))}getQueriesData(e){return v(this,ne).findAll(e).map(({queryKey:t,state:n})=>{const r=n.data;return[t,r]})}setQueryData(e,t,n){const r=this.defaultQueryOptions({queryKey:e}),s=v(this,ne).get(r.queryHash),i=s==null?void 0:s.state.data,l=nv(t,i);if(l!==void 0)return v(this,ne).build(this,r).setData(l,{...n,manual:!0})}setQueriesData(e,t,n){return ue.batch(()=>v(this,ne).findAll(e).map(({queryKey:r})=>[r,this.setQueryData(r,t,n)]))}getQueryState(e){var n;const t=this.defaultQueryOptions({queryKey:e});return(n=v(this,ne).get(t.queryHash))==null?void 0:n.state}removeQueries(e){const t=v(this,ne);ue.batch(()=>{t.findAll(e).forEach(n=>{t.remove(n)})})}resetQueries(e,t){const n=v(this,ne);return ue.batch(()=>(n.findAll(e).forEach(r=>{r.reset()}),this.refetchQueries({type:"active",...e},t)))}cancelQueries(e,t={}){const n={revert:!0,...t},r=ue.batch(()=>v(this,ne).findAll(e).map(s=>s.cancel(n)));return Promise.all(r).then(Te).catch(Te)}invalidateQueries(e,t={}){return ue.batch(()=>(v(this,ne).findAll(e).forEach(n=>{n.invalidate()}),(e==null?void 0:e.refetchType)==="none"?Promise.resolve():this.refetchQueries({...e,type:(e==null?void 0:e.refetchType)??(e==null?void 0:e.type)??"active"},t)))}refetchQueries(e,t={}){const n={...t,cancelRefetch:t.cancelRefetch??!0},r=ue.batch(()=>v(this,ne).findAll(e).filter(s=>!s.isDisabled()&&!s.isStatic()).map(s=>{let i=s.fetch(void 0,n);return n.throwOnError||(i=i.catch(Te)),s.state.fetchStatus==="paused"?Promise.resolve():i}));return Promise.all(r).then(Te)}fetchQuery(e){const t=this.defaultQueryOptions(e);t.retry===void 0&&(t.retry=!1);const n=v(this,ne).build(this,t);return n.isStaleByTime(wn(t.staleTime,n))?n.fetch(t):Promise.resolve(n.state.data)}prefetchQuery(e){return this.fetchQuery(e).then(Te).catch(Te)}fetchInfiniteQuery(e){return e._type="infinite",this.fetchQuery(e)}prefetchInfiniteQuery(e){return this.fetchInfiniteQuery(e).then(Te).catch(Te)}ensureInfiniteQueryData(e){return e._type="infinite",this.ensureQueryData(e)}resumePausedMutations(){return cl.isOnline()?v(this,an).resumePausedMutations():Promise.resolve()}getQueryCache(){return v(this,ne)}getMutationCache(){return v(this,an)}getDefaultOptions(){return v(this,on)}setDefaultOptions(e){_(this,on,e)}setQueryDefaults(e,t){v(this,_r).set(Xn(e),{queryKey:e,defaultOptions:t})}getQueryDefaults(e){const t=[...v(this,_r).values()],n={};return t.forEach(r=>{$s(e,r.queryKey)&&Object.assign(n,r.defaultOptions)}),n}setMutationDefaults(e,t){v(this,Lr).set(Xn(e),{mutationKey:e,defaultOptions:t})}getMutationDefaults(e){const t=[...v(this,Lr).values()],n={};return t.forEach(r=>{$s(e,r.mutationKey)&&Object.assign(n,r.defaultOptions)}),n}defaultQueryOptions(e){if(e._defaulted)return e;const t={...v(this,on).queries,...this.getQueryDefaults(e.queryKey),...e,_defaulted:!0};return t.queryHash||(t.queryHash=Cu(t.queryKey,t)),t.refetchOnReconnect===void 0&&(t.refetchOnReconnect=t.networkMode!=="always"),t.throwOnError===void 0&&(t.throwOnError=!!t.suspense),!t.networkMode&&t.persister&&(t.networkMode="offlineFirst"),t.queryFn===ju&&(t.enabled=!1),t}defaultMutationOptions(e){return e!=null&&e._defaulted?e:{...v(this,on).mutations,...(e==null?void 0:e.mutationKey)&&this.getMutationDefaults(e.mutationKey),...e,_defaulted:!0}}clear(){v(this,ne).clear(),v(this,an).clear()}},ne=new WeakMap,an=new WeakMap,on=new WeakMap,_r=new WeakMap,Lr=new WeakMap,un=new WeakMap,Tr=new WeakMap,Fr=new WeakMap,Ed),Vh=w.createContext(void 0),vt=e=>{const t=w.useContext(Vh);if(!t)throw new Error("No QueryClient set, use QueryClientProvider to set one");return t},Ev=({client:e,children:t})=>(w.useEffect(()=>(e.mount(),()=>{e.unmount()}),[e]),o.jsx(Vh.Provider,{value:e,children:t})),qh=w.createContext(!1),Cv=()=>w.useContext(qh);qh.Provider;function jv(){let e=!1;return{clearReset:()=>{e=!1},reset:()=>{e=!0},isReset:()=>e}}var Nv=w.createContext(jv()),Pv=()=>w.useContext(Nv),Rv=(e,t,n)=>{const r=n!=null&&n.state.error&&typeof e.throwOnError=="function"?Nu(e.throwOnError,[n.state.error,n]):e.throwOnError;(e.suspense||e.experimental_prefetchInRender||r)&&(t.isReset()||(e.retryOnMount=!1))},_v=e=>{w.useEffect(()=>{e.clearReset()},[e])},Lv=({result:e,errorResetBoundary:t,throwOnError:n,query:r,suspense:s})=>e.isError&&!t.isReset()&&!e.isFetching&&r&&(s&&e.data===void 0||Nu(n,[e.error,r])),Tv=e=>{if(e.suspense){const n=s=>s==="static"?s:Math.max(s??1e3,1e3),r=e.staleTime;e.staleTime=typeof r=="function"?(...s)=>n(r(...s)):n(r),typeof e.gcTime=="number"&&(e.gcTime=Math.max(e.gcTime,1e3))}},Fv=(e,t)=>e.isLoading&&e.isFetching&&!t,Ov=(e,t)=>(e==null?void 0:e.suspense)&&t.isPending,nd=(e,t,n)=>t.fetchOptimistic(e).catch(()=>{n.clearReset()});function bv(e,t,n){var x,g,S,E;const r=Cv(),s=Pv(),i=vt(),l=i.defaultQueryOptions(e);(g=(x=i.getDefaultOptions().queries)==null?void 0:x._experimental_beforeQuery)==null||g.call(x,l);const a=i.getQueryCache().get(l.queryHash),u=e.subscribed!==!1;l._optimisticResults=r?"isRestoring":u?"optimistic":void 0,Tv(l),Rv(l,s,a),_v(s);const c=!i.getQueryCache().get(l.queryHash),[p]=w.useState(()=>new t(i,l)),d=p.getOptimisticResult(l),m=!r&&u;if(w.useSyncExternalStore(w.useCallback(f=>{const h=m?p.subscribe(ue.batchCalls(f)):Te;return p.updateResult(),h},[p,m]),()=>p.getCurrentResult(),()=>p.getCurrentResult()),w.useEffect(()=>{p.setOptions(l)},[l,p]),Ov(l,d))throw nd(l,p,s);if(Lv({result:d,errorResetBoundary:s,throwOnError:l.throwOnError,query:a,suspense:l.suspense}))throw d.error;if((E=(S=i.getDefaultOptions().queries)==null?void 0:S._experimental_afterQuery)==null||E.call(S,l,d),l.experimental_prefetchInRender&&!zs.isServer()&&Fv(d,r)){const f=c?nd(l,p,s):a==null?void 0:a.promise;f==null||f.catch(Te).finally(()=>{p.updateResult()})}return l.notifyOnChangeProps?d:p.trackResult(d)}function me(e,t){return bv(e,mv)}function Ne(e,t){const n=vt(),[r]=w.useState(()=>new wv(n,e));w.useEffect(()=>{r.setOptions(e)},[r,e]);const s=w.useSyncExternalStore(w.useCallback(l=>r.subscribe(ue.batchCalls(l)),[r]),()=>r.getCurrentResult(),()=>r.getCurrentResult()),i=w.useCallback((l,a)=>{r.mutate(l,a).catch(Te)},[r]);if(s.error&&Nu(r.options.throwOnError,[s.error]))throw s.error;return{...s,mutate:i,mutateAsync:s.mutate}}/** + * react-router v7.18.3 + * + * Copyright (c) Remix Software Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE.md file in the root directory of this source tree. + * + * @license MIT + */var Ru=/^(?:[a-z][a-z0-9+.-]*:|[\\/]{2})/i,Gh=/^[\\/]{2}/;function Mv(e,t){return t+e.replace(/\\/g,"/")}var rd="popstate";function sd(e){return typeof e=="object"&&e!=null&&"pathname"in e&&"search"in e&&"hash"in e&&"state"in e&&"key"in e}function Dv(e={}){function t(r,s){var c;let i=(c=s.state)==null?void 0:c.masked,{pathname:l,search:a,hash:u}=i||r.location;return Eo("",{pathname:l,search:a,hash:u},s.state&&s.state.usr||null,s.state&&s.state.key||"default",i?{pathname:r.location.pathname,search:r.location.search,hash:r.location.hash}:void 0)}function n(r,s){return typeof s=="string"?s:Ur(s)}return $v(t,n,null,e)}function Z(e,t){if(e===!1||e===null||typeof e>"u")throw new Error(t)}function Pt(e,t){if(!e){typeof console<"u"&&console.warn(t);try{throw new Error(t)}catch{}}}function Iv(){return Math.random().toString(36).substring(2,10)}function id(e,t){return{usr:e.state,key:e.key,idx:t,masked:e.mask?{pathname:e.pathname,search:e.search,hash:e.hash}:void 0}}function Eo(e,t,n=null,r,s){return{pathname:typeof e=="string"?e:e.pathname,search:"",hash:"",...typeof t=="string"?Wr(t):t,state:n,key:t&&t.key||r||Iv(),mask:s}}function Ur({pathname:e="/",search:t="",hash:n=""}){return t&&t!=="?"&&(e+=t.charAt(0)==="?"?t:"?"+t),n&&n!=="#"&&(e+=n.charAt(0)==="#"?n:"#"+n),e}function Wr(e){let t={};if(e){let n=e.indexOf("#");n>=0&&(t.hash=e.substring(n),e=e.substring(0,n));let r=e.indexOf("?");r>=0&&(t.search=e.substring(r),e=e.substring(0,r)),e&&(t.pathname=e)}return t}function $v(e,t,n,r={}){let{window:s=document.defaultView,v5Compat:i=!1}=r,l=s.history,a="POP",u=null,c=p();c==null&&(c=0,l.replaceState({...l.state,idx:c},""));function p(){return(l.state||{idx:null}).idx}function d(){a="POP";let E=p(),f=E==null?null:E-c;c=E,u&&u({action:a,location:S.location,delta:f})}function m(E,f){a="PUSH";let h=sd(E)?E:Eo(S.location,E,f);c=p()+1;let y=id(h,c),k=S.createHref(h.mask||h);try{l.pushState(y,"",k)}catch(C){if(C instanceof DOMException&&C.name==="DataCloneError")throw C;s.location.assign(k)}i&&u&&u({action:a,location:S.location,delta:1})}function x(E,f){a="REPLACE";let h=sd(E)?E:Eo(S.location,E,f);c=p();let y=id(h,c),k=S.createHref(h.mask||h);l.replaceState(y,"",k),i&&u&&u({action:a,location:S.location,delta:0})}function g(E){return zv(s,E)}let S={get action(){return a},get location(){return e(s,l)},listen(E){if(u)throw new Error("A history only accepts one active listener");return s.addEventListener(rd,d),u=E,()=>{s.removeEventListener(rd,d),u=null}},createHref(E){return t(s,E)},createURL:g,encodeLocation(E){let f=g(E);return{pathname:f.pathname,search:f.search,hash:f.hash}},push:m,replace:x,go(E){return l.go(E)}};return S}function zv(e,t,n=!1){let r="http://localhost";e&&(r=e.location.origin!=="null"?e.location.origin:e.location.href),Z(r,"No window.location.(origin|href) available to create URL");let s=typeof t=="string"?t:Ur(t);return s=s.replace(/ $/,"%20"),!n&&Gh.test(s)&&(s=r+s),new URL(s,r)}function Yh(e,t,n="/"){return Uv(e,t,n,!1)}function Uv(e,t,n,r,s){let i=typeof t=="string"?Wr(t):t,l=Kt(i.pathname||"/",n);if(l==null)return null;let a=Av(e),u=null,c=Jv(l);for(let p=0;u==null&&p{let p={relativePath:c===void 0?l.path||"":c,caseSensitive:l.caseSensitive===!0,childrenIndex:a,route:l};if(p.relativePath.startsWith("/")){if(!p.relativePath.startsWith(r)&&u)return;Z(p.relativePath.startsWith(r),`Absolute route path "${p.relativePath}" nested under path "${r}" is not valid. An absolute child route path must start with the combined path of all its parent routes.`),p.relativePath=p.relativePath.slice(r.length)}let d=mt([r,p.relativePath]),m=n.concat(p);l.children&&l.children.length>0&&(Z(l.index!==!0,`Index routes must not have child routes. Please remove all child routes from route path "${d}".`),Xh(l.children,t,m,d,u)),!(l.path==null&&!l.index)&&t.push({path:d,score:Gv(d,l.index),routesMeta:m.map((x,g)=>{let[S,E]=ep(x.relativePath,x.caseSensitive,g===m.length-1);return{...x,matcher:S,compiledParams:E}})})};return e.forEach((l,a)=>{var u;if(l.path===""||!((u=l.path)!=null&&u.includes("?")))i(l,a);else for(let c of Jh(l.path))i(l,a,!0,c)}),t}function Jh(e){let t=e.split("/");if(t.length===0)return[];let[n,...r]=t,s=n.endsWith("?"),i=n.replace(/\?$/,"");if(r.length===0)return s?[i,""]:[i];let l=Jh(r.join("/")),a=[];return a.push(...l.map(u=>u===""?i:[i,u].join("/"))),s&&a.push(...l),a.map(u=>e.startsWith("/")&&u===""?"/":u)}function Qv(e){e.sort((t,n)=>t.score!==n.score?n.score-t.score:Yv(t.routesMeta.map(r=>r.childrenIndex),n.routesMeta.map(r=>r.childrenIndex)))}var Bv=/^:[\w-]+$/,Hv=3,Kv=2,Wv=1,Vv=10,qv=-2,ld=e=>e==="*";function Gv(e,t){let n=e.split("/"),r=n.length;return n.some(ld)&&(r+=qv),t&&(r+=Kv),n.filter(s=>!ld(s)).reduce((s,i)=>s+(Bv.test(i)?Hv:i===""?Wv:Vv),r)}function Yv(e,t){return e.length===t.length&&e.slice(0,-1).every((r,s)=>r===t[s])?e[e.length-1]-t[t.length-1]:0}function Xv(e,t,n=!1){let{routesMeta:r}=e,s={},i="/",l=[];for(let a=0;a{if(p==="*"){let g=a[m]||"";l=Ar(i.slice(0,i.length-g.length),1)}const x=a[m];return d&&!x?c[p]=void 0:c[p]=(x||"").replace(/%2F/g,"/"),c},{}),pathname:i,pathnameBase:l,pattern:e}}function ep(e,t=!1,n=!0){Pt(e==="*"||!e.endsWith("*")||e.endsWith("/*"),`Route path "${e}" will be treated as if it were "${e.replace(/\*$/,"/*")}" because the \`*\` character must always follow a \`/\` in the pattern. To get rid of this warning, please change the route path to "${e.replace(/\*$/,"/*")}".`);let r=[],s="^"+e.replace(/\/*\*?$/,"").replace(/^\/*/,"/").replace(/[\\.*+^${}|()[\]]/g,"\\$&").replace(/\/:([\w-]+)(\?)?/g,(l,a,u,c,p)=>{if(r.push({paramName:a,isOptional:u!=null}),u){let d=p.charAt(c+l.length);return d&&d!=="/"?"/([^\\/]*)":"(?:/([^\\/]*))?"}return"/([^\\/]+)"}).replace(/\/([\w-]+)\?(\/|$)/g,"(/$1)?$2");return e.endsWith("*")?(r.push({paramName:"*"}),s+=e==="*"||e==="/*"?"(.*)$":"(?:\\/(.+)|\\/*)$"):n?s+="\\/*$":e!==""&&e!=="/"&&(s+="(?:(?=\\/|$))"),[new RegExp(s,t?void 0:"i"),r]}function Jv(e){try{return e.split("/").map(t=>decodeURIComponent(t).replace(/\//g,"%2F")).join("/")}catch(t){return Pt(!1,`The URL path "${e}" could not be decoded because it is a malformed URL segment. This is probably due to a bad percent encoding (${t}).`),e}}function Kt(e,t){if(t==="/")return e;if(!e.toLowerCase().startsWith(t.toLowerCase()))return null;let n=t.endsWith("/")?t.length-1:t.length,r=e.charAt(n);return r&&r!=="/"?null:e.slice(n)||"/"}function Zv(e,t="/"){let{pathname:n,search:r="",hash:s=""}=typeof e=="string"?Wr(e):e,i;return n?(n=np(n),n.startsWith("/")||n.startsWith("\\")?i=ad(n.substring(1),"/"):i=ad(n,t)):i=t,{pathname:i,search:ng(r),hash:rg(s)}}function ad(e,t){let n=Ar(t).split("/");return e.split("/").forEach(s=>{s===".."?n.length>1&&n.pop():s!=="."&&n.push(s)}),n.length>1?n.join("/"):"/"}function ca(e,t,n,r){return`Cannot include a '${e}' character in a manually specified \`to.${t}\` field [${JSON.stringify(r)}]. Please separate it out to the \`to.${n}\` field. Alternatively you may provide the full path as a string in and the router will parse it for you.`}function eg(e){return e.filter((t,n)=>n===0||t.route.path&&t.route.path.length>0)}function tp(e){let t=eg(e);return t.map((n,r)=>r===t.length-1?n.pathname:n.pathnameBase)}function _u(e,t,n,r=!1){let s;typeof e=="string"?s=Wr(e):(s={...e},Z(!s.pathname||!s.pathname.includes("?"),ca("?","pathname","search",s)),Z(!s.pathname||!s.pathname.includes("#"),ca("#","pathname","hash",s)),Z(!s.search||!s.search.includes("#"),ca("#","search","hash",s)));let i=e===""||s.pathname==="",l=i?"/":s.pathname,a;if(l==null)a=n;else{let d=t.length-1;if(!r&&l.startsWith("..")){let m=l.split("/");for(;m[0]==="..";)m.shift(),d-=1;s.pathname=m.join("/")}a=d>=0?t[d]:"/"}let u=Zv(s,a),c=l&&l!=="/"&&l.endsWith("/"),p=(i||l===".")&&n.endsWith("/");return!u.pathname.endsWith("/")&&(c||p)&&(u.pathname+="/"),u}var np=e=>e.replace(/[\\/]{2,}/g,"/"),mt=e=>np(e.join("/"));function Ar(e,t=0){let n=e.length;for(;n>t&&e.charCodeAt(n-1)===47;)n--;return n===e.length?e:e.slice(0,n)}var tg=e=>Ar(e).replace(/^\/*/,"/"),ng=e=>!e||e==="?"?"":e.startsWith("?")?e:"?"+e,rg=e=>!e||e==="#"?"":e.startsWith("#")?e:"#"+e,sg=class{constructor(e,t,n,r=!1){this.status=e,this.statusText=t||"",this.internal=r,n instanceof Error?(this.data=n.toString(),this.error=n):this.data=n}};function ig(e){return e!=null&&typeof e.status=="number"&&typeof e.statusText=="string"&&typeof e.internal=="boolean"&&"data"in e}function lg(e){let t=e.map(n=>n.route.path).filter(Boolean);return mt(t)||"/"}var rp=typeof window<"u"&&typeof window.document<"u"&&typeof window.document.createElement<"u";function sp(e,t){let n=e;if(typeof n!="string"||!Ru.test(n))return{absoluteURL:void 0,isExternal:!1,to:n};let r=n,s=!1;if(rp)try{let i=new URL(window.location.href),l=Gh.test(n)?new URL(Mv(n,i.protocol)):new URL(n),a=Kt(l.pathname,t);l.origin===i.origin&&a!=null?n=a+l.search+l.hash:s=!0}catch{Pt(!1,` contains an invalid URL which will probably break when clicked - please update to a valid URL path.`)}return{absoluteURL:r,isExternal:s,to:n}}Object.getOwnPropertyNames(Object.prototype).sort().join("\0");var od=new URL("http://localhost");function ip(e){if(e.createURL)return e.createURL("/");try{return new URL(e.createHref("/"),od)}catch{return od}}function da(e,t){return e.origin===t.origin&&(e.origin!=="null"||e.protocol===t.protocol&&e.host===t.host)}function ag(e,t){if(e.startsWith("//"))return!0;let n=t.protocol.toLowerCase();return e.toLowerCase().startsWith(n)?t.host===""||e.slice(n.length).startsWith("//"):!1}function lp(e,t,n,r){let s=null;try{s=e==null?null:new URL(e,n)}catch{}let i=new URL(t,n),l=s!=null&&!da(s,n),a=!da(i,n);if(r==="reject"){if(l||a)throw new Error("External navigation is not allowed")}else if(a&&(s==null||!ag(e,s)||!da(s,i)))throw new Error("External navigation is not allowed")}var ap=["POST","PUT","PATCH","DELETE"];new Set(ap);var og=["GET",...ap];new Set(og);var ug=["about:","blob:","chrome:","chrome-untrusted:","content:","data:","devtools:","file:","filesystem:","javascript:"];function cg(e){try{return ug.includes(new URL(e).protocol)}catch{return!1}}var Vr=w.createContext(null);Vr.displayName="DataRouter";var Rl=w.createContext(null);Rl.displayName="DataRouterState";var op=w.createContext(!1);function dg(){return w.useContext(op)}var up=w.createContext({isTransitioning:!1});up.displayName="ViewTransition";var fg=w.createContext(new Map);fg.displayName="Fetchers";var hg=w.createContext(null);hg.displayName="Await";var lt=w.createContext(null);lt.displayName="Navigation";var Ys=w.createContext(null);Ys.displayName="Location";var Rt=w.createContext({outlet:null,matches:[],isDataRoute:!1});Rt.displayName="Route";var Lu=w.createContext(null);Lu.displayName="RouteError";var cp="REACT_ROUTER_ERROR",pg="REDIRECT",mg="ROUTE_ERROR_RESPONSE";function yg(e){if(e.startsWith(`${cp}:${pg}:{`))try{let t=JSON.parse(e.slice(28));if(typeof t=="object"&&t&&typeof t.status=="number"&&typeof t.statusText=="string"&&typeof t.location=="string"&&typeof t.reloadDocument=="boolean"&&typeof t.replace=="boolean")return t}catch{}}function vg(e){if(e.startsWith(`${cp}:${mg}:{`))try{let t=JSON.parse(e.slice(40));if(typeof t=="object"&&t&&typeof t.status=="number"&&typeof t.statusText=="string")return new sg(t.status,t.statusText,t.data)}catch{}}function gg(e,{relative:t}={}){Z(Xs(),"useHref() may be used only in the context of a component.");let{basename:n,navigator:r}=w.useContext(lt),{hash:s,pathname:i,search:l}=Zs(e,{relative:t}),a=i;return n!=="/"&&(a=i==="/"?n:mt([n,i])),r.createHref({pathname:a,search:l,hash:s})}function Xs(){return w.useContext(Ys)!=null}function _t(){return Z(Xs(),"useLocation() may be used only in the context of a component."),w.useContext(Ys).location}var dp="You should call navigate() in a React.useEffect(), not when your component is first rendered.";function fp(e){w.useContext(lt).static||w.useLayoutEffect(e)}function Js(){let{isDataRoute:e}=w.useContext(Rt);return e?Tg():xg()}function xg(){Z(Xs(),"useNavigate() may be used only in the context of a component.");let e=w.useContext(Vr),{basename:t,navigator:n}=w.useContext(lt),{matches:r}=w.useContext(Rt),{pathname:s}=_t(),i=JSON.stringify(tp(r)),l=w.useRef(!1);return fp(()=>{l.current=!0}),w.useCallback((u,c={})=>{if(Pt(l.current,dp),!l.current)return;if(typeof u=="number"){n.go(u);return}let p=_u(u,JSON.parse(i),s,c.relative==="path");e==null&&t!=="/"&&(p.pathname=p.pathname==="/"?t:mt([t,p.pathname])),lp(typeof u=="string"?u:Ur(u),n.createHref(p),ip(n),"reject"),(c.replace?n.replace:n.push)(p,c.state,c)},[t,n,i,s,e])}w.createContext(null);function _l(){let{matches:e}=w.useContext(Rt),t=e[e.length-1];return(t==null?void 0:t.params)??{}}function Zs(e,{relative:t}={}){let{matches:n}=w.useContext(Rt),{pathname:r}=_t(),s=JSON.stringify(tp(n));return w.useMemo(()=>_u(e,JSON.parse(s),r,t==="path"),[e,s,r,t])}function wg(e,t){return hp(e,t)}function hp(e,t,n){var E;Z(Xs(),"useRoutes() may be used only in the context of a component.");let{navigator:r}=w.useContext(lt),{matches:s}=w.useContext(Rt),i=s[s.length-1],l=i?i.params:{},a=i?i.pathname:"/",u=i?i.pathnameBase:"/",c=i&&i.route;{let f=c&&c.path||"";mp(a,!c||f.endsWith("*")||f.endsWith("*?"),`You rendered descendant (or called \`useRoutes()\`) at "${a}" (under ) but the parent route path has no trailing "*". This means if you navigate deeper, the parent won't match anymore and therefore the child routes will never render. + +Please change the parent to .`)}let p=_t(),d;if(t){let f=typeof t=="string"?Wr(t):t;Z(u==="/"||((E=f.pathname)==null?void 0:E.startsWith(u)),`When overriding the location using \`\` or \`useRoutes(routes, location)\`, the location pathname must begin with the portion of the URL pathname that was matched by all parent routes. The current pathname base is "${u}" but pathname "${f.pathname}" was given in the \`location\` prop.`),d=f}else d=p;let m=d.pathname||"/",x=m;if(u!=="/"){let f=u.replace(/^\//,"").split("/");x="/"+m.replace(/^\//,"").split("/").slice(f.length).join("/")}let g=n&&n.state.matches.length?n.state.matches.map(f=>Object.assign(f,{route:n.manifest[f.route.id]||f.route})):Yh(e,{pathname:x});Pt(c||g!=null,`No routes matched location "${d.pathname}${d.search}${d.hash}" `),Pt(g==null||g[g.length-1].route.element!==void 0||g[g.length-1].route.Component!==void 0||g[g.length-1].route.lazy!==void 0,`Matched leaf route at location "${d.pathname}${d.search}${d.hash}" does not have an element or Component. This means it will render an with a null value by default resulting in an "empty" page.`);let S=jg(g&&g.map(f=>Object.assign({},f,{params:Object.assign({},l,f.params),pathname:mt([u,r.encodeLocation?r.encodeLocation(f.pathname.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:f.pathname]),pathnameBase:f.pathnameBase==="/"?u:mt([u,r.encodeLocation?r.encodeLocation(f.pathnameBase.replace(/%/g,"%25").replace(/\?/g,"%3F").replace(/#/g,"%23")).pathname:f.pathnameBase])})),s,n);return t&&S?w.createElement(Ys.Provider,{value:{location:{pathname:"/",search:"",hash:"",state:null,key:"default",mask:void 0,...d},navigationType:"POP"}},S):S}function Sg(){let e=Lg(),t=ig(e)?`${e.status} ${e.statusText}`:e instanceof Error?e.message:JSON.stringify(e),n=e instanceof Error?e.stack:null,r="rgba(200,200,200, 0.5)",s={padding:"0.5rem",backgroundColor:r},i={padding:"2px 4px",backgroundColor:r},l=null;return console.error("Error handled by React Router default ErrorBoundary:",e),l=w.createElement(w.Fragment,null,w.createElement("p",null,"💿 Hey developer 👋"),w.createElement("p",null,"You can provide a way better UX than this when your app throws errors by providing your own ",w.createElement("code",{style:i},"ErrorBoundary")," or"," ",w.createElement("code",{style:i},"errorElement")," prop on your route.")),w.createElement(w.Fragment,null,w.createElement("h2",null,"Unexpected Application Error!"),w.createElement("h3",{style:{fontStyle:"italic"}},t),n?w.createElement("pre",{style:s},n):null,l)}var kg=w.createElement(Sg,null),pp=class extends w.Component{constructor(e){super(e),this.state={location:e.location,revalidation:e.revalidation,error:e.error}}static getDerivedStateFromError(e){return{error:e}}static getDerivedStateFromProps(e,t){return t.location!==e.location||t.revalidation!=="idle"&&e.revalidation==="idle"?{error:e.error,location:e.location,revalidation:e.revalidation}:{error:e.error!==void 0?e.error:t.error,location:t.location,revalidation:e.revalidation||t.revalidation}}componentDidCatch(e,t){this.props.onError?this.props.onError(e,t):console.error("React Router caught the following error during render",e)}render(){let e=this.state.error;if(this.context&&typeof e=="object"&&e&&"digest"in e&&typeof e.digest=="string"){const n=vg(e.digest);n&&(e=n)}let t=e!==void 0?w.createElement(Rt.Provider,{value:this.props.routeContext},w.createElement(Lu.Provider,{value:e,children:this.props.component})):this.props.children;return this.context?w.createElement(Eg,{error:e},t):t}};pp.contextType=op;var fa=new WeakMap;function Eg({children:e,error:t}){let{basename:n,navigator:r}=w.useContext(lt);if(typeof t=="object"&&t&&"digest"in t&&typeof t.digest=="string"){let s=yg(t.digest);if(s){let i=fa.get(t);if(i)throw i;let l=sp(s.location,n),a=l.absoluteURL||l.to;if(lp(s.location,a,ip(r),"allow-explicit"),cg(a))throw new Error("Invalid redirect location");if(rp&&!fa.get(t))if(l.isExternal||s.reloadDocument)window.location.href=a;else{const u=Promise.resolve().then(()=>window.__reactRouterDataRouter.navigate(l.to,{replace:s.replace}));throw fa.set(t,u),u}return w.createElement("meta",{httpEquiv:"refresh",content:`0;url=${a}`})}}return e}function Cg({routeContext:e,match:t,children:n}){let r=w.useContext(Vr);return r&&r.static&&r.staticContext&&(t.route.errorElement||t.route.ErrorBoundary)&&(r.staticContext._deepestRenderedBoundaryId=t.route.id),w.createElement(Rt.Provider,{value:e},n)}function jg(e,t=[],n){let r=n==null?void 0:n.state;if(e==null){if(!r)return null;if(r.errors)e=r.matches;else if(t.length===0&&!r.initialized&&r.matches.length>0)e=r.matches;else return null}let s=e,i=r==null?void 0:r.errors;if(i!=null){let p=s.findIndex(d=>d.route.id&&(i==null?void 0:i[d.route.id])!==void 0);Z(p>=0,`Could not find a matching route for errors on route IDs: ${Object.keys(i).join(",")}`),s=s.slice(0,Math.min(s.length,p+1))}let l=!1,a=-1;if(n&&r){l=r.renderFallback;for(let p=0;p=0?s=s.slice(0,a+1):s=[s[0]];break}}}}let u=n==null?void 0:n.onError,c=r&&u?(p,d)=>{var m,x;u(p,{location:r.location,params:((x=(m=r.matches)==null?void 0:m[0])==null?void 0:x.params)??{},pattern:lg(r.matches),errorInfo:d})}:void 0;return s.reduceRight((p,d,m)=>{let x,g=!1,S=null,E=null;r&&(x=i&&d.route.id?i[d.route.id]:void 0,S=d.route.errorElement||kg,l&&(a<0&&m===0?(mp("route-fallback",!1,"No `HydrateFallback` element provided to render during initial hydration"),g=!0,E=null):a===m&&(g=!0,E=d.route.hydrateFallbackElement||null)));let f=t.concat(s.slice(0,m+1)),h=()=>{let y;return x?y=S:g?y=E:d.route.Component?y=w.createElement(d.route.Component,null):d.route.element?y=d.route.element:y=p,w.createElement(Cg,{match:d,routeContext:{outlet:p,matches:f,isDataRoute:r!=null},children:y})};return r&&(d.route.ErrorBoundary||d.route.errorElement||m===0)?w.createElement(pp,{location:r.location,revalidation:r.revalidation,component:S,error:x,children:h(),routeContext:{outlet:null,matches:f,isDataRoute:!0},onError:c}):h()},null)}function Tu(e){return`${e} must be used within a data router. See https://reactrouter.com/en/main/routers/picking-a-router.`}function Ng(e){let t=w.useContext(Vr);return Z(t,Tu(e)),t}function Pg(e){let t=w.useContext(Rl);return Z(t,Tu(e)),t}function Rg(e){let t=w.useContext(Rt);return Z(t,Tu(e)),t}function Fu(e){let t=Rg(e),n=t.matches[t.matches.length-1];return Z(n.route.id,`${e} can only be used on routes that contain a unique "id"`),n.route.id}function _g(){return Fu("useRouteId")}function Lg(){var r;let e=w.useContext(Lu),t=Pg("useRouteError"),n=Fu("useRouteError");return e!==void 0?e:(r=t.errors)==null?void 0:r[n]}function Tg(){let{router:e}=Ng("useNavigate"),t=Fu("useNavigate"),n=w.useRef(!1);return fp(()=>{n.current=!0}),w.useCallback(async(s,i={})=>{Pt(n.current,dp),n.current&&(typeof s=="number"?await e.navigate(s):await e.navigate(s,{fromRouteId:t,...i}))},[e,t])}var ud={};function mp(e,t,n){!t&&!ud[e]&&(ud[e]=!0,Pt(!1,n))}w.memo(Fg);function Fg({routes:e,manifest:t,future:n,state:r,isStatic:s,onError:i}){return hp(e,void 0,{manifest:t,state:r,isStatic:s,onError:i})}function Ln(e){Z(!1,"A is only ever to be used as the child of element, never rendered directly. Please wrap your in a .")}function Og({basename:e="/",children:t=null,location:n,navigationType:r="POP",navigator:s,static:i=!1,useTransitions:l}){Z(!Xs(),"You cannot render a inside another . You should never have more than one in your app.");let a=e.replace(/^\/*/,"/"),u=w.useMemo(()=>({basename:a,navigator:s,static:i,useTransitions:l,future:{}}),[a,s,i,l]);typeof n=="string"&&(n=Wr(n));let{pathname:c="/",search:p="",hash:d="",state:m=null,key:x="default",mask:g}=n,S=w.useMemo(()=>{let E=Kt(c,a);return E==null?null:{location:{pathname:E,search:p,hash:d,state:m,key:x,mask:g},navigationType:r}},[a,c,p,d,m,x,r,g]);return Pt(S!=null,` is not able to match the URL "${c}${p}${d}" because it does not start with the basename, so the won't render anything.`),S==null?null:w.createElement(lt.Provider,{value:u},w.createElement(Ys.Provider,{children:t,value:S}))}function bg({children:e,location:t}){return wg(Co(e),t)}function Co(e,t=[]){let n=[];return w.Children.forEach(e,(r,s)=>{if(!w.isValidElement(r))return;let i=[...t,s];if(r.type===w.Fragment){n.push.apply(n,Co(r.props.children,i));return}Z(r.type===Ln,`[${typeof r.type=="string"?r.type:r.type.name}] is not a component. All component children of must be a or `),Z(!r.props.index||!r.props.children,"An index route cannot have child routes.");let l={id:r.props.id||i.join("-"),caseSensitive:r.props.caseSensitive,element:r.props.element,Component:r.props.Component,index:r.props.index,path:r.props.path,middleware:r.props.middleware,loader:r.props.loader,action:r.props.action,hydrateFallbackElement:r.props.hydrateFallbackElement,HydrateFallback:r.props.HydrateFallback,errorElement:r.props.errorElement,ErrorBoundary:r.props.ErrorBoundary,hasErrorBoundary:r.props.hasErrorBoundary===!0||r.props.ErrorBoundary!=null||r.props.errorElement!=null,shouldRevalidate:r.props.shouldRevalidate,handle:r.props.handle,lazy:r.props.lazy};r.props.children&&(l.children=Co(r.props.children,i)),n.push(l)}),n}var Ii="get",$i="application/x-www-form-urlencoded";function Ll(e){return typeof HTMLElement<"u"&&e instanceof HTMLElement}function Mg(e){return Ll(e)&&e.tagName.toLowerCase()==="button"}function Dg(e){return Ll(e)&&e.tagName.toLowerCase()==="form"}function Ig(e){return Ll(e)&&e.tagName.toLowerCase()==="input"}function $g(e){return!!(e.metaKey||e.altKey||e.ctrlKey||e.shiftKey)}function zg(e,t){return e.button===0&&(!t||t==="_self")&&!$g(e)}var Ei=null;function Ug(){if(Ei===null)try{new FormData(document.createElement("form"),0),Ei=!1}catch{Ei=!0}return Ei}var Ag=new Set(["application/x-www-form-urlencoded","multipart/form-data","text/plain"]);function ha(e){return e!=null&&!Ag.has(e)?(Pt(!1,`"${e}" is not a valid \`encType\` for \`
\`/\`\` and will default to "${$i}"`),null):e}function Qg(e,t){let n,r,s,i,l;if(Dg(e)){let a=e.getAttribute("action");r=a?Kt(a,t):null,n=e.getAttribute("method")||Ii,s=ha(e.getAttribute("enctype"))||$i,i=new FormData(e)}else if(Mg(e)||Ig(e)&&(e.type==="submit"||e.type==="image")){let a=e.form;if(a==null)throw new Error('Cannot submit a