diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 00224b7..71ea18b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,12 +1,66 @@ name: CI on: + workflow_call: push: branches: [ master, main ] pull_request: branches: [ master, main ] jobs: + console: + name: Public console build and browser regression + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v4 + - uses: actions/setup-node@v4 + with: + node-version: '24' + cache: npm + cache-dependency-path: web/package-lock.json + - uses: actions/setup-go@v5 + with: + go-version-file: go.mod + cache-dependency-path: | + go.sum + api/go.sum + - name: Verify public source reproduces embedded assets + run: bash scripts/sync-ui.sh --check + - name: Audit complete console dependency tree + run: npm audit --prefix web + - name: Start disposable MongoDB replica set + run: | + docker run -d --name console-mongo -p 127.0.0.1:27017:27017 mongo:7.0.43 --replSet rs0 --bind_ip_all + for i in $(seq 1 30); do docker exec console-mongo mongosh --quiet --eval 'db.adminCommand({ping:1})' && break; sleep 1; done + docker exec console-mongo mongosh --quiet --eval 'rs.initiate({_id:"rs0",members:[{_id:0,host:"localhost:27017"}]})' + for i in $(seq 1 30); do docker exec console-mongo mongosh --quiet --eval 'if(!db.hello().isWritablePrimary)quit(1)' && break; sleep 1; done + docker exec console-mongo mongosh --quiet --eval 'if(!db.hello().isWritablePrimary)quit(1)' + - name: Build the same engine commit with embedded UI + working-directory: api + run: go build -o /tmp/argon-console-api . + - name: Start production console in isolated demo mode + run: | + PORT=18081 ARGON_DEMO_MODE=1 ARGON_METADATA_DB=argon_console_ci /tmp/argon-console-api >/tmp/argon-console-engine.log 2>&1 & + for i in $(seq 1 30); do curl --fail --silent http://127.0.0.1:18081/api/v1/meta >/dev/null && break; sleep 1; done + curl --fail --silent http://127.0.0.1:18081/api/v1/meta + - name: Install browser + working-directory: web + run: npx playwright install --with-deps chromium + - name: Verify Undo, recovery, conflict review and responsive UI + working-directory: web + env: + CONSOLE_URL: http://127.0.0.1:18081 + run: npm run test:browser + - uses: actions/upload-artifact@v4 + if: always() + continue-on-error: true # Optional evidence; the browser/build steps remain required. + with: + name: public-console-evidence + path: | + /tmp/argon-console-checks + /tmp/argon-console-engine.log + test: name: Test runs-on: ubuntu-latest @@ -47,6 +101,9 @@ jobs: - name: Download dependencies run: go mod download + - name: Compile an external Go v2 consumer + run: bash scripts/check-go-module.sh + - uses: actions/setup-node@v4 with: node-version: '22' @@ -61,7 +118,7 @@ jobs: run: | docker run -d --name ci-minio -p 9010:9000 \ -e MINIO_ROOT_USER=argon -e MINIO_ROOT_PASSWORD=argon12345 \ - minio/minio server /data + quay.io/minio/minio:RELEASE.2025-09-07T16-13-09Z@sha256:14cea493d9a34af32f524e538b8346cf79f3321eff8e708c1e2960462bd8936e server /data for i in $(seq 1 30); do curl -sf http://localhost:9010/minio/health/live && break sleep 1 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 242c795..dc3d3ce 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -12,6 +12,10 @@ concurrency: cancel-in-progress: false jobs: + validate: + name: Validate the tagged source + uses: ./.github/workflows/ci.yml + prepare: name: Validate release version runs-on: ubuntu-latest @@ -19,6 +23,8 @@ jobs: version: ${{ steps.version.outputs.version }} steps: - uses: actions/checkout@v4 + with: + fetch-depth: 0 - uses: actions/setup-node@v4 with: node-version: '22' @@ -27,67 +33,55 @@ jobs: env: RELEASE_TAG: ${{ github.ref_name }} run: | - version=$(node scripts/release-version.js "$RELEASE_TAG") + version=$(node scripts/release-version.js "$RELEASE_TAG" --check) echo "version=$version" >> "$GITHUB_OUTPUT" - node scripts/release-version.js --check + # Nested Go modules need their own semantic-version tag. Both tags + # must identify the reviewed source that the reusable CI validates. + test "$(git rev-parse "refs/tags/api/v${version}^{commit}")" = "$(git rev-parse HEAD)" - name: Check release tooling run: node --test scripts/release-version.test.js npm/scripts/install.test.js - build: - name: Build binaries - needs: prepare + release: + name: Build and publish verified binaries + needs: [prepare, validate] runs-on: ubuntu-latest - strategy: - matrix: - goos: [linux, darwin, windows] - goarch: [amd64, arm64] - exclude: - - goos: windows - goarch: arm64 + permissions: + contents: write steps: - uses: actions/checkout@v4 - - name: Set up Go - uses: actions/setup-go@v5 + - uses: actions/setup-node@v4 + with: + node-version: '24' + - 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 + # Cross-compile in one job. Final release assets are uploaded directly; + # publication does not depend on temporary Actions artifact storage. + - name: Build every supported platform 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: [prepare, build] - runs-on: ubuntu-latest - permissions: - contents: write - steps: - - uses: actions/download-artifact@v4 - with: - pattern: binaries-* - path: dist/ - merge-multiple: true + for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64; do + export GOOS="${target%/*}" GOARCH="${target#*/}" + asset="argon-${GOOS}-${GOARCH}" + if [ "$GOOS" = windows ]; then asset="$asset.exe"; fi + go build -trimpath -ldflags="-s -w -X github.com/argon-lab/argon/v2/pkg/version.Build=$RELEASE_VERSION" -o "../dist/$asset" . + done + - name: Record engine, public console and binary provenance + env: + RELEASE_VERSION: ${{ needs.prepare.outputs.version }} + run: node scripts/release-provenance.mjs dist - name: Generate checksums working-directory: dist - run: sha256sum argon-* > SHA256SUMS - - name: Create release + run: sha256sum argon-* release-provenance.json > SHA256SUMS + - name: Create release with all required assets uses: softprops/action-gh-release@v2 with: files: dist/* diff --git a/CHANGELOG.md b/CHANGELOG.md index 94cdf0b..b37f926 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,41 @@ Planned: GCS chunk-store backend; an opt-in read-your-writes barrier in the wire proxy (hold a write's ack until the ingester confirms the WAL entry — a synchronization barrier, not in-proxy capture). +## [2.1.2] - 2026-09-24 + +### Fixed + +- REST branch creation drains the live parent's capture before fixing its fork + point and refuses degraded history; omitted `from` defaults to `main`. +- Concurrent engine/CLI startup preserves the current unique WAL index instead + of dropping and rebuilding it on every connection. Legacy definitions still + migrate when needed. +- Canceling capture while enabling images for a new collection preserves the + resumable boundary and stops cleanly instead of marking a permanent history gap. +- Go consumers use valid `github.com/argon-lab/argon/v2` and + `github.com/argon-lab/argon/api/v2` modules, with separate matching release tags. +- Console Undo applies the exact actor and bounded LSN range just reviewed; + changing scope invalidates review, including delayed preview responses. +- Expired/reset demo sessions offer a fresh start, clear stale queries and + recover old deep links. Late old-session failures cannot end a renewed session. + +### Import and release hardening + +- Real imports require `--source-quiesced`: stop source writes and DDL for the + entire copy. Preflight rejects unreadable/unsupported collections before + creating target data. Imports remain hidden until successful completion. +- Failed or canceled imports remove their unpublished project/history so the + name can be retried. `argon import cleanup --project P --yes` recovers an + unfinished import after a killed process; completed projects are protected. +- Release publication depends on the complete CI suite for the exact tagged + source, consistent committed version metadata and matching root/API tags. + CI also compiles an external Go consumer of both v2 modules. +- The MIT console source is public in `web/`. Locked builds reproduce the + embedded assets; browser regressions run against the same engine commit. + Release provenance records engine/UI source and every binary checksum. +- Publishing and performance documentation now describes the actual release + flow, source-quiescence contract and completed small-scale benchmark evidence. + ## [2.1.1] - 2026-09-07 ### Fixed diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 09cfab3..7c8f629 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -39,9 +39,9 @@ Please read and follow our [Code of Conduct](CODE_OF_CONDUCT.md) to ensure a wel ### Prerequisites -- Go 1.21+ +- Go 1.26.6+ (see `go.mod`) - Docker (for MongoDB and MinIO) -- Node 20+ and Python 3.10+ only if you touch the driver-compatibility +- Node.js 24 for the console (`web/`); Python 3.10+ for the driver-compatibility harness (`compat/`) ### MongoDB (replica set required) @@ -70,11 +70,13 @@ golangci-lint run ./... # run in each module you touched The S3 chunk-store tests are gated: they skip unless `ARGON_TEST_S3_ENDPOINT` / `ARGON_TEST_S3_BUCKET` (plus `AWS_*` -credentials) point at an S3-compatible store. Locally, MinIO works: +credentials) point at an S3-compatible store. For a disposable local test fixture, use the pinned historical MinIO image +below. It is not a production storage recommendation; community binaries are +[no longer maintained](https://github.com/minio/minio#source-only-distribution). ```bash docker run -d --name argon-minio -p 9010:9000 \ - -e MINIO_ROOT_USER=argon -e MINIO_ROOT_PASSWORD=argon12345 minio/minio server /data + -e MINIO_ROOT_USER=argon -e MINIO_ROOT_PASSWORD=argon12345 quay.io/minio/minio:RELEASE.2025-09-07T16-13-09Z server /data ARGON_TEST_S3_ENDPOINT=http://localhost:9010 ARGON_TEST_S3_BUCKET=argon-test \ AWS_ACCESS_KEY_ID=argon AWS_SECRET_ACCESS_KEY=argon12345 AWS_REGION=us-east-1 \ go test ./tests/wal/ -run TestChunkStore -count=1 @@ -84,6 +86,15 @@ The driver-compatibility harness (`bash compat/run.sh`) runs real pymongo and mongoose workloads against a checked-out branch and verifies WAL convergence; CI runs it on every push. +### Console source and reproducible assets + +The current console is public in [`web/`](web/README.md), under MIT. Run +`bash scripts/sync-ui.sh` from this repository to rebuild the assets embedded +in the Go binary. `bash scripts/sync-ui.sh --check` verifies the committed +assets and their SHA-256 provenance. Commit source and built assets together. +No private companion checkout is needed. CI tests the production console +against the same engine commit, including Undo scope and expired sessions. + ### Two rules the tests enforce - **Determinism**: replaying the same WAL prefix must always produce the @@ -139,9 +150,10 @@ convergence; CI runs it on every push. ### Before Submitting -- [ ] Run `make lint` to check code style -- [ ] Run `make test` to ensure all tests pass -- [ ] Run `make bench` if you've made performance-related changes +- [ ] Run `go vet ./...` in each changed Go module +- [ ] Run the engine, API and CLI tests described above +- [ ] Run `bash scripts/sync-ui.sh --check` for console changes +- [ ] Use the [benchmark suite](https://github.com/argon-lab/benchmarks) for performance claims - [ ] Update documentation for API changes - [ ] Add tests for new functionality - [ ] Rebase on latest main branch @@ -305,10 +317,10 @@ We value all contributions! Contributors will be: export ARGON_LOG_LEVEL=debug # Run with race detector -go run -race ./cmd/argon +(cd cli && go run -race . console --no-browser) -# Profile CPU usage -go run ./cmd/argon --cpuprofile=cpu.prof +# Profile engine tests +go test ./tests/wal -run Test -cpuprofile=cpu.prof ``` ### Common Issues @@ -321,7 +333,7 @@ go run ./cmd/argon --cpuprofile=cpu.prof ```bash # Run specific tests -go test -run TestBranchCreation ./engine +go test ./tests/wal -run TestBranch -count=1 # Update all dependencies go get -u ./... diff --git a/README.md b/README.md index 4bdc4a9..7320a2a 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # Argon — Git for MongoDB

- + Argon — Git for MongoDB, built for AI agents: branch off prod, run an agent, undo the session

@@ -51,8 +51,8 @@ main ──branch──▶ experiment ──checkout──▶ mongodb://… ← ``` ```bash -# 0 · Bring your data in ("git clone") — or: argon projects create myapp -argon import database --uri mongodb://localhost:27017 --database myapp --project myapp +# 0 · Stop source writers and DDL for the import — or: argon projects create myapp +argon import database --uri mongodb://localhost:27017 --database myapp --project myapp --source-quiesced # 1 · Branch — instant, no copy argon branches create experiment -p myapp @@ -74,6 +74,8 @@ argon restore reset -p myapp -b main --time 2026-07-07T09:00:00Z --backup pre-in Prefer clicking? `argon console` serves a local web console (UI + REST API), supervises capture, reaps expired sandboxes every minute, and opens your browser. +The console's MIT-licensed source is in [web/](web/README.md); see the +[rebuild instructions](CONTRIBUTING.md#console-source-and-reproducible-assets). For a complete managed workflow, run [the two-agent pinned dataset example](examples/pinned_agents.py). ## What you get @@ -83,21 +85,21 @@ For a complete managed workflow, run [the two-agent pinned dataset example](exam | **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` | exact change-stream images → history, one actor label per branch | -| **Time travel** | `argon time-travel query` | any historical state, by LSN or timestamp | +| **Time travel** | `argon time-travel query` | query captured document states at retained LSNs; restore/pin also accept timestamps | | **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 | +| **Dataset pins** | `argon pin create` / `pin sandbox` | named captured states protected from GC and resets while the pin exists | | **Web console** | `argon console` | local UI + REST API in one command | 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 +Stop writers before release. Existing pins protect their referenced 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 +Storage retention uses snapshots + retention-window GC to keep state plus a window of history, not every write forever. Details and the consistency model, stated honestly: [ARCHITECTURE.md](docs/ARCHITECTURE.md). @@ -105,17 +107,33 @@ model, stated honestly: [ARCHITECTURE.md](docs/ARCHITECTURE.md). ```bash claude mcp add argon -- argon mcp # 13 tools: sandbox, diff, merge, undo, pins -pip install argon-agents # LangGraph checkpointer + Mem0, over REST +# Install the v0.2.0 release wheel; PyPI currently has the older v0.1.0 API. +python3 -m pip install 'argon-agents[langgraph] @ https://github.com/argon-lab/argon-agents/releases/download/v0.2.0/argon_agents-0.2.0-py3-none-any.whl' ``` +Start `argon console --no-browser` in another terminal, then: + ```python -saver = ArgonCheckpointSaver.from_sandbox(argon, "myapp") # checkpoint on a disposable branch -saver.merge() # adopt the run — or .discard() +from argon_agents import ArgonClient, ArgonCheckpointSaver + +argon = ArgonClient("http://127.0.0.1:1818") +argon.get_or_create_project("myapp") +saver = ArgonCheckpointSaver.from_sandbox(argon, "myapp") +# Compile and run your LangGraph graph with checkpointer=saver, then review: +plan = argon.merge_preview("myapp", saver.sandbox.branch) +print(plan) +# After reviewing this exact plan, apply it explicitly: +# argon.merge_apply(plan["id"]) +# Or reject the run: saver.discard() argon.create_pin("myapp", "eval-v1") # pin the dataset once run = argon.sandbox_from_pin("myapp", "eval-v1") # identical state, every eval run ``` +`saver.merge()` is a convenience call that previews and applies immediately; +use the separate calls above when approval is required. Pins protect captured +document state while they exist; keep independent backups. + The full agent workflow: [docs/AGENTS.md](docs/AGENTS.md). ## Documentation @@ -134,7 +152,7 @@ The full agent workflow: [docs/AGENTS.md](docs/AGENTS.md). [Issues](https://github.com/argon-lab/argon/issues) · [Discussions](https://github.com/argon-lab/argon/discussions) · [Contributing](CONTRIBUTING.md) · -[argonlabs.tech](https://www.argonlabs.tech) +[argonlabs.tech](https://argonlabs.tech) · [Blog](https://argonlabs.tech/blog) --- diff --git a/VERSION b/VERSION index 3e3c2f1..eca07e4 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -2.1.1 +2.1.2 diff --git a/api/go.mod b/api/go.mod index 0e89aa3..e2fc24d 100644 --- a/api/go.mod +++ b/api/go.mod @@ -1,15 +1,15 @@ -module github.com/argon-lab/argon/api +module github.com/argon-lab/argon/api/v2 go 1.26.6 require ( - github.com/argon-lab/argon v0.0.0 + github.com/argon-lab/argon/v2 v2.1.2 github.com/gin-gonic/gin v1.9.1 github.com/stretchr/testify v1.9.0 go.mongodb.org/mongo-driver v1.17.7 ) -replace github.com/argon-lab/argon => ../ +replace github.com/argon-lab/argon/v2 => ../ require ( github.com/aws/aws-sdk-go-v2 v1.42.1 // indirect diff --git a/api/main.go b/api/main.go index 6356bea..fc6e500 100644 --- a/api/main.go +++ b/api/main.go @@ -19,8 +19,8 @@ import ( "syscall" "time" - "github.com/argon-lab/argon/api/server" - "github.com/argon-lab/argon/pkg/walcli" + "github.com/argon-lab/argon/api/v2/server" + "github.com/argon-lab/argon/v2/pkg/walcli" ) func main() { diff --git a/api/server/api_test.go b/api/server/api_test.go index 2457640..0b4ef7c 100644 --- a/api/server/api_test.go +++ b/api/server/api_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/argon-lab/argon/pkg/walcli" + "github.com/argon-lab/argon/v2/pkg/walcli" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" diff --git a/api/server/branch_capture_test.go b/api/server/branch_capture_test.go new file mode 100644 index 0000000..4959a8b --- /dev/null +++ b/api/server/branch_capture_test.go @@ -0,0 +1,81 @@ +package server + +import ( + "context" + "fmt" + "net/http" + "testing" + "time" + + "github.com/argon-lab/argon/v2/pkg/walcli" + "github.com/stretchr/testify/require" + "go.mongodb.org/mongo-driver/bson" +) + +func TestAPI_CreateBranchDrainsNativeParent(t *testing.T) { + ctx, cancel := context.WithTimeout(context.Background(), 40*time.Second) + defer cancel() + dbName := fmt.Sprintf("argon_api_fork_%d", time.Now().UnixNano()) + services, err := walcli.NewServicesAt("mongodb://localhost:27017", dbName) + require.NoError(t, err) + router := NewRouterWith(services, Options{}) + t.Cleanup(func() { + router.Shutdown() + projects, _ := services.Projects.ListProjects() + for _, project := range projects { + branches, _ := services.Branches.ListBranches(project.ID) + for _, branch := range branches { + if branch.PhysicalDB != "" { + _ = services.Client.Database(branch.PhysicalDB).Drop(context.Background()) + } + } + } + _ = services.Client.Database(dbName).Drop(context.Background()) + _ = services.Client.Disconnect(context.Background()) + }) + code, _ := do(t, router, "POST", "/api/v1/projects", map[string]string{"name": "fork"}) + require.Equal(t, http.StatusCreated, code) + code, _ = do(t, router, "POST", "/api/v1/projects/fork/branches/main/checkout", nil) + require.Equal(t, http.StatusOK, code) + projectID := mustProjectID(t, services, "fork") + parent, err := services.Branches.GetBranch(projectID, "main") + require.NoError(t, err) + + // Stop capture to make the otherwise timing-dependent gap deterministic. + // The REST fork must restart/drain it, including a completed native write. + require.NoError(t, services.Ingest.Stop(ctx, parent.ID)) + physical := services.Client.Database(parent.PhysicalDB) + _, err = physical.Collection("notes").InsertOne(ctx, bson.M{"_id": "pending", "value": "must inherit"}) + require.NoError(t, err) + before, err := services.Branches.GetBranchByID(parent.ID) + require.NoError(t, err) + code, response := do(t, router, "POST", "/api/v1/projects/fork/branches", map[string]string{"name": "child"}) + require.Equal(t, http.StatusCreated, code, "%v", response) + child, err := services.Branches.GetBranch(projectID, "child") + require.NoError(t, err) + require.Equal(t, parent.ID, child.ParentID, "omitted from defaults to main") + require.Greater(t, child.BaseLSN, before.HeadLSN) + code, response = do(t, router, "POST", "/api/v1/projects/fork/branches/child/checkout", nil) + require.Equal(t, http.StatusOK, code, "%v", response) + child, err = services.Branches.GetBranchByID(child.ID) + require.NoError(t, err) + var inherited bson.M + require.NoError(t, services.Client.Database(child.PhysicalDB).Collection("notes").FindOne(ctx, bson.M{"_id": "pending"}).Decode(&inherited)) + require.Equal(t, "must inherit", inherited["value"]) + + // A DDL gap cannot be made durable by draining. It must refuse the fork, + // rather than creating an apparently valid branch at an incomplete head. + require.NoError(t, physical.Collection("notes").Drop(ctx)) + require.Eventually(t, func() bool { + for _, status := range services.Ingest.Statuses() { + if status.BranchID == parent.ID && status.State == "degraded" { + return true + } + } + return false + }, 10*time.Second, 20*time.Millisecond) + code, response = do(t, router, "POST", "/api/v1/projects/fork/branches", map[string]string{"name": "unsafe", "from": "main"}) + require.Equal(t, http.StatusServiceUnavailable, code, "%v", response) + _, err = services.Branches.GetBranch(projectID, "unsafe") + require.Error(t, err) +} diff --git a/api/server/console.go b/api/server/console.go index 3e2b13c..74b3dab 100644 --- a/api/server/console.go +++ b/api/server/console.go @@ -8,7 +8,7 @@ package server import ( "crypto/subtle" "fmt" - "github.com/argon-lab/argon/pkg/version" + "github.com/argon-lab/argon/v2/pkg/version" "net" "net/http" "net/url" @@ -25,7 +25,7 @@ import ( ) // Version shares the embedded release metadata with the CLI. Release builds -// override github.com/argon-lab/argon/pkg/version.Build via -ldflags. +// override github.com/argon-lab/argon/v2/pkg/version.Build via -ldflags. var Version = version.String() // Options are the cross-cutting server settings. The zero value is an open diff --git a/api/server/demo_test.go b/api/server/demo_test.go index 86d2808..e8f0dd4 100644 --- a/api/server/demo_test.go +++ b/api/server/demo_test.go @@ -10,7 +10,7 @@ import ( "testing" "time" - "github.com/argon-lab/argon/pkg/walcli" + "github.com/argon-lab/argon/v2/pkg/walcli" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" ) diff --git a/api/server/router.go b/api/server/router.go index ce56005..6c3e0d1 100644 --- a/api/server/router.go +++ b/api/server/router.go @@ -17,7 +17,7 @@ import ( "sync" "time" - "github.com/argon-lab/argon/pkg/walcli" + "github.com/argon-lab/argon/v2/pkg/walcli" "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson/primitive" ) @@ -305,16 +305,22 @@ func (r *Router) createBranch(c *gin.Context) { abortErr(c, http.StatusBadRequest, err) return } - parentID := "" - if body.From != "" { - parent, err := r.services.Branches.GetBranch(projectID, body.From) - if err != nil { - abortErr(c, http.StatusNotFound, fmt.Errorf("parent branch %q not found", body.From)) - return - } - parentID = parent.ID + if body.From == "" { + body.From = "main" + } + parent, err := r.services.Branches.GetBranch(projectID, body.From) + if err != nil { + abortErr(c, http.StatusNotFound, fmt.Errorf("parent branch %q not found", body.From)) + return + } + // The fork point is the parent's durable WAL head. A native write may + // already be acknowledged while capture is behind, so drain before + // CreateBranch reloads and fixes that head for the child's lifetime. + if err := r.services.SyncBranch(c.Request.Context(), parent.ID); err != nil { + abortErr(c, http.StatusServiceUnavailable, err) + return } - branch, err := r.services.Branches.CreateBranch(projectID, body.Name, parentID) + branch, err := r.services.Branches.CreateBranch(projectID, body.Name, parent.ID) if err != nil { abortErr(c, http.StatusConflict, err) return diff --git a/api/server/security_test.go b/api/server/security_test.go index ed4c841..d677b7b 100644 --- a/api/server/security_test.go +++ b/api/server/security_test.go @@ -9,7 +9,7 @@ import ( "testing" "time" - "github.com/argon-lab/argon/pkg/walcli" + "github.com/argon-lab/argon/v2/pkg/walcli" "github.com/gin-gonic/gin" "github.com/stretchr/testify/require" ) diff --git a/api/server/ui.go b/api/server/ui.go index aae7f0d..65eac42 100644 --- a/api/server/ui.go +++ b/api/server/ui.go @@ -1,5 +1,5 @@ // Serving the embedded web console. The SPA build is vendored into -// ui/dist by scripts/sync-ui.sh (a placeholder page ships by default), so +// ui/dist from public web/ source by scripts/sync-ui.sh, so // one binary carries both the control plane and its UI. package server diff --git a/api/server/ui/dist/.source b/api/server/ui/dist/.source deleted file mode 100644 index a823c63..0000000 --- a/api/server/ui/dist/.source +++ /dev/null @@ -1,2 +0,0 @@ -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 deleted file mode 100644 index 6311d5f..0000000 --- a/api/server/ui/dist/assets/index-3FWB-cCO.js +++ /dev/null @@ -1,51 +0,0 @@ -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 + )} + {meta.data?.demo && demo} + {meta.data?.read_only && read-only} + {meta.data && {meta.data.version}} + {meta.isError && engine unreachable} + + + + {demo && session.data && ( +
+ + Your session-scoped sample project expires{" "} + . Native database access + is available locally. + + + + +
+ )} + + {sessionNotice && !sessionLost && ( +

+ {sessionNotice} +

+ )} + {meta.data?.demo && (sessionLost || session.isError) && ( +
+

+ {sessionLost + ? "Your sample session has ended" + : "Your sample session could not start"} +

+

+ Sample data expires and may reset when the demo restarts. Start a + new session to continue. +

+ + {recover.isError && } +
+ )} + {meta.isPending && } + {meta.isError && } + {meta.data?.demo && session.isPending && } + {meta.data?.demo && session.isError && ( + + )} + {meta.data && (!meta.data.demo || (demo && !session.isError)) && ( +
+ + } /> + } /> + } + /> + } /> + } /> + + nothing here. +

+ } + /> +
+
+ )} + + {meta.data?.demo && } + + {demo && tourKey !== null && ( + setTourKey(null)} + /> + )} + + ); +} diff --git a/web/src/Tour.tsx b/web/src/Tour.tsx new file mode 100644 index 0000000..8323fda --- /dev/null +++ b/web/src/Tour.tsx @@ -0,0 +1,240 @@ +import { LocalLink } from "./funnel"; +import { useEffect, useMemo, useState } from "react"; +import { useNavigate } from "react-router-dom"; +import { api } from "./api"; +import { Button } from "./ui"; + +const DONE_KEY = "argon.tour.done"; + +export function tourWasSeen(): boolean { + try { + return localStorage.getItem(DONE_KEY) === "1"; + } catch { + return false; + } +} + +type Step = { + title: string; + body: string; + // Where this step lives: "project" stays on the project page, "branch" + // needs the agent-run branch (created on the run step). + page: "project" | "branch"; + anchor?: string; // data-tour target to scroll to + ring +}; + +const STEPS: Step[] = [ + { + title: "Welcome — this is your own sandbox", + body: "This is a session-scoped, temporary sample project on a hosted Argon engine. Native MongoDB connections are available in your local deployment. Argon gives MongoDB Git-like branches, time travel, merges, and per-actor undo. Let's walk the whole loop in about a minute.", + page: "project", + }, + { + title: "1 · Run an agent session", + body: "Next forks planner and executor from the same pinned $49 order. The script accepts planner’s $44 proposal into main. Executor proposes $1 on its separate branch. Review its real conflict, then undo or discard it.", + page: "project", + anchor: "scenario", + }, + { + title: "2 · Every write has an actor", + body: "Executor’s branch carries its actor in history. Planner uses a separate branch from the same pin. For native drivers, attribution belongs to the branch or run, not to individual clients sharing a connection.", + page: "branch", + anchor: "agents", + }, + { + title: "3 · Time-travel the data", + body: "Pick a collection (try orders), then hit ▶ play — or drag the slider. You're watching the collection exactly as it stood at each point in history, reconstructed from the log. Only retained history with complete capture images can be reconstructed safely.", + page: "branch", + anchor: "timetravel", + }, + { + title: "4 · Diff and merge — a data pull request", + body: "Click 'compute diff against parent', then 'create merge plan'. The plan is a reviewable data PR. Planner’s accepted $44 and executor’s proposed $1 conflict on the same order. Inspect all three versions before selecting a resolution strategy.", + page: "branch", + anchor: "diff", + }, + { + title: "5 · Undo one agent", + body: "Back in the Agents panel, 'undo this actor →' reverts a single agent's writes with append-only compensations — nothing is destroyed, the undo is itself history. This is the undo button for AI agents.", + page: "branch", + anchor: "agents", + }, + { + title: "That's the loop", + body: "Continue with the same order example on your local engine. The quickstart includes MongoDB replica-set setup, capture supervision and the runnable Python assertions.", + page: "project", + }, +]; + +// Ring the target panel; retry briefly since it may mount after navigation. +function highlight(anchor: string | undefined): () => void { + let el: HTMLElement | null = null; + let tries = 0; + const clear = () => el?.classList.remove("tour-ring"); + const tick = () => { + if (!anchor) return; + const found = document.querySelector( + `[data-tour="${anchor}"]`, + ); + if (found) { + el = found; + el.classList.add("tour-ring"); + el.scrollIntoView({ behavior: "smooth", block: "center" }); + } else if (tries++ < 12) { + setTimeout(tick, 100); + } + }; + tick(); + return clear; +} + +export default function Tour({ + project, + onClose, +}: { + project: string; + onClose: () => void; +}) { + const navigate = useNavigate(); + const [i, setI] = useState(0); + const [branch, setBranch] = useState(null); + const step = STEPS[i]; + + const run = useMemo( + () => ({ + scenario: async () => { + // Reuse an existing run branch if the visitor already made one. + const { branches } = await api.branches(project); + const existing = (branches ?? []).find((b) => + b.name.startsWith("agent-run-"), + ); + if (existing) return existing.name; + const res = await api.demoScenario(); + return res.branch; + }, + }), + [project], + ); + const [busy, setBusy] = useState(false); + const [error, setError] = useState(null); + + // Opening (or restarting) the tour brings the top of the page into view, + // so the welcome step and the card are unmistakably together. + useEffect(() => { + window.scrollTo({ top: 0, behavior: "smooth" }); + }, []); + + // On each step, land on the right page and ring its anchor. + useEffect(() => { + const target = + step.page === "branch" && branch + ? `/p/${project}/b/${branch}` + : `/p/${project}`; + if (window.location.pathname !== target) navigate(target); + const clear = highlight(step.anchor); + return clear; + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [i, branch]); + + const finish = () => { + try { + localStorage.setItem(DONE_KEY, "1"); + } catch { + /* Storage is optional. */ + } + onClose(); + }; + + const next = async () => { + // Leaving the "run" step: make sure a branch exists first. + if (step.anchor === "scenario" && !branch) { + setBusy(true); + setError(null); + try { + setBranch(await run.scenario()); + } catch (e) { + setError( + e instanceof Error + ? e.message + : "Could not run the scenario. Try again.", + ); + return; + } finally { + setBusy(false); + } + } + if (i === STEPS.length - 1) finish(); + else setI((n) => n + 1); + }; + + // Steps without a panel to point at (welcome, finish) show as a centered + // dialog behind a dim backdrop — unmissable, and clearly the thing the + // "guided tour" button opened. Steps that reference a panel dock to the + // corner and ring their target, so the page stays usable. + const centered = !step.anchor; + + const card = ( +
+
+ + Guided tour · {i + 1}/{STEPS.length} + + +
+
+

{step.title}

+

+ {step.body} +

+ {error && ( +

+ {error} +

+ )} + {i === STEPS.length - 1 && ( +

+ +

+ )} +
+ {i > 0 && ( + + )} +
+ +
+
+
+
+ ); + + if (centered) { + return ( +
+ {card} +
+ ); + } + return card; +} diff --git a/web/src/api.ts b/web/src/api.ts new file mode 100644 index 0000000..2490ed0 --- /dev/null +++ b/web/src/api.ts @@ -0,0 +1,341 @@ +// Typed client for the engine's REST control plane. Same-origin by +// default (the engine serves this SPA); a different origin and a bearer +// token can be set in localStorage for development against a remote API. + +export type Project = { + id: string; + name: string; + main_branch_id: string; + created_at: string; +}; + +export type Branch = { + id: string; + project_id: string; + name: string; + parent_id?: string; + head_lsn: number; + base_lsn: number; + created_at: string; + created_lsn: number; + is_deleted: boolean; + physical_db?: string; + state?: string; + checked_out_lsn?: number; + expires_at?: string | null; +}; + +export type Entry = { + id?: string; + lsn: number; + timestamp: string; + project_id: string; + branch_id: string; + operation: string; + collection?: string; + document_id?: string; + txn_id?: string; + actor?: string; +}; + +// TimeTravelInfo has no json tags server-side; fields arrive as Go names. +export type TimeTravelInfo = { + BranchID: string; + BranchName: string; + EarliestLSN: number; + LatestLSN: number; + EarliestTime?: string; + LatestTime?: string; + EntryCount: number; +}; + +export type MergeChange = { + collection: string; + document_id: string; + delete?: boolean; + document?: Record; +}; + +export type MergeConflict = { + collection: string; + document_id: string; + base?: Record; + ours?: Record; + theirs?: Record; +}; + +export type MergePlan = { + id: string; + project_id: string; + source_branch: string; + target_branch: string; + source_head: number; + target_head: number; + base_lsn: number; + changes: MergeChange[] | null; + conflicts: MergeConflict[] | null; + status: string; + strategy?: string; + created_at: string; + applied_at?: string; +}; + +export type Meta = { + version: string; + read_only: boolean; + demo?: boolean; + demo_ttl_minutes?: number; + native_connections?: boolean; + actor_scope?: string; + ddl_capture?: boolean; +}; + +export type CaptureStatus = { + branch_id: string; + state: string; + actor?: string; + error?: string; + updated_at?: string; + last_captured_at?: string; + head_lsn?: number; + last_event_lag_ms?: number; +}; + +export type DemoSession = { project: string; expires_at: string }; + +export type Sandbox = { branch: Branch; connection_string?: string }; + +export type Pin = { + id?: string; + project_id: string; + branch_id: string; + name: string; + lsn: number; + note?: string; + created_at: string; +}; + +export type CheckoutInfo = { + connection_string: string; + physical_db: string; + lsn: number; + collections: number; + documents: number; +}; + +export type SandboxInfo = { + branch: string; + connection_string: string; + expires_at: string; + forked_from: string; + fork_lsn: number; + pin?: string; +}; + +export type UndoResult = { + from_lsn: number; + to_lsn: number; + compensations: number; + conflicts: number; + unrecoverable: number; + dry_run: boolean; + restored?: number; + deleted?: number; +}; + +export const DEMO_SESSION_LOST = "argon:demo-session-lost"; +function stored(key: string): string | null { + try { + return localStorage.getItem(key); + } catch { + return null; + } +} +const base = stored("argon.api") ?? ""; +const token = stored("argon.token"); +// A renewal supersedes every request started under the previous cookie. +// Query cancellation alone cannot prevent a late response from arriving. +let demoGeneration = 0; + +async function req( + path: string, + init?: { method?: string; body?: unknown }, +): Promise { + const requestGeneration = demoGeneration; + const headers: Record = {}; + if (token) headers.Authorization = `Bearer ${token}`; + if (init?.body !== undefined) headers["Content-Type"] = "application/json"; + const res = await fetch(base + path, { + method: init?.method ?? "GET", + headers, + body: init?.body !== undefined ? JSON.stringify(init.body) : undefined, + }); + const body = await res.json().catch(() => ({})); + if (!res.ok) { + if ( + res.status === 401 && + requestGeneration === demoGeneration && + body.error === "no demo session; POST /api/v1/demo/session first" + ) { + window.dispatchEvent(new Event(DEMO_SESSION_LOST)); + } + throw new Error(body.error ?? `${res.status} ${res.statusText}`); + } + if (path === "/api/v1/demo/session") demoGeneration += 1; + return body as T; +} + +const post = (path: string, body?: unknown) => + req(path, { method: "POST", body: body ?? {} }); +const del = (path: string) => req(path, { method: "DELETE" }); + +const enc = encodeURIComponent; + +export const api = { + meta: () => req("/api/v1/meta"), + ingesters: () => + req<{ ingesters: string[]; count: number; capture?: CaptureStatus[] }>( + "/api/v1/status/ingesters", + ), + + demoSession: () => post("/api/v1/demo/session"), + demoScenario: () => + post<{ + branch: string; + branches?: string[]; + accepted_branch?: string; + pin?: string; + actors: string[]; + hint: string; + }>("/api/v1/demo/scenario"), + + projects: () => req<{ projects: Project[] | null }>("/api/v1/projects"), + createProject: (name: string) => post("/api/v1/projects", { name }), + + branches: (p: string) => + req<{ branches: Branch[] | null }>(`/api/v1/projects/${enc(p)}/branches`), + branch: (p: string, b: string) => + req<{ branch: Branch; connection_string?: string }>( + `/api/v1/projects/${enc(p)}/branches/${enc(b)}`, + ), + createBranch: (p: string, name: string, from: string) => + post(`/api/v1/projects/${enc(p)}/branches`, { name, from }), + deleteBranch: (p: string, b: string) => + del<{ deleted: boolean }>(`/api/v1/projects/${enc(p)}/branches/${enc(b)}`), + checkout: (p: string, b: string) => + post( + `/api/v1/projects/${enc(p)}/branches/${enc(b)}/checkout`, + ), + release: (p: string, b: string) => + post<{ released: boolean }>( + `/api/v1/projects/${enc(p)}/branches/${enc(b)}/release`, + ), + createSnapshot: (p: string, b: string) => + post<{ snapshots: number; lsn: number }>( + `/api/v1/projects/${enc(p)}/branches/${enc(b)}/snapshots`, + ), + + entries: (p: string, b: string, params: Record) => { + const q = new URLSearchParams( + Object.entries(params).map(([k, v]) => [k, String(v)]), + ); + return req<{ entries: Entry[] | null; has_more: boolean }>( + `/api/v1/projects/${enc(p)}/branches/${enc(b)}/entries?${q}`, + ); + }, + timeTravelInfo: (p: string, b: string) => + req( + `/api/v1/projects/${enc(p)}/branches/${enc(b)}/time-travel`, + ), + timeTravelSummary: (p: string, b: string, lsn: number) => + req<{ lsn: number; collections: Record }>( + `/api/v1/projects/${enc(p)}/branches/${enc(b)}/time-travel/query?lsn=${lsn}`, + ), + timeTravelDocs: ( + p: string, + b: string, + lsn: number, + collection: string, + skip = 0, + limit = 25, + ) => + req<{ + lsn: number; + collection: string; + total: number; + documents: Record[]; + }>( + `/api/v1/projects/${enc(p)}/branches/${enc(b)}/time-travel/query?lsn=${lsn}&collection=${enc(collection)}&skip=${skip}&limit=${limit}`, + ), + + diff: (p: string, b: string) => + req(`/api/v1/projects/${enc(p)}/branches/${enc(b)}/diff`), + mergePreview: (p: string, b: string) => + post( + `/api/v1/projects/${enc(p)}/branches/${enc(b)}/merge-preview`, + ), + mergePlans: (p: string) => + req<{ plans: MergePlan[] | null }>(`/api/v1/merge-plans?project=${enc(p)}`), + mergePlan: (id: string) => req(`/api/v1/merge-plans/${enc(id)}`), + mergeApply: (id: string, strategy?: string) => + post<{ applied: number; conflicts_resolved: number }>( + `/api/v1/merge-plans/${enc(id)}/apply`, + strategy ? { strategy } : {}, + ), + + undo: ( + p: string, + b: string, + args: { + from_lsn: number; + to_lsn?: number; + actor?: string; + dry_run: boolean; + }, + ) => + post( + `/api/v1/projects/${enc(p)}/branches/${enc(b)}/undo`, + args, + ), + + pins: (p: string) => + req<{ pins: Pin[] | null }>(`/api/v1/projects/${enc(p)}/pins`), + createPin: ( + p: string, + args: { name: string; branch?: string; lsn?: number; note?: string }, + ) => post(`/api/v1/projects/${enc(p)}/pins`, args), + deletePin: (p: string, name: string) => + del<{ deleted: boolean }>(`/api/v1/projects/${enc(p)}/pins/${enc(name)}`), + branchFromPin: (p: string, pin: string, name: string) => + post(`/api/v1/projects/${enc(p)}/pins/${enc(pin)}/branches`, { + name, + }), + sandboxFromPin: (p: string, pin: string, ttl_minutes?: number) => + post(`/api/v1/projects/${enc(p)}/pins/${enc(pin)}/sandboxes`, { + ...(ttl_minutes ? { ttl_minutes } : {}), + }), + + sandboxes: (p: string) => + req<{ sandboxes: Sandbox[] | null }>( + `/api/v1/projects/${enc(p)}/sandboxes`, + ), + createSandbox: ( + p: string, + args: { name?: string; from?: string; ttl_minutes?: number }, + ) => post(`/api/v1/projects/${enc(p)}/sandboxes`, args), + discardSandbox: (p: string, b: string) => + del<{ discarded: boolean }>( + `/api/v1/projects/${enc(p)}/sandboxes/${enc(b)}`, + ), + extendSandbox: (p: string, b: string, ttl_minutes: number) => + post<{ expires_at: string }>( + `/api/v1/projects/${enc(p)}/sandboxes/${enc(b)}/extend`, + { + ttl_minutes, + }, + ), + keepSandbox: (p: string, b: string) => + post<{ kept: boolean }>( + `/api/v1/projects/${enc(p)}/sandboxes/${enc(b)}/keep`, + ), +}; diff --git a/web/src/funnel.tsx b/web/src/funnel.tsx new file mode 100644 index 0000000..4198364 --- /dev/null +++ b/web/src/funnel.tsx @@ -0,0 +1,85 @@ +import { useEffect, useState } from "react"; +const EVENTS = [ + "demo_entered", + "first_diff", + "first_merge", + "first_undo", + "quickstart_opened", +] as const; +type Event = (typeof EVENTS)[number]; +const CHOICE = "argon.analytics"; +export const QUICKSTART = "https://argonlabs.tech/quickstart"; +export function track(event: Event) { + try { + if ( + !EVENTS.includes(event) || + navigator.doNotTrack === "1" || + localStorage.getItem(CHOICE) !== "yes" + ) + return; + const key = `argon.funnel.${event}`; + if (sessionStorage.getItem(key)) return; + sessionStorage.setItem(key, "1"); + void fetch("/api/v1/events", { + method: "POST", + headers: { "Content-Type": "application/json" }, + body: JSON.stringify({ event }), + keepalive: true, + credentials: "omit", + }).catch(() => {}); + } catch { + /* Restricted browser storage must not break the console. */ + } +} +export function LocalLink({ + children = "Continue locally →", +}: { + children?: React.ReactNode; +}) { + return ( +
track("quickstart_opened")} + > + {children} + + ); +} +export function NativeNotice() { + return ( +

+ The hosted demo supports sample-data reviews. Native MongoDB connections + and physical sandboxes require your local engine. +

+ ); +} +export function FunnelChoice() { + const [enabled, setEnabled] = useState(false); + useEffect(() => { + try { + setEnabled(localStorage.getItem(CHOICE) === "yes"); + } catch {} + }, []); + return ( + + ); +} diff --git a/web/src/hooks.ts b/web/src/hooks.ts new file mode 100644 index 0000000..7ad34eb --- /dev/null +++ b/web/src/hooks.ts @@ -0,0 +1,39 @@ +import { useQuery } from "@tanstack/react-query"; +import { api } from "./api"; + +export function useMeta() { + return useQuery({ queryKey: ["meta"], queryFn: api.meta }); +} + +// Write actions disappear when the server says it is read-only — the +// hosted demo serves some projects look-but-don't-touch. +export function useReadOnly(): boolean { + const meta = useMeta(); + return meta.data?.read_only ?? false; +} + +export function useDemo(): boolean { + const meta = useMeta(); + return meta.data?.demo ?? false; +} + +// In demo mode the session cookie is the identity. App owns the expiry timer, +// 401 recovery and explicit renewal; never silently swap projects in the background. +export function useDemoSession() { + const demo = useDemo(); + return useQuery({ + queryKey: ["demo-session"], + queryFn: api.demoSession, + enabled: demo, + staleTime: Infinity, + retry: 2, + }); +} + +// Do not expose native actions before capability metadata arrives. +export function useNativeConnections(): boolean { + const meta = useMeta(); + return ( + !!meta.data && !meta.data.demo && meta.data.native_connections !== false + ); +} diff --git a/web/src/index.css b/web/src/index.css new file mode 100644 index 0000000..25c5c95 --- /dev/null +++ b/web/src/index.css @@ -0,0 +1,60 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + @apply bg-brand-dark text-brand-text antialiased; +} + +/* The guided tour rings the panel it's describing. */ +.tour-ring { + box-shadow: + 0 0 0 1px #96a7ff, + 0 0 0 6px rgba(150, 167, 255, 0.18); +} + +/* The tour card animates in on every (re)open, so clicking "guided tour" + always produces visible motion — even when a card is already showing. */ +@keyframes tourIn { + from { + opacity: 0; + transform: translateY(14px) scale(0.97); + } + to { + opacity: 1; + transform: none; + } +} +.tour-card { + animation: tourIn 0.3s ease-out; +} + +/* Preserve the complete document/actor text without widening mobile pages. */ +@media (max-width: 640px) { + table { + display: block; + overflow-x: auto; + max-width: 100%; + } + th, + td { + min-width: 4rem; + padding-right: 0.75rem; + } +} +a:focus-visible, +button:focus-visible, +input:focus-visible, +select:focus-visible { + outline: 2px solid #96a7ff; + outline-offset: 3px; +} +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + scroll-behavior: auto !important; + animation: none !important; + transition: none !important; + } +} diff --git a/web/src/main.tsx b/web/src/main.tsx new file mode 100644 index 0000000..801e0a8 --- /dev/null +++ b/web/src/main.tsx @@ -0,0 +1,20 @@ +import React from "react"; +import ReactDOM from "react-dom/client"; +import { QueryClient, QueryClientProvider } from "@tanstack/react-query"; +import { BrowserRouter } from "react-router-dom"; +import App from "./App"; +import "./index.css"; + +const queryClient = new QueryClient({ + defaultOptions: { queries: { retry: 1, staleTime: 3000 } }, +}); + +ReactDOM.createRoot(document.getElementById("root")!).render( + + + + + + + , +); diff --git a/web/src/pages/Branch.tsx b/web/src/pages/Branch.tsx new file mode 100644 index 0000000..792a7bf --- /dev/null +++ b/web/src/pages/Branch.tsx @@ -0,0 +1,952 @@ +import { LocalLink, NativeNotice, track } from "../funnel"; +import { useEffect, useMemo, useRef, useState } from "react"; +import { Link, useNavigate, useParams } from "react-router-dom"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { api, Entry, UndoResult } from "../api"; +import { useReadOnly, useNativeConnections, useDemo } from "../hooks"; +import { + actorColor, + Badge, + Button, + ConfirmButton, + Dot, + ErrorNote, + Json, + Loading, + Mono, + Panel, + Select, + TextInput, +} from "../ui"; + +// A prefill request from the agent lens into the undo panel: which actor's +// writes to stage, and from which LSN. The nonce lets the same actor be +// re-requested (it changes even when actor/fromLSN repeat). +type UndoRequest = { fromLSN: number; actor: string; nonce: number }; + +// One ascending pass over the branch's history, shared (react-query dedupes +// the key) by the scrubber's frame stops and the agent lens's per-actor +// stats. 500 entries is plenty for a console view; the timeline paginates +// separately for the full log. +function useHistory(project: string, branch: string) { + return useQuery({ + queryKey: ["history-asc", project, branch], + queryFn: () => api.entries(project, branch, { order: "asc", limit: 500 }), + refetchInterval: 5000, + }); +} + +type ActorStat = { + actor: string; + count: number; + minLSN: number; + collections: string[]; +}; + +function actorStats(entries: Entry[]): ActorStat[] { + const by = new Map(); + for (const e of entries) { + if (!e.actor || !e.collection) continue; + const s = by.get(e.actor) ?? { + actor: e.actor, + count: 0, + minLSN: e.lsn, + collections: [], + }; + s.count += 1; + s.minLSN = Math.min(s.minLSN, e.lsn); + if (!s.collections.includes(e.collection)) s.collections.push(e.collection); + by.set(e.actor, s); + } + return [...by.values()].sort((a, b) => a.minLSN - b.minLSN); +} + +function Actions({ project, branch }: { project: string; branch: string }) { + const native = useNativeConnections(); + const status = useQuery({ + queryKey: ["ingesters"], + queryFn: api.ingesters, + refetchInterval: 5000, + }); + const readOnly = useReadOnly(); + const navigate = useNavigate(); + const qc = useQueryClient(); + const q = useQuery({ + queryKey: ["branch", project, branch], + queryFn: () => api.branch(project, branch), + refetchInterval: 5000, + }); + const refresh = () => { + qc.invalidateQueries({ queryKey: ["branch", project, branch] }); + qc.invalidateQueries({ queryKey: ["branches", project] }); + qc.invalidateQueries({ queryKey: ["ingesters"] }); + }; + const checkout = useMutation({ + mutationFn: () => api.checkout(project, branch), + onSuccess: refresh, + }); + const release = useMutation({ + mutationFn: () => api.release(project, branch), + onSuccess: refresh, + }); + const snapshot = useMutation({ + mutationFn: () => api.createSnapshot(project, branch), + }); + const remove = useMutation({ + mutationFn: () => api.deleteBranch(project, branch), + onSuccess: () => { + qc.invalidateQueries({ queryKey: ["branches", project] }); + navigate(`/p/${project}`); + }, + }); + + const capture = status.data?.capture?.find( + (c) => c.branch_id === q.data?.branch.id, + ); + const err = checkout.error ?? release.error ?? snapshot.error ?? remove.error; + return ( + + {q.isError && } + {q.data && ( + <> +
+ + head {q.data.branch.head_lsn} · base {q.data.branch.base_lsn} + + {q.data.branch.state === "live" && ( + + live · {q.data.branch.physical_db} + + )} + {q.data.branch.expires_at && sandbox} +
+ + {native && q.data.connection_string && ( +
+ + {q.data.connection_string} + + +
+ )} + + {!readOnly && ( +
+ {native && + (q.data.branch.state === "live" ? ( + + ) : ( + + ))} + + {branch !== "main" && ( + remove.mutate()} + > + delete branch + + )} + {snapshot.isSuccess && ( + + snapshot @ lsn {snapshot.data.lsn} + + )} +
+ )} + {checkout.isSuccess && !q.data.connection_string && ( +

+ checked out — refreshing… +

+ )} + {err && ( +
+ +
+ )} + {!native && ( +
+ +
+ )} + {status.isError && } + {capture && ( +
+

+ Capture: {capture.state} · actor:{" "} + {capture.actor || "unassigned"} +

+ {capture.updated_at && ( +

+ Status updated {new Date(capture.updated_at).toLocaleString()} +

+ )} + {capture.last_captured_at && ( +

+ Last checkpoint{" "} + {new Date(capture.last_captured_at).toLocaleString()} · + captured LSN {capture.head_lsn ?? "unknown"} +

+ )} + {capture.last_event_lag_ms !== undefined && ( +

+ Last observed capture delay: {capture.last_event_lag_ms} ms + (not current queue lag) +

+ )} + {capture.error && ( +

+ {capture.error} +

+ )} +

+ Actor attribution is shared by this branch/run, not individual + driver clients. Drop/rename DDL is unsupported and marks history + incomplete. +

+
+ )} + {!readOnly && native && q.data.branch.state === "live" && ( +

+ Keep the engine running. Confirm capture is healthy before + reviewing native writes; incomplete images can prevent undo. +

+ )} + + )} +
+ ); +} + +function Diff({ project, branch }: { project: string; branch: string }) { + const readOnly = useReadOnly(); + const navigate = useNavigate(); + const qc = useQueryClient(); + const [open, setOpen] = useState(false); + const diff = useQuery({ + queryKey: ["diff", project, branch], + queryFn: () => api.diff(project, branch), + enabled: open, + }); + const preview = useMutation({ + mutationFn: () => api.mergePreview(project, branch), + onSuccess: (plan) => { + qc.invalidateQueries({ queryKey: ["plans", project] }); + navigate(`/p/${project}/merges/${plan.id}`); + }, + }); + + useEffect(() => { + if (open && diff.isSuccess) track("first_diff"); + }, [open, diff.isSuccess]); + + if (branch === "main") return null; + return ( + + {!open && ( + + )} + {open && diff.isFetching && } + {open && diff.isError && } + {open && diff.data && ( + <> +

+ {diff.data.source_branch} → {diff.data.target_branch} ·{" "} + {(diff.data.changes ?? []).length} changes ·{" "} + + {(diff.data.conflicts ?? []).length} conflicts + +

+
+ {(diff.data.changes ?? []).slice(0, 20).map((ch, i) => ( +

+ + {ch.delete ? "delete" : "put"} + {" "} + + {ch.collection}/{ch.document_id} + +

+ ))} + {(diff.data.changes ?? []).length > 20 && ( +

+ … {(diff.data.changes ?? []).length - 20} more +

+ )} +
+ {!readOnly && (diff.data.changes ?? []).length > 0 && ( +
+ + + persists a reviewable data PR + +
+ )} + {preview.isError && } + + )} +
+ ); +} + +function Undo({ + project, + branch, + actors, + request, +}: { + project: string; + branch: string; + actors: string[]; + request: UndoRequest | null; +}) { + const readOnly = useReadOnly(); + const qc = useQueryClient(); + const [fromLSN, setFromLSN] = useState(""); + const [toLSN, setToLSN] = useState(""); + const [actor, setActor] = useState(""); + type Scope = { from_lsn: number; to_lsn?: number; actor?: string }; + type Review = { result: UndoResult; scope: Scope }; + const [review, setReview] = useState(null); + const revision = useRef(0); + const plan = review?.result; + const invalidateReview = () => { + revision.current += 1; + setReview(null); + }; + + const run = useMutation({ + mutationFn: (args: { dry: boolean; scope: Scope; revision: number }) => + api.undo(project, branch, { ...args.scope, dry_run: args.dry }), + onSuccess: (res, args) => { + // A slow response must not restore a review invalidated by an edit. + if (args.revision === revision.current) { + setReview({ + result: res, + scope: { + from_lsn: res.from_lsn, + to_lsn: res.to_lsn, + ...(args.scope.actor ? { actor: args.scope.actor } : {}), + }, + }); + } + if (!res.dry_run) { + track("first_undo"); + qc.invalidateQueries({ queryKey: ["entries", project, branch] }); + qc.invalidateQueries({ queryKey: ["history-asc", project, branch] }); + qc.invalidateQueries({ queryKey: ["branch", project, branch] }); + qc.invalidateQueries({ queryKey: ["tt-info", project, branch] }); + } + }, + }); + const runMut = run.mutate; + + // The agent lens can stage an actor's writes: fill the form and dry-run + // immediately, so "undo agent:executor" is one click over there. + useEffect(() => { + if (!request) return; + const f = String(request.fromLSN); + setFromLSN(f); + setToLSN(""); + setActor(request.actor); + revision.current += 1; + setReview(null); + runMut({ + dry: true, + scope: { from_lsn: request.fromLSN, actor: request.actor }, + revision: revision.current, + }); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [request?.nonce]); + + if (readOnly) return null; + return ( + +
+ from lsn + { + invalidateReview(); + setFromLSN(value); + }} + width="w-24" + placeholder="990" + /> + + to lsn (opt) + + { + invalidateReview(); + setToLSN(value); + }} + width="w-24" + placeholder="head" + /> + + actor (opt) + + { + setActor(v); + setPages(1); + }} + options={[ + { value: "", label: "all" }, + ...actors.map((a) => ({ value: a, label: a })), + ]} + /> +
+ + {q.isPending && } + {q.isError && } + {q.data && entries.length === 0 && ( +

+ {demo ? ( + <> + No writes yet. Run the sample agent session from the project page, + or start locally. + + ) : ( + <> + No captured writes yet. Check out a branch and keep capture + healthy while writing with your driver. CLI:{" "} + argon checkout + argon watch. + + )} +

+ )} + {entries.length > 0 && ( + <> + + + + + + + + + + + + {entries.map((e: Entry) => ( + + + + + + + + ))} + +
lsnopdocumentactorat
{e.lsn} + + {e.operation} + + + {e.collection + ? `${e.collection}/${e.document_id ?? ""}` + : "—"} + + {e.actor && ( + + {e.actor} + + )} + + {new Date(e.timestamp).toLocaleTimeString()} +
+ {q.data?.has_more && ( +
+ +
+ )} + + )} +
+ ); +} + +function TimeTravel({ project, branch }: { project: string; branch: string }) { + const info = useQuery({ + queryKey: ["tt-info", project, branch], + queryFn: () => api.timeTravelInfo(project, branch), + }); + const history = useHistory(project, branch); + + const [lsn, setLsn] = useState(null); + const [collection, setCollection] = useState(""); + const [playing, setPlaying] = useState(false); + const effectiveLSN = lsn ?? info.data?.LatestLSN ?? 0; + + // The frames worth landing on: LSNs where a data entry changed state. + // Falls back to the endpoints if nothing carries a collection yet. + const stops = useMemo(() => { + const s = new Set(); + for (const e of history.data?.entries ?? []) { + if (e.collection) s.add(e.lsn); + } + if (info.data) { + s.add(info.data.EarliestLSN); + s.add(info.data.LatestLSN); + } + return [...s].sort((a, b) => a - b); + }, [history.data, info.data]); + + // Playback: advance to the next stop on a timer; stop at the end. + useEffect(() => { + if (!playing || stops.length === 0) return; + const id = setInterval(() => { + setLsn((cur) => { + const at = cur ?? stops[stops.length - 1]; + const next = stops.find((s) => s > at); + if (next === undefined) { + setPlaying(false); + return at; + } + return next; + }); + }, 900); + return () => clearInterval(id); + }, [playing, stops]); + + const summary = useQuery({ + queryKey: ["tt-summary", project, branch, effectiveLSN], + queryFn: () => api.timeTravelSummary(project, branch, effectiveLSN), + enabled: !!info.data && info.data.EntryCount > 0, + placeholderData: (prev) => prev, // hold the last frame while the next loads — no flicker + }); + const docs = useQuery({ + queryKey: ["tt-docs", project, branch, effectiveLSN, collection], + queryFn: () => + api.timeTravelDocs(project, branch, effectiveLSN, collection), + enabled: !!collection && !!info.data, + placeholderData: (prev) => prev, + }); + + if (info.isPending) + return ( + + + + ); + if (info.isError) + return ( + + + + ); + const i = info.data!; + if (i.EntryCount === 0) { + return ( + +

+ No data entries to travel through yet. +

+
+ ); + } + + const stepTo = (dir: 1 | -1) => { + setPlaying(false); + setLsn((cur) => { + const at = cur ?? i.LatestLSN; + const next = + dir === 1 + ? stops.find((s) => s > at) + : [...stops].reverse().find((s) => s < at); + return next ?? at; + }); + }; + + return ( + +
+ + + + + lsn {i.EarliestLSN} + + { + setPlaying(false); + setLsn(Number(e.target.value)); + }} + className="w-56 accent-[#96A7FF]" + /> + + {i.LatestLSN} + + @ {effectiveLSN} + {effectiveLSN !== i.LatestLSN && ( + + )} +
+ +
+ {!summary.data && summary.isPending && } + {summary.data && ( +
+ {Object.entries(summary.data.collections) + .sort() + .map(([name, count]) => ( + + ))} + {Object.keys(summary.data.collections).length === 0 && ( +

+ Empty at this LSN. +

+ )} +
+ )} +
+ + {collection && ( +
+ {!docs.data && docs.isPending && } + {docs.isError && } + {docs.data && ( + <> +

+ {collection} @ lsn {docs.data.lsn} · {docs.data.total} docs + {docs.data.total > docs.data.documents.length && + ` (showing ${docs.data.documents.length})`} +

+ + + )} +
+ )} +
+ ); +} + +// The agent lens: who wrote what on this branch, and one-click undo of a +// single actor's writes. This is the "undo button for AI agents" made +// concrete — a session is a set of actors, and any one can be reverted. +function AgentLens({ + project, + branch, + onUndoActor, +}: { + project: string; + branch: string; + onUndoActor: (fromLSN: number, actor: string) => void; +}) { + const readOnly = useReadOnly(); + const history = useHistory(project, branch); + const stats = useMemo( + () => actorStats(history.data?.entries ?? []), + [history.data], + ); + + if (history.isPending) + return ( + + + + ); + if (stats.length === 0) return null; + + return ( + +

+ Scripted API writes carry explicit actors. Native drivers share the + actor configured for their branch/run. Undo requires complete, retained + history; always inspect the dry run. +

+
+ {stats.map((s) => ( +
+ + {s.actor} + + + {s.count} {s.count === 1 ? "write" : "writes"} · from lsn{" "} + {s.minLSN} · {s.collections.join(", ")} + + {!readOnly && ( + + )} +
+ ))} +
+
+ ); +} + +export default function Branch() { + const { project = "", branch = "" } = useParams(); + const [actors, setActors] = useState([]); + const [undoRequest, setUndoRequest] = useState(null); + const undoRef = useRef(null); + + const requestUndo = (fromLSN: number, actor: string) => { + setUndoRequest({ fromLSN, actor, nonce: Date.now() }); + undoRef.current?.scrollIntoView({ behavior: "smooth", block: "start" }); + }; + + return ( +
+ + + + + + + +
+ +
+
+ ); +} diff --git a/web/src/pages/MergePlan.tsx b/web/src/pages/MergePlan.tsx new file mode 100644 index 0000000..44ea602 --- /dev/null +++ b/web/src/pages/MergePlan.tsx @@ -0,0 +1,202 @@ +import { LocalLink, track } from "../funnel"; +import { useState } from "react"; +import { Link, useParams } from "react-router-dom"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { api } from "../api"; +import { useReadOnly } from "../hooks"; +import { + Badge, + ConfirmButton, + ErrorNote, + Json, + Loading, + Panel, + Select, +} from "../ui"; + +export default function MergePlan() { + const { project = "", id = "" } = useParams(); + const readOnly = useReadOnly(); + const qc = useQueryClient(); + const q = useQuery({ + queryKey: ["plan", id], + queryFn: () => api.mergePlan(id), + }); + const [strategy, setStrategy] = useState(""); + + const apply = useMutation({ + mutationFn: () => api.mergeApply(id, strategy || undefined), + onSuccess: () => { + track("first_merge"); + qc.invalidateQueries({ queryKey: ["plan", id] }); + qc.invalidateQueries({ queryKey: ["plans", project] }); + qc.invalidateQueries({ queryKey: ["branches", project] }); + }, + }); + + const conflicts = q.data?.conflicts ?? []; + const canApply = q.data?.status === "pending"; + + return ( +
+ + + {q.isPending && } + {q.isError && } + {q.data && ( + <> + +
+ {q.data.status} + {q.data.strategy && strategy: {q.data.strategy}} + + source head {q.data.source_head} · target head{" "} + {q.data.target_head} · base {q.data.base_lsn} + + {q.data.applied_at && ( + + applied {new Date(q.data.applied_at).toLocaleString()} + + )} +
+ + {!readOnly && canApply && ( +
+ {conflicts.length > 0 && ( + <> + + {conflicts.length} conflicts — pick a strategy + + ({ value: b.name, label: b.name }))} + /> + + {create.isError && } +
+ ); +} + +function Sandboxes({ + project, + branches, +}: { + project: string; + branches: Branch[]; +}) { + const readOnly = useReadOnly(); + const qc = useQueryClient(); + const q = useQuery({ + queryKey: ["sandboxes", project], + queryFn: () => api.sandboxes(project), + refetchInterval: 15000, + }); + const [from, setFrom] = useState("main"); + const [mins, setMins] = useState("60"); + const refresh = () => { + qc.invalidateQueries({ queryKey: ["sandboxes", project] }); + qc.invalidateQueries({ queryKey: ["branches", project] }); + }; + const create = useMutation({ + mutationFn: () => + api.createSandbox(project, { from, ttl_minutes: Number(mins) || 60 }), + onSuccess: refresh, + }); + const act = useMutation({ + mutationFn: async ({ + verb, + name, + }: { + verb: "extend" | "keep" | "discard"; + name: string; + }): Promise => { + if (verb === "extend") + return api.extendSandbox(project, name, Number(mins) || 60); + if (verb === "keep") return api.keepSandbox(project, name); + return api.discardSandbox(project, name); + }, + onSuccess: refresh, + }); + + const boxes = q.data?.sandboxes ?? []; + return ( + + {q.isPending && } + {q.isError && } + {q.data && boxes.length === 0 && ( +

+ No live sandboxes. A sandbox forks a branch, checks it out and expires + on a TTL. +

+ )} + {boxes.length > 0 && ( + + + + + + + + + {boxes.map((s) => ( + + + + + + ))} + +
sandboxexpires +
+ + {s.branch.name} + + + {s.branch.expires_at && ( + {ttl(s.branch.expires_at)} + )} + + {!readOnly && ( + + + + + act.mutate({ verb: "discard", name: s.branch.name }) + } + > + discard + + + )} +
+ )} + {act.isError && } + {!readOnly && ( +
+ from + ({ value: b.name, label: b.name }))} + /> + + {create.isError && } +
+ )} +
+ ); +} + +function AgentScenario({ project }: { project: string }) { + const qc = useQueryClient(); + const run = useMutation({ + mutationFn: api.demoScenario, + onSuccess: () => { + qc.invalidateQueries({ queryKey: ["branches", project] }); + qc.invalidateQueries({ queryKey: ["plans", project] }); + }, + }); + return ( + +

+ Two agents fork the same baseline pin. Planner proposes $44 and the + script accepts it into main; executor proposes $1 on a separate branch. + Review that conflict, undo executor on its branch, or undo the accepted + merge on main. +

+
+ + {run.data && ( + + {run.data.hint} + + )} +
+ {run.data && ( +
+

+ Shared pin:{" "} + + {run.data.pin ?? "baseline"} + +

+
+ {(run.data.branches ?? [run.data.branch]).map((name) => ( + + {name === run.data.accepted_branch + ? "Planner (accepted)" + : "Executor (review conflict)"}{" "} + → + + ))} + + Main (accepted data) → + +
+
+ )} + {run.isError && ( +
+ +
+ )} +
+ ); +} + +export default function Project() { + const { project = "" } = useParams(); + const readOnly = useReadOnly(); + const demo = useDemo(); + const native = useNativeConnections(); + const branches = useQuery({ + queryKey: ["branches", project], + queryFn: () => api.branches(project), + refetchInterval: 5000, + }); + const ingesters = useQuery({ + queryKey: ["ingesters"], + queryFn: api.ingesters, + refetchInterval: 5000, + }); + const plans = useQuery({ + queryKey: ["plans", project], + queryFn: () => api.mergePlans(project), + }); + + const capture = new Map( + (ingesters.data?.capture ?? []).map((c) => [c.branch_id, c]), + ); + const list = branches.data?.branches ?? []; + + return ( +
+ + + {demo && } + + +

+ LSN is a history position. HEAD is the latest recorded change; BASE is + the fork point. A live database needs healthy capture before its + writes are reviewable. +

+ {ingesters.isError && } + {branches.isPending && } + {branches.isError && } + {branches.data && ( + + + + + + + + + + + {outline(list).map(({ branch: b, depth }) => ( + + + + + + + ))} + +
branchheadbasestate
+ + {depth > 0 ? "└ " : ""} + + + {b.name} + + {b.head_lsn} + {b.base_lsn} + + + {b.state === "live" && ( + + live + + )} + {capture.has(b.id) && ( + {`capture: ${capture.get(b.id)!.state}`} + )} + {b.state === "live" && !capture.has(b.id) && ( + capture not running + )} + {b.expires_at && ( + {ttl(b.expires_at)} + )} + +
+ )} + {!readOnly && branches.data && ( + + )} +
+ + {native ? ( + + ) : ( + + + + )} + +
+ ); +} diff --git a/web/src/pages/Projects.tsx b/web/src/pages/Projects.tsx new file mode 100644 index 0000000..b853752 --- /dev/null +++ b/web/src/pages/Projects.tsx @@ -0,0 +1,75 @@ +import { useState } from "react"; +import { Link } from "react-router-dom"; +import { useMutation, useQuery, useQueryClient } from "@tanstack/react-query"; +import { api } from "../api"; +import { useReadOnly, useDemo } from "../hooks"; +import { Button, ErrorNote, Loading, Mono, Panel, TextInput } from "../ui"; + +export default function Projects() { + const q = useQuery({ queryKey: ["projects"], queryFn: api.projects }); + const readOnly = useReadOnly(); + const demo = useDemo(); + const qc = useQueryClient(); + const [name, setName] = useState(""); + + const create = useMutation({ + mutationFn: () => api.createProject(name.trim()), + onSuccess: () => { + setName(""); + qc.invalidateQueries({ queryKey: ["projects"] }); + }, + }); + + return ( + + {q.isPending && } + {q.isError && } + {q.data && + ((q.data.projects ?? []).length === 0 ? ( +

+ No projects yet. Create one below, or import an existing database + with argon import database. +

+ ) : ( + + + + + + + + + + {(q.data.projects ?? []).map((p) => ( + + + + + + ))} + +
namecreatedid
+ + {p.name} + + + {new Date(p.created_at).toLocaleString()} + {p.id}
+ ))} + + {!readOnly && !demo && ( +
+ + + {create.isError && } +
+ )} +
+ ); +} diff --git a/web/src/ui.tsx b/web/src/ui.tsx new file mode 100644 index 0000000..ab06144 --- /dev/null +++ b/web/src/ui.tsx @@ -0,0 +1,241 @@ +// Small shared pieces of the spec-sheet look: 1px borders, mono labels, +// status dots, zero decoration. + +import { ReactNode, useEffect, useState } from "react"; + +export function Panel({ + title, + children, + anchor, +}: { + title?: string; + children: ReactNode; + anchor?: string; // named target for the guided tour to scroll to + highlight +}) { + return ( +
+ {title && ( +
+ {title} +
+ )} +
{children}
+
+ ); +} + +export function Tile({ size = 32 }: { size?: number }) { + return ( + + + 18 + + Ar + + ); +} + +export function Dot({ on }: { on: boolean }) { + return ( + + ); +} + +export function Badge({ + children, + tone = "muted", +}: { + children: ReactNode; + tone?: "muted" | "primary"; +}) { + return ( + + {children} + + ); +} + +export function Mono({ children }: { children: ReactNode }) { + return {children}; +} + +export function Loading({ what }: { what: string }) { + return

loading {what}…

; +} + +export function ErrorNote({ error }: { error: unknown }) { + return ( +

+ {error instanceof Error ? error.message : String(error)} +

+ ); +} + +// Countdown renders "in 54m" and ticks once a minute. +export function Countdown({ to }: { to: string }) { + const [, tick] = useState(0); + useEffect(() => { + const id = setInterval(() => tick((n) => n + 1), 30_000); + return () => clearInterval(id); + }, []); + const ms = new Date(to).getTime() - Date.now(); + if (ms <= 0) return now; + const min = Math.round(ms / 60_000); + return in {min >= 90 ? `${Math.round(min / 60)}h` : `${min}m`}; +} + +// Stable soft color per actor so timelines read at a glance. +const actorPalette = [ + "#96A7FF", + "#7FD1AE", + "#E8B87F", + "#D18FD1", + "#8FC7E8", + "#E88F8F", +]; +export function actorColor(actor: string): string { + let h = 0; + for (let i = 0; i < actor.length; i++) + h = (h * 31 + actor.charCodeAt(i)) >>> 0; + return actorPalette[h % actorPalette.length]; +} + +export function Json({ value }: { value: unknown }) { + return ( +
+      {JSON.stringify(value, null, 2)}
+    
+ ); +} + +// --- action primitives (hidden entirely in read-only mode) --- + +export function Button({ + children, + onClick, + tone = "quiet", + disabled, + title, +}: { + children: ReactNode; + onClick: () => void; + tone?: "quiet" | "solid" | "danger"; + disabled?: boolean; + title?: string; +}) { + const tones = { + quiet: + "border-brand-edge text-brand-text-darker hover:border-brand-primary hover:text-brand-primary", + solid: + "border-brand-primary bg-brand-primary text-brand-dark hover:bg-brand-secondary", + danger: "border-red-400/50 text-red-400 hover:border-red-400", + }[tone]; + return ( + + ); +} + +// Two-step inline confirmation — no native dialogs (they block the tab +// and read as foreign chrome). Click once to arm, again to fire. +export function ConfirmButton({ + children, + onConfirm, + tone = "danger", + disabled, +}: { + children: ReactNode; + onConfirm: () => void; + tone?: "quiet" | "solid" | "danger"; + disabled?: boolean; +}) { + const [armed, setArmed] = useState(false); + if (!armed) { + return ( + + ); + } + return ( + + + + + ); +} + +export function TextInput({ + value, + onChange, + placeholder, + width = "w-44", +}: { + value: string; + onChange: (v: string) => void; + placeholder?: string; + width?: string; +}) { + return ( + onChange(e.target.value)} + placeholder={placeholder} + /> + ); +} + +export function Select({ + value, + onChange, + options, +}: { + value: string; + onChange: (v: string) => void; + options: { value: string; label: string }[]; +}) { + return ( + + ); +} diff --git a/web/tailwind.config.js b/web/tailwind.config.js new file mode 100644 index 0000000..b6b6b5a --- /dev/null +++ b/web/tailwind.config.js @@ -0,0 +1,24 @@ +/** @type {import('tailwindcss').Config} */ +// Brand tokens shared with argon-website (noble-gas identity). +export default { + content: ["./index.html", "./src/**/*.{ts,tsx}"], + theme: { + extend: { + colors: { + "brand-dark": "#0B0E14", // page background + "brand-surface": "#111521", // panels + "brand-edge": "#222838", // 1px borders + "brand-muted": "#8F9BB3", // secondary labels + "brand-primary": "#96A7FF", // argon glow + "brand-secondary": "#6D7FE0", // deeper glow (hover / fills) + "brand-text": "#E8EBF2", + "brand-text-darker": "#9AA3B5", + }, + fontFamily: { + sans: ["Inter", "system-ui", "sans-serif"], + mono: ["ui-monospace", "JetBrains Mono", "SFMono-Regular", "Menlo", "monospace"], + }, + }, + }, + plugins: [], +}; diff --git a/web/tsconfig.json b/web/tsconfig.json new file mode 100644 index 0000000..986b0ff --- /dev/null +++ b/web/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "lib": ["ES2022", "DOM", "DOM.Iterable"], + "module": "ESNext", + "moduleResolution": "bundler", + "jsx": "react-jsx", + "strict": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "noFallthroughCasesInSwitch": true, + "skipLibCheck": true, + "isolatedModules": true, + "useDefineForClassFields": true, + "allowImportingTsExtensions": true, + "noEmit": true + }, + "include": ["src"] +} diff --git a/web/vite.config.ts b/web/vite.config.ts new file mode 100644 index 0000000..d3cb5b2 --- /dev/null +++ b/web/vite.config.ts @@ -0,0 +1,17 @@ +import { defineConfig } from "vite"; +import react from "@vitejs/plugin-react"; + +// In dev, proxy the API to a local engine (`argon console --no-browser` +// or the standalone api binary). In production the SPA is served by the +// engine itself, so everything is same-origin. +const apiOrigin = process.env.ARGON_API_ORIGIN ?? "http://127.0.0.1:1818"; + +export default defineConfig({ + plugins: [react()], + server: { + proxy: { + "/api": apiOrigin, + "/health": apiOrigin, + }, + }, +});