From 50ad1798f287444a65db8ab4960531029a10429f Mon Sep 17 00:00:00 2001 From: amilz <85324096+amilz@users.noreply.github.com> Date: Wed, 24 Jun 2026 10:09:46 -0700 Subject: [PATCH] feat(games): add world-cup example with justfile-driven CI Add the World Cup bracket-prediction game as a self-contained example under a new games/ category: a Pinocchio program with Codama-generated TypeScript/Rust clients, LiteSVM integration tests, and a webapp shell. It pins its own toolchain in a nested workspace, so it is excluded from the root Cargo workspace, the legacy pinocchio CI (.ghaignore), and root Biome. A new just.yml workflow discovers justfile-driven examples and runs their setup/build/test recipes. Co-authored-by: jo <17280917+dev-jodee@users.noreply.github.com> --- .github/.ghaignore | 6 +- .github/.justignore | 2 + .github/workflows/just.yml | 108 + README.md | 6 + biome.jsonc | 2 +- games/world-cup/README.md | 20 + games/world-cup/pinocchio/.env.example | 3 + .../.github/actions/setup/action.yml | 147 + .../pinocchio/.github/workflows/build.yml | 57 + .../pinocchio/.github/workflows/format.yml | 30 + .../pinocchio/.github/workflows/idl-check.yml | 20 + .../pinocchio/.github/workflows/lint.yml | 30 + .../pinocchio/.github/workflows/test.yml | 50 + games/world-cup/pinocchio/.gitignore | 44 + games/world-cup/pinocchio/.nvmrc | 1 + games/world-cup/pinocchio/.prettierignore | 26 + games/world-cup/pinocchio/.prettierrc.json | 1 + games/world-cup/pinocchio/CLAUDE.md | 113 + games/world-cup/pinocchio/Cargo.toml | 43 + games/world-cup/pinocchio/LICENSE | 9 + games/world-cup/pinocchio/README.md | 48 + games/world-cup/pinocchio/SECURITY.md | 9 + .../pinocchio/clients/rust/Cargo.toml | 29 + .../pinocchio/clients/rust/src/lib.rs | 9 + .../pinocchio/clients/typescript/package.json | 38 + .../clients/typescript/src/bracket-display.ts | 62 + .../clients/typescript/src/bracket.ts | 138 + .../clients/typescript/src/constants.ts | 7 + .../clients/typescript/src/fifa-2026.ts | 260 + .../pinocchio/clients/typescript/src/index.ts | 16 + .../clients/typescript/src/leaderboard.ts | 151 + .../clients/typescript/src/scoring.ts | 38 + .../pinocchio/clients/typescript/src/teams.ts | 26 + .../typescript/test/bracket-display.test.ts | 64 + .../clients/typescript/test/bracket.test.ts | 124 + .../clients/typescript/test/fifa-2026.test.ts | 119 + .../typescript/test/leaderboard.test.ts | 140 + .../clients/typescript/test/scoring.test.ts | 74 + .../clients/typescript/tsconfig.json | 19 + .../clients/typescript/tsup.config.ts | 11 + games/world-cup/pinocchio/eslint.config.mjs | 47 + games/world-cup/pinocchio/idl/world_cup.json | 1799 +++ games/world-cup/pinocchio/justfile | 184 + games/world-cup/pinocchio/package.json | 52 + games/world-cup/pinocchio/pnpm-lock.yaml | 11770 ++++++++++++++++ games/world-cup/pinocchio/pnpm-workspace.yaml | 5 + games/world-cup/pinocchio/program/Cargo.toml | 31 + games/world-cup/pinocchio/program/build.rs | 38 + .../pinocchio/program/src/entrypoint.rs | 27 + .../world-cup/pinocchio/program/src/errors.rs | 145 + .../pinocchio/program/src/event_engine.rs | 200 + .../program/src/events/bracket_closed.rs | 32 + .../program/src/events/bracket_submitted.rs | 41 + .../program/src/events/config_initialized.rs | 38 + .../program/src/events/goals_posted.rs | 32 + .../program/src/events/market_finalized.rs | 38 + .../pinocchio/program/src/events/mod.rs | 25 + .../program/src/events/pot_claimed.rs | 35 + .../program/src/events/result_posted.rs | 36 + .../program/src/events/score_refreshed.rs | 35 + .../program/src/events/tournament_locked.rs | 32 + .../program/src/instructions/claim.rs | 85 + .../program/src/instructions/close_bracket.rs | 77 + .../program/src/instructions/emit_event.rs | 22 + .../program/src/instructions/finalize.rs | 118 + .../program/src/instructions/helpers/mod.rs | 71 + .../program/src/instructions/init_config.rs | 128 + .../program/src/instructions/lock.rs | 66 + .../pinocchio/program/src/instructions/mod.rs | 187 + .../program/src/instructions/post_goals.rs | 95 + .../program/src/instructions/post_result.rs | 105 + .../program/src/instructions/refresh_score.rs | 114 + .../src/instructions/submit_bracket.rs | 152 + games/world-cup/pinocchio/program/src/lib.rs | 55 + .../pinocchio/program/src/state/bracket.rs | 104 + .../pinocchio/program/src/state/common.rs | 101 + .../pinocchio/program/src/state/config.rs | 123 + .../pinocchio/program/src/state/mod.rs | 20 + .../pinocchio/program/src/state/oracle.rs | 99 + .../pinocchio/program/src/state/vault.rs | 12 + .../world-cup/pinocchio/program/src/tests.rs | 182 + .../pinocchio/program/src/tournament.rs | 166 + games/world-cup/pinocchio/rust-toolchain.toml | 2 + games/world-cup/pinocchio/rustfmt.toml | 5 + .../pinocchio/scripts/create-bracket.ts | 147 + .../pinocchio/scripts/generate-clients.ts | 34 + .../pinocchio/scripts/generate-ts-client.ts | 25 + games/world-cup/pinocchio/scripts/init.ts | 49 + .../tests/integration-tests/Cargo.toml | 24 + .../tests/integration-tests/src/lib.rs | 32 + .../src/test_account_meta.rs | 66 + .../tests/integration-tests/src/test_claim.rs | 117 + .../src/test_close_bracket.rs | 64 + .../integration-tests/src/test_finalize.rs | 118 + .../integration-tests/src/test_init_config.rs | 56 + .../tests/integration-tests/src/test_lock.rs | 61 + .../integration-tests/src/test_post_goals.rs | 46 + .../integration-tests/src/test_post_result.rs | 64 + .../src/test_refresh_score.rs | 81 + .../src/test_submit_bracket.rs | 86 + .../integration-tests/src/utils/asserts.rs | 52 + .../integration-tests/src/utils/constants.rs | 5 + .../integration-tests/src/utils/cu_tracker.rs | 36 + .../tests/integration-tests/src/utils/idl.rs | 34 + .../tests/integration-tests/src/utils/mod.rs | 8 + .../tests/integration-tests/src/utils/pda.rs | 23 + .../src/utils/test_helpers.rs | 323 + games/world-cup/pinocchio/tsconfig.json | 15 + games/world-cup/pinocchio/webapp/.env.example | 8 + games/world-cup/pinocchio/webapp/.gitignore | 32 + games/world-cup/pinocchio/webapp/README.md | 26 + .../pinocchio/webapp/api/lib/bpf-loader.ts | 143 + .../webapp/api/lib/deploy-builder.ts | 80 + .../webapp/api/lib/program-status.ts | 118 + games/world-cup/pinocchio/webapp/api/og.tsx | 303 + .../pinocchio/webapp/api/package.json | 16 + .../world-cup/pinocchio/webapp/api/server.ts | 769 + games/world-cup/pinocchio/webapp/index.html | 14 + .../world-cup/pinocchio/webapp/middleware.ts | 45 + games/world-cup/pinocchio/webapp/package.json | 55 + .../pinocchio/webapp/postcss.config.js | 6 + .../webapp/public/fonts/InterVariable.woff2 | Bin 0 -> 352240 bytes .../pinocchio/webapp/public/solana-logo.svg | 13 + .../pinocchio/webapp/public/vite.svg | 1 + .../webapp/scripts/config-manager.ts | 94 + .../pinocchio/webapp/scripts/helpers.ts | 119 + .../webapp/scripts/init-test-environment.ts | 72 + .../pinocchio/webapp/scripts/mint-usdc.ts | 56 + .../pinocchio/webapp/scripts/package.json | 18 + games/world-cup/pinocchio/webapp/src/App.css | 42 + games/world-cup/pinocchio/webapp/src/App.tsx | 40 + .../pinocchio/webapp/src/assets/react.svg | 1 + .../webapp/src/assets/solana-logo.svg | 13 + .../components/account/account-data-access.ts | 140 + .../src/components/account/account-ui.tsx | 362 + .../webapp/src/components/app-alert.tsx | 21 + .../webapp/src/components/app-header.tsx | 279 + .../webapp/src/components/app-layout.tsx | 20 + .../webapp/src/components/app-modal.tsx | 39 + .../webapp/src/components/app-providers.tsx | 58 + .../src/components/bracket/action-bar.tsx | 66 + .../components/bracket/bracket-display.tsx | 236 + .../src/components/bracket/bracket-search.tsx | 51 + .../src/components/bracket/demo-oracle.ts | 65 + .../webapp/src/components/bracket/flag.tsx | 32 + .../src/components/bracket/matchup-card.tsx | 126 + .../webapp/src/components/bracket/rounds.ts | 71 + .../src/components/bracket/share-button.tsx | 43 + .../src/components/bracket/summary-rail.tsx | 181 + .../webapp/src/components/bracket/teams.ts | 78 + .../components/bracket/use-bracket-builder.ts | 96 + .../src/components/cluster/cluster-ui.tsx | 75 + .../cluster/use-cluster-version.tsx | 15 + .../webapp/src/components/home/hero.tsx | 103 + .../webapp/src/components/load-error.tsx | 29 + .../webapp/src/components/nav-items.ts | 11 + .../src/components/react-query-provider.tsx | 16 + .../src/components/solana/solana-provider.tsx | 180 + .../use-wallet-transaction-sign-and-send.tsx | 72 + .../time-travel/time-travel-button.tsx | 268 + .../webapp/src/components/toast-tx.tsx | 11 + .../src/components/token/add-token-dialog.tsx | 150 + .../src/components/token/token-picker.tsx | 57 + .../webapp/src/components/ui/alert.tsx | 51 + .../src/components/ui/blurred-overlay.tsx | 38 + .../webapp/src/components/ui/button.tsx | 22 + .../webapp/src/components/ui/card.tsx | 59 + .../webapp/src/components/ui/dialog.tsx | 122 + .../src/components/ui/dropdown-menu.tsx | 217 + .../webapp/src/components/ui/label.tsx | 19 + .../webapp/src/components/ui/sonner.tsx | 24 + .../src/components/use-transaction-toast.tsx | 18 + .../pinocchio/webapp/src/config/networks.ts | 46 + .../pinocchio/webapp/src/hooks/use-bracket.ts | 27 + .../webapp/src/hooks/use-cluster-config.ts | 9 + .../webapp/src/hooks/use-create-token.ts | 126 + .../webapp/src/hooks/use-leaderboard.ts | 44 + .../pinocchio/webapp/src/hooks/use-rpc.ts | 9 + .../webapp/src/hooks/use-selected-token.tsx | 50 + .../webapp/src/hooks/use-time-travel.ts | 63 + .../webapp/src/hooks/use-token-config.ts | 64 + .../webapp/src/hooks/use-tournament.ts | 47 + .../world-cup/pinocchio/webapp/src/index.css | 321 + .../pinocchio/webapp/src/lib/api-client.ts | 162 + .../webapp/src/lib/bpf-loader-browser.ts | 204 + .../pinocchio/webapp/src/lib/cluster.ts | 8 + .../pinocchio/webapp/src/lib/custom-rpc.ts | 55 + .../pinocchio/webapp/src/lib/custom-tokens.ts | 24 + .../pinocchio/webapp/src/lib/error-utils.ts | 20 + .../pinocchio/webapp/src/lib/format.ts | 14 + .../webapp/src/lib/parse-program-error.ts | 64 + .../webapp/src/lib/program-keypair.ts | 24 + .../pinocchio/webapp/src/lib/share.ts | 65 + .../pinocchio/webapp/src/lib/token-display.ts | 57 + .../pinocchio/webapp/src/lib/token-program.ts | 15 + .../pinocchio/webapp/src/lib/tx-packer.ts | 89 + .../pinocchio/webapp/src/lib/types.ts | 37 + .../pinocchio/webapp/src/lib/utils.ts | 122 + .../pinocchio/webapp/src/lib/validators.ts | 5 + games/world-cup/pinocchio/webapp/src/main.tsx | 24 + .../webapp/src/routes/bracket-view.tsx | 59 + .../pinocchio/webapp/src/routes/bracket.tsx | 300 + .../pinocchio/webapp/src/routes/home.tsx | 64 + .../webapp/src/routes/leaderboard.tsx | 183 + .../pinocchio/webapp/tailwind.config.js | 5 + .../webapp/test/deploy-builder.test.ts | 15 + .../webapp/test/token-display.test.ts | 51 + .../pinocchio/webapp/tsconfig.app.json | 36 + .../world-cup/pinocchio/webapp/tsconfig.json | 4 + .../pinocchio/webapp/tsconfig.node.json | 26 + games/world-cup/pinocchio/webapp/vercel.json | 8 + .../world-cup/pinocchio/webapp/vite.config.ts | 52 + 212 files changed, 28598 insertions(+), 2 deletions(-) create mode 100644 .github/.justignore create mode 100644 .github/workflows/just.yml create mode 100644 games/world-cup/README.md create mode 100644 games/world-cup/pinocchio/.env.example create mode 100644 games/world-cup/pinocchio/.github/actions/setup/action.yml create mode 100644 games/world-cup/pinocchio/.github/workflows/build.yml create mode 100644 games/world-cup/pinocchio/.github/workflows/format.yml create mode 100644 games/world-cup/pinocchio/.github/workflows/idl-check.yml create mode 100644 games/world-cup/pinocchio/.github/workflows/lint.yml create mode 100644 games/world-cup/pinocchio/.github/workflows/test.yml create mode 100644 games/world-cup/pinocchio/.gitignore create mode 100644 games/world-cup/pinocchio/.nvmrc create mode 100644 games/world-cup/pinocchio/.prettierignore create mode 100644 games/world-cup/pinocchio/.prettierrc.json create mode 100644 games/world-cup/pinocchio/CLAUDE.md create mode 100644 games/world-cup/pinocchio/Cargo.toml create mode 100644 games/world-cup/pinocchio/LICENSE create mode 100644 games/world-cup/pinocchio/README.md create mode 100644 games/world-cup/pinocchio/SECURITY.md create mode 100644 games/world-cup/pinocchio/clients/rust/Cargo.toml create mode 100644 games/world-cup/pinocchio/clients/rust/src/lib.rs create mode 100644 games/world-cup/pinocchio/clients/typescript/package.json create mode 100644 games/world-cup/pinocchio/clients/typescript/src/bracket-display.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/src/bracket.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/src/constants.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/src/fifa-2026.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/src/index.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/src/leaderboard.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/src/scoring.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/src/teams.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/test/bracket-display.test.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/test/bracket.test.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/test/fifa-2026.test.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/test/leaderboard.test.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/test/scoring.test.ts create mode 100644 games/world-cup/pinocchio/clients/typescript/tsconfig.json create mode 100644 games/world-cup/pinocchio/clients/typescript/tsup.config.ts create mode 100644 games/world-cup/pinocchio/eslint.config.mjs create mode 100644 games/world-cup/pinocchio/idl/world_cup.json create mode 100644 games/world-cup/pinocchio/justfile create mode 100644 games/world-cup/pinocchio/package.json create mode 100644 games/world-cup/pinocchio/pnpm-lock.yaml create mode 100644 games/world-cup/pinocchio/pnpm-workspace.yaml create mode 100644 games/world-cup/pinocchio/program/Cargo.toml create mode 100644 games/world-cup/pinocchio/program/build.rs create mode 100644 games/world-cup/pinocchio/program/src/entrypoint.rs create mode 100644 games/world-cup/pinocchio/program/src/errors.rs create mode 100644 games/world-cup/pinocchio/program/src/event_engine.rs create mode 100644 games/world-cup/pinocchio/program/src/events/bracket_closed.rs create mode 100644 games/world-cup/pinocchio/program/src/events/bracket_submitted.rs create mode 100644 games/world-cup/pinocchio/program/src/events/config_initialized.rs create mode 100644 games/world-cup/pinocchio/program/src/events/goals_posted.rs create mode 100644 games/world-cup/pinocchio/program/src/events/market_finalized.rs create mode 100644 games/world-cup/pinocchio/program/src/events/mod.rs create mode 100644 games/world-cup/pinocchio/program/src/events/pot_claimed.rs create mode 100644 games/world-cup/pinocchio/program/src/events/result_posted.rs create mode 100644 games/world-cup/pinocchio/program/src/events/score_refreshed.rs create mode 100644 games/world-cup/pinocchio/program/src/events/tournament_locked.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/claim.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/close_bracket.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/emit_event.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/finalize.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/helpers/mod.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/init_config.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/lock.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/mod.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/post_goals.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/post_result.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/refresh_score.rs create mode 100644 games/world-cup/pinocchio/program/src/instructions/submit_bracket.rs create mode 100644 games/world-cup/pinocchio/program/src/lib.rs create mode 100644 games/world-cup/pinocchio/program/src/state/bracket.rs create mode 100644 games/world-cup/pinocchio/program/src/state/common.rs create mode 100644 games/world-cup/pinocchio/program/src/state/config.rs create mode 100644 games/world-cup/pinocchio/program/src/state/mod.rs create mode 100644 games/world-cup/pinocchio/program/src/state/oracle.rs create mode 100644 games/world-cup/pinocchio/program/src/state/vault.rs create mode 100644 games/world-cup/pinocchio/program/src/tests.rs create mode 100644 games/world-cup/pinocchio/program/src/tournament.rs create mode 100644 games/world-cup/pinocchio/rust-toolchain.toml create mode 100644 games/world-cup/pinocchio/rustfmt.toml create mode 100644 games/world-cup/pinocchio/scripts/create-bracket.ts create mode 100644 games/world-cup/pinocchio/scripts/generate-clients.ts create mode 100644 games/world-cup/pinocchio/scripts/generate-ts-client.ts create mode 100644 games/world-cup/pinocchio/scripts/init.ts create mode 100644 games/world-cup/pinocchio/tests/integration-tests/Cargo.toml create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/lib.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/test_account_meta.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/test_claim.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/test_close_bracket.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/test_finalize.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/test_init_config.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/test_lock.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/test_post_goals.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/test_post_result.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/test_refresh_score.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/test_submit_bracket.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/utils/asserts.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/utils/constants.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/utils/cu_tracker.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/utils/idl.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/utils/mod.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/utils/pda.rs create mode 100644 games/world-cup/pinocchio/tests/integration-tests/src/utils/test_helpers.rs create mode 100644 games/world-cup/pinocchio/tsconfig.json create mode 100644 games/world-cup/pinocchio/webapp/.env.example create mode 100644 games/world-cup/pinocchio/webapp/.gitignore create mode 100644 games/world-cup/pinocchio/webapp/README.md create mode 100644 games/world-cup/pinocchio/webapp/api/lib/bpf-loader.ts create mode 100644 games/world-cup/pinocchio/webapp/api/lib/deploy-builder.ts create mode 100644 games/world-cup/pinocchio/webapp/api/lib/program-status.ts create mode 100644 games/world-cup/pinocchio/webapp/api/og.tsx create mode 100644 games/world-cup/pinocchio/webapp/api/package.json create mode 100644 games/world-cup/pinocchio/webapp/api/server.ts create mode 100644 games/world-cup/pinocchio/webapp/index.html create mode 100644 games/world-cup/pinocchio/webapp/middleware.ts create mode 100644 games/world-cup/pinocchio/webapp/package.json create mode 100644 games/world-cup/pinocchio/webapp/postcss.config.js create mode 100644 games/world-cup/pinocchio/webapp/public/fonts/InterVariable.woff2 create mode 100644 games/world-cup/pinocchio/webapp/public/solana-logo.svg create mode 100644 games/world-cup/pinocchio/webapp/public/vite.svg create mode 100644 games/world-cup/pinocchio/webapp/scripts/config-manager.ts create mode 100644 games/world-cup/pinocchio/webapp/scripts/helpers.ts create mode 100644 games/world-cup/pinocchio/webapp/scripts/init-test-environment.ts create mode 100644 games/world-cup/pinocchio/webapp/scripts/mint-usdc.ts create mode 100644 games/world-cup/pinocchio/webapp/scripts/package.json create mode 100644 games/world-cup/pinocchio/webapp/src/App.css create mode 100644 games/world-cup/pinocchio/webapp/src/App.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/assets/react.svg create mode 100644 games/world-cup/pinocchio/webapp/src/assets/solana-logo.svg create mode 100644 games/world-cup/pinocchio/webapp/src/components/account/account-data-access.ts create mode 100644 games/world-cup/pinocchio/webapp/src/components/account/account-ui.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/app-alert.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/app-header.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/app-layout.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/app-modal.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/app-providers.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/action-bar.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/bracket-display.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/bracket-search.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/demo-oracle.ts create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/flag.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/matchup-card.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/rounds.ts create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/share-button.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/summary-rail.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/teams.ts create mode 100644 games/world-cup/pinocchio/webapp/src/components/bracket/use-bracket-builder.ts create mode 100644 games/world-cup/pinocchio/webapp/src/components/cluster/cluster-ui.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/cluster/use-cluster-version.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/home/hero.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/load-error.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/nav-items.ts create mode 100644 games/world-cup/pinocchio/webapp/src/components/react-query-provider.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/solana/solana-provider.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/solana/use-wallet-transaction-sign-and-send.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/time-travel/time-travel-button.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/toast-tx.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/token/add-token-dialog.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/token/token-picker.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/ui/alert.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/ui/blurred-overlay.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/ui/button.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/ui/card.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/ui/dialog.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/ui/dropdown-menu.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/ui/label.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/ui/sonner.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/components/use-transaction-toast.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/config/networks.ts create mode 100644 games/world-cup/pinocchio/webapp/src/hooks/use-bracket.ts create mode 100644 games/world-cup/pinocchio/webapp/src/hooks/use-cluster-config.ts create mode 100644 games/world-cup/pinocchio/webapp/src/hooks/use-create-token.ts create mode 100644 games/world-cup/pinocchio/webapp/src/hooks/use-leaderboard.ts create mode 100644 games/world-cup/pinocchio/webapp/src/hooks/use-rpc.ts create mode 100644 games/world-cup/pinocchio/webapp/src/hooks/use-selected-token.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/hooks/use-time-travel.ts create mode 100644 games/world-cup/pinocchio/webapp/src/hooks/use-token-config.ts create mode 100644 games/world-cup/pinocchio/webapp/src/hooks/use-tournament.ts create mode 100644 games/world-cup/pinocchio/webapp/src/index.css create mode 100644 games/world-cup/pinocchio/webapp/src/lib/api-client.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/bpf-loader-browser.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/cluster.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/custom-rpc.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/custom-tokens.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/error-utils.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/format.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/parse-program-error.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/program-keypair.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/share.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/token-display.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/token-program.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/tx-packer.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/types.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/utils.ts create mode 100644 games/world-cup/pinocchio/webapp/src/lib/validators.ts create mode 100644 games/world-cup/pinocchio/webapp/src/main.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/routes/bracket-view.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/routes/bracket.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/routes/home.tsx create mode 100644 games/world-cup/pinocchio/webapp/src/routes/leaderboard.tsx create mode 100644 games/world-cup/pinocchio/webapp/tailwind.config.js create mode 100644 games/world-cup/pinocchio/webapp/test/deploy-builder.test.ts create mode 100644 games/world-cup/pinocchio/webapp/test/token-display.test.ts create mode 100644 games/world-cup/pinocchio/webapp/tsconfig.app.json create mode 100644 games/world-cup/pinocchio/webapp/tsconfig.json create mode 100644 games/world-cup/pinocchio/webapp/tsconfig.node.json create mode 100644 games/world-cup/pinocchio/webapp/vercel.json create mode 100644 games/world-cup/pinocchio/webapp/vite.config.ts diff --git a/.github/.ghaignore b/.github/.ghaignore index 784194c41..6452220d5 100644 --- a/.github/.ghaignore +++ b/.github/.ghaignore @@ -67,4 +67,8 @@ tokens/escrow/steel tokens/pda-mint-authority/steel tokens/spl-token-minter/steel tokens/token-swap/steel -tokens/transfer-tokens/steel \ No newline at end of file +tokens/transfer-tokens/steel + +# justfile-driven example: built and tested by .github/workflows/just.yml, +# not the legacy pinocchio CI (it has no build-and-test script) +games/world-cup/pinocchio \ No newline at end of file diff --git a/.github/.justignore b/.github/.justignore new file mode 100644 index 000000000..dff950460 --- /dev/null +++ b/.github/.justignore @@ -0,0 +1,2 @@ +# Justfile-driven, self-contained example workspaces to skip in just.yml. +# One directory path per line; comments and blank lines are ignored. diff --git a/.github/workflows/just.yml b/.github/workflows/just.yml new file mode 100644 index 000000000..71fd419ff --- /dev/null +++ b/.github/workflows/just.yml @@ -0,0 +1,108 @@ +name: Just + +# Self-contained examples that drive their own build and test through a `justfile` +# (standalone Cargo/pnpm workspace, pinned toolchain, Codama clients, LiteSVM tests). +# Discovery key: any directory containing a `justfile`. Each must expose `setup`, +# `build`, and `test` recipes. Exclusions live in `.github/.justignore`. + +on: + schedule: + - cron: "0 0 * * *" + push: + branches: + - main + pull_request: + types: [opened, synchronize, reopened] + branches: + - main + +env: + CARGO_NET_RETRY: "10" + CARGO_REGISTRIES_CRATES_IO_PROTOCOL: sparse + # See https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/ + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true + +jobs: + discover: + runs-on: ubuntu-latest + permissions: + pull-requests: read + outputs: + projects: ${{ steps.find.outputs.projects }} + any: ${{ steps.find.outputs.any }} + steps: + - uses: actions/checkout@v7 + with: + fetch-depth: 0 + - name: Discover justfile examples + id: find + run: | + # Strip comments/blanks from the ignore list into a regex (matches nothing if absent). + ignore_pattern=$(grep -v '^#' .github/.justignore 2>/dev/null | grep -v '^$' | tr '\n' '|' | sed 's/|$//') + [ -z "$ignore_pattern" ] && ignore_pattern='^$' + + all=$(find . -name justfile -not -path '*/node_modules/*' -printf '%h\n' \ + | sed 's#^\./##' | sort -u | grep -vE "$ignore_pattern" || true) + + # On push/schedule run everything; on PR keep only examples with changed files. + if [[ "${{ github.event_name }}" == "pull_request" ]]; then + changed=$(git diff --name-only "${{ github.event.pull_request.base.sha }}" HEAD) + # A workflow change re-runs every example. + if echo "$changed" | grep -q '^.github/workflows/just.yml$'; then + projects="$all" + else + projects="" + for p in $all; do + if echo "$changed" | grep -q "^$p/"; then + projects+="$p"$'\n' + fi + done + projects=$(echo "$projects" | grep -v '^$' || true) + fi + else + projects="$all" + fi + + if [[ -n "$projects" ]]; then + echo "Examples to build and test:" + echo "$projects" + echo "any=true" >> "$GITHUB_OUTPUT" + echo "projects=$(echo "$projects" | jq -R -s -c 'split("\n") | map(select(length > 0))')" >> "$GITHUB_OUTPUT" + else + echo "No examples to build and test." + echo "any=false" >> "$GITHUB_OUTPUT" + echo "projects=[]" >> "$GITHUB_OUTPUT" + fi + + build-and-test: + needs: discover + if: needs.discover.outputs.any == 'true' + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + project: ${{ fromJson(needs.discover.outputs.projects) }} + name: ${{ matrix.project }} + steps: + - uses: actions/checkout@v7 + - uses: pnpm/action-setup@v4 + - name: Use Node.js + uses: actions/setup-node@v5 + with: + node-version-file: ${{ matrix.project }}/.nvmrc + check-latest: true + - name: Install just + uses: extractions/setup-just@v3 + - name: Setup Solana + uses: heyAyushh/setup-solana@v5.9 + with: + solana-cli-version: stable + - name: Build and test + working-directory: ${{ matrix.project }} + run: | + solana -V + rustc -V + just setup + just check-generated + just build + just test diff --git a/README.md b/README.md index 2b1dc0458..0f7048fa8 100644 --- a/README.md +++ b/README.md @@ -336,5 +336,11 @@ Use a data source for offchain data (called an Oracle) to perform activities onc Use Shank and Solita to generate IDLs and TypeScript clients for native Solana programs, the same way Anchor does for Anchor programs. [native](./tools/shank-and-solita/native) +## Games +### World Cup bracket prediction + +A bracket-prediction game: entrants pay a fee to submit a 32-game bracket, an oracle posts results, scores are tallied on-chain, and the unique winner sweeps the pot. A full Pinocchio + Codama project with a TypeScript client and a webapp. + +[pinocchio](./games/world-cup/pinocchio) --- diff --git a/biome.jsonc b/biome.jsonc index a42a61129..3dd19fdad 100644 --- a/biome.jsonc +++ b/biome.jsonc @@ -1,7 +1,7 @@ { "$schema": "https://biomejs.dev/schemas/2.4.12/schema.json", "files": { - "includes": ["**", "!**/Assets"] + "includes": ["**", "!**/Assets", "!games/world-cup/**"] }, "formatter": { // Matches more existing code, diff --git a/games/world-cup/README.md b/games/world-cup/README.md new file mode 100644 index 000000000..bfb9b74fd --- /dev/null +++ b/games/world-cup/README.md @@ -0,0 +1,20 @@ +# World Cup bracket prediction + +A bracket-prediction game on Solana. Entrants pay a fixed fee to submit a +consistency-checked 32-game bracket; an admin oracle records results; a +permissionless `refresh_score` folds each bracket into a provable on-chain +tally; the unique winner sweeps the pot. The ranking key is total — score, then +goal-closeness, then earliest submission — so exactly one winner always exists. + +Lifecycle: `init_config` → `submit_bracket` → `lock` → `post_result` / +`post_goals` → `refresh_score` → `finalize` → `claim`. + +This is a faithful, self-contained port of the upstream project: a Pinocchio +on-chain program with Codama-generated TypeScript and Rust clients, LiteSVM +integration tests, and a Vite + React webapp shell. It pins its own toolchain +and dependencies (`pinocchio 0.11.1`, `codama`, `pinocchio-token-2022`) in a +nested workspace, so it builds and tests via its own `justfile` rather than the +repo's shared CI. See the [pinocchio](./pinocchio) directory for the source, +build commands, and tests. + +[pinocchio](./pinocchio) diff --git a/games/world-cup/pinocchio/.env.example b/games/world-cup/pinocchio/.env.example new file mode 100644 index 000000000..9111463c0 --- /dev/null +++ b/games/world-cup/pinocchio/.env.example @@ -0,0 +1,3 @@ +# ADMNbyyTcGfd4CKkfryMuSX1hWy6tKGuyyuEwSSDwxh4 +ADMIN= +RPC_URL="https://api.devnet.solana.com" diff --git a/games/world-cup/pinocchio/.github/actions/setup/action.yml b/games/world-cup/pinocchio/.github/actions/setup/action.yml new file mode 100644 index 000000000..c78981944 --- /dev/null +++ b/games/world-cup/pinocchio/.github/actions/setup/action.yml @@ -0,0 +1,147 @@ +name: 'Setup CI Environment' +description: 'Shared setup for Rust, Solana, and pnpm' + +inputs: + install-rust: + description: 'Install Rust toolchain' + required: false + default: 'true' + rust-toolchain: + description: 'Rust toolchain to install' + required: false + default: '1.92' + rust-components: + description: 'Rust components to install' + required: false + default: 'rustfmt, clippy' + enable-rust-cache: + description: 'Enable Rust caching (restore/save)' + required: false + default: 'true' + save-rust-cache: + description: 'Save the Rust cache after this job (only enable for the build job)' + required: false + default: 'false' + rust-cache-key: + description: 'Key for the Rust cache' + required: false + default: 'build' + install-solana: + description: 'Install Solana CLI' + required: false + default: 'true' + solana-version: + description: "Solana CLI version to install (e.g., 'v4.0.0')" + required: false + default: 'v4.0.0' + install-just: + description: 'Install just' + required: false + default: 'true' + install-pnpm: + description: 'Install pnpm and Node.js' + required: false + default: 'true' + install-pnpm-dependencies: + description: 'Install pnpm dependencies' + required: false + default: 'true' + +runs: + using: 'composite' + steps: + - name: Setup Rust + if: inputs.install-rust == 'true' + uses: dtolnay/rust-toolchain@master + with: + toolchain: ${{ inputs.rust-toolchain }} + components: ${{ inputs.rust-components }} + + - name: Rust cache + if: inputs.install-rust == 'true' && inputs.enable-rust-cache == 'true' + uses: Swatinem/rust-cache@v2 + with: + workspaces: '. -> target' + shared-key: ${{ inputs.rust-cache-key }} + save-if: ${{ inputs.save-rust-cache }} + cache-on-failure: true + + - name: Resolve Solana release + if: inputs.install-solana == 'true' + id: solana-release + shell: bash + run: | + version='${{ inputs.solana-version }}' + if [[ "$version" =~ ^[0-9] ]]; then + version="v$version" + fi + echo "version=$version" >> "$GITHUB_OUTPUT" + + - name: Cache Solana CLI + if: inputs.install-solana == 'true' + id: solana-cache + uses: actions/cache@v4 + with: + path: | + ~/.local/share/solana + ~/.cache/solana + key: ${{ runner.os }}-solana-${{ inputs.solana-version }} + + - name: Install Solana CLI + if: inputs.install-solana == 'true' && steps.solana-cache.outputs.cache-hit != 'true' + shell: bash + run: | + curl -sSfL "https://release.anza.xyz/${{ steps.solana-release.outputs.version }}/install" | sh + + - name: Add Solana to PATH + if: inputs.install-solana == 'true' + shell: bash + run: echo "$HOME/.local/share/solana/install/active_release/bin" >> $GITHUB_PATH + + - name: Create Solana keypair + if: inputs.install-solana == 'true' + shell: bash + run: | + mkdir -p ~/.config/solana + [ -f ~/.config/solana/id.json ] || solana-keygen new --no-bip39-passphrase -o ~/.config/solana/id.json + + - name: Add local bin to PATH + shell: bash + run: echo "$HOME/.local/bin" >> $GITHUB_PATH + + - name: Install just + if: inputs.install-just == 'true' + uses: extractions/setup-just@v4 + with: + just-version: '1.50.0' + + - name: Install pnpm + if: inputs.install-pnpm == 'true' + uses: pnpm/action-setup@v4 + + - name: Setup Node.js + if: inputs.install-pnpm == 'true' + uses: actions/setup-node@v6 + with: + node-version-file: '.nvmrc' + + - name: Get pnpm store directory + if: inputs.install-pnpm == 'true' + id: pnpm-store + shell: bash + run: echo "path=$(pnpm store path)" >> $GITHUB_OUTPUT + + - name: Cache pnpm store + if: inputs.install-pnpm == 'true' + id: pnpm-cache + uses: actions/cache@v4 + with: + path: ${{ steps.pnpm-store.outputs.path }} + key: ${{ runner.os }}-pnpm-${{ hashFiles('pnpm-lock.yaml') }} + restore-keys: | + ${{ runner.os }}-pnpm- + + - name: Install pnpm dependencies + if: inputs.install-pnpm == 'true' && inputs.install-pnpm-dependencies == 'true' + shell: bash + run: pnpm install --frozen-lockfile diff --git a/games/world-cup/pinocchio/.github/workflows/build.yml b/games/world-cup/pinocchio/.github/workflows/build.yml new file mode 100644 index 000000000..f6c949be9 --- /dev/null +++ b/games/world-cup/pinocchio/.github/workflows/build.yml @@ -0,0 +1,57 @@ +name: Build + +on: + pull_request: + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +env: + SOLANA_VERSION: '4.0.0' + +jobs: + build: + runs-on: ubuntu-latest + timeout-minutes: 45 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1 + + - uses: ./.github/actions/setup + with: + rust-cache-key: 'build' + save-rust-cache: 'true' + solana-version: ${{ env.SOLANA_VERSION }} + + - name: Build program and client + run: just build + + webapp-build: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1 + + - uses: ./.github/actions/setup + with: + install-rust: 'false' + install-solana: 'false' + install-just: 'false' + enable-rust-cache: 'false' + + - name: Generate and build TypeScript client + run: | + pnpm run generate-clients + pnpm --filter @solana/world-cup build + + - name: Build webapp + run: pnpm --filter webapp build diff --git a/games/world-cup/pinocchio/.github/workflows/format.yml b/games/world-cup/pinocchio/.github/workflows/format.yml new file mode 100644 index 000000000..47acbe955 --- /dev/null +++ b/games/world-cup/pinocchio/.github/workflows/format.yml @@ -0,0 +1,30 @@ +name: Format + +on: + pull_request: + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + format: + runs-on: ubuntu-latest + timeout-minutes: 15 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1 + + - uses: ./.github/actions/setup + with: + install-solana: 'false' + rust-cache-key: 'format' + + - name: Check formatting + run: just fmt-check diff --git a/games/world-cup/pinocchio/.github/workflows/idl-check.yml b/games/world-cup/pinocchio/.github/workflows/idl-check.yml new file mode 100644 index 000000000..9471334a4 --- /dev/null +++ b/games/world-cup/pinocchio/.github/workflows/idl-check.yml @@ -0,0 +1,20 @@ +name: IDL Check + +on: + push: + branches: [main] + pull_request: + +jobs: + check-generated: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v6 + + - uses: ./.github/actions/setup + with: + install-solana: 'false' + rust-cache-key: 'idl-check' + + - name: Check generated files + run: just check-generated diff --git a/games/world-cup/pinocchio/.github/workflows/lint.yml b/games/world-cup/pinocchio/.github/workflows/lint.yml new file mode 100644 index 000000000..06babbb29 --- /dev/null +++ b/games/world-cup/pinocchio/.github/workflows/lint.yml @@ -0,0 +1,30 @@ +name: Lint + +on: + pull_request: + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +jobs: + lint: + runs-on: ubuntu-latest + timeout-minutes: 20 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1 + + - uses: ./.github/actions/setup + with: + install-solana: 'false' + rust-cache-key: 'lint' + + - name: Check linting + run: just lint-check diff --git a/games/world-cup/pinocchio/.github/workflows/test.yml b/games/world-cup/pinocchio/.github/workflows/test.yml new file mode 100644 index 000000000..c1765d768 --- /dev/null +++ b/games/world-cup/pinocchio/.github/workflows/test.yml @@ -0,0 +1,50 @@ +name: Test + +on: + pull_request: + push: + branches: [main] + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + +permissions: + contents: read + +env: + SOLANA_VERSION: '4.0.0' + +jobs: + unit-test: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1 + + - uses: ./.github/actions/setup + with: + install-solana: 'false' + rust-cache-key: 'unit-test' + save-rust-cache: 'true' + + - name: Run unit tests + run: just unit-test + + integration-test: + runs-on: ubuntu-latest + timeout-minutes: 30 + steps: + - uses: actions/checkout@v6 + with: + fetch-depth: 1 + + - uses: ./.github/actions/setup + with: + rust-cache-key: 'integration-test' + solana-version: ${{ env.SOLANA_VERSION }} + + - name: Run integration tests + run: just integration-test diff --git a/games/world-cup/pinocchio/.gitignore b/games/world-cup/pinocchio/.gitignore new file mode 100644 index 000000000..3ba92b811 --- /dev/null +++ b/games/world-cup/pinocchio/.gitignore @@ -0,0 +1,44 @@ +**/target +.idea +**/node_modules +dist +.next +bun.lockb + +**/generated/ + +# Solana test validator ledger data +test-ledger/ +**/test-ledger/ +.validator-ledger + +# Log files +*.log +**/cu_report.md + +# Local config (contains generated mint addresses) +config.json + +# Environment secrets +.env +.env.local +**/.env.local + +keys/ + +# Webapp output +webapp/playwright-report/ +webapp/test-results/ +webapp/tsconfig.tsbuildinfo + +# TypeDoc generated API docs +clients/typescript/docs/ + +# Vercel project config +.vercel + +.claude/ + +# Editor / tool config +.emdash.json +.vscode/ diff --git a/games/world-cup/pinocchio/.nvmrc b/games/world-cup/pinocchio/.nvmrc new file mode 100644 index 000000000..3fe3b1570 --- /dev/null +++ b/games/world-cup/pinocchio/.nvmrc @@ -0,0 +1 @@ +24.13.0 diff --git a/games/world-cup/pinocchio/.prettierignore b/games/world-cup/pinocchio/.prettierignore new file mode 100644 index 000000000..46a60b6ca --- /dev/null +++ b/games/world-cup/pinocchio/.prettierignore @@ -0,0 +1,26 @@ +# IDL files +idl/ + +# Generated files +clients/typescript/src/generated/ + +# Build outputs +dist/ +build/ +target/ +**/.next/ +**/playwright-report/ +**/test-results/ + +# Dependencies +node_modules/ +package.json +pnpm-lock.yaml + +# TypeDoc generated API docs +clients/typescript/docs/ + +# Editor / tool config +.emdash.json +.vscode/ +.remember/ diff --git a/games/world-cup/pinocchio/.prettierrc.json b/games/world-cup/pinocchio/.prettierrc.json new file mode 100644 index 000000000..070fcfbd0 --- /dev/null +++ b/games/world-cup/pinocchio/.prettierrc.json @@ -0,0 +1 @@ +"@solana/prettier-config-solana" diff --git a/games/world-cup/pinocchio/CLAUDE.md b/games/world-cup/pinocchio/CLAUDE.md new file mode 100644 index 000000000..ae6e5995f --- /dev/null +++ b/games/world-cup/pinocchio/CLAUDE.md @@ -0,0 +1,113 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## What this is + +A World Cup bracket-prediction game on Solana. Entrants pay a fixed fee to submit +a consistency-checked 32-game bracket; an admin oracle records results; a +permissionless, idempotent `refresh_score` folds each bracket into a provable +global tally; the unique winner sweeps the pot. The ranking key is total — score, +then goal-closeness, then earliest submission — so exactly one winner always exists. +The on-chain program, the generated client, and the webapp shell are wired together +end-to-end. + +## Required Versions + +- **Rust**: See `rust-toolchain.toml` +- **Node.js**: See `.nvmrc` +- **pnpm**: See `package.json` `packageManager` field + +## Build Commands + +```bash +just build # program .so → IDL → TS client → dist +just generate-idl # Generate IDL via Codama (cargo build with build.rs) +just generate-clients # Generate TypeScript client from IDL +just build-program # Build .so binary only (cargo build-sbf) +just build-client # Build TypeScript client (tsup) +just test # unit + integration tests +just unit-test # Rust host unit tests +just integration-test # LiteSVM integration tests (builds the .so first) +just fmt # cargo fmt + prettier +just check # fmt-check + lint-check +just webapp-dev # Start the webapp dev server +``` + +## Architecture + +Solana program using **Pinocchio** (lightweight `no_std` framework) with **Codama** +for IDL-driven client generation. + +### Client generation pipeline + +``` +Rust code with #[codama(...)] attributes + ↓ +program/build.rs → idl/world_cup.json + ↓ +scripts/generate-clients.ts + ↓ +clients/typescript/src/generated/ (gitignored; re-exported from src/index.ts) +``` + +### Program + +- `program/src/lib.rs` — declares the program ID, wires modules +- `program/src/tournament.rs` — pure logic: bracket tree topology, consistency rules, weighted scoring (host unit-tested) +- `program/src/instructions/` — `init_config`, `submit_bracket`, `lock`, `post_result`, `post_goals`, `refresh_score`, `finalize`, `claim`, `close_bracket`, `emit_event` (self-CPI target) + `helpers/` (account checks, PDA creation) +- `program/src/state/` — `Config`, `Oracle`, `Bracket` PDA structs + `Vault` marker + `common.rs` (discriminator, tournament state, PDA derivation) +- `program/src/event_engine.rs` — Anchor-compatible self-CPI event emission +- `program/src/events/` — one event struct per state-changing instruction +- `program/src/errors.rs` — error codes (100s generic / 200s lifecycle / 300s bracket / 400s oracle / 500s finalize+claim / 600s event) +- `program/src/tests.rs` — host unit tests for pure logic + +### Accounts + +Global singletons unless noted: + +- **Config** — PDA `["config"]`. Admin, lifecycle `state`, `lock_ts`, entry fee, and the provable global tally (`best_score`/`best_closeness`/`best_index`, `entrant_count`, `refreshed_count`, `tally_mask`, `winner`). +- **Oracle** — PDA `["oracle"]`. Per-game `results[32]` (immutable once set), `decided_mask`, and the Round-of-32 `total_goals_r32`. +- **Bracket** — PDA `["bracket", owner]`. One per wallet: `picks[32]`, tiebreaker guess, cached score, `tally_mask`, `entry_index` (submission order). +- **Vault** — program-owned, zero-data PDA `["vault"]` that escrows the pot. + +### Events + +Events use Anchor-compatible self-CPI: the program invokes its own `emit_event` +instruction, signed by the `event_authority` PDA (derived at compile time via +`const-crypto`). Indexers detect the inner instruction by the 8-byte event tag. + +### Program ID + +`wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA` (keypair in `keys/`, gitignored) + +## Workspace Structure + +- `program/` — Pinocchio program (workspace member `world-cup-program`) +- `tests/integration-tests/` — LiteSVM integration tests (`tests-world-cup`) +- `clients/typescript/` — Codama-generated TS client (`@solana/world-cup`) +- `webapp/` — Vite + React Solana app shell +- `scripts/` — Codama client generation +- `idl/` — generated IDL, committed (regenerated by `just generate-idl`); the client `generated/` dirs are gitignored and regenerated from it + +## Conventions + +- **Pinocchio, not Anchor**: use `pinocchio::AccountView`, `Address`, `ProgramResult`. +- **No `mod.rs` business logic**: module declarations and re-exports only. +- **No code comments**: prefer clear names and small functions. +- **PDA seeds co-located with state**: each state struct exposes its seed pattern; derivation helpers live in `state/common.rs`. +- **Codama attributes drive IDL**: keep `#[codama(...)]` macros in sync with Rust types — `just generate-idl && git diff` catches drift. + +## Lifecycle + +`init_config` (admin sets `lock_ts`; creates Config + Oracle + vault) → `submit_bracket` +(entrants pay the fixed fee; rent funds the Bracket, the remainder escrows to the vault) +→ `lock` (admin, once `Clock >= lock_ts`) → `post_result` ×32 then `post_goals` (admin +oracle; goals require all results posted) → `refresh_score` ×N (permissionless; folds +each bracket into the tally once the oracle is complete, idempotent via `tally_mask`) → +`finalize` (admin proves the unique winner against the total ranking key) → `claim` +(winner sweeps the vault, repeatable) and `close_bracket` (permissionless; rolls a +finalized bracket's rent into the pot). + +When extending: keep `#[codama(...)]` attributes in sync, emit an event per new +instruction, and add an integration test per instruction in `tests/integration-tests/`. diff --git a/games/world-cup/pinocchio/Cargo.toml b/games/world-cup/pinocchio/Cargo.toml new file mode 100644 index 000000000..74009c325 --- /dev/null +++ b/games/world-cup/pinocchio/Cargo.toml @@ -0,0 +1,43 @@ +[workspace] +members = [ + "clients/rust", + "program", + "tests/integration-tests", +] +resolver = "2" + +[workspace.package] +version = "0.1.0" +edition = "2021" +license = "MIT" +repository = "https://github.com/solana-foundation/world-cup" + +[workspace.metadata.cli] +solana = "3.1.10" + +[workspace.lints.rust] +unused_imports = "deny" +dead_code = "warn" +unused_variables = "warn" +deprecated = "warn" +unexpected_cfgs = { level = "warn", check-cfg = [ + 'cfg(target_os, values("solana"))', +] } + +[workspace.dependencies] +codama = "0.9.2" +const-crypto = "0.3" +pinocchio = { version = "0.11.1", features = ["cpi", "copy"] } +pinocchio-system = "0.6.1" +pinocchio-token = "0.6.0" +pinocchio-token-2022 = "0.3.1" +serde_json = "1" +solana-address = { version = "2", features = ["curve25519"] } +solana-security-txt = "1.1.3" +thiserror = { version = "2", default-features = false } + +[profile.release] +overflow-checks = true +opt-level = 3 +lto = true +codegen-units = 1 diff --git a/games/world-cup/pinocchio/LICENSE b/games/world-cup/pinocchio/LICENSE new file mode 100644 index 000000000..ea30a4597 --- /dev/null +++ b/games/world-cup/pinocchio/LICENSE @@ -0,0 +1,9 @@ +MIT License + +Copyright (c) 2026 Solana Foundation + +Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/games/world-cup/pinocchio/README.md b/games/world-cup/pinocchio/README.md new file mode 100644 index 000000000..580cbfe94 --- /dev/null +++ b/games/world-cup/pinocchio/README.md @@ -0,0 +1,48 @@ +# World Cup + +A World Cup bracket-prediction game on Solana — a Pinocchio on-chain program, +a Codama-generated TypeScript client, and a React webapp shell, wired together +end-to-end. + +Entrants pay a fixed fee to submit a consistency-checked 32-game bracket; an +admin oracle records results; a permissionless `refresh_score` folds each bracket +into a provable on-chain tally; the unique winner sweeps the pot. The ranking key +is total — score, then goal-closeness, then earliest submission — so exactly one +winner always exists. + +## Layout + +| Path | What | +| -------------------------- | --------------------------------------------------------------- | +| `program/` | Pinocchio program (`world-cup-program`) | +| `tests/integration-tests/` | LiteSVM integration tests (`tests-world-cup`) | +| `clients/typescript/` | Codama-generated TS client (`@solana/world-cup`) | +| `webapp/` | Vite + React Solana app shell (wallet, cluster, deploy, faucet) | +| `scripts/` | Codama client generation | +| `idl/` | Generated IDL | + +## Quick start + +```bash +# Prerequisites: rustup, the Solana CLI, pnpm, just +just setup # install JS dependencies +just build # program .so → IDL → TS client +just test # unit + LiteSVM integration tests +just webapp-dev # start the webapp +``` + +## The program + +Accounts: a singleton `Config` (admin, lifecycle, global tally), a singleton +`Oracle` (game results + Round-of-32 goal total), per-wallet `Bracket`s, and a +pot `["vault"]` PDA. + +Instructions: `init_config`, `submit_bracket`, `lock`, `post_result`, +`post_goals`, `refresh_score`, `finalize`, `claim`, `close_bracket`. + +Edit the Rust types, then `just generate-clients` regenerates the IDL and the +TypeScript client. + +## License + +MIT — see [LICENSE](LICENSE). diff --git a/games/world-cup/pinocchio/SECURITY.md b/games/world-cup/pinocchio/SECURITY.md new file mode 100644 index 000000000..72a0f0c7f --- /dev/null +++ b/games/world-cup/pinocchio/SECURITY.md @@ -0,0 +1,9 @@ +# Security Policy + +## Reporting security problems + +**DO NOT CREATE A GITHUB ISSUE** to report a security problem. + +Instead please use this [Report a Vulnerability](https://github.com/solana-foundation/world-cup/security/advisories/new) link. +Provide a helpful title and detailed description of the problem. +Expect a response as fast as possible in the advisory, typically within 72 hours. diff --git a/games/world-cup/pinocchio/clients/rust/Cargo.toml b/games/world-cup/pinocchio/clients/rust/Cargo.toml new file mode 100644 index 000000000..9beb88c33 --- /dev/null +++ b/games/world-cup/pinocchio/clients/rust/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "world-cup-client" +version = "0.1.0" +edition = "2021" +description = "Rust client for the World Cup Solana program" +license = { workspace = true } +repository = { workspace = true } + +[dependencies] +borsh = { version = "1.6", features = ["derive"] } +num-derive = "0.4" +num-traits = "0.2" +thiserror = "2.0" + +solana-account = { version = "~3.4", optional = true } +solana-account-info = "~3.1" +solana-address = { version = "2.6.0", features = ["borsh", "copy", "curve25519", "decode"] } +solana-cpi = "~3.1" +solana-instruction = { version = "~3.4", features = ["borsh"] } +solana-program-error = "~3.0" +solana-rpc-client = { version = "3.1.8", optional = true } + +serde = { version = "1.0", features = ["derive"], optional = true } +serde_with = { version = "3.20", optional = true } + +[features] +default = [] +serde = ["dep:serde", "dep:serde_with"] +fetch = ["dep:solana-account", "dep:solana-rpc-client"] diff --git a/games/world-cup/pinocchio/clients/rust/src/lib.rs b/games/world-cup/pinocchio/clients/rust/src/lib.rs new file mode 100644 index 000000000..5b07d6ddc --- /dev/null +++ b/games/world-cup/pinocchio/clients/rust/src/lib.rs @@ -0,0 +1,9 @@ +#![allow(warnings)] +#![allow(unused_imports)] + +pub mod generated; +pub use generated::*; + +pub use generated::accounts::*; +pub use generated::errors::*; +pub use generated::programs::*; diff --git a/games/world-cup/pinocchio/clients/typescript/package.json b/games/world-cup/pinocchio/clients/typescript/package.json new file mode 100644 index 000000000..5439f0152 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/package.json @@ -0,0 +1,38 @@ +{ + "name": "@solana/world-cup", + "version": "0.1.0", + "description": "TypeScript SDK and @solana/kit plugin for the World Cup bracket-prediction Solana program.", + "type": "module", + "license": "MIT", + "exports": { + ".": { + "types": "./dist/index.d.ts", + "import": "./dist/index.js", + "require": "./dist/index.cjs" + } + }, + "files": [ + "dist" + ], + "scripts": { + "build": "tsup", + "clean": "rm -rf dist", + "clean:generated": "rm -rf src/generated", + "test": "tsx --test test/*.test.ts" + }, + "dependencies": { + "@solana/kit-plugin-rpc": "^0.11.1", + "@solana/kit-plugin-signer": "^0.10.0", + "@solana/program-client-core": "^6.10.0" + }, + "peerDependencies": { + "@solana/kit": "^6.10.0" + }, + "devDependencies": { + "@solana/kit": "^6.10.0", + "@types/node": "^25.7.0", + "tsup": "^8.3.0", + "tsx": "^4.22.0", + "typescript": "^5.7.0" + } +} diff --git a/games/world-cup/pinocchio/clients/typescript/src/bracket-display.ts b/games/world-cup/pinocchio/clients/typescript/src/bracket-display.ts new file mode 100644 index 000000000..7190e29dc --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/src/bracket-display.ts @@ -0,0 +1,62 @@ +import { FINAL_GAME, GAME_COUNT, Round, roundOf } from './bracket.js'; +import { TEAM_NAMES, teamName } from './teams.js'; + +/** Human-readable label for each {@link Round}. */ +const ROUND_LABELS: Readonly> = { + [Round.R32]: 'Round of 32', + [Round.R16]: 'Round of 16', + [Round.Qf]: 'Quarterfinal', + [Round.Sf]: 'Semifinal', + [Round.Final]: 'Final', + [Round.ThirdPlace]: 'Third-place playoff', +}; + +/** One game's resolved outcome in a bracket, ready for display. */ +export type BracketGameRow = { + /** Game index `0..31`. */ + game: number; + /** The round this game belongs to. */ + round: Round; + /** Human-readable round label, e.g. `"Round of 16"`. */ + roundLabel: string; + /** Resolved display name of the picked winner. */ + winnerName: string; + /** Positional slot of the picked winner. */ + winnerSlot: number; +}; + +/** + * Expands a bracket's 32 picks into a per-game breakdown: round, round label, + * winning team slot, and resolved team name for every game index `0..31`. + * Pass `names` to override the default {@link TEAM_NAMES} placeholders. + */ +export function bracketRows(picks: ReadonlyArray, names: ReadonlyArray = TEAM_NAMES): BracketGameRow[] { + if (picks.length !== GAME_COUNT) { + throw new RangeError(`expected ${GAME_COUNT} picks, got ${picks.length}`); + } + return picks.map((winnerSlot, game) => { + const round = roundOf(game); + return { + game, + round, + roundLabel: ROUND_LABELS[round], + winnerName: teamName(winnerSlot, names), + winnerSlot, + }; + }); +} + +/** The picked champion: the Final (game 30) winner's slot and resolved name. */ +export type Champion = { name: string; slot: number }; + +/** + * The picked champion — the winner of the Final (game `30`). Pass `names` to + * override the default {@link TEAM_NAMES} placeholders. + */ +export function champion(picks: ReadonlyArray, names: ReadonlyArray = TEAM_NAMES): Champion { + if (picks.length !== GAME_COUNT) { + throw new RangeError(`expected ${GAME_COUNT} picks, got ${picks.length}`); + } + const slot = picks[FINAL_GAME]; + return { name: teamName(slot, names), slot }; +} diff --git a/games/world-cup/pinocchio/clients/typescript/src/bracket.ts b/games/world-cup/pinocchio/clients/typescript/src/bracket.ts new file mode 100644 index 000000000..dc4014579 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/src/bracket.ts @@ -0,0 +1,138 @@ +import { getSubmitBracketInstructionAsync, type SubmitBracketAsyncInput } from './generated/index.js'; +import type { SubmitBracketDataArgs } from './generated/types/submitBracketData.js'; + +/** Total games: 31 knockout games + the third-place playoff. */ +export const GAME_COUNT = 32; + +/** Number of competing teams (positional identities `0..32`). */ +export const TEAM_COUNT = 32; + +/** Index of the Final; its winner is the bracket's picked champion. */ +export const FINAL_GAME = 30; + +/** Index of the third-place playoff game. */ +export const THIRD_PLACE_GAME = 31; + +/** The round a game belongs to, derived from its index. */ +export enum Round { + R32 = 0, + R16 = 1, + Qf = 2, + Sf = 3, + Final = 4, + ThirdPlace = 5, +} + +/** The round a game index belongs to. */ +export function roundOf(game: number): Round { + if (game <= 15) return Round.R32; + if (game <= 23) return Round.R16; + if (game <= 27) return Round.Qf; + if (game <= 29) return Round.Sf; + if (game === 30) return Round.Final; + if (game === 31) return Round.ThirdPlace; + return Round.Final; +} + +/** The two feeder games for a non-leaf knockout game (`g` in `16..=30`). */ +export function children(g: number): [number, number] { + const base = (g - 16) * 2; + return [base, base + 1]; +} + +/** The two team slots contesting a Round-of-32 game (`g` in `0..=15`). */ +export function r32Slots(g: number): [number, number] { + return [2 * g, 2 * g + 1]; +} + +/** The two competitors of the third-place game: the losers of the two semifinals. */ +export function thirdPlaceSlots(slots: ReadonlyArray): [number, number] { + const loser28 = slots[28] === slots[24] ? slots[25] : slots[24]; + const loser29 = slots[29] === slots[26] ? slots[27] : slots[26]; + return [loser28, loser29]; +} + +/** Outcome of {@link validateBracket}. On failure, `game` is the offending index. */ +export type BracketValidation = { game: number; ok: false; reason: string } | { ok: true }; + +/** + * Verifies a full bracket is internally consistent, mirroring the on-chain + * `validate_bracket` check: every pick is a team the bracket itself advanced from + * one of the game's two feeders. Use before `submitBracket` to reject invalid + * brackets without a failed transaction. + */ +export function validateBracket(picks: ReadonlyArray): BracketValidation { + if (picks.length !== GAME_COUNT) { + return { game: -1, ok: false, reason: `expected ${GAME_COUNT} picks, got ${picks.length}` }; + } + for (let g = 0; g < GAME_COUNT; g++) { + const pick = picks[g]; + if (pick < 0 || pick >= TEAM_COUNT) { + return { game: g, ok: false, reason: `team ${pick} out of range 0..${TEAM_COUNT}` }; + } + if (g < 16) { + const [a, b] = r32Slots(g); + if (pick !== a && pick !== b) { + return { game: g, ok: false, reason: `team ${pick} does not play in game ${g} (slots ${a}, ${b})` }; + } + } else if (g <= 30) { + const [c0, c1] = children(g); + if (pick !== picks[c0] && pick !== picks[c1]) { + return { game: g, ok: false, reason: `team ${pick} was not advanced from feeders ${c0}, ${c1}` }; + } + } else { + const [l0, l1] = thirdPlaceSlots(picks); + if (pick !== l0 && pick !== l1) { + return { game: g, ok: false, reason: `team ${pick} is not a semifinal loser (${l0}, ${l1})` }; + } + } + } + return { ok: true }; +} + +/** True when `picks` would pass the on-chain consistency check. */ +export function isValidBracket(picks: ReadonlyArray): boolean { + return validateBracket(picks).ok; +} + +function pickOne(a: number, b: number): number { + return Math.random() < 0.5 ? a : b; +} + +/** + * Generates a random internally-consistent bracket. The result always passes + * {@link validateBracket}. Pass `tiebreakerGuess` to fix the Round-of-32 goal-total + * guess; otherwise a random value in `0..=200` is used. + */ +export function randomBracket(tiebreakerGuess?: number): SubmitBracketDataArgs { + const picks = new Array(GAME_COUNT); + for (let g = 0; g < 16; g++) { + const [a, b] = r32Slots(g); + picks[g] = pickOne(a, b); + } + for (let g = 16; g <= 30; g++) { + const [c0, c1] = children(g); + picks[g] = pickOne(picks[c0], picks[c1]); + } + const [l0, l1] = thirdPlaceSlots(picks); + picks[THIRD_PLACE_GAME] = pickOne(l0, l1); + return { + picks, + tiebreakerGuess: tiebreakerGuess ?? Math.floor(Math.random() * 201), + }; +} + +/** + * Builds a `submitBracket` instruction with a random valid bracket — for testing, + * demos, or a "feeling lucky" submit. Accepts the same accounts as the generated + * builder; the bracket data is generated for you. + */ +export function yolo( + input: Omit & { tiebreakerGuess?: number }, +): ReturnType { + const { tiebreakerGuess, ...accounts } = input; + return getSubmitBracketInstructionAsync({ + ...accounts, + submitBracketData: randomBracket(tiebreakerGuess), + }); +} diff --git a/games/world-cup/pinocchio/clients/typescript/src/constants.ts b/games/world-cup/pinocchio/clients/typescript/src/constants.ts new file mode 100644 index 000000000..705047ce0 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/src/constants.ts @@ -0,0 +1,7 @@ +import { WORLD_CUP_PROGRAM_ADDRESS } from './generated/index.js'; + +/** Deployed program address, sourced from Codama-generated bindings. */ +export const PROGRAM_ID = WORLD_CUP_PROGRAM_ADDRESS; + +/** PDA seed for the event authority (self-CPI event emission). */ +export const EVENT_AUTHORITY_SEED = 'event_authority'; diff --git a/games/world-cup/pinocchio/clients/typescript/src/fifa-2026.ts b/games/world-cup/pinocchio/clients/typescript/src/fifa-2026.ts new file mode 100644 index 000000000..a37a12296 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/src/fifa-2026.ts @@ -0,0 +1,260 @@ +import { children, GAME_COUNT, r32Slots, TEAM_COUNT, THIRD_PLACE_GAME, thirdPlaceSlots } from './bracket.js'; + +/** + * Edition-specific bracket labels for the FIFA World Cup 2026 knockout stage. + * + * The program is label-agnostic — games and team slots are just positional ids + * `0..31`. FIFA, by contrast, names matches `M73..M104` (scheduling order, not + * bracket order) and seeds slots from group positions (`1C`, `2F`, `3ABCDF`, …). + * This module is the single source of truth tying those official labels onto the + * internal indices, chosen so the program's fixed `children()` adjacency + * reproduces the real bracket. NEXT-TOURNAMENT REPLACEMENT POINT: swap this file. + */ + +/** Internal game index `0..31` → official FIFA match label (`"M74"`, …). */ +export const MATCH_LABELS: readonly string[] = [ + 'M74', + 'M77', + 'M73', + 'M75', + 'M83', + 'M84', + 'M81', + 'M82', // R32, games 0..7 + 'M76', + 'M78', + 'M79', + 'M80', + 'M86', + 'M88', + 'M85', + 'M87', // R32, games 8..15 + 'M89', + 'M90', + 'M93', + 'M94', + 'M91', + 'M92', + 'M95', + 'M96', // R16, games 16..23 + 'M97', + 'M98', + 'M99', + 'M100', // Quarterfinals, games 24..27 + 'M101', + 'M102', // Semifinals, games 28..29 + 'M104', // Final, game 30 + 'M103', // Third-place playoff, game 31 +]; + +/** + * Kickoff instant per game index as a UTC ISO-8601 timestamp, mirroring the + * official bracket. Stored as absolute instants (not wall-clock strings) so each + * client can render a match in the viewer's own local timezone. The 2026 + * tournament spans five venue timezones — PT, MT, CT, ET, and Mexico's UTC-6, + * which (unlike US Central) does not observe DST — so a bare date/time would be + * ambiguous. Comments note the venue-local kickoff each instant was derived from. + */ +export const MATCH_KICKOFFS: readonly string[] = [ + '2026-06-29T20:30:00Z', // 0 M74 Boston 16:30 ET + '2026-06-30T21:00:00Z', // 1 M77 NY/NJ 17:00 ET + '2026-06-28T19:00:00Z', // 2 M73 Los Angeles 12:00 PT + '2026-06-30T01:00:00Z', // 3 M75 Monterrey 19:00 (UTC-6) + '2026-07-02T23:00:00Z', // 4 M83 Toronto 19:00 ET + '2026-07-02T19:00:00Z', // 5 M84 Los Angeles 12:00 PT + '2026-07-02T00:00:00Z', // 6 M81 SF Bay 17:00 PT + '2026-07-01T20:00:00Z', // 7 M82 Seattle 13:00 PT + '2026-06-29T17:00:00Z', // 8 M76 Houston 12:00 CT + '2026-06-30T17:00:00Z', // 9 M78 Dallas 12:00 CT + '2026-07-01T01:00:00Z', // 10 M79 Mexico City 19:00 (UTC-6) + '2026-07-01T16:00:00Z', // 11 M80 Atlanta 12:00 ET + '2026-07-03T22:00:00Z', // 12 M86 Miami 18:00 ET + '2026-07-03T18:00:00Z', // 13 M88 Dallas 13:00 CT + '2026-07-03T03:00:00Z', // 14 M85 Vancouver 20:00 PT + '2026-07-04T01:30:00Z', // 15 M87 Kansas City 20:30 CT + '2026-07-04T21:00:00Z', // 16 M89 Philadelphia 17:00 ET + '2026-07-04T17:00:00Z', // 17 M90 Houston 12:00 CT + '2026-07-06T19:00:00Z', // 18 M93 Dallas 14:00 CT + '2026-07-07T00:00:00Z', // 19 M94 Seattle 17:00 PT + '2026-07-05T20:00:00Z', // 20 M91 NY/NJ 16:00 ET + '2026-07-06T00:00:00Z', // 21 M92 Mexico City 18:00 (UTC-6) + '2026-07-07T16:00:00Z', // 22 M95 Atlanta 12:00 ET + '2026-07-07T20:00:00Z', // 23 M96 Vancouver 13:00 PT + '2026-07-09T20:00:00Z', // 24 M97 Boston 16:00 ET + '2026-07-10T19:00:00Z', // 25 M98 Los Angeles 12:00 PT + '2026-07-11T21:00:00Z', // 26 M99 Miami 17:00 ET + '2026-07-12T01:00:00Z', // 27 M100 Kansas City 20:00 CT + '2026-07-14T19:00:00Z', // 28 M101 Dallas 14:00 CT + '2026-07-15T19:00:00Z', // 29 M102 Atlanta 15:00 ET + '2026-07-19T19:00:00Z', // 30 M104 NY/NJ 15:00 ET (Final) + '2026-07-18T21:00:00Z', // 31 M103 Miami 17:00 ET (Third place) +]; + +/** + * Team slot `0..31` → seeded label. Already-qualified teams (Germany, USA, + * Mexico) are concrete; the rest are group-position placeholders (`1C` = winner + * of Group C, `2F` = runner-up of Group F, `3ABCDF` = third place from one of + * those groups) until the draw fills them. Slot order is bracket order: this is + * what makes the internal tree reproduce FIFA's matchups, so do not reorder. + */ +export const SLOT_LABELS: readonly string[] = [ + 'Germany', + '3ABCDF', + '1I', + '3CDFGH', + '2A', + '2B', + '1F', + '2C', // slots 0..7 + '2K', + '2L', + '1H', + '2J', + 'USA', + '3BEFIJ', + '1G', + '3AEHIJ', // slots 8..15 + '1C', + '2F', + '2E', + '2I', + 'Mexico', + '3CEFHI', + '1L', + '3EHIJK', // slots 16..23 + 'Argentina', + '2H', + '2D', + '2G', + '1B', + '3EFGIJ', + '1K', + '3DEIJL', // slots 24..31 +]; + +const GAME_INDEX_BY_LABEL: ReadonlyMap = new Map(MATCH_LABELS.map((label, index) => [label, index])); + +/** The official match label for a game index `0..31`. Throws when out of range. */ +export function matchLabel(game: number): string { + const label = MATCH_LABELS[game]; + if (label === undefined) throw new RangeError(`game ${game} out of range 0..${GAME_COUNT}`); + return label; +} + +/** The game index `0..31` for an official match label (`"M74"`). Throws when unknown. */ +export function gameIndexOf(label: string): number { + const game = GAME_INDEX_BY_LABEL.get(label); + if (game === undefined) throw new RangeError(`unknown match label ${label}`); + return game; +} + +/** A match's two competitors as display labels: team slots for the Round of 32, + * feeder-match references (`"W74"`) for later rounds, and the semifinal + * runners-up (`"RU101"`) for the third-place playoff. */ +export function contestantsOf(game: number): [string, string] { + if (game < 0 || game >= GAME_COUNT) throw new RangeError(`game ${game} out of range 0..${GAME_COUNT}`); + if (game < 16) { + const [a, b] = r32Slots(game); + return [SLOT_LABELS[a], SLOT_LABELS[b]]; + } + if (game === THIRD_PLACE_GAME) { + return [`RU${matchLabel(28).slice(1)}`, `RU${matchLabel(29).slice(1)}`]; + } + const [c0, c1] = children(game); + return [`W${matchLabel(c0).slice(1)}`, `W${matchLabel(c1).slice(1)}`]; +} + +/** + * Translates an official result ("Germany won M74") into the `{ game, winner }` + * payload for a `post_result` instruction, guarding that `winnerSlot` is actually + * a competitor of that match. Round-of-32 matches validate against their two team + * slots directly. Later rounds need the oracle's current `results` (slot per game, + * {@link UNDECIDED} for unposted) to know who reached the match — pass it to get + * the same contestant check the program enforces; omit it to validate range only. + */ +export function resultForMatch( + label: string, + winnerSlot: number, + results?: ReadonlyArray, +): { game: number; winner: number } { + const game = gameIndexOf(label); + if (!Number.isInteger(winnerSlot) || winnerSlot < 0 || winnerSlot >= TEAM_COUNT) { + throw new RangeError(`winner slot ${winnerSlot} out of range 0..${TEAM_COUNT}`); + } + if (game < 16) { + const [a, b] = r32Slots(game); + if (winnerSlot !== a && winnerSlot !== b) { + throw new Error(`${label} is contested by slots ${a} and ${b}, not ${winnerSlot}`); + } + } else if (results !== undefined) { + const [c0, c1] = game === THIRD_PLACE_GAME ? thirdPlaceSlots(results) : pickFeederWinners(game, results); + if (winnerSlot !== c0 && winnerSlot !== c1) { + throw new Error(`${label} is contested by slots ${c0} and ${c1}, not ${winnerSlot}`); + } + } + return { game, winner: winnerSlot }; +} + +function pickFeederWinners(game: number, results: ReadonlyArray): [number, number] { + const [c0, c1] = children(game); + return [results[c0], results[c1]]; +} + +/** + * Asserts the FIFA label tables are internally consistent: the match labels are a + * bijection over `M73..M104`, every slot label is distinct, and the official + * feeder structure (transcribed in {@link FIFA_FEEDERS}) matches the program's + * `children()` adjacency through {@link MATCH_LABELS}. Throws on any drift so a + * mistyped label or a reordered slot is caught instead of silently producing the + * wrong matchups. + */ +export function assertFifaScheduleConsistent(): void { + if (MATCH_LABELS.length !== GAME_COUNT) throw new Error(`expected ${GAME_COUNT} match labels`); + if (SLOT_LABELS.length !== TEAM_COUNT) throw new Error(`expected ${TEAM_COUNT} slot labels`); + if (MATCH_KICKOFFS.length !== GAME_COUNT) throw new Error(`expected ${GAME_COUNT} match kickoffs`); + for (const iso of MATCH_KICKOFFS) { + if (Number.isNaN(Date.parse(iso))) throw new Error(`invalid kickoff timestamp: ${iso}`); + } + + const numbers = MATCH_LABELS.map(label => Number(label.slice(1))); + const unique = new Set(numbers); + if (unique.size !== GAME_COUNT) throw new Error('match labels are not unique'); + for (let m = 73; m <= 104; m++) { + if (!unique.has(m)) throw new Error(`missing match M${m}`); + } + if (new Set(SLOT_LABELS).size !== TEAM_COUNT) throw new Error('slot labels are not unique'); + + for (const [label, feeders] of FIFA_FEEDERS) { + const game = gameIndexOf(label); + const [d0, d1] = game === THIRD_PLACE_GAME ? [matchLabel(28), matchLabel(29)] : children(game).map(matchLabel); + const derived = new Set([d0, d1]); + if (new Set(feeders).size !== 2 || derived.size !== 2 || !feeders.every(f => derived.has(f))) { + throw new Error(`feeders for ${label} should be ${feeders.join(', ')} but resolved to ${d0}, ${d1}`); + } + } +} + +/** + * Official feeder matches for each non-Round-of-32 match (`[match, [feederA, + * feederB]]`), transcribed directly from the bracket independent of the internal + * topology. {@link assertFifaScheduleConsistent} checks the index mapping + * reproduces these. + */ +export const FIFA_FEEDERS: readonly [string, readonly [string, string]][] = [ + ['M89', ['M74', 'M77']], + ['M90', ['M73', 'M75']], + ['M91', ['M76', 'M78']], + ['M92', ['M79', 'M80']], + ['M93', ['M83', 'M84']], + ['M94', ['M81', 'M82']], + ['M95', ['M86', 'M88']], + ['M96', ['M85', 'M87']], + ['M97', ['M89', 'M90']], + ['M98', ['M93', 'M94']], + ['M99', ['M91', 'M92']], + ['M100', ['M95', 'M96']], + ['M101', ['M97', 'M98']], + ['M102', ['M99', 'M100']], + ['M104', ['M101', 'M102']], + ['M103', ['M101', 'M102']], +]; diff --git a/games/world-cup/pinocchio/clients/typescript/src/index.ts b/games/world-cup/pinocchio/clients/typescript/src/index.ts new file mode 100644 index 000000000..cf249eaf0 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/src/index.ts @@ -0,0 +1,16 @@ +// Re-export everything generated (instruction builders, find*Pda, codecs, account types, program). +export * from './generated/index.js'; +// Hand-written constants. +export * from './constants.js'; +// Hand-written bracket helpers (validation, random bracket, yolo instruction). +export * from './bracket.js'; +// Hand-written scoring helpers (mirrors on-chain weighted scoring). +export * from './scoring.js'; +// Hand-written leaderboard helpers (fetch all brackets, rank by live score). +export * from './leaderboard.js'; +// Placeholder team-name mapping (single launch-day replacement point). +export * from './teams.js'; +// FIFA 2026 bracket labels: match (M73..M104) + slot mapping, oracle helper. +export * from './fifa-2026.js'; +// Bracket display helpers (per-game rows, champion). +export * from './bracket-display.js'; diff --git a/games/world-cup/pinocchio/clients/typescript/src/leaderboard.ts b/games/world-cup/pinocchio/clients/typescript/src/leaderboard.ts new file mode 100644 index 000000000..2d0c11de8 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/src/leaderboard.ts @@ -0,0 +1,151 @@ +import { + type Address, + type Base58EncodedBytes, + getBase58Decoder, + getBase64Encoder, + type GetProgramAccountsApi, + type Rpc, +} from '@solana/kit'; + +import { children, FINAL_GAME, THIRD_PLACE_GAME } from './bracket.js'; +import { + AccountDiscriminator, + type Bracket, + getAccountDiscriminatorEncoder, + getBracketDecoder, + getBracketEncoder, + type Oracle, + WORLD_CUP_PROGRAM_ADDRESS, +} from './generated/index.js'; +import { closeness, scoreBracket } from './scoring.js'; + +/** Byte length of a Bracket account; every account is fixed-size, so this is exact. */ +export const BRACKET_ACCOUNT_SIZE = getBracketEncoder().fixedSize; + +/** A decoded Bracket account paired with its on-chain address (the bracket PDA). */ +export interface BracketAccount { + address: Address; + data: Bracket; +} + +/** Options for {@link fetchAllBrackets}; defaults target the deployed program. */ +export interface FetchAllBracketsConfig { + /** Override the program to query; defaults to {@link WORLD_CUP_PROGRAM_ADDRESS}. */ + programAddress?: Address; +} + +/** + * The base58 memcmp bytes that select Bracket accounts by their leading + * discriminator. Derived from the codec rather than hardcoded so it tracks the IDL. + */ +function bracketDiscriminatorFilterBytes(): Base58EncodedBytes { + const bytes = getAccountDiscriminatorEncoder().encode(AccountDiscriminator.Bracket); + return getBase58Decoder().decode(bytes) as Base58EncodedBytes; +} + +/** + * Fetches every Bracket account owned by the program in a single `getProgramAccounts` + * call, narrowed by two TypeSafe filters: the fixed account size and a discriminator + * memcmp at offset 0. Each account already carries its `picks`, so no follow-up + * `getMultipleAccounts` is needed to score the field. + */ +export async function fetchAllBrackets( + rpc: Rpc, + config: FetchAllBracketsConfig = {}, +): Promise { + const programAddress = config.programAddress ?? WORLD_CUP_PROGRAM_ADDRESS; + const accounts = await rpc + .getProgramAccounts(programAddress, { + encoding: 'base64', + filters: [ + { dataSize: BigInt(BRACKET_ACCOUNT_SIZE) }, + { memcmp: { bytes: bracketDiscriminatorFilterBytes(), encoding: 'base58', offset: 0n } }, + ], + }) + .send(); + + const base64 = getBase64Encoder(); + const decoder = getBracketDecoder(); + return accounts.map(({ account, pubkey }) => ({ + address: pubkey, + data: decoder.decode(base64.encode(account.data[0])), + })); +} + +/** One ranked row in the leaderboard, scored live against the oracle. */ +export interface LeaderboardEntry { + /** The bracket PDA address. */ + address: Address; + /** The picked champion's positional team slot — the bracket's 1st place (Final winner). */ + championSlot: number; + /** `|guess - actual|` once Round-of-32 goals are posted; otherwise `null`. */ + closeness: number | null; + /** The wallet that submitted the bracket. */ + owner: Address; + /** 1-based rank; entries with equal `(score, closeness)` share a rank. */ + rank: number; + /** The picked runner-up's team slot — the bracket's 2nd place (Final loser). */ + runnerUpSlot: number; + /** Live weighted score against the oracle's decided games; `0` before any results. */ + score: number; + /** The picked third-place team slot — the bracket's 3rd place (third-place playoff winner). */ + thirdPlaceSlot: number; + /** The entrant's Round-of-32 total-goals guess. */ + tiebreakerGuess: number; +} + +type ScoredEntry = Omit; + +/** Score desc, then closeness asc (nulls last), then owner asc for a stable order. */ +function compareEntries(a: ScoredEntry, b: ScoredEntry): number { + if (a.score !== b.score) return b.score - a.score; + if (a.closeness !== b.closeness) { + if (a.closeness == null) return 1; + if (b.closeness == null) return -1; + return a.closeness - b.closeness; + } + return a.owner < b.owner ? -1 : a.owner > b.owner ? 1 : 0; +} + +/** Two entries tie — and therefore share a rank — when score and closeness match. */ +function sameRank(a: ScoredEntry, b: ScoredEntry): boolean { + return a.score === b.score && a.closeness === b.closeness; +} + +/** + * Ranks brackets by live score, mirroring the on-chain ordering key + * `(score DESC, closeness ASC)`. Scores are computed against `oracle.results` (so + * standings are current regardless of whether `refresh_score` has folded a bracket), + * and closeness is only populated once the oracle has posted Round-of-32 goals. When + * `oracle` is `null`, every entry scores `0` and shares the top rank. Pure and + * RPC-free for easy testing. + */ +export function buildLeaderboard(brackets: ReadonlyArray, oracle: Oracle | null): LeaderboardEntry[] { + const goalsPosted = oracle != null && oracle.goalsPosted > 0; + const [finalistGameA, finalistGameB] = children(FINAL_GAME); + + const scored: ScoredEntry[] = brackets.map(({ address, data }) => { + const championSlot = data.picks[FINAL_GAME]; + const finalistA = data.picks[finalistGameA]; + return { + address, + championSlot, + closeness: goalsPosted ? closeness(data.tiebreakerGuess, oracle.totalGoalsR32) : null, + owner: data.owner, + runnerUpSlot: championSlot === finalistA ? data.picks[finalistGameB] : finalistA, + score: oracle ? scoreBracket(data.picks, oracle.results) : 0, + thirdPlaceSlot: data.picks[THIRD_PLACE_GAME], + tiebreakerGuess: data.tiebreakerGuess, + }; + }); + + scored.sort(compareEntries); + + let rank = 0; + let prev: ScoredEntry | null = null; + return scored.map((entry, i) => { + if (prev == null || !sameRank(prev, entry)) rank = i + 1; + prev = entry; + return { rank, ...entry }; + }); +} diff --git a/games/world-cup/pinocchio/clients/typescript/src/scoring.ts b/games/world-cup/pinocchio/clients/typescript/src/scoring.ts new file mode 100644 index 000000000..4ae4ac333 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/src/scoring.ts @@ -0,0 +1,38 @@ +import { GAME_COUNT, roundOf } from './bracket.js'; + +/** + * Per-round score weight (classic doubling); the third-place playoff is a bonus + * game weighted like a semifinal. Index by `roundOf(game)`. + */ +export const ROUND_WEIGHT: ReadonlyArray = [1, 2, 4, 8, 16, 8]; + +/** Sentinel for an undecided game result in the oracle. */ +export const UNDECIDED = 255; + +/** The score weight for a game index, derived from its round. */ +export function roundWeight(game: number): number { + return ROUND_WEIGHT[roundOf(game)]; +} + +/** + * Sums a bracket's weighted score against the decided games in `results`, + * mirroring the on-chain `score_bracket`. A game contributes its round weight + * only when its result is decided (not {@link UNDECIDED}) and the pick matches. + */ +export function scoreBracket(picks: ReadonlyArray, results: ReadonlyArray): number { + if (picks.length !== GAME_COUNT || results.length !== GAME_COUNT) { + throw new RangeError(`expected ${GAME_COUNT} picks and results`); + } + let score = 0; + for (let g = 0; g < GAME_COUNT; g++) { + if (results[g] !== UNDECIDED && picks[g] === results[g]) { + score += roundWeight(g); + } + } + return score; +} + +/** Absolute difference between a tiebreaker guess and the actual Round-of-32 goal total. */ +export function closeness(guess: number, actual: number): number { + return Math.abs(guess - actual); +} diff --git a/games/world-cup/pinocchio/clients/typescript/src/teams.ts b/games/world-cup/pinocchio/clients/typescript/src/teams.ts new file mode 100644 index 000000000..17b5b5683 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/src/teams.ts @@ -0,0 +1,26 @@ +import { TEAM_COUNT } from './bracket.js'; +import { SLOT_LABELS } from './fifa-2026.js'; + +/** + * Display names for the 32 positional team slots (`0..31`), defaulting to the + * FIFA 2026 seeding: already-qualified teams as country names and the rest as + * group-position placeholders (`1C`, `2F`, `3ABCDF`, …) — see {@link SLOT_LABELS}. + * + * LAUNCH-DAY REPLACEMENT POINT: as the draw fills group positions, this array is + * the single source the webapp swaps in to flow real names through every display + * helper, and nothing else needs to change. Callers that want to override without + * editing this file can pass their own `names` array to the display helpers. The + * slot order is bracket order and must not change. + */ +export const TEAM_NAMES: readonly string[] = SLOT_LABELS; + +/** + * The display name for a positional team slot. Defaults to {@link TEAM_NAMES}; + * pass `names` to override. Throws `RangeError` when `slot` is outside `0..31`. + */ +export function teamName(slot: number, names: ReadonlyArray = TEAM_NAMES): string { + if (!Number.isInteger(slot) || slot < 0 || slot >= TEAM_COUNT) { + throw new RangeError(`team slot ${slot} out of range 0..${TEAM_COUNT}`); + } + return names[slot]; +} diff --git a/games/world-cup/pinocchio/clients/typescript/test/bracket-display.test.ts b/games/world-cup/pinocchio/clients/typescript/test/bracket-display.test.ts new file mode 100644 index 000000000..ca5b945ea --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/test/bracket-display.test.ts @@ -0,0 +1,64 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { GAME_COUNT, randomBracket, Round, roundOf } from '../src/bracket.ts'; +import { bracketRows, champion } from '../src/bracket-display.ts'; +import { teamName, TEAM_NAMES } from '../src/teams.ts'; + +describe('teams', () => { + test('TEAM_NAMES has 32 entries defaulting to the FIFA seeding', () => { + assert.equal(TEAM_NAMES.length, 32); + assert.equal(TEAM_NAMES[0], 'Germany'); + assert.equal(TEAM_NAMES[31], '3DEIJL'); + }); + + test('teamName resolves a slot and honors a custom names override', () => { + assert.equal(teamName(0), 'Germany'); + assert.equal(teamName(5, ['A', 'B', 'C', 'D', 'E', 'USA']), 'USA'); + }); + + test('teamName throws RangeError on out-of-range slots', () => { + assert.throws(() => teamName(-1), RangeError); + assert.throws(() => teamName(32), RangeError); + assert.throws(() => teamName(1.5), RangeError); + }); +}); + +describe('bracket-display', () => { + test('champion matches picks[30]', () => { + const { picks } = randomBracket(); + const c = champion(picks); + assert.equal(c.slot, picks[30]); + assert.equal(c.name, TEAM_NAMES[picks[30]]); + }); + + test('champion honors a custom names override', () => { + const { picks } = randomBracket(); + const names = Array.from({ length: 32 }, (_, i) => `X${i}`); + assert.equal(champion(picks, names).name, names[picks[30]]); + }); + + test('bracketRows returns 32 rows with correct round and resolved names', () => { + const { picks } = randomBracket(); + const rows = bracketRows(picks); + assert.equal(rows.length, GAME_COUNT); + for (const sample of [0, 15, 16, 23, 24, 27, 28, 29, 30, 31]) { + const row = rows[sample]; + assert.equal(row.game, sample); + assert.equal(row.round, roundOf(sample)); + assert.equal(row.winnerSlot, picks[sample]); + assert.equal(row.winnerName, TEAM_NAMES[picks[sample]]); + } + assert.equal(rows[30].round, Round.Final); + assert.equal(rows[31].round, Round.ThirdPlace); + assert.equal(rows[30].roundLabel, 'Final'); + assert.equal(rows[31].roundLabel, 'Third-place playoff'); + }); + + test('bracketRows honors a custom names override', () => { + const { picks } = randomBracket(); + const names = Array.from({ length: 32 }, (_, i) => `Squad ${i}`); + const rows = bracketRows(picks, names); + assert.equal(rows[0].winnerName, names[picks[0]]); + }); +}); diff --git a/games/world-cup/pinocchio/clients/typescript/test/bracket.test.ts b/games/world-cup/pinocchio/clients/typescript/test/bracket.test.ts new file mode 100644 index 000000000..ef09123bd --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/test/bracket.test.ts @@ -0,0 +1,124 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { createNoopSigner } from '@solana/kit'; + +import { + children, + GAME_COUNT, + isValidBracket, + parseSubmitBracketInstruction, + r32Slots, + randomBracket, + Round, + roundOf, + THIRD_PLACE_GAME, + thirdPlaceSlots, + validateBracket, + yolo, +} from '../src/index.ts'; + +describe('topology', () => { + test('roundOf maps game indices to rounds', () => { + assert.equal(roundOf(0), Round.R32); + assert.equal(roundOf(15), Round.R32); + assert.equal(roundOf(16), Round.R16); + assert.equal(roundOf(23), Round.R16); + assert.equal(roundOf(24), Round.Qf); + assert.equal(roundOf(27), Round.Qf); + assert.equal(roundOf(28), Round.Sf); + assert.equal(roundOf(29), Round.Sf); + assert.equal(roundOf(30), Round.Final); + assert.equal(roundOf(31), Round.ThirdPlace); + }); + + test('r32Slots returns the two team slots of a Round-of-32 game', () => { + assert.deepEqual(r32Slots(0), [0, 1]); + assert.deepEqual(r32Slots(1), [2, 3]); + assert.deepEqual(r32Slots(15), [30, 31]); + }); + + test('children returns the two feeder games of a knockout game', () => { + assert.deepEqual(children(16), [0, 1]); + assert.deepEqual(children(30), [28, 29]); + }); + + test('thirdPlaceSlots returns the two semifinal losers', () => { + const slots = new Array(GAME_COUNT).fill(0); + slots[24] = 1; + slots[25] = 2; + slots[26] = 3; + slots[27] = 4; + slots[28] = 1; // SF 28 winner is 1 -> loser is 2 + slots[29] = 4; // SF 29 winner is 4 -> loser is 3 + assert.deepEqual(thirdPlaceSlots(slots), [2, 3]); + }); +}); + +describe('validateBracket', () => { + test('accepts a randomly generated bracket', () => { + assert.equal(validateBracket(randomBracket().picks).ok, true); + }); + + test('rejects a bracket of the wrong length', () => { + assert.deepEqual(validateBracket([1, 2, 3]), { + ok: false, + game: -1, + reason: `expected ${GAME_COUNT} picks, got 3`, + }); + }); + + test('rejects an out-of-range team', () => { + const picks = randomBracket().picks; + picks[0] = 99; + const result = validateBracket(picks); + assert.equal(result.ok, false); + assert.equal(result.ok === false && result.game, 0); + }); + + test('rejects a team that does not play in a Round-of-32 game', () => { + const picks = randomBracket().picks; + picks[1] = 5; // game 1 contests slots 2 and 3 + const result = validateBracket(picks); + assert.equal(result.ok, false); + assert.equal(result.ok === false && result.game, 1); + }); + + test('rejects a winner not advanced from its feeders', () => { + const picks = new Array(GAME_COUNT); + for (let g = 0; g < 16; g++) picks[g] = r32Slots(g)[0]; + for (let g = 16; g <= 30; g++) picks[g] = picks[children(g)[0]]!; + picks[THIRD_PLACE_GAME] = thirdPlaceSlots(picks)[0]; + picks[16] = picks[2]!; // not a feeder winner of game 16 (feeders 0,1) + const result = validateBracket(picks); + assert.equal(result.ok, false); + assert.equal(result.ok === false && result.game, 16); + }); +}); + +describe('randomBracket', () => { + test('always produces a valid bracket', () => { + for (let i = 0; i < 1000; i++) { + assert.equal(isValidBracket(randomBracket().picks), true); + } + }); + + test('honors a fixed tiebreaker guess', () => { + assert.equal(randomBracket(42).tiebreakerGuess, 42); + }); + + test('generates a tiebreaker in range when unspecified', () => { + const { tiebreakerGuess } = randomBracket(); + assert.ok(tiebreakerGuess >= 0 && tiebreakerGuess <= 200); + }); +}); + +describe('yolo', () => { + test('builds a submitBracket instruction with a valid random bracket', async () => { + const entrant = createNoopSigner('11111111111111111111111111111112'); + const instruction = await yolo({ entrant }); + const parsed = parseSubmitBracketInstruction(instruction); + assert.equal(isValidBracket(parsed.data.submitBracketData.picks), true); + assert.equal(parsed.accounts.entrant.address, entrant.address); + }); +}); diff --git a/games/world-cup/pinocchio/clients/typescript/test/fifa-2026.test.ts b/games/world-cup/pinocchio/clients/typescript/test/fifa-2026.test.ts new file mode 100644 index 000000000..e95c27cde --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/test/fifa-2026.test.ts @@ -0,0 +1,119 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { children, GAME_COUNT, r32Slots, TEAM_COUNT } from '../src/bracket.ts'; +import { + assertFifaScheduleConsistent, + contestantsOf, + FIFA_FEEDERS, + gameIndexOf, + MATCH_LABELS, + matchLabel, + resultForMatch, + SLOT_LABELS, +} from '../src/fifa-2026.ts'; +import { TEAM_NAMES } from '../src/teams.ts'; + +describe('match labels', () => { + test('are a bijection over M73..M104', () => { + assert.equal(MATCH_LABELS.length, GAME_COUNT); + const numbers = MATCH_LABELS.map(label => Number(label.slice(1))); + assert.equal(new Set(numbers).size, GAME_COUNT); + for (let m = 73; m <= 104; m++) { + assert.ok(numbers.includes(m), `missing M${m}`); + } + }); + + test('matchLabel and gameIndexOf round-trip for every game', () => { + for (let g = 0; g < GAME_COUNT; g++) { + assert.equal(gameIndexOf(matchLabel(g)), g); + } + }); + + test('the final is M104 and the third-place playoff is M103', () => { + assert.equal(matchLabel(30), 'M104'); + assert.equal(matchLabel(31), 'M103'); + }); + + test('throw on out-of-range index and unknown label', () => { + assert.throws(() => matchLabel(32)); + assert.throws(() => gameIndexOf('M999')); + }); +}); + +describe('schedule consistency', () => { + test('assertFifaScheduleConsistent passes', () => { + assert.doesNotThrow(assertFifaScheduleConsistent); + }); + + test('the index mapping reproduces the official feeder structure', () => { + for (const [label, feeders] of FIFA_FEEDERS) { + const game = gameIndexOf(label); + const derived = game === 31 ? [matchLabel(28), matchLabel(29)] : children(game).map(matchLabel); + assert.deepEqual(new Set(derived), new Set(feeders), `feeders for ${label}`); + } + }); +}); + +describe('slot labels', () => { + test('are 32 distinct entries', () => { + assert.equal(SLOT_LABELS.length, TEAM_COUNT); + assert.equal(new Set(SLOT_LABELS).size, TEAM_COUNT); + }); + + test('place the already-qualified teams', () => { + assert.equal(SLOT_LABELS[0], 'Germany'); + assert.equal(SLOT_LABELS[12], 'USA'); + assert.equal(SLOT_LABELS[20], 'Mexico'); + }); + + test('TEAM_NAMES defaults to the FIFA seeding', () => { + assert.deepEqual(TEAM_NAMES, SLOT_LABELS); + }); +}); + +describe('contestantsOf', () => { + test('Round-of-32 games show their two team slots', () => { + const [a, b] = r32Slots(0); + assert.deepEqual(contestantsOf(0), [SLOT_LABELS[a], SLOT_LABELS[b]]); + assert.deepEqual(contestantsOf(0), ['Germany', '3ABCDF']); + }); + + test('later rounds show feeder-match winners', () => { + assert.deepEqual(contestantsOf(16), ['W74', 'W77']); // M89 + assert.deepEqual(contestantsOf(30), ['W101', 'W102']); // M104 final + }); + + test('the third-place playoff shows the semifinal runners-up', () => { + assert.deepEqual(contestantsOf(31), ['RU101', 'RU102']); // M103 + }); + + test('throws on out-of-range game indices', () => { + assert.throws(() => contestantsOf(-1)); + assert.throws(() => contestantsOf(32)); + }); +}); + +describe('resultForMatch', () => { + test('translates a Round-of-32 winner to a post_result payload', () => { + assert.deepEqual(resultForMatch('M74', 0), { game: 0, winner: 0 }); + assert.deepEqual(resultForMatch('M74', 1), { game: 0, winner: 1 }); + }); + + test('rejects a winner that does not contest the match', () => { + assert.throws(() => resultForMatch('M74', 2)); // M74 is slots 0,1 + }); + + test('rejects an out-of-range winner slot', () => { + assert.throws(() => resultForMatch('M74', 99)); + }); + + test('validates later rounds against the oracle results when provided', () => { + const results = new Array(GAME_COUNT).fill(0); + results[0] = 1; // winner of game 0 (feeder of M89/game 16) is slot 1 + results[1] = 2; // winner of game 1 is slot 2 + assert.deepEqual(resultForMatch('M89', 1, results), { game: 16, winner: 1 }); + assert.deepEqual(resultForMatch('M89', 2, results), { game: 16, winner: 2 }); + assert.throws(() => resultForMatch('M89', 3, results)); // 3 did not reach M89 + }); +}); diff --git a/games/world-cup/pinocchio/clients/typescript/test/leaderboard.test.ts b/games/world-cup/pinocchio/clients/typescript/test/leaderboard.test.ts new file mode 100644 index 000000000..26c9b9ad3 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/test/leaderboard.test.ts @@ -0,0 +1,140 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import type { Address } from '@solana/kit'; + +import { children, FINAL_GAME, randomBracket, THIRD_PLACE_GAME } from '../src/bracket.ts'; +import type { Oracle } from '../src/generated/index.ts'; +import { buildLeaderboard, type BracketAccount } from '../src/leaderboard.ts'; + +function bracketAccount(owner: string, picks: ReadonlyArray, tiebreakerGuess = 0): BracketAccount { + return { + address: `${owner}-pda` as Address, + data: { + bump: 255, + discriminator: 2, + owner: owner as Address, + picks: [...picks], + score: 0, + tallyMask: 0, + tiebreakerGuess, + }, + }; +} + +function makeOracle( + results: ReadonlyArray, + opts: { goalsPosted?: boolean; totalGoalsR32?: number } = {}, +): Oracle { + return { + bump: 255, + decidedMask: 0, + discriminator: 1, + goalsPosted: opts.goalsPosted ? 1 : 0, + results: [...results], + totalGoalsR32: opts.totalGoalsR32 ?? 0, + }; +} + +describe('buildLeaderboard', () => { + test('ranks by live score descending', () => { + const { picks } = randomBracket(); + const perfect = picks.slice(); + const missedFinal = picks.slice(); + missedFinal[30] = (picks[30] + 1) % 32; // wrong final pick → loses the 16-pt game + const allWrong = picks.map(p => (p + 1) % 32); + + const entries = buildLeaderboard( + [bracketAccount('C', allWrong), bracketAccount('A', perfect), bracketAccount('B', missedFinal)], + makeOracle(picks), + ); + + assert.deepEqual( + entries.map(e => e.owner), + ['A', 'B', 'C'], + ); + assert.deepEqual( + entries.map(e => e.rank), + [1, 2, 3], + ); + assert.equal(entries[0].score, 88); + assert.equal(entries[1].score, 72); + assert.equal(entries[2].score, 0); + }); + + test('equal score and closeness share a rank (1, 1, 3)', () => { + const { picks } = randomBracket(); + const entries = buildLeaderboard( + [ + bracketAccount('A', picks, 10), + bracketAccount('B', picks, 10), + bracketAccount( + 'C', + picks.map(p => (p + 1) % 32), + 10, + ), + ], + makeOracle(picks, { goalsPosted: true, totalGoalsR32: 14 }), + ); + + assert.deepEqual( + entries.map(e => e.rank), + [1, 1, 3], + ); + // Same score + same closeness for A and B. + assert.equal(entries[0].closeness, 4); + assert.equal(entries[1].closeness, 4); + }); + + test('derives the podium slots (1st/2nd/3rd) from the picks', () => { + const { picks } = randomBracket(); + const [{ championSlot, runnerUpSlot, thirdPlaceSlot }] = buildLeaderboard([bracketAccount('A', picks)], null); + + const [sfA, sfB] = children(FINAL_GAME); // the two semifinals feeding the Final + assert.equal(championSlot, picks[FINAL_GAME]); + assert.equal(thirdPlaceSlot, picks[THIRD_PLACE_GAME]); + // The runner-up is the finalist that isn't the champion. + assert.deepEqual([championSlot, runnerUpSlot].sort(), [picks[sfA], picks[sfB]].sort()); + assert.notEqual(championSlot, runnerUpSlot); + }); + + test('closeness is null until Round-of-32 goals are posted', () => { + const { picks } = randomBracket(); + const entries = buildLeaderboard([bracketAccount('A', picks, 10)], makeOracle(picks)); + assert.equal(entries[0].closeness, null); + }); + + test('breaks score ties by closeness ascending', () => { + const { picks } = randomBracket(); + const entries = buildLeaderboard( + [bracketAccount('A', picks, 99), bracketAccount('B', picks, 13)], + makeOracle(picks, { goalsPosted: true, totalGoalsR32: 14 }), + ); + // B's guess (13) is closer to 14 than A's (99), so B ranks first despite equal score. + assert.deepEqual( + entries.map(e => e.owner), + ['B', 'A'], + ); + assert.deepEqual( + entries.map(e => e.rank), + [1, 2], + ); + }); + + test('with no oracle, every entry scores 0 and shares the top rank', () => { + const { picks } = randomBracket(); + const entries = buildLeaderboard([bracketAccount('A', picks, 5), bracketAccount('B', picks, 9)], null); + assert.deepEqual( + entries.map(e => e.score), + [0, 0], + ); + assert.deepEqual( + entries.map(e => e.rank), + [1, 1], + ); + assert.deepEqual( + entries.map(e => e.closeness), + [null, null], + ); + }); +}); diff --git a/games/world-cup/pinocchio/clients/typescript/test/scoring.test.ts b/games/world-cup/pinocchio/clients/typescript/test/scoring.test.ts new file mode 100644 index 000000000..68abddca1 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/test/scoring.test.ts @@ -0,0 +1,74 @@ +import assert from 'node:assert/strict'; +import { describe, test } from 'node:test'; + +import { GAME_COUNT, randomBracket } from '../src/bracket.ts'; +import { closeness, ROUND_WEIGHT, roundWeight, scoreBracket, UNDECIDED } from '../src/scoring.ts'; + +describe('ROUND_WEIGHT', () => { + test('matches the on-chain per-round weights', () => { + assert.deepEqual(ROUND_WEIGHT, [1, 2, 4, 8, 16, 8]); + }); + + test('roundWeight derives a game weight from its round', () => { + assert.equal(roundWeight(0), 1); + assert.equal(roundWeight(16), 2); + assert.equal(roundWeight(24), 4); + assert.equal(roundWeight(28), 8); + assert.equal(roundWeight(30), 16); + assert.equal(roundWeight(31), 8); + }); +}); + +describe('scoreBracket', () => { + test('a perfect bracket scores the full weight sum', () => { + const { picks } = randomBracket(); + let expected = 0; + for (let g = 0; g < GAME_COUNT; g++) expected += roundWeight(g); + assert.equal(scoreBracket(picks, picks), expected); + }); + + test('ignores games still UNDECIDED in the oracle', () => { + const { picks } = randomBracket(); + const results = picks.slice(); + results[0] = UNDECIDED; + results[30] = UNDECIDED; + const expected = scoreBracket(picks, picks) - roundWeight(0) - roundWeight(30); + assert.equal(scoreBracket(picks, results), expected); + }); + + test('counts only matching decided picks', () => { + const picks = new Array(GAME_COUNT).fill(UNDECIDED); + const results = new Array(GAME_COUNT).fill(UNDECIDED); + picks[0] = 0; + results[0] = 0; // match, R32 weight 1 + picks[16] = 0; + results[16] = 1; // decided but mismatched + assert.equal(scoreBracket(picks, results), 1); + }); + + test('returns zero when nothing matches', () => { + const { picks } = randomBracket(); + const results = picks.map(p => (p === 0 ? 1 : 0)); + assert.equal(scoreBracket(picks, results), 0); + }); + + test('returns zero when every result is undecided', () => { + const { picks } = randomBracket(); + const results = new Array(GAME_COUNT).fill(UNDECIDED); + assert.equal(scoreBracket(picks, results), 0); + }); + + test('throws when picks or results are not full-length', () => { + const full = new Array(GAME_COUNT).fill(UNDECIDED); + assert.throws(() => scoreBracket([], full), RangeError); + assert.throws(() => scoreBracket(full, []), RangeError); + }); +}); + +describe('closeness', () => { + test('is the absolute difference between guess and actual', () => { + assert.equal(closeness(10, 14), 4); + assert.equal(closeness(14, 10), 4); + assert.equal(closeness(7, 7), 0); + }); +}); diff --git a/games/world-cup/pinocchio/clients/typescript/tsconfig.json b/games/world-cup/pinocchio/clients/typescript/tsconfig.json new file mode 100644 index 000000000..e668b6870 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/tsconfig.json @@ -0,0 +1,19 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "ESNext", + "moduleResolution": "bundler", + "lib": ["ES2022"], + "types": ["node"], + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "resolveJsonModule": true, + "declaration": true, + "declarationMap": true, + "outDir": "./dist", + "rootDir": "./src" + }, + "include": ["src/**/*"], + "exclude": ["node_modules", "dist"] +} diff --git a/games/world-cup/pinocchio/clients/typescript/tsup.config.ts b/games/world-cup/pinocchio/clients/typescript/tsup.config.ts new file mode 100644 index 000000000..2d1438ec4 --- /dev/null +++ b/games/world-cup/pinocchio/clients/typescript/tsup.config.ts @@ -0,0 +1,11 @@ +import { defineConfig } from 'tsup'; + +export default defineConfig({ + entry: ['src/index.ts'], + format: ['esm', 'cjs'], + dts: true, + clean: true, + splitting: false, + sourcemap: true, + shims: true, +}); diff --git a/games/world-cup/pinocchio/eslint.config.mjs b/games/world-cup/pinocchio/eslint.config.mjs new file mode 100644 index 000000000..253ed2ef0 --- /dev/null +++ b/games/world-cup/pinocchio/eslint.config.mjs @@ -0,0 +1,47 @@ +import solanaConfig from '@solana/eslint-config-solana'; +import reactHooksPlugin from 'eslint-plugin-react-hooks'; + +export default [ + ...solanaConfig, + { + files: ['webapp/src/**/*.{ts,tsx}'], + plugins: { + 'react-hooks': reactHooksPlugin, + }, + rules: { + ...reactHooksPlugin.configs.recommended.rules, + '@typescript-eslint/no-base-to-string': 'off', + '@typescript-eslint/no-floating-promises': 'off', + '@typescript-eslint/no-misused-promises': 'off', + '@typescript-eslint/no-unsafe-argument': 'off', + '@typescript-eslint/no-unsafe-assignment': 'off', + '@typescript-eslint/no-unsafe-enum-comparison': 'off', + '@typescript-eslint/no-unsafe-member-access': 'off', + '@typescript-eslint/no-unsafe-return': 'off', + '@typescript-eslint/restrict-template-expressions': 'off', + '@typescript-eslint/unbound-method': 'off', + }, + }, + { + ignores: [ + '**/.claude/**', + '**/.remember/**', + '**/.git/**', + '**/dist/**', + '**/node_modules/**', + '**/target/**', + '**/generated/**', + 'clients/typescript/src/generated/**', + 'clients/typescript/test/**', + 'clients/typescript/*.config.ts', + 'webapp/api/**', + 'webapp/scripts/**', + 'webapp/test/**', + 'webapp/*.config.js', + '**/playwright-report/**', + '**/test-results/**', + 'eslint.config.mjs', + '**/*.mjs', + ], + }, +]; diff --git a/games/world-cup/pinocchio/idl/world_cup.json b/games/world-cup/pinocchio/idl/world_cup.json new file mode 100644 index 000000000..bfca3f67c --- /dev/null +++ b/games/world-cup/pinocchio/idl/world_cup.json @@ -0,0 +1,1799 @@ +{ + "additionalPrograms": [], + "kind": "rootNode", + "program": { + "accounts": [ + { + "data": { + "fields": [], + "kind": "structTypeNode" + }, + "kind": "accountNode", + "name": "eventAuthority", + "pda": { + "kind": "pdaLinkNode", + "name": "eventAuthority" + } + }, + { + "data": { + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "bump", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "owner", + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "picks", + "type": { + "count": { + "kind": "fixedCountNode", + "value": 32 + }, + "item": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + }, + "kind": "arrayTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "tiebreakerGuess", + "type": { + "endian": "le", + "format": "u16", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "score", + "type": { + "endian": "le", + "format": "u16", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "tallyMask", + "type": { + "endian": "le", + "format": "u32", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "entryIndex", + "type": { + "endian": "le", + "format": "u32", + "kind": "numberTypeNode" + } + } + ], + "kind": "structTypeNode" + }, + "kind": "accountNode", + "name": "bracket", + "pda": { + "kind": "pdaLinkNode", + "name": "bracket" + } + }, + { + "data": { + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "bump", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "state", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "admin", + "type": { + "kind": "publicKeyTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "lockTs", + "type": { + "endian": "le", + "format": "i64", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "entryFee", + "type": { + "endian": "le", + "format": "u64", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "entrantCount", + "type": { + "endian": "le", + "format": "u32", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "refreshedCount", + "type": { + "endian": "le", + "format": "u32", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "tallyMask", + "type": { + "endian": "le", + "format": "u32", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "bestScore", + "type": { + "endian": "le", + "format": "u16", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "bestCloseness", + "type": { + "endian": "le", + "format": "u16", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "bestIndex", + "type": { + "endian": "le", + "format": "u32", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "winner", + "type": { + "kind": "publicKeyTypeNode" + } + } + ], + "kind": "structTypeNode" + }, + "kind": "accountNode", + "name": "config", + "pda": { + "kind": "pdaLinkNode", + "name": "config" + } + }, + { + "data": { + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "bump", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "goalsPosted", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "results", + "type": { + "count": { + "kind": "fixedCountNode", + "value": 32 + }, + "item": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + }, + "kind": "arrayTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "decidedMask", + "type": { + "endian": "le", + "format": "u32", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "totalGoalsR32", + "type": { + "endian": "le", + "format": "u16", + "kind": "numberTypeNode" + } + } + ], + "kind": "structTypeNode" + }, + "kind": "accountNode", + "name": "oracle", + "pda": { + "kind": "pdaLinkNode", + "name": "oracle" + } + }, + { + "data": { + "fields": [], + "kind": "structTypeNode" + }, + "kind": "accountNode", + "name": "vault", + "pda": { + "kind": "pdaLinkNode", + "name": "vault" + } + } + ], + "definedTypes": [ + { + "kind": "definedTypeNode", + "name": "initConfigData", + "type": { + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "lockTs", + "type": { + "endian": "le", + "format": "i64", + "kind": "numberTypeNode" + } + } + ], + "kind": "structTypeNode" + } + }, + { + "kind": "definedTypeNode", + "name": "postGoalsData", + "type": { + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "totalGoalsR32", + "type": { + "endian": "le", + "format": "u16", + "kind": "numberTypeNode" + } + } + ], + "kind": "structTypeNode" + } + }, + { + "kind": "definedTypeNode", + "name": "postResultData", + "type": { + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "game", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "winner", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + } + ], + "kind": "structTypeNode" + } + }, + { + "kind": "definedTypeNode", + "name": "submitBracketData", + "type": { + "fields": [ + { + "kind": "structFieldTypeNode", + "name": "picks", + "type": { + "count": { + "kind": "fixedCountNode", + "value": 32 + }, + "item": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + }, + "kind": "arrayTypeNode" + } + }, + { + "kind": "structFieldTypeNode", + "name": "tiebreakerGuess", + "type": { + "endian": "le", + "format": "u16", + "kind": "numberTypeNode" + } + } + ], + "kind": "structTypeNode" + } + }, + { + "kind": "definedTypeNode", + "name": "accountDiscriminator", + "type": { + "kind": "enumTypeNode", + "size": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + }, + "variants": [ + { + "discriminator": 0, + "kind": "enumEmptyVariantTypeNode", + "name": "config" + }, + { + "discriminator": 1, + "kind": "enumEmptyVariantTypeNode", + "name": "oracle" + }, + { + "discriminator": 2, + "kind": "enumEmptyVariantTypeNode", + "name": "bracket" + } + ] + } + }, + { + "kind": "definedTypeNode", + "name": "tournamentState", + "type": { + "kind": "enumTypeNode", + "size": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + }, + "variants": [ + { + "discriminator": 0, + "kind": "enumEmptyVariantTypeNode", + "name": "registration" + }, + { + "discriminator": 1, + "kind": "enumEmptyVariantTypeNode", + "name": "locked" + }, + { + "discriminator": 2, + "kind": "enumEmptyVariantTypeNode", + "name": "finalized" + } + ] + } + } + ], + "errors": [ + { + "code": 100, + "kind": "errorNode", + "message": "Account must be a signer", + "name": "notSigner" + }, + { + "code": 101, + "kind": "errorNode", + "message": "Account must be writable", + "name": "accountNotWritable" + }, + { + "code": 102, + "kind": "errorNode", + "message": "Expected system program", + "name": "notSystemProgram" + }, + { + "code": 103, + "kind": "errorNode", + "message": "Not enough account keys provided", + "name": "notEnoughAccountKeys" + }, + { + "code": 104, + "kind": "errorNode", + "message": "Invalid instruction", + "name": "invalidInstruction" + }, + { + "code": 105, + "kind": "errorNode", + "message": "Invalid account data", + "name": "invalidAccountData" + }, + { + "code": 106, + "kind": "errorNode", + "message": "Invalid account discriminator", + "name": "invalidAccountDiscriminator" + }, + { + "code": 107, + "kind": "errorNode", + "message": "Arithmetic overflow", + "name": "arithmeticOverflow" + }, + { + "code": 108, + "kind": "errorNode", + "message": "Account is not owned by this program", + "name": "notProgramOwned" + }, + { + "code": 200, + "kind": "errorNode", + "message": "Invalid config PDA derivation", + "name": "invalidConfigPda" + }, + { + "code": 201, + "kind": "errorNode", + "message": "Config account already exists", + "name": "configAlreadyExists" + }, + { + "code": 202, + "kind": "errorNode", + "message": "Signer is not the tournament admin", + "name": "unauthorized" + }, + { + "code": 203, + "kind": "errorNode", + "message": "Instruction not allowed in the current tournament state", + "name": "invalidState" + }, + { + "code": 204, + "kind": "errorNode", + "message": "Registration has closed (kickoff reached)", + "name": "registrationClosed" + }, + { + "code": 205, + "kind": "errorNode", + "message": "Lock time has not been reached yet", + "name": "notYetLocked" + }, + { + "code": 206, + "kind": "errorNode", + "message": "Lock timestamp must be in the future", + "name": "invalidLockTs" + }, + { + "code": 300, + "kind": "errorNode", + "message": "Invalid bracket PDA derivation", + "name": "invalidBracketPda" + }, + { + "code": 301, + "kind": "errorNode", + "message": "Bracket already exists for this wallet", + "name": "bracketAlreadyExists" + }, + { + "code": 302, + "kind": "errorNode", + "message": "Bracket pick is out of range or inconsistent", + "name": "invalidPick" + }, + { + "code": 303, + "kind": "errorNode", + "message": "Bracket has already been folded into the final tally", + "name": "alreadyFolded" + }, + { + "code": 400, + "kind": "errorNode", + "message": "Invalid oracle PDA derivation", + "name": "invalidOraclePda" + }, + { + "code": 401, + "kind": "errorNode", + "message": "Game index is out of range", + "name": "invalidGame" + }, + { + "code": 402, + "kind": "errorNode", + "message": "Result is inconsistent with feeder games", + "name": "invalidResult" + }, + { + "code": 403, + "kind": "errorNode", + "message": "A feeder game has not been decided yet", + "name": "feederNotDecided" + }, + { + "code": 404, + "kind": "errorNode", + "message": "Result for this game has already been posted", + "name": "resultAlreadyPosted" + }, + { + "code": 405, + "kind": "errorNode", + "message": "Round-of-32 goal total has already been posted", + "name": "goalsAlreadyPosted" + }, + { + "code": 500, + "kind": "errorNode", + "message": "Invalid pot vault PDA derivation", + "name": "invalidVaultPda" + }, + { + "code": 501, + "kind": "errorNode", + "message": "Oracle is not complete (all games + goals required)", + "name": "oracleNotComplete" + }, + { + "code": 502, + "kind": "errorNode", + "message": "Not every bracket has been refreshed at the final state", + "name": "notFullyRefreshed" + }, + { + "code": 503, + "kind": "errorNode", + "message": "Provided bracket does not match the winning key", + "name": "bracketNotBest" + }, + { + "code": 504, + "kind": "errorNode", + "message": "Signer is not the recorded winner", + "name": "notWinner" + }, + { + "code": 505, + "kind": "errorNode", + "message": "Pot has already been claimed or released", + "name": "alreadyClaimed" + }, + { + "code": 600, + "kind": "errorNode", + "message": "Invalid event authority PDA", + "name": "invalidEventAuthority" + }, + { + "code": 601, + "kind": "errorNode", + "message": "Invalid event data", + "name": "invalidEventData" + } + ], + "events": [], + "instructions": [ + { + "accounts": [ + { + "docs": [ + "Tournament admin; funds and owns the config" + ], + "isSigner": true, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "admin" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "config" + }, + "seeds": [] + }, + "docs": [ + "Singleton config PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "config" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "oracle" + }, + "seeds": [] + }, + "docs": [ + "Singleton oracle PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "oracle" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "vault" + }, + "seeds": [] + }, + "docs": [ + "Pot vault PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "vault" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111" + }, + "docs": [ + "The system program" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "systemProgram" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "eventAuthority" + }, + "seeds": [] + }, + "docs": [ + "The event authority PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "eventAuthority" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA" + }, + "docs": [ + "This program (for self-CPI event emission)" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "selfProgram" + } + ], + "arguments": [ + { + "defaultValue": { + "kind": "numberValueNode", + "number": 0 + }, + "defaultValueStrategy": "omitted", + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "instructionArgumentNode", + "name": "initConfigData", + "type": { + "kind": "definedTypeLinkNode", + "name": "initConfigData" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "kind": "instructionNode", + "name": "initConfig" + }, + { + "accounts": [ + { + "docs": [ + "The entrant submitting and paying for a bracket" + ], + "isSigner": true, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "entrant" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "config" + }, + "seeds": [] + }, + "docs": [ + "Singleton config PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "config" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "bracket" + }, + "seeds": [ + { + "kind": "pdaSeedValueNode", + "name": "owner", + "value": { + "kind": "accountValueNode", + "name": "entrant" + } + } + ] + }, + "docs": [ + "The bracket PDA being created" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "bracket" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "vault" + }, + "seeds": [] + }, + "docs": [ + "Pot vault PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "vault" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "11111111111111111111111111111111" + }, + "docs": [ + "The system program" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "systemProgram" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "eventAuthority" + }, + "seeds": [] + }, + "docs": [ + "The event authority PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "eventAuthority" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA" + }, + "docs": [ + "This program (for self-CPI event emission)" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "selfProgram" + } + ], + "arguments": [ + { + "defaultValue": { + "kind": "numberValueNode", + "number": 1 + }, + "defaultValueStrategy": "omitted", + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "instructionArgumentNode", + "name": "submitBracketData", + "type": { + "kind": "definedTypeLinkNode", + "name": "submitBracketData" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "kind": "instructionNode", + "name": "submitBracket" + }, + { + "accounts": [ + { + "docs": [ + "Tournament admin" + ], + "isSigner": true, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "admin" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "config" + }, + "seeds": [] + }, + "docs": [ + "Singleton config PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "config" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "eventAuthority" + }, + "seeds": [] + }, + "docs": [ + "The event authority PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "eventAuthority" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA" + }, + "docs": [ + "This program (for self-CPI event emission)" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "selfProgram" + } + ], + "arguments": [ + { + "defaultValue": { + "kind": "numberValueNode", + "number": 2 + }, + "defaultValueStrategy": "omitted", + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "kind": "instructionNode", + "name": "lock" + }, + { + "accounts": [ + { + "docs": [ + "Tournament admin (oracle)" + ], + "isSigner": true, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "admin" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "config" + }, + "seeds": [] + }, + "docs": [ + "Singleton config PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "config" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "oracle" + }, + "seeds": [] + }, + "docs": [ + "Singleton oracle PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "oracle" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "eventAuthority" + }, + "seeds": [] + }, + "docs": [ + "The event authority PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "eventAuthority" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA" + }, + "docs": [ + "This program (for self-CPI event emission)" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "selfProgram" + } + ], + "arguments": [ + { + "defaultValue": { + "kind": "numberValueNode", + "number": 3 + }, + "defaultValueStrategy": "omitted", + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "instructionArgumentNode", + "name": "postResultData", + "type": { + "kind": "definedTypeLinkNode", + "name": "postResultData" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "kind": "instructionNode", + "name": "postResult" + }, + { + "accounts": [ + { + "docs": [ + "Tournament admin (oracle)" + ], + "isSigner": true, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "admin" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "config" + }, + "seeds": [] + }, + "docs": [ + "Singleton config PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "config" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "oracle" + }, + "seeds": [] + }, + "docs": [ + "Singleton oracle PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "oracle" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "eventAuthority" + }, + "seeds": [] + }, + "docs": [ + "The event authority PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "eventAuthority" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA" + }, + "docs": [ + "This program (for self-CPI event emission)" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "selfProgram" + } + ], + "arguments": [ + { + "defaultValue": { + "kind": "numberValueNode", + "number": 4 + }, + "defaultValueStrategy": "omitted", + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + }, + { + "kind": "instructionArgumentNode", + "name": "postGoalsData", + "type": { + "kind": "definedTypeLinkNode", + "name": "postGoalsData" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "kind": "instructionNode", + "name": "postGoals" + }, + { + "accounts": [ + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "config" + }, + "seeds": [] + }, + "docs": [ + "Singleton config PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "config" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "oracle" + }, + "seeds": [] + }, + "docs": [ + "Singleton oracle PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "oracle" + }, + { + "docs": [ + "The bracket PDA being scored" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "bracket" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "eventAuthority" + }, + "seeds": [] + }, + "docs": [ + "The event authority PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "eventAuthority" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA" + }, + "docs": [ + "This program (for self-CPI event emission)" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "selfProgram" + } + ], + "arguments": [ + { + "defaultValue": { + "kind": "numberValueNode", + "number": 5 + }, + "defaultValueStrategy": "omitted", + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "kind": "instructionNode", + "name": "refreshScore" + }, + { + "accounts": [ + { + "docs": [ + "Tournament admin" + ], + "isSigner": true, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "admin" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "config" + }, + "seeds": [] + }, + "docs": [ + "Singleton config PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "config" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "oracle" + }, + "seeds": [] + }, + "docs": [ + "Singleton oracle PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "oracle" + }, + { + "docs": [ + "The bracket claimed to be the unique winner" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "bracket" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "eventAuthority" + }, + "seeds": [] + }, + "docs": [ + "The event authority PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "eventAuthority" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA" + }, + "docs": [ + "This program (for self-CPI event emission)" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "selfProgram" + } + ], + "arguments": [ + { + "defaultValue": { + "kind": "numberValueNode", + "number": 6 + }, + "defaultValueStrategy": "omitted", + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "kind": "instructionNode", + "name": "finalize" + }, + { + "accounts": [ + { + "docs": [ + "The recorded winner claiming the pot" + ], + "isSigner": true, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "winner" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "config" + }, + "seeds": [] + }, + "docs": [ + "Singleton config PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "config" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "vault" + }, + "seeds": [] + }, + "docs": [ + "Pot vault PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "vault" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "eventAuthority" + }, + "seeds": [] + }, + "docs": [ + "The event authority PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "eventAuthority" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA" + }, + "docs": [ + "This program (for self-CPI event emission)" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "selfProgram" + } + ], + "arguments": [ + { + "defaultValue": { + "kind": "numberValueNode", + "number": 7 + }, + "defaultValueStrategy": "omitted", + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "kind": "instructionNode", + "name": "claim" + }, + { + "accounts": [ + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "config" + }, + "seeds": [] + }, + "docs": [ + "Singleton config PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "config" + }, + { + "docs": [ + "The bracket PDA being closed" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "bracket" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "vault" + }, + "seeds": [] + }, + "docs": [ + "Pot vault PDA" + ], + "isSigner": false, + "isWritable": true, + "kind": "instructionAccountNode", + "name": "vault" + }, + { + "defaultValue": { + "kind": "pdaValueNode", + "pda": { + "kind": "pdaLinkNode", + "name": "eventAuthority" + }, + "seeds": [] + }, + "docs": [ + "The event authority PDA" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "eventAuthority" + }, + { + "defaultValue": { + "kind": "publicKeyValueNode", + "publicKey": "wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA" + }, + "docs": [ + "This program (for self-CPI event emission)" + ], + "isSigner": false, + "isWritable": false, + "kind": "instructionAccountNode", + "name": "selfProgram" + } + ], + "arguments": [ + { + "defaultValue": { + "kind": "numberValueNode", + "number": 8 + }, + "defaultValueStrategy": "omitted", + "kind": "instructionArgumentNode", + "name": "discriminator", + "type": { + "endian": "le", + "format": "u8", + "kind": "numberTypeNode" + } + } + ], + "discriminators": [ + { + "kind": "fieldDiscriminatorNode", + "name": "discriminator", + "offset": 0 + } + ], + "kind": "instructionNode", + "name": "closeBracket" + } + ], + "kind": "programNode", + "name": "worldCup", + "pdas": [ + { + "kind": "pdaNode", + "name": "eventAuthority", + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "encoding": "utf8", + "kind": "stringTypeNode" + }, + "value": { + "kind": "stringValueNode", + "string": "event_authority" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "bracket", + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "encoding": "utf8", + "kind": "stringTypeNode" + }, + "value": { + "kind": "stringValueNode", + "string": "bracket" + } + }, + { + "kind": "variablePdaSeedNode", + "name": "owner", + "type": { + "kind": "publicKeyTypeNode" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "config", + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "encoding": "utf8", + "kind": "stringTypeNode" + }, + "value": { + "kind": "stringValueNode", + "string": "config" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "oracle", + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "encoding": "utf8", + "kind": "stringTypeNode" + }, + "value": { + "kind": "stringValueNode", + "string": "oracle" + } + } + ] + }, + { + "kind": "pdaNode", + "name": "vault", + "seeds": [ + { + "kind": "constantPdaSeedNode", + "type": { + "encoding": "utf8", + "kind": "stringTypeNode" + }, + "value": { + "kind": "stringValueNode", + "string": "vault" + } + } + ] + } + ], + "publicKey": "wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA", + "version": "0.1.0" + }, + "standard": "codama", + "version": "1.0.0" +} diff --git a/games/world-cup/pinocchio/justfile b/games/world-cup/pinocchio/justfile new file mode 100644 index 000000000..86fc43c2d --- /dev/null +++ b/games/world-cup/pinocchio/justfile @@ -0,0 +1,184 @@ +# World Cup - Solana program build automation +# https://github.com/casey/just + +# Use bash for all recipes +set shell := ["bash", "-uc"] + +# Variables +program_dir := "program" +ts_client_dir := "clients/typescript" +webapp_dir := "webapp" +idl_file := "idl/world_cup.json" +generated_paths := "idl clients/typescript/src/generated clients/rust/src/generated" + +# List available recipes +default: + @just --list + +# ============================================ +# Setup +# ============================================ + +# Install dependencies +setup: + #!/usr/bin/env bash + set -euo pipefail + commands=(pnpm cargo solana-keygen) + for cmd in "${commands[@]}"; do + if ! command -v "$cmd" &>/dev/null; then + echo "Error: $cmd is required but not installed" + exit 1 + fi + done + pnpm install + echo "✓ Setup complete" + +# Print program ID from keypair +program-id: + @sed -n 's/.*declare_id!("\([^"]*\)").*/\1/p' "{{program_dir}}/src/lib.rs" + +# ============================================ +# Build +# ============================================ + +# Build everything (program + client) +build: build-program build-client + +# Compile Solana program to .so +build-program: + cd {{program_dir}} && cargo build-sbf + @echo "✓ Program built" + +# Generate IDL from Rust source +generate-idl: + pnpm run generate-idl + @echo "✓ IDL generated" + +# Generate TypeScript client from IDL +generate-clients: generate-idl + pnpm run generate-clients + @echo "✓ Clients generated" + +# Check that committed IDL and generated clients are current +check-generated: generate-clients + #!/usr/bin/env bash + set -euo pipefail + if ! git diff --quiet -- {{generated_paths}} || [[ -n "$(git ls-files --others --exclude-standard -- {{generated_paths}})" ]]; then + echo "Error: IDL or generated clients are out of date" + echo "Run: just generate-clients" + git status --short -- {{generated_paths}} + exit 1 + fi + echo "✓ IDL and generated clients are up-to-date" + +# Build TypeScript client +build-client: generate-clients + cd {{ts_client_dir}} && pnpm run build + @echo "✓ TypeScript client built" + +# Build the generated Rust client +build-rust-client: generate-clients + cargo build -p world-cup-client + @echo "✓ Rust client built" + +# ============================================ +# Test +# ============================================ + +# Run all tests (unit + integration + client) +test: unit-test integration-test client-test + +# Run Rust unit tests +unit-test: + cargo test -p world-cup-program + +# Run LiteSVM integration tests (builds the .so first) +integration-test: build-program + cargo test -p tests-world-cup + +# Run TypeScript client tests +client-test: + cd {{ts_client_dir}} && pnpm test + +# ============================================ +# Admin +# ============================================ + +# Initialize on-chain config/oracle/vault (reads ADMIN, RPC_URL from .env) +init: + pnpm exec tsx --env-file=.env scripts/init.ts + +# ============================================ +# Webapp +# ============================================ + +# Start the webapp dev server +webapp-dev: + cd {{webapp_dir}} && pnpm run dev + +# Build the webapp +webapp-build: build-client + cd {{webapp_dir}} && pnpm run build + +# Render a sample X share card (Germany/USA/Mexico, no RPC) and open it. Pass an address for a real bracket. +webapp-og-example address="": + #!/usr/bin/env bash + set -euo pipefail + cd {{webapp_dir}} + query="demo=1" + [ -n "{{address}}" ] && query="b={{address}}" + out="${TMPDIR:-/tmp}/world-cup-og-example.png" + pnpm exec vite --port 5199 --strictPort >/tmp/world-cup-og-dev.log 2>&1 & + pid=$! + trap 'kill "$pid" 2>/dev/null || true' EXIT + for _ in $(seq 1 40); do + curl -sf "http://localhost:5199/api/og?$query" -o "$out" && break + sleep 0.5 + done + echo "✓ Saved $out" + open "$out" 2>/dev/null || xdg-open "$out" 2>/dev/null || true + +# ============================================ +# Format and lint +# ============================================ + +# Check formatting without fixing +fmt-check: + @cargo fmt -p world-cup-program -p tests-world-cup --check + @pnpm run format:check + @echo "✓ Format check passed" + +# Auto-format all code +fmt: + @cargo fmt -p world-cup-program -p tests-world-cup + @pnpm run format + @echo "✓ Code formatted" + +# Lint with auto-fix +lint: + @cargo clippy --workspace --exclude world-cup-client --all-targets --no-deps --fix -- -D warnings + @pnpm run lint:fix + @echo "✓ Code linted" + +# Check linting without fixing +lint-check: + @cargo clippy --workspace --exclude world-cup-client --all-targets --no-deps -- -D warnings + @pnpm run lint + @echo "✓ Lint check passed" + +# Run all code quality checks +check: fmt-check lint-check + +# ============================================ +# Clean +# ============================================ + +# Clean build artifacts and deps +clean: + #!/usr/bin/env bash + set -euo pipefail + cargo clean + cd {{ts_client_dir}} && pnpm run clean || true + cd - + rm -rf {{webapp_dir}}/{node_modules,dist} + echo "✓ Clean complete" diff --git a/games/world-cup/pinocchio/package.json b/games/world-cup/pinocchio/package.json new file mode 100644 index 000000000..8ee32589d --- /dev/null +++ b/games/world-cup/pinocchio/package.json @@ -0,0 +1,52 @@ +{ + "name": "world-cup-monorepo", + "type": "module", + "private": true, + "packageManager": "pnpm@10.15.1+sha512.34e538c329b5553014ca8e8f4535997f96180a1d0f614339357449935350d924e22f8614682191264ec33d1462ac21561aff97f6bb18065351c162c7e8f6de67", + "scripts": { + "format": "prettier --write .", + "format:check": "prettier --check .", + "generate-idl": "cd program && GENERATE_IDL=1 cargo check", + "generate-clients": "tsx ./scripts/generate-clients.ts", + "generate-ts-client": "tsx ./scripts/generate-ts-client.ts", + "lint": "pnpm run generate-clients && pnpm --filter @solana/world-cup build && eslint .", + "lint:fix": "pnpm run generate-clients && pnpm --filter @solana/world-cup build && eslint . --fix" + }, + "devDependencies": { + "@codama/nodes-from-anchor": "^1.5.0", + "@codama/renderers-js": "^2.2.0", + "@codama/renderers-rust": "^3.1.0", + "@eslint/js": "^9.39.4", + "@solana/eslint-config-solana": "6.0.0", + "@solana/kit": "^6.10.0", + "@solana/kit-plugin-rpc": "^0.11.1", + "@solana/kit-plugin-signer": "^0.10.0", + "@solana/prettier-config-solana": "^0.0.6", + "@solana/world-cup": "workspace:*", + "@types/eslint": "^9.6.1", + "@types/eslint__js": "^9.14.0", + "@types/node": "^25.7.0", + "codama": "^1.7.0", + "eslint": "^9.39.2", + "eslint-plugin-jest": "^29.12.1", + "eslint-plugin-react-hooks": "^7.1.1", + "eslint-plugin-simple-import-sort": "^12.1.1", + "eslint-plugin-sort-keys-fix": "^1.1.2", + "eslint-plugin-typescript-sort-keys": "^3.3.0", + "globals": "^16.5.0", + "prettier": "^3.8.3", + "tsx": "^4.22.0", + "typescript": "^5.9.3", + "typescript-eslint": "^8.60.0" + }, + "pnpm": { + "overrides": { + "bn.js": "5.2.3", + "flatted": "3.4.2", + "minimatch": "9.0.9", + "picomatch": "4.0.4", + "rollup": "4.60.2", + "ws@^8.0.0": "8.20.1" + } + } +} diff --git a/games/world-cup/pinocchio/pnpm-lock.yaml b/games/world-cup/pinocchio/pnpm-lock.yaml new file mode 100644 index 000000000..d9507a91a --- /dev/null +++ b/games/world-cup/pinocchio/pnpm-lock.yaml @@ -0,0 +1,11770 @@ +lockfileVersion: '9.0' + +settings: + autoInstallPeers: true + excludeLinksFromLockfile: false + +overrides: + bn.js: 5.2.3 + flatted: 3.4.2 + minimatch: 9.0.9 + picomatch: 4.0.4 + rollup: 4.60.2 + ws@^8.0.0: 8.20.1 + +importers: + + .: + devDependencies: + '@codama/nodes-from-anchor': + specifier: ^1.5.0 + version: 1.5.1(typescript@5.9.3) + '@codama/renderers-js': + specifier: ^2.2.0 + version: 2.3.0(typescript@5.9.3) + '@codama/renderers-rust': + specifier: ^3.1.0 + version: 3.1.0(typescript@5.9.3) + '@eslint/js': + specifier: ^9.39.4 + version: 9.39.4 + '@solana/eslint-config-solana': + specifier: 6.0.0 + version: 6.0.0(@eslint/js@9.39.4)(@types/eslint@9.6.1)(@types/eslint__js@9.14.0)(eslint-plugin-jest@29.15.2(@typescript-eslint/eslint-plugin@8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(jest@30.4.2(@types/node@25.9.3))(typescript@5.9.3))(eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(globals@16.5.0)(jest@30.4.2(@types/node@25.9.3))(typescript-eslint@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(typescript@5.9.3) + '@solana/kit': + specifier: ^6.10.0 + version: 6.10.0(typescript@5.9.3) + '@solana/kit-plugin-rpc': + specifier: ^0.11.1 + version: 0.11.1(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana/kit-plugin-signer': + specifier: ^0.10.0 + version: 0.10.0(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana/prettier-config-solana': + specifier: ^0.0.6 + version: 0.0.6(prettier@3.8.4) + '@solana/world-cup': + specifier: workspace:* + version: link:clients/typescript + '@types/eslint': + specifier: ^9.6.1 + version: 9.6.1 + '@types/eslint__js': + specifier: ^9.14.0 + version: 9.14.0 + '@types/node': + specifier: ^25.7.0 + version: 25.9.3 + codama: + specifier: ^1.7.0 + version: 1.8.0 + eslint: + specifier: ^9.39.2 + version: 9.39.4(jiti@2.7.0) + eslint-plugin-jest: + specifier: ^29.12.1 + version: 29.15.2(@typescript-eslint/eslint-plugin@8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(jest@30.4.2(@types/node@25.9.3))(typescript@5.9.3) + eslint-plugin-react-hooks: + specifier: ^7.1.1 + version: 7.1.1(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-simple-import-sort: + specifier: ^12.1.1 + version: 12.1.1(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-sort-keys-fix: + specifier: ^1.1.2 + version: 1.1.2 + eslint-plugin-typescript-sort-keys: + specifier: ^3.3.0 + version: 3.3.0(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + globals: + specifier: ^16.5.0 + version: 16.5.0 + prettier: + specifier: ^3.8.3 + version: 3.8.4 + tsx: + specifier: ^4.22.0 + version: 4.22.4 + typescript: + specifier: ^5.9.3 + version: 5.9.3 + typescript-eslint: + specifier: ^8.60.0 + version: 8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + + clients/typescript: + dependencies: + '@solana/kit-plugin-rpc': + specifier: ^0.11.1 + version: 0.11.1(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana/kit-plugin-signer': + specifier: ^0.10.0 + version: 0.10.0(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana/program-client-core': + specifier: ^6.10.0 + version: 6.10.0(typescript@5.9.3) + devDependencies: + '@solana/kit': + specifier: ^6.10.0 + version: 6.10.0(typescript@5.9.3) + '@types/node': + specifier: ^25.7.0 + version: 25.9.3 + tsup: + specifier: ^8.3.0 + version: 8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0) + tsx: + specifier: ^4.22.0 + version: 4.22.4 + typescript: + specifier: ^5.7.0 + version: 5.9.3 + + webapp: + dependencies: + '@base-ui/react': + specifier: 1.5.0 + version: 1.5.0(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dialog': + specifier: ^1.1.4 + version: 1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-dropdown-menu': + specifier: ^2.1.4 + version: 2.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-label': + specifier: ^2.1.1 + version: 2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': + specifier: ^1.1.1 + version: 1.3.0(@types/react@19.2.17)(react@19.2.7) + '@solana-program/token': + specifier: ^0.13.0 + version: 0.13.0(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana-program/token-2022': + specifier: ^0.9.0 + version: 0.9.0(@solana/kit@6.10.0(typescript@5.9.3))(@solana/sysvars@6.10.0(typescript@5.9.3)) + '@solana/connector': + specifier: ^0.2.4 + version: 0.2.4(@solana/keychain-aws-kms@0.2.1(typescript@5.9.3))(@solana/keychain-turnkey@0.2.1(typescript@5.9.3))(@solana/keychain-vault@0.2.1(typescript@5.9.3))(react-native@0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)(typescript@5.9.3) + '@solana/design-system': + specifier: ^1.0.1 + version: 1.0.1(@base-ui/react@1.5.0(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(motion@12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@4.3.1) + '@solana/kit': + specifier: ^6.9.0 + version: 6.10.0(typescript@5.9.3) + '@solana/world-cup': + specifier: workspace:* + version: link:../clients/typescript + '@tailwindcss/postcss': + specifier: ^4.3.0 + version: 4.3.1 + '@tanstack/react-query': + specifier: ^5.101.0 + version: 5.101.0(react@19.2.7) + '@vercel/og': + specifier: ^0.11.1 + version: 0.11.1 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 + country-flag-icons: + specifier: 1.6.17 + version: 1.6.17 + jotai: + specifier: ^2.20.0 + version: 2.20.1(@babel/core@7.29.7)(@babel/template@7.29.7)(@types/react@19.2.17)(react@19.2.7) + lucide-react: + specifier: ^1.17.0 + version: 1.21.0(react@19.2.7) + motion: + specifier: ^12.40.0 + version: 12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + next-themes: + specifier: ^0.4.6 + version: 0.4.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: + specifier: ^19.2.6 + version: 19.2.7 + react-dom: + specifier: ^19.2.6 + version: 19.2.7(react@19.2.7) + react-error-boundary: + specifier: ^6.1.0 + version: 6.1.2(react@19.2.7) + react-router: + specifier: ^7.16.0 + version: 7.18.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + sonner: + specifier: ^2.0.7 + version: 2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + tailwind-merge: + specifier: ^3.6.0 + version: 3.6.0 + tw-animate-css: + specifier: ^1.3.6 + version: 1.4.0 + devDependencies: + '@types/node': + specifier: ^25.7.0 + version: 25.9.3 + '@types/react': + specifier: ^19.2.5 + version: 19.2.17 + '@types/react-dom': + specifier: ^19.2.3 + version: 19.2.3(@types/react@19.2.17) + '@vitejs/plugin-react': + specifier: ^6.0.2 + version: 6.0.2(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0)) + autoprefixer: + specifier: ^10.5.0 + version: 10.5.0(postcss@8.5.15) + playwright: + specifier: ^1.60.0 + version: 1.61.0 + postcss: + specifier: ^8.5.14 + version: 8.5.15 + tailwindcss: + specifier: ^4.3.0 + version: 4.3.1 + tsx: + specifier: ^4.22.0 + version: 4.22.4 + typescript: + specifier: ~5.9.3 + version: 5.9.3 + vite: + specifier: ^8.0.13 + version: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) + + webapp/api: + dependencies: + '@solana-program/system': + specifier: ^0.12.0 + version: 0.12.2(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana/kit': + specifier: ^6.9.0 + version: 6.10.0(typescript@5.9.3) + devDependencies: + tsx: + specifier: ^4.22.0 + version: 4.22.4 + + webapp/scripts: + dependencies: + '@solana-program/system': + specifier: latest + version: 0.12.2(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana-program/token': + specifier: latest + version: 0.14.0(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana-program/token-2022': + specifier: latest + version: 0.12.0(@solana/kit@6.10.0(typescript@5.9.3))(@solana/sysvars@6.10.0(typescript@5.9.3)) + '@solana/kit': + specifier: latest + version: 6.10.0(typescript@5.9.3) + devDependencies: + tsx: + specifier: ^4.22.0 + version: 4.22.4 + +packages: + + '@alloc/quick-lru@5.2.0': + resolution: {integrity: sha512-UrcABB+4bUrFABwbluTIBErXwvbsU/V7TZWfmbgJfbkwiBuziS9gxdODUyuiecfdGQ85jglMW6juS3+z5TsKLw==} + engines: {node: '>=10'} + + '@aws-crypto/crc32@5.2.0': + resolution: {integrity: sha512-nLbCWqQNgUiwwtFsen1AdzAtvuLRsQS8rYgMuxCrdKf9kOssamGLuPwyTY9wyYblNr9+1XM8v6zoDTPPSIeANg==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/sha256-browser@5.2.0': + resolution: {integrity: sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==} + + '@aws-crypto/sha256-js@5.2.0': + resolution: {integrity: sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==} + engines: {node: '>=16.0.0'} + + '@aws-crypto/supports-web-crypto@5.2.0': + resolution: {integrity: sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==} + + '@aws-crypto/util@5.2.0': + resolution: {integrity: sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==} + + '@aws-sdk/client-kms@3.1072.0': + resolution: {integrity: sha512-OlFNYrdhaiENzZPKC9oJsSxkKiWJiC3SxCXNe9MfsPIXgLXQrkFB9tkgTs8qugzDadK4CuGO43sf+i58bS5UNw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/core@3.974.22': + resolution: {integrity: sha512-YofH63shc6YRdXjz80BJkpJW+Bkn0Cuu2dn4Rv7s9G2Idt58tgtzQEWxrR2xVljlVfIBeUjPuULnSVYLke3sUQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-env@3.972.48': + resolution: {integrity: sha512-h6FEC95fbexUd6zxm4PdgS82bTcI2PRtUb2ZwMipb/Xr8bPwtf0G8rBo2jp7NA24Mbx2JA8/WingiYpA9RCCyw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-http@3.972.50': + resolution: {integrity: sha512-lJO3OLpjvz5m/RSBQmsG/CEUGsvCy5ruxKwPQaOCqxqCMuyYT2BZwQUTDZVVwqQ9LrZKuK24JSa6r31hL/tvkg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-ini@3.972.55': + resolution: {integrity: sha512-TBoF4buBGYhXjdZAryayY2TrkQj2B2KfE/msG4V53XCt+w0EhEwM2JRjx8p2grJ2C6gtH5++SAwEvGMRdi0yyw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-login@3.972.54': + resolution: {integrity: sha512-hBWI3wZTdTGiuMfmPts6AWbAjFfRniOQnqx68tc2cQvRKWawFbN9wkLOVPWM1FAOyowZU73mC6Fi+rHSHNyLFw==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-node@3.972.57': + resolution: {integrity: sha512-u6dClpzNdWf1HGWz4wwhdXi1wiOofCLniM9S4BQQGlLAN9TW7VB+ld5V533GdKrYMaFeBGFqKnj0JCYvynLqwQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-process@3.972.48': + resolution: {integrity: sha512-w6VZwojPt12WnEkAUy6Nu4K6sWCbBmR7QX390b0nE6vRvkXbrYr9Lq9VySGkfjiMjpUA87op+J4EgvRmtWIDoQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-sso@3.972.54': + resolution: {integrity: sha512-23uZpIpF2SIFDCa1fcWa202tK4gGeyvX6GIIAjiB8WBsvsVRBMnJ/7dCxHzxf7eZT7GToJg837LDIBnZsl/VUg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/credential-provider-web-identity@3.972.54': + resolution: {integrity: sha512-0Iv5QttS6wcATlodYKgvQj6B9Db51rx7NU9fqu0PoLeS4BIgdYMc/QK4smwLwpm5RFrs02V/eLyEFp3FklvlNQ==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/nested-clients@3.997.22': + resolution: {integrity: sha512-4IwtcYSxEIVw5hcp8ogq0CMbFNZFw7jJUetpfFUhFFeqsa1K8j2Ihg2hnxLyOp3stMZnXda6VzOmPi1AFZQXcg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/signature-v4-multi-region@3.996.35': + resolution: {integrity: sha512-6L/VWs+Wch2stHemCGTmUNqKLMzURxQDK5boNG3Jn3kAOp71meDUuS5sbObpEvFxHDq0uWeSLFDNSYsjNt+Dlg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/token-providers@3.1071.0': + resolution: {integrity: sha512-4LDW2Qob6LoLFuqYSYZq2AyTE9koSE9+i+n5UZcm10GpmQOK0zRD9L4uYlzItiTKksIWgC/qMFChAi3RvKYtMg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/types@3.973.13': + resolution: {integrity: sha512-pEHZqRkAlHfnfAU9tK+WpKv/gBNjGJrHMgA3A0iYRGyswBS2t0pfez+lWlwktb3Bqa0ovh7w/QJTFwp3fDxLNg==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/util-locate-window@3.965.8': + resolution: {integrity: sha512-uUbMs1cBZPafD0ohUj6EwNf0fPZ534NvBxHox4hjX+0Rxq5paSYUem7+hi833pYrzrcnBATKIYpR02MDXT5M9g==} + engines: {node: '>=20.0.0'} + + '@aws-sdk/xml-builder@3.972.30': + resolution: {integrity: sha512-StElZPEoBquWwNqw1AcfpzEyZqJvFxouG+mpDNYlcH6ZOrqd2CuIryv+8LV8gNHZUOyKyJF3Dq9vxaXEmDR9TQ==} + engines: {node: '>=20.0.0'} + + '@aws/lambda-invoke-store@0.2.4': + resolution: {integrity: sha512-iY8yvjE0y651BixKNPgmv1WrQc+GZ142sb0z4gYnChDDY2YqI4P/jsSopBWrKfAt7LOJAkOXt7rC/hms+WclQQ==} + engines: {node: '>=18.0.0'} + + '@babel/code-frame@7.29.7': + resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} + engines: {node: '>=6.9.0'} + + '@babel/compat-data@7.29.7': + resolution: {integrity: sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==} + engines: {node: '>=6.9.0'} + + '@babel/core@7.29.7': + resolution: {integrity: sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==} + engines: {node: '>=6.9.0'} + + '@babel/generator@7.29.7': + resolution: {integrity: sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ==} + engines: {node: '>=6.9.0'} + + '@babel/helper-compilation-targets@7.29.7': + resolution: {integrity: sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-globals@7.29.7': + resolution: {integrity: sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-imports@7.29.7': + resolution: {integrity: sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==} + engines: {node: '>=6.9.0'} + + '@babel/helper-module-transforms@7.29.7': + resolution: {integrity: sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + + '@babel/helper-plugin-utils@7.29.7': + resolution: {integrity: sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-string-parser@7.29.7': + resolution: {integrity: sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-identifier@7.29.7': + resolution: {integrity: sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==} + engines: {node: '>=6.9.0'} + + '@babel/helper-validator-option@7.29.7': + resolution: {integrity: sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==} + engines: {node: '>=6.9.0'} + + '@babel/helpers@7.29.7': + resolution: {integrity: sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==} + engines: {node: '>=6.9.0'} + + '@babel/parser@7.29.7': + resolution: {integrity: sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg==} + engines: {node: '>=6.0.0'} + hasBin: true + + '@babel/plugin-syntax-async-generators@7.8.4': + resolution: {integrity: sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-bigint@7.8.3': + resolution: {integrity: sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-properties@7.12.13': + resolution: {integrity: sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-class-static-block@7.14.5': + resolution: {integrity: sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-attributes@7.29.7': + resolution: {integrity: sha512-zGYcYfq/WmZ4V+kBIXQon9dSSc8ircGZqw9ZaNhhGj9nZkeBu1jHLBDQqYYi5WA9uawvA2sIMbry2nCFhf5Djg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-import-meta@7.10.4': + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-json-strings@7.8.3': + resolution: {integrity: sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-jsx@7.29.7': + resolution: {integrity: sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4': + resolution: {integrity: sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3': + resolution: {integrity: sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-numeric-separator@7.10.4': + resolution: {integrity: sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-object-rest-spread@7.8.3': + resolution: {integrity: sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3': + resolution: {integrity: sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-optional-chaining@7.8.3': + resolution: {integrity: sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-private-property-in-object@7.14.5': + resolution: {integrity: sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-top-level-await@7.14.5': + resolution: {integrity: sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/plugin-syntax-typescript@7.29.7': + resolution: {integrity: sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + + '@babel/runtime@7.29.7': + resolution: {integrity: sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==} + engines: {node: '>=6.9.0'} + + '@babel/template@7.29.7': + resolution: {integrity: sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==} + engines: {node: '>=6.9.0'} + + '@babel/traverse@7.29.7': + resolution: {integrity: sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw==} + engines: {node: '>=6.9.0'} + + '@babel/types@7.29.7': + resolution: {integrity: sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA==} + engines: {node: '>=6.9.0'} + + '@base-ui/react@1.5.0': + resolution: {integrity: sha512-z1gSAlced1yY+iM+mHDEtIkD8UI3Ebs52MuBPxvV6f5hRutk+xvCH/wuB7hDqDzK9JG5FoMz5nhrqtSs1wjt1A==} + engines: {node: '>=14.0.0'} + peerDependencies: + '@date-fns/tz': ^1.2.0 + '@types/react': ^17 || ^18 || ^19 + date-fns: ^4.0.0 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@date-fns/tz': + optional: true + '@types/react': + optional: true + date-fns: + optional: true + + '@base-ui/utils@0.2.9': + resolution: {integrity: sha512-x/PDDCYzoqPpjrdyb3VcyylTI2IjUXEtYDGi5foh7KsnmNJIIaVwA2GLgDH1dps1GgXiJbA60hM+AyuTfQzIvw==} + peerDependencies: + '@types/react': ^17 || ^18 || ^19 + react: ^17 || ^18 || ^19 + react-dom: ^17 || ^18 || ^19 + peerDependenciesMeta: + '@types/react': + optional: true + + '@bcoe/v8-coverage@0.2.3': + resolution: {integrity: sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==} + + '@codama/cli@1.5.3': + resolution: {integrity: sha512-RgLwZ24sGkPDwaH3DovOY3e1VXPnPwDBXojYXyOzPmEjQ23yTKacrLa3Zlt/XjMsXv9cLOym5OheC+gG6GxIpg==} + hasBin: true + + '@codama/errors@1.8.0': + resolution: {integrity: sha512-A0FNhbfS1PBSK0nS+g65IR8+OKkifuIJCCnLCUBXb+I/OYMGlJMycMpU4pwAEEGS5GAnue7D/llXE+KpUaMi8w==} + hasBin: true + + '@codama/fragments@0.1.1': + resolution: {integrity: sha512-+DeC2YklyYf+qjRkoTKeG6HFgwsW7hiQko7er18dgsxF15M316EwYL2W40nKDPWlEhB/iME+sZR5++VQPUO/6w==} + + '@codama/node-types@1.8.0': + resolution: {integrity: sha512-KE9K9jjEdeFKtDKRrjjm5YwEkg7l+YwoWiH2w1UXJL/x6P5uul6+O5WnGsJn8IFtBVSLN4hbD7YSsZ0/lktJxQ==} + + '@codama/nodes-from-anchor@1.5.1': + resolution: {integrity: sha512-AQee53GV/OY+jJE4PsORPoSagFwGMul1cpSBYhKzvxcrJg1xBesiblPqweNDVIW3NyskHB+x1kQpuq6bsJdb+w==} + + '@codama/nodes@1.8.0': + resolution: {integrity: sha512-rl+7BxYatAE6uq5h9b5fEilGLd3YeJaJxqgLDAvdKQ5pspq6ch5ww9NiigkwdvDYli1Yk56PRhMZdLsiZIVgAA==} + + '@codama/renderers-core@1.3.9': + resolution: {integrity: sha512-DwMxltM+cldAK+rgtE3jVOmrGZuP7fA/ZLu6vgrsQYBp5dkOXCyiGBdpAz0VlhxaN4lB5TzT2Ia+EVv5G4YdGQ==} + + '@codama/renderers-js@2.3.0': + resolution: {integrity: sha512-PSvoLATBx7EomzZgCXegPTn5TxaFjA+NIraNUx22vNZ6rxPxu5Tctq8KxeXaaPCnKLpBUKcwmhUPRO4QLNQlvg==} + engines: {node: '>=20.18.0'} + + '@codama/renderers-rust@3.1.0': + resolution: {integrity: sha512-E/GSUCuiIpFj+ij3NbduH/h3sNDo39Bq14vj2atxdbbrPmu4clWvIEjXtbmP03qhudH73TxbYO8dWg/NwRi18A==} + engines: {node: '>=20.18.0'} + + '@codama/validators@1.8.0': + resolution: {integrity: sha512-gDmS85DwWmT41+PWTlbBrkSopGKW4UPhEcX+SLb2fF/uXMpJQXcgLE8BE9Fr7/DO+M9yFtGOVrnfDSCwepORGg==} + + '@codama/visitors-core@1.8.0': + resolution: {integrity: sha512-CLO0icVvzAutjI7imuN1Rib0/GIBc7hhwQ5gcE3aVAVBHUNS4M27BzagqYTpL0cMC9I1tL9c6lhpCBV2kKs6Zg==} + + '@codama/visitors@1.8.0': + resolution: {integrity: sha512-vQ863YkHBdLWZeaiPKisiRe0bbuBEBe9xDWVcLCCLRsmKCQuS+GB4bKxIwrlTr9cxCOGyQLkI7B/yAqyYEdbmw==} + + '@emnapi/core@1.10.0': + resolution: {integrity: sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==} + + '@emnapi/runtime@1.10.0': + resolution: {integrity: sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==} + + '@emnapi/wasi-threads@1.2.1': + resolution: {integrity: sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==} + + '@esbuild/aix-ppc64@0.27.7': + resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + + '@esbuild/android-arm64@0.27.7': + resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + + '@esbuild/android-arm@0.27.7': + resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + + '@esbuild/android-x64@0.27.7': + resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + + '@esbuild/darwin-arm64@0.27.7': + resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + + '@esbuild/darwin-x64@0.27.7': + resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + + '@esbuild/freebsd-arm64@0.27.7': + resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.27.7': + resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + + '@esbuild/linux-arm64@0.27.7': + resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + + '@esbuild/linux-arm@0.27.7': + resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + + '@esbuild/linux-ia32@0.27.7': + resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + + '@esbuild/linux-loong64@0.27.7': + resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + + '@esbuild/linux-mips64el@0.27.7': + resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + + '@esbuild/linux-ppc64@0.27.7': + resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + + '@esbuild/linux-riscv64@0.27.7': + resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + + '@esbuild/linux-s390x@0.27.7': + resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + + '@esbuild/linux-x64@0.27.7': + resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + + '@esbuild/netbsd-arm64@0.27.7': + resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.27.7': + resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + + '@esbuild/openbsd-arm64@0.27.7': + resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.27.7': + resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + + '@esbuild/openharmony-arm64@0.27.7': + resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + + '@esbuild/sunos-x64@0.27.7': + resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + + '@esbuild/win32-arm64@0.27.7': + resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + + '@esbuild/win32-ia32@0.27.7': + resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + + '@esbuild/win32-x64@0.27.7': + resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + + '@eslint-community/eslint-utils@4.9.1': + resolution: {integrity: sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 + + '@eslint-community/regexpp@4.12.2': + resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} + engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} + + '@eslint/config-array@0.21.2': + resolution: {integrity: sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/config-helpers@0.4.2': + resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/core@0.17.0': + resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/eslintrc@3.3.5': + resolution: {integrity: sha512-4IlJx0X0qftVsN5E+/vGujTRIFtwuLbNsVUe7TO6zYPDR1O6nFwvwhIKEKSrl6dZchmYBITazxKoUYOjdtjlRg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/js@9.39.4': + resolution: {integrity: sha512-nE7DEIchvtiFTwBw4Lfbu59PG+kCofhjsKaCWzxTpt4lfRjRMqG6uMBzKXuEcyXhOHoUp9riAm7/aWYGhXZ9cw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/object-schema@2.1.7': + resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@eslint/plugin-kit@0.4.1': + resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@floating-ui/core@1.7.5': + resolution: {integrity: sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==} + + '@floating-ui/dom@1.7.6': + resolution: {integrity: sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==} + + '@floating-ui/react-dom@2.1.8': + resolution: {integrity: sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==} + peerDependencies: + react: '>=16.8.0' + react-dom: '>=16.8.0' + + '@floating-ui/utils@0.2.11': + resolution: {integrity: sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==} + + '@heroicons/react@2.2.0': + resolution: {integrity: sha512-LMcepvRaS9LYHJGsF0zzmgKCUim/X3N/DQKc4jepAXJ7l8QxJ1PmxJzqplF2Z3FE4PqBAIGyJAQ/w4B5dsqbtQ==} + peerDependencies: + react: '>= 16 || ^19.0.0-rc' + + '@humanfs/core@0.19.2': + resolution: {integrity: sha512-UhXNm+CFMWcbChXywFwkmhqjs3PRCmcSa/hfBgLIb7oQ5HNb1wS0icWsGtSAUNgefHeI+eBrA8I1fxmbHsGdvA==} + engines: {node: '>=18.18.0'} + + '@humanfs/node@0.16.8': + resolution: {integrity: sha512-gE1eQNZ3R++kTzFUpdGlpmy8kDZD/MLyHqDwqjkVQI0JMdI1D51sy1H958PNXYkM2rAac7e5/CnIKZrHtPh3BQ==} + engines: {node: '>=18.18.0'} + + '@humanfs/types@0.15.0': + resolution: {integrity: sha512-ZZ1w0aoQkwuUuC7Yf+7sdeaNfqQiiLcSRbfI08oAxqLtpXQr9AIVX7Ay7HLDuiLYAaFPu8oBYNq/QIi9URHJ3Q==} + engines: {node: '>=18.18.0'} + + '@humanwhocodes/module-importer@1.0.1': + resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} + engines: {node: '>=12.22'} + + '@humanwhocodes/retry@0.4.3': + resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} + engines: {node: '>=18.18'} + + '@iarna/toml@2.2.5': + resolution: {integrity: sha512-trnsAYxU3xnS1gPHPyU961coFyLkh4gAD/0zQ5mymY4yOZ+CYvsPqUbOFSw0aDM4y0tV7tiFxL/1XfXPNC6IPg==} + + '@img/colour@1.1.0': + resolution: {integrity: sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==} + engines: {node: '>=18'} + + '@img/sharp-darwin-arm64@0.34.5': + resolution: {integrity: sha512-imtQ3WMJXbMY4fxb/Ndp6HBTNVtWCUI0WdobyheGf5+ad6xX8VIDO8u2xE4qc/fr08CKG/7dDseFtn6M6g/r3w==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [darwin] + + '@img/sharp-darwin-x64@0.34.5': + resolution: {integrity: sha512-YNEFAF/4KQ/PeW0N+r+aVVsoIY0/qxxikF2SWdp+NRkmMB7y9LBZAVqQ4yhGCm/H3H270OSykqmQMKLBhBJDEw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-darwin-arm64@1.2.4': + resolution: {integrity: sha512-zqjjo7RatFfFoP0MkQ51jfuFZBnVE2pRiaydKJ1G/rHZvnsrHAOcQALIi9sA5co5xenQdTugCvtb1cuf78Vf4g==} + cpu: [arm64] + os: [darwin] + + '@img/sharp-libvips-darwin-x64@1.2.4': + resolution: {integrity: sha512-1IOd5xfVhlGwX+zXv2N93k0yMONvUlANylbJw1eTah8K/Jtpi15KC+WSiaX/nBmbm2HxRM1gZ0nSdjSsrZbGKg==} + cpu: [x64] + os: [darwin] + + '@img/sharp-libvips-linux-arm64@1.2.4': + resolution: {integrity: sha512-excjX8DfsIcJ10x1Kzr4RcWe1edC9PquDRRPx3YVCvQv+U5p7Yin2s32ftzikXojb1PIFc/9Mt28/y+iRklkrw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linux-arm@1.2.4': + resolution: {integrity: sha512-bFI7xcKFELdiNCVov8e44Ia4u2byA+l3XtsAj+Q8tfCwO6BQ8iDojYdvoPMqsKDkuoOo+X6HZA0s0q11ANMQ8A==} + cpu: [arm] + os: [linux] + + '@img/sharp-libvips-linux-ppc64@1.2.4': + resolution: {integrity: sha512-FMuvGijLDYG6lW+b/UvyilUWu5Ayu+3r2d1S8notiGCIyYU/76eig1UfMmkZ7vwgOrzKzlQbFSuQfgm7GYUPpA==} + cpu: [ppc64] + os: [linux] + + '@img/sharp-libvips-linux-riscv64@1.2.4': + resolution: {integrity: sha512-oVDbcR4zUC0ce82teubSm+x6ETixtKZBh/qbREIOcI3cULzDyb18Sr/Wcyx7NRQeQzOiHTNbZFF1UwPS2scyGA==} + cpu: [riscv64] + os: [linux] + + '@img/sharp-libvips-linux-s390x@1.2.4': + resolution: {integrity: sha512-qmp9VrzgPgMoGZyPvrQHqk02uyjA0/QrTO26Tqk6l4ZV0MPWIW6LTkqOIov+J1yEu7MbFQaDpwdwJKhbJvuRxQ==} + cpu: [s390x] + os: [linux] + + '@img/sharp-libvips-linux-x64@1.2.4': + resolution: {integrity: sha512-tJxiiLsmHc9Ax1bz3oaOYBURTXGIRDODBqhveVHonrHJ9/+k89qbLl0bcJns+e4t4rvaNBxaEZsFtSfAdquPrw==} + cpu: [x64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + resolution: {integrity: sha512-FVQHuwx1IIuNow9QAbYUzJ+En8KcVm9Lk5+uGUQJHaZmMECZmOlix9HnH7n1TRkXMS0pGxIJokIVB9SuqZGGXw==} + cpu: [arm64] + os: [linux] + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + resolution: {integrity: sha512-+LpyBk7L44ZIXwz/VYfglaX/okxezESc6UxDSoyo2Ks6Jxc4Y7sGjpgU9s4PMgqgjj1gZCylTieNamqA1MF7Dg==} + cpu: [x64] + os: [linux] + + '@img/sharp-linux-arm64@0.34.5': + resolution: {integrity: sha512-bKQzaJRY/bkPOXyKx5EVup7qkaojECG6NLYswgktOZjaXecSAeCWiZwwiFf3/Y+O1HrauiE3FVsGxFg8c24rZg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linux-arm@0.34.5': + resolution: {integrity: sha512-9dLqsvwtg1uuXBGZKsxem9595+ujv0sJ6Vi8wcTANSFpwV/GONat5eCkzQo/1O6zRIkh0m/8+5BjrRr7jDUSZw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm] + os: [linux] + + '@img/sharp-linux-ppc64@0.34.5': + resolution: {integrity: sha512-7zznwNaqW6YtsfrGGDA6BRkISKAAE1Jo0QdpNYXNMHu2+0dTrPflTLNkpc8l7MUP5M16ZJcUvysVWWrMefZquA==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ppc64] + os: [linux] + + '@img/sharp-linux-riscv64@0.34.5': + resolution: {integrity: sha512-51gJuLPTKa7piYPaVs8GmByo7/U7/7TZOq+cnXJIHZKavIRHAP77e3N2HEl3dgiqdD/w0yUfiJnII77PuDDFdw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [riscv64] + os: [linux] + + '@img/sharp-linux-s390x@0.34.5': + resolution: {integrity: sha512-nQtCk0PdKfho3eC5MrbQoigJ2gd1CgddUMkabUj+rBevs8tZ2cULOx46E7oyX+04WGfABgIwmMC0VqieTiR4jg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [s390x] + os: [linux] + + '@img/sharp-linux-x64@0.34.5': + resolution: {integrity: sha512-MEzd8HPKxVxVenwAa+JRPwEC7QFjoPWuS5NZnBt6B3pu7EG2Ge0id1oLHZpPJdn3OQK+BQDiw9zStiHBTJQQQQ==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-linuxmusl-arm64@0.34.5': + resolution: {integrity: sha512-fprJR6GtRsMt6Kyfq44IsChVZeGN97gTD331weR1ex1c1rypDEABN6Tm2xa1wE6lYb5DdEnk03NZPqA7Id21yg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [linux] + + '@img/sharp-linuxmusl-x64@0.34.5': + resolution: {integrity: sha512-Jg8wNT1MUzIvhBFxViqrEhWDGzqymo3sV7z7ZsaWbZNDLXRJZoRGrjulp60YYtV4wfY8VIKcWidjojlLcWrd8Q==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [linux] + + '@img/sharp-wasm32@0.34.5': + resolution: {integrity: sha512-OdWTEiVkY2PHwqkbBI8frFxQQFekHaSSkUIJkwzclWZe64O1X4UlUjqqqLaPbUpMOQk6FBu/HtlGXNblIs0huw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [wasm32] + + '@img/sharp-win32-arm64@0.34.5': + resolution: {integrity: sha512-WQ3AgWCWYSb2yt+IG8mnC6Jdk9Whs7O0gxphblsLvdhSpSTtmu69ZG1Gkb6NuvxsNACwiPV6cNSZNzt0KPsw7g==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [arm64] + os: [win32] + + '@img/sharp-win32-ia32@0.34.5': + resolution: {integrity: sha512-FV9m/7NmeCmSHDD5j4+4pNI8Cp3aW+JvLoXcTUo0IqyjSfAZJ8dIUmijx1qaJsIiU+Hosw6xM5KijAWRJCSgNg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [ia32] + os: [win32] + + '@img/sharp-win32-x64@0.34.5': + resolution: {integrity: sha512-+29YMsqY2/9eFEiW93eqWnuLcWcufowXewwSNIT6UwZdUUCrM3oFjMWH/Z6/TMmb4hlFenmfAVbpWeup2jryCw==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + cpu: [x64] + os: [win32] + + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@isaacs/ttlcache@1.4.1': + resolution: {integrity: sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==} + engines: {node: '>=12'} + + '@istanbuljs/load-nyc-config@1.1.0': + resolution: {integrity: sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==} + engines: {node: '>=8'} + + '@istanbuljs/schema@0.1.6': + resolution: {integrity: sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==} + engines: {node: '>=8'} + + '@jest/console@30.4.1': + resolution: {integrity: sha512-v3bhyxUh9Hgmo5p6hAOXe14/R3ZxZDOsvHleh4B07z3m/x4/ngPUXEm9XwK4sF4u+f+P2ORb0Ge+MgpaqRMVDA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/core@30.4.2': + resolution: {integrity: sha512-TZJA6cPJUFxoWhxaLo8t0VX/MZX2wPWr0uIDvLSHIvN4gu9h02vSzqI2kBADG1ExqQlC+cY09xKMSreivvrChQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/diff-sequences@30.4.0': + resolution: {integrity: sha512-zOpzlfUs45l6u7jm39qr87JCHUDsaeCtvL+kQe/Vn9jSnRB4/5IPXISm0h9I1vZW/o00Kn4UTJ2MOlhnUGwv3g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/environment@30.4.1': + resolution: {integrity: sha512-AK9yNRqgKxiabqMoe4oW+3/TSSeV8vkdC7BGaxZdU0AFXfOpofTLqdru2GXKZghP3sdgwE9XXpnVwfZ8JnFV4w==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect-utils@30.4.1': + resolution: {integrity: sha512-ZBn5CglH8fBsQsvs4VWNzD4aWfUYks+IdOOQU3MEK71ol/BcVm+P+rtb1KpiFBpSWSCE27uOahyyf1vfqOVbcQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/expect@30.4.1': + resolution: {integrity: sha512-ginrj6TMgh2GshLUGCjO94Ptx9HhdZA/I6A9iUfyeLKFtdAjnKzHDgzgP9HYQgbxM1lbXScQ2eUBz2lGeVDPWA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/fake-timers@30.4.1': + resolution: {integrity: sha512-iW5umdmfPeWzehrVhugFQZqCchSCud5S1l2YT0O9ZhjRR0ExclANDZkiSBwzqtnlOn0J1JXvO+HZ6rkuyOVOgQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/get-type@30.1.0': + resolution: {integrity: sha512-eMbZE2hUnx1WV0pmURZY9XoXPkUYjpc55mb0CrhtdWLtzMQPFvu/rZkTLZFTsdaVQa+Tr4eWAteqcUzoawq/uA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/globals@30.4.1': + resolution: {integrity: sha512-ZbuY4cmXC8DkxYjfvT2DbcHWL2T6vmsMhXCDcmTB2T0y0gaezBI77ufq5ZAIdcRkYZ7NEQEDg1xFeKbxUJ5v5Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/pattern@30.4.0': + resolution: {integrity: sha512-RAWn3+f9u8BsHijKJ71uHcFp6vmyEt6VvoWXkl6hKF3qVIuWNmudVjg12DlBPGup/frIl5UcUlH5HfEuvHpEXg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/reporters@30.4.1': + resolution: {integrity: sha512-/SnkPCzEQpUaBH81kjdEdDdo2WZl5hxw+BmLDGWjRkm8o7XlhjwsU36cqwe5PGBE5WYpBvDzRSdXx9rbGuJtNA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + '@jest/schemas@29.6.3': + resolution: {integrity: sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/schemas@30.4.1': + resolution: {integrity: sha512-i6b4qw5qnP8c5FEeBJg/uZQ4ddrkN6Ca8qISJh0pr7a5hfn3h3v5x60BEbOC7OYAGZNMs1LfFLwnW2CuK8F57Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/snapshot-utils@30.4.1': + resolution: {integrity: sha512-ObY4ljvQ95mt6iwKtVLetR/4yXiAgl3H4nJxhztr0MTjrN97TwDYrnCp/kF60Ec9HdhkWTHSu+Hg05aXfngpOA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/source-map@30.0.1': + resolution: {integrity: sha512-MIRWMUUR3sdbP36oyNyhbThLHyJ2eEDClPCiHVbrYAe5g3CHRArIVpBw7cdSB5fr+ofSfIb2Tnsw8iEHL0PYQg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-result@30.4.1': + resolution: {integrity: sha512-/ZG7pgEiOmmWkN9TplKbOu4id2N5lh7FHwRwlkgBVAzGdRH+OkkQ8wX/kIxg4zmd3ZQvAL1RwL2yWsvNYYECTw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/test-sequencer@30.4.1': + resolution: {integrity: sha512-PeYE+4td5rKjoRPxztObrXU+H8hsjZfxKMXOcmrr34JerSyB/ROOxbbicz8B7A5j9R9VayDnVPvBmedqCsFCdw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/transform@30.4.1': + resolution: {integrity: sha512-Wz0LyktlTvRefoymh+n64hQ84KNXsRGcwdoZ8CSa0Ea+fgYcHZlnk+hDP7v2MS7il2bQ5uTEIxf4/NNfhMN4KQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jest/types@29.6.3': + resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + '@jest/types@30.4.1': + resolution: {integrity: sha512-f1x/vJXIfjOlEmejYpbkbgw1gOqpPECwMvMEtBqe47j7H2Hg8h8w3o3ikhSXq3MI15kg+oQ0exWO0uCtTNJLoQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + '@jridgewell/gen-mapping@0.3.13': + resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} + + '@jridgewell/remapping@2.3.5': + resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} + + '@jridgewell/resolve-uri@3.1.2': + resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} + engines: {node: '>=6.0.0'} + + '@jridgewell/source-map@0.3.11': + resolution: {integrity: sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==} + + '@jridgewell/sourcemap-codec@1.5.5': + resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} + + '@jridgewell/trace-mapping@0.3.31': + resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} + + '@nanostores/persistent@1.1.0': + resolution: {integrity: sha512-e6vfv7H99VkCfSoNTR/qNVMj6vXwWcsEL+LCQQamej5GK9iDefKxPCJjdOpBi1p4lNCFIQ+9VjYF1spvvc2p6A==} + engines: {node: ^20.0.0 || >=22.0.0} + peerDependencies: + nanostores: ^0.9.0 || ^0.10.0 || ^0.11.0 || ^1.0.0 + + '@napi-rs/wasm-runtime@1.1.5': + resolution: {integrity: sha512-AWPoBRJ9tsnVhor4sjO7rkni+7p+2IAEFj6cx06UgP10jkQHqay/36uRV/bFkgrh18D9vb4cr8Q0Pthskgzy+Q==} + peerDependencies: + '@emnapi/core': ^1.7.1 + '@emnapi/runtime': ^1.7.1 + + '@noble/curves@1.9.7': + resolution: {integrity: sha512-gbKGcRUYIjA3/zCCNaWDciTMFI0dCkvou3TL8Zmy5Nc7sJ47a0jtOeZoTaMxkuqRo9cRhjOdZJXegxYE5FN/xw==} + engines: {node: ^14.21.3 || >=16} + + '@noble/curves@2.2.0': + resolution: {integrity: sha512-T/BoHgFXirb0ENSPBquzX0rcjXeM6Lo892a2jlYJkqk83LqZx0l1Of7DzlKJ6jkpvMrkHSnAcgb5JegL8SeIkQ==} + engines: {node: '>= 20.19.0'} + + '@noble/ed25519@3.1.0': + resolution: {integrity: sha512-pfcObRY3CtvwfaG9Mt5XqZdKmAQppl37tHUeuBhDUbiwJBCVY4/A4lbMvb1xKhMDx96AqAqZpMWuBX1HulhX4g==} + + '@noble/hashes@1.8.0': + resolution: {integrity: sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==} + engines: {node: ^14.21.3 || >=16} + + '@noble/hashes@2.2.0': + resolution: {integrity: sha512-IYqDGiTXab6FniAgnSdZwgWbomxpy9FtYvLKs7wCUs2a8RkITG+DFGO1DM9cr+E3/RgADRpFjrKVaJ1z6sjtEg==} + engines: {node: '>= 20.19.0'} + + '@nodable/entities@2.2.0': + resolution: {integrity: sha512-9uGyhaQavEUMC8AIddIjau4NsnsXhou+j5sBAGojCM1oxmQpVKTWR/9JxABD6UAv12vpIms55fPZKFQEhG6uBg==} + + '@nodelib/fs.scandir@2.1.5': + resolution: {integrity: sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==} + engines: {node: '>= 8'} + + '@nodelib/fs.stat@2.0.5': + resolution: {integrity: sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==} + engines: {node: '>= 8'} + + '@nodelib/fs.walk@1.2.8': + resolution: {integrity: sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==} + engines: {node: '>= 8'} + + '@oxc-project/types@0.133.0': + resolution: {integrity: sha512-KzkdCd6Uxqnf6l3HOw1xfatAlUURA0g14cvBYFyJ5SaNOQbOUvBr9PKArcPcrNIeRsBdgcUzOGrhKveVpvOIGA==} + + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@pkgr/core@0.3.6': + resolution: {integrity: sha512-SEeaJLb3qBNF/OaXnaR1NmmBbFYk1zC0ZH/52fATcRPLFg/p791YrcyFFy44Bo9sLaGuSuLp5Q6axbb/O+v/RA==} + engines: {node: ^14.18.0 || >=16.0.0} + + '@radix-ui/primitive@1.1.4': + resolution: {integrity: sha512-7AdCK9PQyiljKoBDbN8OuctCbd/esdwZPQ8RtOE3SsyQtUpiPb+ND75q0jEhC1m1ecBI0MFNeLJvwIh9iKHRcQ==} + + '@radix-ui/react-arrow@1.1.10': + resolution: {integrity: sha512-j2VTDz1vgCsmuG0k5lBfOcM8n5JPFqZBcMryasFjHYMhwxYL5SRUV5lMSUpRdNtw3D/Sv8pzJtrlAgkssYSsQQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-collection@1.1.10': + resolution: {integrity: sha512-IVVz4EvBcKjrzKgof714qDnz/SzQAkLA2Emh5edlHbgcE6fNd3Un6CJLlaYcnm8N4JmAtzQgse4dOKxcD2yc9g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-compose-refs@1.1.3': + resolution: {integrity: sha512-rYOP8OMnuuPMQF1uhPVlGNcCDlkokKqGFE3JcxFViIkAXP7EvFWUliJAstrapypaBLJNHbZL6jGhbVDGTwmVhA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-context@1.1.4': + resolution: {integrity: sha512-QwH4PO5urrbO+FaGd5Aglg+YJgWTyyuZ3g/6mKvsqraLkglDdckw9JafgL5McL5VEJ6EPNduPaT3ZE9BttDAqg==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dialog@1.1.17': + resolution: {integrity: sha512-TDTYmpdq8dI2+Xgvgj9AJ8Ghqq+Eph/TRVEdaFQPDItIY+6QSkU7MJMeevw1568Yw/2Ijz8BTphPSP2XejKphw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-direction@1.1.2': + resolution: {integrity: sha512-C3vFhbyi4SW3PmbAi6Awpu4OzJtd0MxGurvSsYtr7p7nM8RNB3VAF3CUmnp2j50knpkrRcB7+ycVXzgLgF6yNA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-dismissable-layer@1.1.13': + resolution: {integrity: sha512-2v+zNAWWe0ySxgC0D0yeXMPQ23xZVgXZTerTz+JKlmdRj6gfTqmCcR29jb6d290DezXPGgruHWDX/vYUebtErg==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-dropdown-menu@2.1.18': + resolution: {integrity: sha512-PZGV82gFk0WltDRI//SsG28ZIjlo9ANTmoNYg0jLNzXXiDsAy5PkOOYQaVD1pPxY6t7gxffb1QMD6qaUvsBZdw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-focus-guards@1.1.4': + resolution: {integrity: sha512-cot/aB/mOm0IYVYTTmQcEEK1M48lZWi8FlYe5nDPQQ8NYZUlXEFgncJ9p2Kzer3RKSrY7cTTpEMLZKNo9QoP5Q==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-focus-scope@1.1.10': + resolution: {integrity: sha512-Fas/lXQqhVvqwAb64s5RFeHiHYElZ6SUQbZaNd6EkfhP/Al7wTIQ9WIR4QVX475tlu5yFCEdDcJH6/UwsZjMWw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-id@1.1.2': + resolution: {integrity: sha512-orBC88futVpqCmhX1p4cvquNHsELQ+w+vBJnuj3ftETI5bJb0bZn3Tqu3SWN2IOcPycTnMGnhwoermvISt72sA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-label@2.1.10': + resolution: {integrity: sha512-ib0zvq2ZsAqKm5tRnqGJn3vOxSgIts5ToxsXT0q1S/GfLD1Zj7UOEnkw8u2w6sRmn47djpQWuSU1DCL1R29/yw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-menu@2.1.18': + resolution: {integrity: sha512-lj8Rxjtn6zJq1oSbE/uDtAwCbB9BnxgHD+8MwJMuTh6u1dPamYhW9iuELr/Z8d0D/UysFblYYHeBPwi7T4k0YQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-popper@1.3.1': + resolution: {integrity: sha512-bhnq/0DEPTi2lsOD3J5rTL65qUKHbKbhqHsmN9TMiclSXpipi651ooUKPPp6G5lF/WiHBdn1s0Wuqsn+myVAvw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-portal@1.1.12': + resolution: {integrity: sha512-m309havGzsjLHHaIX50G5PlvRs3xkgPCsGk/5PTvYm8D5q33yG0J7w/712PTOhid7NTaFETtnSXjngHQavvhVw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-presence@1.1.6': + resolution: {integrity: sha512-zdTk4PlUO0E18HnZ3wYbW0KkJJxWCdiNYp6g6X1PtONFhxVkg01vliTJAmwIszU6mHiyBOoW9P0rAugl5/hULQ==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-primitive@2.1.6': + resolution: {integrity: sha512-wetd0QI77DbvrPpTAvH1SqOxsYF2wZe5TNxqwOd5Ty4XDpV3dpV0s8K/1MGMJBeY5o7lg8ub5VIt1Ub+yVen6g==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-roving-focus@1.1.13': + resolution: {integrity: sha512-9gkwneI0guf8JDmrFxPjJF6Ozzgioyw+/lonYNCwefS9ZHA05er0BVHiXr+LbWGHxUfczvMY6G1oiZZi1VzjRw==} + peerDependencies: + '@types/react': '*' + '@types/react-dom': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@types/react-dom': + optional: true + + '@radix-ui/react-slot@1.3.0': + resolution: {integrity: sha512-MojKku4U/miO8Av4Dkb+ctMAQx7JmY96LmtDQlAarCRtd7rN52QCSzBF+XAvr5S6coSVj9HEPBgHAHKEJVk/WA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-callback-ref@1.1.2': + resolution: {integrity: sha512-xCso9j1/u8sEgP1RNHjFrXJLApL8LiqOkI1R4ywuN00rxWdYg4oQXuwKLS3i0j5NWLromUD27/4nlxj2UFVvIw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-controllable-state@1.2.3': + resolution: {integrity: sha512-PLzC90MS+ReootmjC597dvopoelpZ8Q61HJkDXZSExitIq7PL55vHNnesAHwguHK0aPfBnpdNzQtv1uliaqQrA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-effect-event@0.0.3': + resolution: {integrity: sha512-6c8ZqvPTWILEKnyVkP53EGRCcpnJiKTC21sS/6R1GF5xKyHJJWQEPfkqlcgUkdRQivd6tb23abUwe4ngWmY0JA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-escape-keydown@1.1.2': + resolution: {integrity: sha512-2uVLvLjgO7NZCWw01/FdqRwmA42J0BcjPMUCA+koFEOAb+zjqIP7SiFz/7zWPrKnVmSqr76Omq2ALyCuX4dhLw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-layout-effect@1.1.2': + resolution: {integrity: sha512-jrBWOxZITuGcnjRCM2t2U5ZPkCLxD+Ym6DjfssS5haTj2iiak/DOb64JeN6OdLfLgptb6/e2kKR+ZuTrGoZTPA==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-rect@1.1.2': + resolution: {integrity: sha512-d8a+bBY/FxikNPlgJJoaBHZX+zKVbWHYJGTLnLvveQgFSTntkGdEKv3JDtHrMS0DNYpllz2nRsTLGLKYttbpmw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-use-size@1.1.2': + resolution: {integrity: sha512-giWQp+4mxjBPt4KZ0MmyuykFNWfbDxKt4x+fPkRYmgRFJSbCZFzUglvMb/Kjn38tm10YP4ufiQZDx3zna4LU6w==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/rect@1.1.2': + resolution: {integrity: sha512-xnXE7wG13PI+cxieVssYXlQJuYVRhH9NBoxt3KNwzghDIA69GMm7d4wXRouHIYjE+KvS6U/MsMO73NdS2MH9ZA==} + + '@react-native/assets-registry@0.86.0': + resolution: {integrity: sha512-nIaXbm2jX1OTYp0qbviJ3O6KZivoE8z3BnhUQ2LsqfZSWRoOK/n1qsiAr6oALiNKWnXY3j2KPwtYORnZzp8xew==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/codegen@0.86.0': + resolution: {integrity: sha512-uTs9DBo3+/lUqinsGZK0FKJRBVClrwMXoZToaDxE1Q2SL2e55vs2GwyZfIKzPl5uJnbu4PfFMIp0/mLXLWUMuA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@babel/core': '*' + + '@react-native/community-cli-plugin@0.86.0': + resolution: {integrity: sha512-Jv8p1ebEPfTzs8gmrjsdT2XMXFfeAg45Pman+XPLFGaSeGAZkutRFRyX9Cs9aGTSOyIA9YPJ6vDNb1ayTf1FKQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@react-native-community/cli': '*' + '@react-native/metro-config': 0.86.0 + peerDependenciesMeta: + '@react-native-community/cli': + optional: true + '@react-native/metro-config': + optional: true + + '@react-native/debugger-frontend@0.86.0': + resolution: {integrity: sha512-7Mb3nDfyJeys+ELF75Ageu7VKERlnIMoO+aNPoXqTXvz+b41L6l2CqMyLpDHxkBSlenij6gEepPNgaIyWHbJZw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/debugger-shell@0.86.0': + resolution: {integrity: sha512-Y0zEkZzLz8ou6o/VLml1A31X/rMgc6DRjwxwzPMa94qRTMY070WeBCNTITQo4kKTBAUgbxh07oXPQqp0Tpja8w==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/dev-middleware@0.86.0': + resolution: {integrity: sha512-20pTO6yTybmvXvro520H6C7jydIQnLKOl5qFtVEcHSdFrY63r3OGei+Rx9bILgSRmH6jgnfEcijcMx7pwWuQtw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/gradle-plugin@0.86.0': + resolution: {integrity: sha512-a1RcfaEDqWExCGfCwadIxt4l8FvKYgFqeMf2uzeKyAOnb+vTGNIeCvifFL2MqvgaeYxlER437HbMIajGcuJ1pQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/js-polyfills@0.86.0': + resolution: {integrity: sha512-zYy/Cjd1VTnZ2iCNaG9bDF9C3l2ntESiPRscjIlI5FKugu6aeTwsDSv1aI8Bc4Kp3vEdoVg+UQhLAhE4svREaQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + '@react-native/normalize-colors@0.86.0': + resolution: {integrity: sha512-kG0wfCGghUKlfxkJyyHCDVutWVYWK7/DG58ojA/4v9EfulgF+osuSQmlbNb3rcKX58qutm7JcldSeVLgGFha9g==} + + '@react-native/virtualized-lists@0.86.0': + resolution: {integrity: sha512-4/ZLXdf/OSpPDVO0AsQ1SJdRIzt5t9BNQ46QwGgxvX7/cirYR5k8KXctNGGgW8lQo2gZChEfY2zFCZg9nM/jiw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + peerDependencies: + '@types/react': ^19.2.0 + react: '*' + react-native: 0.86.0 + peerDependenciesMeta: + '@types/react': + optional: true + + '@resvg/resvg-wasm@2.4.0': + resolution: {integrity: sha512-C7c51Nn4yTxXFKvgh2txJFNweaVcfUPQxwEUFw4aWsCmfiBDJsTSwviIF8EcwjQ6k8bPyMWCl1vw4BdxE569Cg==} + engines: {node: '>= 10'} + + '@rolldown/binding-android-arm64@1.0.3': + resolution: {integrity: sha512-454rs7jHngixp/NMxd5srYD57OnzSlZ/eFTETjORQHLwJG1lRtmNOJcBerZlfu4GjKqeq8aCCIQrMdHyhI51Hw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [android] + + '@rolldown/binding-darwin-arm64@1.0.3': + resolution: {integrity: sha512-PcAhP+ynjURNyy8SKGl5DQP94aGuB/7JrXJb/t7P+hanXvQVMWzUvRRhBAcg/lNRadBhoUPqSoP4xw5tR/KBEA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [darwin] + + '@rolldown/binding-darwin-x64@1.0.3': + resolution: {integrity: sha512-9YpfeUvSE2RS7wysJ81uOZkXJz7f7Q55H2Gvp3VEw/EsahqDtrphrZ0EwDLK5vvKOzaCrBsjF8JmnMLcUt78Gg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [darwin] + + '@rolldown/binding-freebsd-x64@1.0.3': + resolution: {integrity: sha512-yB1IlAsSNHncV6SCTL27/MVGR5htvQsoGxIv5KMGXALp+Ll1wYsn+x98M9MW7qa+NdSbvrrY7ANI4wLJ0n1e6g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [freebsd] + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + resolution: {integrity: sha512-Yi30IVAAfLUCy2MseFjbB1jAMDl1VMCAas5StnYp8da9+CKvMd2H2cbEjWcw5NPaPqzvYkVIaF1nNUG+b7u/sw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm] + os: [linux] + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + resolution: {integrity: sha512-jsO7R8To+AdlYgUmN5sHSCZbfhtMBkO0WUx8iORQnPcMMdgr7qM2DQmMwgabs3GhNztdmoKkMKQFHD6DTMCIQw==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-arm64-musl@1.0.3': + resolution: {integrity: sha512-VWkUHwWriDciit80wleYwKILoR/KMvxh/IdwS/paX+ZgpuRpCrKLUdadJbc0NpBEiyhpYawsJ73j9aCvOH+f7Q==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [linux] + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + resolution: {integrity: sha512-5f1laC0SlIR0yDbFCd8acUhvJIag6N3zC5P7oUPN6wX0aOma+uKJ0wBDH5aq7I1PVI2ttTlhJwzwRIBnLiSGEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [ppc64] + os: [linux] + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + resolution: {integrity: sha512-Iq4ko0r4XsgbrF/LunNgHtAGLRRVE2kXonAXQ/MV0mC6jQpMOhW1SvtZja2EhC/kd05++bP78dsqBeIQyYJ6Yg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [s390x] + os: [linux] + + '@rolldown/binding-linux-x64-gnu@1.0.3': + resolution: {integrity: sha512-B8m6tD5+/N5FeNQFbKlLA/2yVq9ycQP1SeedyEYYKWBNR3ZQbkvIUcNnDNM03lO1l5F2roiiFJGgvoLLyZXtSg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-linux-x64-musl@1.0.3': + resolution: {integrity: sha512-pSdpdUJHkuCxun9LE7jvgUB9qsRgaiyNNCX7m/AvHTcq67AiT/Yhoxvw5zPfhrM8k/BfP8ce/hMOpthKDpEUow==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [linux] + + '@rolldown/binding-openharmony-arm64@1.0.3': + resolution: {integrity: sha512-OXXS3RKJgX2uLwM+gYyuH5omcH8fL1LJs96pZGgtetVCahON57+d4SJHzTgZiOjxgGkSnpXpOsWuPDGAKAigEg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [openharmony] + + '@rolldown/binding-wasm32-wasi@1.0.3': + resolution: {integrity: sha512-JTtb8BWFynicNSoPrehsCzBtOKjZ6jhMiPFEmOiuXg1Fl8dn2KHQob+GuPSGR0dryQa1PQJbzjF3dqO/whhjLg==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [wasm32] + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + resolution: {integrity: sha512-gEdFFEN70A/jxb2svrWsN3aDL7OUtmvlOy+6fa2jxG8K0wQ1ZbdeLGnidov6Yu5/733dI5ySfzFlQ/cb0bSz1g==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [arm64] + os: [win32] + + '@rolldown/binding-win32-x64-msvc@1.0.3': + resolution: {integrity: sha512-eXB7CHuaQdqmJcc3koCNtNPmT/bj2gc999kUFgBxG8Ac0NdgXc4rkCHhqrgrhN3zddvvvrgzj1e90SuSfmyIXA==} + engines: {node: ^20.19.0 || >=22.12.0} + cpu: [x64] + os: [win32] + + '@rolldown/pluginutils@1.0.1': + resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} + + '@rollup/rollup-android-arm-eabi@4.60.2': + resolution: {integrity: sha512-dnlp69efPPg6Uaw2dVqzWRfAWRnYVb1XJ8CyyhIbZeaq4CA5/mLeZ1IEt9QqQxmbdvagjLIm2ZL8BxXv5lH4Yw==} + cpu: [arm] + os: [android] + + '@rollup/rollup-android-arm64@4.60.2': + resolution: {integrity: sha512-OqZTwDRDchGRHHm/hwLOL7uVPB9aUvI0am/eQuWMNyFHf5PSEQmyEeYYheA0EPPKUO/l0uigCp+iaTjoLjVoHg==} + cpu: [arm64] + os: [android] + + '@rollup/rollup-darwin-arm64@4.60.2': + resolution: {integrity: sha512-UwRE7CGpvSVEQS8gUMBe1uADWjNnVgP3Iusyda1nSRwNDCsRjnGc7w6El6WLQsXmZTbLZx9cecegumcitNfpmA==} + cpu: [arm64] + os: [darwin] + + '@rollup/rollup-darwin-x64@4.60.2': + resolution: {integrity: sha512-gjEtURKLCC5VXm1I+2i1u9OhxFsKAQJKTVB8WvDAHF+oZlq0GTVFOlTlO1q3AlCTE/DF32c16ESvfgqR7343/g==} + cpu: [x64] + os: [darwin] + + '@rollup/rollup-freebsd-arm64@4.60.2': + resolution: {integrity: sha512-Bcl6CYDeAgE70cqZaMojOi/eK63h5Me97ZqAQoh77VPjMysA/4ORQBRGo3rRy45x4MzVlU9uZxs8Uwy7ZaKnBw==} + cpu: [arm64] + os: [freebsd] + + '@rollup/rollup-freebsd-x64@4.60.2': + resolution: {integrity: sha512-LU+TPda3mAE2QB0/Hp5VyeKJivpC6+tlOXd1VMoXV/YFMvk/MNk5iXeBfB4MQGRWyOYVJ01625vjkr0Az98OJQ==} + cpu: [x64] + os: [freebsd] + + '@rollup/rollup-linux-arm-gnueabihf@4.60.2': + resolution: {integrity: sha512-2QxQrM+KQ7DAW4o22j+XZ6RKdxjLD7BOWTP0Bv0tmjdyhXSsr2Ul1oJDQqh9Zf5qOwTuTc7Ek83mOFaKnodPjg==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm-musleabihf@4.60.2': + resolution: {integrity: sha512-TbziEu2DVsTEOPif2mKWkMeDMLoYjx95oESa9fkQQK7r/Orta0gnkcDpzwufEcAO2BLBsD7mZkXGFqEdMRRwfw==} + cpu: [arm] + os: [linux] + + '@rollup/rollup-linux-arm64-gnu@4.60.2': + resolution: {integrity: sha512-bO/rVDiDUuM2YfuCUwZ1t1cP+/yqjqz+Xf2VtkdppefuOFS2OSeAfgafaHNkFn0t02hEyXngZkxtGqXcXwO8Rg==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-arm64-musl@4.60.2': + resolution: {integrity: sha512-hr26p7e93Rl0Za+JwW7EAnwAvKkehh12BU1Llm9Ykiibg4uIr2rbpxG9WCf56GuvidlTG9KiiQT/TXT1yAWxTA==} + cpu: [arm64] + os: [linux] + + '@rollup/rollup-linux-loong64-gnu@4.60.2': + resolution: {integrity: sha512-pOjB/uSIyDt+ow3k/RcLvUAOGpysT2phDn7TTUB3n75SlIgZzM6NKAqlErPhoFU+npgY3/n+2HYIQVbF70P9/A==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-loong64-musl@4.60.2': + resolution: {integrity: sha512-2/w+q8jszv9Ww1c+6uJT3OwqhdmGP2/4T17cu8WuwyUuuaCDDJ2ojdyYwZzCxx0GcsZBhzi3HmH+J5pZNXnd+Q==} + cpu: [loong64] + os: [linux] + + '@rollup/rollup-linux-ppc64-gnu@4.60.2': + resolution: {integrity: sha512-11+aL5vKheYgczxtPVVRhdptAM2H7fcDR5Gw4/bTcteuZBlH4oP9f5s9zYO9aGZvoGeBpqXI/9TZZihZ609wKw==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-ppc64-musl@4.60.2': + resolution: {integrity: sha512-i16fokAGK46IVZuV8LIIwMdtqhin9hfYkCh8pf8iC3QU3LpwL+1FSFGej+O7l3E/AoknL6Dclh2oTdnRMpTzFQ==} + cpu: [ppc64] + os: [linux] + + '@rollup/rollup-linux-riscv64-gnu@4.60.2': + resolution: {integrity: sha512-49FkKS6RGQoriDSK/6E2GkAsAuU5kETFCh7pG4yD/ylj9rKhTmO3elsnmBvRD4PgJPds5W2PkhC82aVwmUcJ7A==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-riscv64-musl@4.60.2': + resolution: {integrity: sha512-mjYNkHPfGpUR00DuM1ZZIgs64Hpf4bWcz9Z41+4Q+pgDx73UwWdAYyf6EG/lRFldmdHHzgrYyge5akFUW0D3mQ==} + cpu: [riscv64] + os: [linux] + + '@rollup/rollup-linux-s390x-gnu@4.60.2': + resolution: {integrity: sha512-ALyvJz965BQk8E9Al/JDKKDLH2kfKFLTGMlgkAbbYtZuJt9LU8DW3ZoDMCtQpXAltZxwBHevXz5u+gf0yA0YoA==} + cpu: [s390x] + os: [linux] + + '@rollup/rollup-linux-x64-gnu@4.60.2': + resolution: {integrity: sha512-UQjrkIdWrKI626Du8lCQ6MJp/6V1LAo2bOK9OTu4mSn8GGXIkPXk/Vsp4bLHCd9Z9Iz2OTEaokUE90VweJgIYQ==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-linux-x64-musl@4.60.2': + resolution: {integrity: sha512-bTsRGj6VlSdn/XD4CGyzMnzaBs9bsRxy79eTqTCBsA8TMIEky7qg48aPkvJvFe1HyzQ5oMZdg7AnVlWQSKLTnw==} + cpu: [x64] + os: [linux] + + '@rollup/rollup-openbsd-x64@4.60.2': + resolution: {integrity: sha512-6d4Z3534xitaA1FcMWP7mQPq5zGwBmGbhphh2DwaA1aNIXUu3KTOfwrWpbwI4/Gr0uANo7NTtaykFyO2hPuFLg==} + cpu: [x64] + os: [openbsd] + + '@rollup/rollup-openharmony-arm64@4.60.2': + resolution: {integrity: sha512-NetAg5iO2uN7eB8zE5qrZ3CSil+7IJt4WDFLcC75Ymywq1VZVD6qJ6EvNLjZ3rEm6gB7XW5JdT60c6MN35Z85Q==} + cpu: [arm64] + os: [openharmony] + + '@rollup/rollup-win32-arm64-msvc@4.60.2': + resolution: {integrity: sha512-NCYhOotpgWZ5kdxCZsv6Iudx0wX8980Q/oW4pNFNihpBKsDbEA1zpkfxJGC0yugsUuyDZ7gL37dbzwhR0VI7pQ==} + cpu: [arm64] + os: [win32] + + '@rollup/rollup-win32-ia32-msvc@4.60.2': + resolution: {integrity: sha512-RXsaOqXxfoUBQoOgvmmijVxJnW2IGB0eoMO7F8FAjaj0UTywUO/luSqimWBJn04WNgUkeNhh7fs7pESXajWmkg==} + cpu: [ia32] + os: [win32] + + '@rollup/rollup-win32-x64-gnu@4.60.2': + resolution: {integrity: sha512-qdAzEULD+/hzObedtmV6iBpdL5TIbKVztGiK7O3/KYSf+HIzU257+MX1EXJcyIiDbMAqmbwaufcYPvyRryeZtA==} + cpu: [x64] + os: [win32] + + '@rollup/rollup-win32-x64-msvc@4.60.2': + resolution: {integrity: sha512-Nd/SgG27WoA9e+/TdK74KnHz852TLa94ovOYySo/yMPuTmpckK/jIF2jSwS3g7ELSKXK13/cVdmg1Z/DaCWKxA==} + cpu: [x64] + os: [win32] + + '@shikijs/core@3.23.0': + resolution: {integrity: sha512-NSWQz0riNb67xthdm5br6lAkvpDJRTgB36fxlo37ZzM2yq0PQFFzbd8psqC2XMPgCzo1fW6cVi18+ArJ44wqgA==} + + '@shikijs/engine-javascript@3.23.0': + resolution: {integrity: sha512-aHt9eiGFobmWR5uqJUViySI1bHMqrAgamWE1TYSUoftkAeCCAiGawPMwM+VCadylQtF4V3VNOZ5LmfItH5f3yA==} + + '@shikijs/engine-oniguruma@3.23.0': + resolution: {integrity: sha512-1nWINwKXxKKLqPibT5f4pAFLej9oZzQTsby8942OTlsJzOBZ0MWKiwzMsd+jhzu8YPCHAswGnnN1YtQfirL35g==} + + '@shikijs/langs@3.23.0': + resolution: {integrity: sha512-2Ep4W3Re5aB1/62RSYQInK9mM3HsLeB91cHqznAJMuylqjzNVAVCMnNWRHFtcNHXsoNRayP9z1qj4Sq3nMqYXg==} + + '@shikijs/themes@3.23.0': + resolution: {integrity: sha512-5qySYa1ZgAT18HR/ypENL9cUSGOeI2x+4IvYJu4JgVJdizn6kG4ia5Q1jDEOi7gTbN4RbuYtmHh0W3eccOrjMA==} + + '@shikijs/types@3.23.0': + resolution: {integrity: sha512-3JZ5HXOZfYjsYSk0yPwBrkupyYSLpAE26Qc0HLghhZNGTZg/SKxXIIgoxOpmmeQP0RRSDJTk1/vPfw9tbw+jSQ==} + + '@shikijs/vscode-textmate@10.0.2': + resolution: {integrity: sha512-83yeghZ2xxin3Nj8z1NMd/NCuca+gsYXswywDy5bHvwlWL8tpTQmzGeUuHd9FC3E/SBEMvzJRwWEOz5gGes9Qg==} + + '@shuding/opentype.js@1.4.0-beta.0': + resolution: {integrity: sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==} + engines: {node: '>= 8.0.0'} + hasBin: true + + '@sinclair/typebox@0.27.10': + resolution: {integrity: sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==} + + '@sinclair/typebox@0.34.49': + resolution: {integrity: sha512-brySQQs7Jtn0joV8Xh9ZV/hZb9Ozb0pmazDIASBkYKCjXrXU3mpcFahmK/z4YDhGkQvP9mWJbVyahdtU5wQA+A==} + + '@sinonjs/commons@3.0.1': + resolution: {integrity: sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==} + + '@sinonjs/fake-timers@15.4.0': + resolution: {integrity: sha512-DsG+8/LscQIQg68J6Ef3dv10u6nVyetYn923s3/sus5eaGfTo1of5WMZSLf0UJc9KDuKPilPH0UDJCjvNbDNCA==} + + '@smithy/core@3.25.1': + resolution: {integrity: sha512-zpDbpXBCBsxfLtG2GEUyfgvHvSFrw5CwDZSNzL0v52gx/c3oPlPbm+7W7num8xs6vyiUBn+bvYPHcQDOXZynCQ==} + engines: {node: '>=18.0.0'} + + '@smithy/credential-provider-imds@4.4.1': + resolution: {integrity: sha512-TSAF5NHgxEsllbErYWbK8aLnl5L601NGc5VYJlSPsKnf3YlkhdoBN+geGcaU00oiw2OK3QO5LA3QNXiiWhCidQ==} + engines: {node: '>=18.0.0'} + + '@smithy/fetch-http-handler@5.5.1': + resolution: {integrity: sha512-96JrD1q71anokymx9Iblb+zKmNQYNstlV/25A9ZYIJ2A0rp1r7/GZAIm0bDWSmVvz3DpNOCZuabzsiL+w0UHhw==} + engines: {node: '>=18.0.0'} + + '@smithy/is-array-buffer@2.2.0': + resolution: {integrity: sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==} + engines: {node: '>=14.0.0'} + + '@smithy/node-http-handler@4.8.1': + resolution: {integrity: sha512-emtXvoky671puri18ETf64AFIQUGIEA093F2drXpBgB0OGnBLjcwNR3CA2mYu62IAqNsS56xa5lnTxAgPq7cjw==} + engines: {node: '>=18.0.0'} + + '@smithy/signature-v4@5.5.1': + resolution: {integrity: sha512-X9rVls3En0z3NtrmguTmpRM0/NqtWUxBjal6fcAkwtsub+gOdLZ6kD+V7xhUgFMGdG14bHbZ7M5QjaRI1+DatQ==} + engines: {node: '>=18.0.0'} + + '@smithy/types@4.15.0': + resolution: {integrity: sha512-Z5TAOxygoFvybJV3igo5SloFflSokHx2hu1eFA+DxDTcn+FtKxUSui+rbTRG1pAafMA888Z3MVvCWUuvCrTXjg==} + engines: {node: '>=18.0.0'} + + '@smithy/util-buffer-from@2.2.0': + resolution: {integrity: sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==} + engines: {node: '>=14.0.0'} + + '@smithy/util-utf8@2.3.0': + resolution: {integrity: sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==} + engines: {node: '>=14.0.0'} + + '@solana-mobile/mobile-wallet-adapter-protocol@2.2.9': + resolution: {integrity: sha512-qtWJq0hzKgngVG0So2ViBRPYDculaxgj40WDSP1nzgdg85MXyAmTEjQqV10uSVbZRm9b1hl601HDJX1sHTgeiw==} + peerDependencies: + react-native: '>0.74' + + '@solana-mobile/wallet-standard-mobile@0.4.4': + resolution: {integrity: sha512-LMvqkS5/aEH+EiDje9Dk351go6wO3POysgmobM4qm8RsG5s6rDAW3U0zA+5f2coGCTyRx8BKE1I/9nHlwtBuow==} + + '@solana-program/system@0.12.2': + resolution: {integrity: sha512-MaBeOxlvTruQhA7UYkOb3hVTEHPPagOtd+PvTm6a8rGgvEAP0kD4BbC37NceOaR4ABNqdaCmD5OMVRKgrE6KAg==} + peerDependencies: + '@solana/kit': ^6.4.0 + + '@solana-program/token-2022@0.12.0': + resolution: {integrity: sha512-SXkN6Epy9sC3OEELJLhc0hZtUijsAlR2Nb5gP6jcc0WVrtj5wEAmksWxF/yYrAB8AisJVgxvODkhIAnrd02DIw==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@solana/kit': ^6.4.0 + '@solana/sysvars': ^5.0 + '@solana/zk-sdk': ^0.4.2 + peerDependenciesMeta: + '@solana/zk-sdk': + optional: true + + '@solana-program/token-2022@0.9.0': + resolution: {integrity: sha512-j8fPBc/oUApYF7aW0ub6cIV7dbbtXC+Y6oDcI9SUs6BXXSq+lj7p7XRU+GEH8qWfyQ5ziRiOLI9s2AZjJY1Icg==} + peerDependencies: + '@solana/kit': ^6.0.0 + '@solana/sysvars': ^5.0 + + '@solana-program/token@0.13.0': + resolution: {integrity: sha512-/Apjrd5lwOJGrPB0J5Rv7EBeclvyEBQPAGA85Scm7wBH+GpkbdLDM9uK3TNg8jjFKyWQYai/JtPHbrx7VgFLSg==} + peerDependencies: + '@solana/kit': ^6.5.0 + + '@solana-program/token@0.14.0': + resolution: {integrity: sha512-zpLMr6JZndlsQCQvrm0gezfwdr1lmzOGqN6v2WIYXjtDmbF+xg6zh/MAp2UFHRpv3uDmylEdjtQo05pa2OeaYg==} + engines: {node: '>=24.0.0'} + peerDependencies: + '@solana/kit': ^6.5.0 + + '@solana-program/zk-elgamal-proof@0.2.0': + resolution: {integrity: sha512-znu1asnySKVp0VyOlfXCLZhpdWvyq/tJ7GRrX61Z6vyXXqJ/OMizv2BkgYL/VbzDKkFmUiYfiFwF3gDtZHv7VA==} + peerDependencies: + '@solana/kit': ^5.0 + + '@solana/accounts@5.5.1': + resolution: {integrity: sha512-TfOY9xixg5rizABuLVuZ9XI2x2tmWUC/OoN556xwfDlhBHBjKfszicYYOyD6nbFmwTGYarCmyGIdteXxTXIdhQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/accounts@6.10.0': + resolution: {integrity: sha512-+FxfDOrnifoPlBkF+fr8eeQdgM6xtIgAg9xKMu3WnIz60oZd4Xnry6+ff6t+ePPoZZp397FSg9ZJet68VCWm5Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/addresses@5.5.1': + resolution: {integrity: sha512-5xoah3Q9G30HQghu/9BiHLb5pzlPKRC3zydQDmE3O9H//WfayxTFppsUDCL6FjYUHqj/wzK6CWHySglc2RkpdA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/addresses@6.10.0': + resolution: {integrity: sha512-vEoCGBTxG0HCERAn84KXkrJjl+pDaNzOpZ0qbgcPS98fYxP5yzbKB8SNOY2bzrbkRUmmw5Q3hqTRERemUN2Gcw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/assertions@5.5.1': + resolution: {integrity: sha512-YTCSWAlGwSlVPnWtWLm3ukz81wH4j2YaCveK+TjpvUU88hTy6fmUqxi0+hvAMAe4zKXpJyj3Az7BrLJRxbIm4Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/assertions@6.10.0': + resolution: {integrity: sha512-lKSAdVo+P/6Lp4vs6shstXmFOpvxrABwn4o1462tb7sKkNapk6o9pPFVPGw4DUgPS3WqWRs1j2tmpuVjhQRntg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-core@5.5.1': + resolution: {integrity: sha512-TgBt//bbKBct0t6/MpA8ElaOA3sa8eYVvR7LGslCZ84WiAwwjCY0lW/lOYsFHJQzwREMdUyuEyy5YWBKtdh8Rw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-core@6.10.0': + resolution: {integrity: sha512-nfAl9OMGo4HanIMxGsQoVB7BxMoqBCYEUxl8oEAZZ09pDxnaXQZkTRXEwPPccag37XfW1ciPd1vWPKwB2b0HHQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-data-structures@5.5.1': + resolution: {integrity: sha512-97bJWGyUY9WvBz3mX1UV3YPWGDTez6btCfD0ip3UVEXJbItVuUiOkzcO5iFDUtQT5riKT6xC+Mzl+0nO76gd0w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-data-structures@6.10.0': + resolution: {integrity: sha512-CNasJW3bq5u+632Zt5aJ8rOjAjv2HyenpV8o9kAIqdmV4CBpjCCoBnKn8LkuR/sbeREZxJYfhKTXO/9ruAkw7A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-numbers@5.5.1': + resolution: {integrity: sha512-rllMIZAHqmtvC0HO/dc/21wDuWaD0B8Ryv8o+YtsICQBuiL/0U4AGwH7Pi5GNFySYk0/crSuwfIqQFtmxNSPFw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-numbers@6.10.0': + resolution: {integrity: sha512-CcM+wX4zOiA9zkh8A7t1787A0Ehgmu5+6Z2tKoHew6cNw/dkaUTPa8JnNHbvfsLC8dfHC1BhAEJl86sKmRsfkQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs-strings@5.5.1': + resolution: {integrity: sha512-7klX4AhfHYA+uKKC/nxRGP2MntbYQCR3N6+v7bk1W/rSxYuhNmt+FN8aoThSZtWIKwN6BEyR1167ka8Co1+E7A==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: ^5.0.0 + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true + + '@solana/codecs-strings@6.10.0': + resolution: {integrity: sha512-zlaqkg7K6F6IN4V/Ec8TWkTn054gxv7ZLagvGkuEyAdPQ6BzzsehOm2TqCuyXgJJTCGPLY1bEk6yH9NxANe0kA==} + engines: {node: '>=20.18.0'} + peerDependencies: + fastestsmallesttextencoderdecoder: ^1.0.22 + typescript: '>=5.4.0' + peerDependenciesMeta: + fastestsmallesttextencoderdecoder: + optional: true + typescript: + optional: true + + '@solana/codecs@5.5.1': + resolution: {integrity: sha512-Vea29nJub/bXjfzEV7ZZQ/PWr1pYLZo3z0qW0LQL37uKKVzVFRQlwetd7INk3YtTD3xm9WUYr7bCvYUk3uKy2g==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/codecs@6.10.0': + resolution: {integrity: sha512-lLVuxod4ChWp9i7OvpgIykYG8Q9OGPVXKnHM9VlzDDLylsx7Y1FoQL00sHa7PqFkJVmkBufaA6dcGbQ7FU+lAQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/connector@0.2.4': + resolution: {integrity: sha512-klxVTjgmhdEhzzBt+UEFHgTwpEs2wxECbuQCSjrKAbKOtncS7VFaosva0OwOoyfMkl2aQ7uerUZXW+x5FTOpZQ==} + peerDependencies: + '@solana/connector-debugger': '*' + '@solana/keychain': ^0.2.1 + '@solana/keychain-aws-kms': ^0.2.1 + '@solana/keychain-fireblocks': ^0.2.1 + '@solana/keychain-privy': ^0.2.1 + '@solana/keychain-turnkey': ^0.2.1 + '@solana/keychain-vault': ^0.2.1 + '@solana/web3.js': ^1.0.0 + '@walletconnect/universal-provider': ^2.0.0 + react: '>=18.0.0' + peerDependenciesMeta: + '@solana/connector-debugger': + optional: true + '@solana/keychain': + optional: true + '@solana/keychain-fireblocks': + optional: true + '@solana/keychain-privy': + optional: true + '@solana/web3.js': + optional: true + '@walletconnect/universal-provider': + optional: true + react: + optional: true + + '@solana/design-system@1.0.1': + resolution: {integrity: sha512-8kkrxVyH+9zOfswREYm1mQqVmiQNMF4ANB7XdZCz8QLdqMfRX2FZUrxysnfFOlNPSXFHFI2scSBF8vPWLvRqwg==} + peerDependencies: + '@base-ui/react': ^1.1.0 + motion: ^12.26.0 + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + tailwindcss: ^4.0.0 + + '@solana/errors@5.5.1': + resolution: {integrity: sha512-vFO3p+S7HoyyrcAectnXbdsMfwUzY2zYFUc2DEe5BwpiE9J1IAxPBGjOWO6hL1bbYdBrlmjNx8DXCslqS+Kcmg==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/errors@6.10.0': + resolution: {integrity: sha512-KBLAxCtAXr357JNhCyIDQXWbuSj5vN6w+28FSfcYY6OOSiphmXLAV3V58jgV0C6iNbIzFJFi6yatFyDTdeJsNg==} + engines: {node: '>=20.18.0'} + hasBin: true + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/eslint-config-solana@6.0.0': + resolution: {integrity: sha512-tl3C2ZK8buItUQNVCwnveR2iiLALr5XZ8cevswbTDQN1SA29xQWPFRYR/JPyXLd7iOGNAo4HwvIoxNmkLjdZsQ==} + peerDependencies: + '@eslint/js': ^9.39.1 + '@types/eslint': ^9.6.1 + '@types/eslint__js': ^9.14.0 + eslint: ^9.39.1 + eslint-plugin-jest: ^29.2.1 + eslint-plugin-react-hooks: ^7.0.1 + eslint-plugin-simple-import-sort: ^12.1.1 + eslint-plugin-sort-keys-fix: ^1.1.2 + eslint-plugin-typescript-sort-keys: ^3.3.0 + globals: ^16.5.0 + jest: ^30.0.0 + typescript: ^5.9.3 + typescript-eslint: ^8.49.0 + + '@solana/fast-stable-stringify@5.5.1': + resolution: {integrity: sha512-Ni7s2FN33zTzhTFgRjEbOVFO+UAmK8qi3Iu0/GRFYK4jN696OjKHnboSQH/EacQ+yGqS54bfxf409wU5dsLLCw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fast-stable-stringify@6.10.0': + resolution: {integrity: sha512-iCNed27wk6PKSS3QUtHovRfMWF/jbVWogs2vB4tukKUCsqG4rDfDInIwZ6ur/nY6XTrgi2gMMdZq9GAUlWsbfw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/fixed-points@6.10.0': + resolution: {integrity: sha512-ZkKL0alXH3L7/wMiVG8YUuG8qBKunlM810+YBD7nUPRhifiGsX1zwADViHLYNqLr/jUk0mTYFUcKznTpB/K+Gg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/functional@5.5.1': + resolution: {integrity: sha512-tTHoJcEQq3gQx5qsdsDJ0LEJeFzwNpXD80xApW9o/PPoCNimI3SALkZl+zNW8VnxRrV3l3yYvfHWBKe/X3WG3w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/functional@6.10.0': + resolution: {integrity: sha512-P8cevu4mAqHTXC37h1TVoOh8zhWB2tlOI/R9vWjYPpcLwcyWf8p2qq4LEGHl5kY+1C+4PNX39HsmCocXOPCDkQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instruction-plans@5.5.1': + resolution: {integrity: sha512-7z3CB7YMcFKuVvgcnNY8bY6IsZ8LG61Iytbz7HpNVGX2u1RthOs1tRW8luTzSG1MPL0Ox7afyAVMYeFqSPHnaQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instruction-plans@6.10.0': + resolution: {integrity: sha512-YG7mo4zykzdc6ZTV0BuN6pveK9qeBySzlYYerq578A4eQu3xcypMAYRGAvhMZtWTanjjmD6CKtM0M7kVp0TNxg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instructions@5.5.1': + resolution: {integrity: sha512-h0G1CG6S+gUUSt0eo6rOtsaXRBwCq1+Js2a+Ps9Bzk9q7YHNFA75/X0NWugWLgC92waRp66hrjMTiYYnLBoWOQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/instructions@6.10.0': + resolution: {integrity: sha512-0TToYF+8LXQ3ofPMx+yF6yaM9l4YJvcAPMy0qV5JsrBUFlWXBSANRuudKBQLHMvb+a3OiUTq5X7omuorKMBB3A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/keychain-aws-kms@0.2.1': + resolution: {integrity: sha512-nKbpxRSE+zu+y8ZywJGAbwjxbjtLzbQR35Q5wQ1HWTvM4ZCfLzVqlkX8GYFT3eeWCi+JX4VXJdHfOFofl9D/GA==} + + '@solana/keychain-core@0.2.1': + resolution: {integrity: sha512-jduqFo7M1R2ZH/i5zha9ecktj/f8Xh9hPXvQU6uwY2ZcWg1NROK6fyW5zt4MUI+q+bgh+r77aTk4SXPZy3qdpA==} + + '@solana/keychain-turnkey@0.2.1': + resolution: {integrity: sha512-iUw4GrxrMhTIcdd07ozyWjVViTIp4Ty3isqVMJFd3vVtCfwUgrfM57qLenUwqMjqqxa2k1k2FnC0LrTvdkyy4g==} + + '@solana/keychain-vault@0.2.1': + resolution: {integrity: sha512-W9ykOYqDqG3GBF5sbJUnSvLZXyicTK3atoQZMl7zTORxr+N9vwPAvmPbtLgDS2GKoZUG0RZWFeJgAaNq14Avaw==} + + '@solana/keys@5.5.1': + resolution: {integrity: sha512-KRD61cL7CRL+b4r/eB9dEoVxIf/2EJ1Pm1DmRYhtSUAJD2dJ5Xw8QFuehobOGm9URqQ7gaQl+Fkc1qvDlsWqKg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/keys@6.10.0': + resolution: {integrity: sha512-26IRfdm/hTUCmM7MeEeX0ULSbCM6OzkZTkfkrPircqmRM7xyNqP4hq7u0P7wjb9dl7NfgyG6K7cdvUxrj2e3mA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/kit-plugin-instruction-plan@0.10.0': + resolution: {integrity: sha512-h99B+1Vp5QWU/M/q0UXlTxKJt781vWw5aAopnbgVCy0F3hNaSDZ/gio126Oz0/cipGOnyaJf3NnV79GvxaEqZA==} + peerDependencies: + '@solana/kit': ^6.8.0 + + '@solana/kit-plugin-rpc@0.11.1': + resolution: {integrity: sha512-NpCKBY6y3lmOOZjzm5dvk/+iZsKOH+Wc9TQx5yKZ0RzNOXC6V9i0Inn+niVdkX5ECDJOmClfa64bLcImFJWLuQ==} + peerDependencies: + '@solana/kit': ^6.8.0 + + '@solana/kit-plugin-signer@0.10.0': + resolution: {integrity: sha512-3Gw3R6nQg/2r2+4cSaUZHj5zdbtb0SuA1mkDMd6uH7B+fdH1Ouxnulv1/sN8J0VxBo7tS+YDQA5t0arxX5gj+w==} + peerDependencies: + '@solana/kit': ^6.8.0 + + '@solana/kit@5.5.1': + resolution: {integrity: sha512-irKUGiV2yRoyf+4eGQ/ZeCRxa43yjFEL1DUI5B0DkcfZw3cr0VJtVJnrG8OtVF01vT0OUfYOcUn6zJW5TROHvQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/kit@6.10.0': + resolution: {integrity: sha512-/WnnQp3uARh2JCFSfAakejTAqwmXVuMVTcRn5r2yDwY2yzZ4R6mt/Cl59VPimVLNSoTyN/KsEwhv9omr3ERazQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/nominal-types@5.5.1': + resolution: {integrity: sha512-I1ImR+kfrLFxN5z22UDiTWLdRZeKtU0J/pkWkO8qm/8WxveiwdIv4hooi8pb6JnlR4mSrWhq0pCIOxDYrL9GIQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/nominal-types@6.10.0': + resolution: {integrity: sha512-9ykyBBvnkInH7fCacjJi7zu2PJyd+OCt+VTjIISv070fHzKIMFqZqJJ/dJ0SRH2aHwfB3n86iVsmtBtuxi4KKA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/offchain-messages@5.5.1': + resolution: {integrity: sha512-g+xHH95prTU+KujtbOzj8wn+C7ZNoiLhf3hj6nYq3MTyxOXtBEysguc97jJveUZG0K97aIKG6xVUlMutg5yxhw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/offchain-messages@6.10.0': + resolution: {integrity: sha512-RiEgAueeMkFMC1suOXBIcmCZgtXRxy24yk0DldPB37bB4zwOF1SAaRjNRPjIkGK8RhCYrEpPosnzLyavw9ueRg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/options@5.5.1': + resolution: {integrity: sha512-eo971c9iLNLmk+yOFyo7yKIJzJ/zou6uKpy6mBuyb/thKtS/haiKIc3VLhyTXty3OH2PW8yOlORJnv4DexJB8A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/options@6.10.0': + resolution: {integrity: sha512-RO9UT3UYD8/Cu2uM6ZXbKvLeMnVD42+g9JRds7Pfs4AhiOyg4R4TJrQUAppTgavPTO3PBRlWtWOC05ZH/yAIbg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-core@5.5.1': + resolution: {integrity: sha512-VUZl30lDQFJeiSyNfzU1EjYt2QZvoBFKEwjn1lilUJw7KgqD5z7mbV7diJhT+dLFs36i0OsjXvq5kSygn8YJ3A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-core@6.10.0': + resolution: {integrity: sha512-JE70YTQOfFACVFGvoJon4Scc/eHUWjMu8Ovo35CcV2kHTAHYMCd4UkBd2gmlhK0vRMMomsQi1ZLPlAlTq0OoUQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/plugin-interfaces@6.10.0': + resolution: {integrity: sha512-vr0/l9wcM4orwGr8cjkFWaJ9A4HvzuAv00jMFNMg0Spd0GZqnwnpW+D/fXa1lIJnTRaF3EeEjLh4VjKU037T0Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/prettier-config-solana@0.0.6': + resolution: {integrity: sha512-/s55hDoAyh5QyltQh/jjNK3AgACEq885+DnC6lYhrmYZiV6I0iHITWYnKd8d23KRKs/RBjlaQH54MiafeoI9hw==} + peerDependencies: + prettier: ^3.7.4 + + '@solana/program-client-core@6.10.0': + resolution: {integrity: sha512-4PPbTLdC1ylHIuvhOFDP8RnSkXPCFjNFWGslzc+UFKnoR4ajzBcByX94jmaruDMk5ncxgj7tr9pzJTvfGHIaMA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/programs@5.5.1': + resolution: {integrity: sha512-7U9kn0Jsx1NuBLn5HRTFYh78MV4XN145Yc3WP/q5BlqAVNlMoU9coG5IUTJIG847TUqC1lRto3Dnpwm6T4YRpA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/programs@6.10.0': + resolution: {integrity: sha512-qn/HeLP5KGUJXVub3fyGe69/rWaLX4jzwm6V/1pNxJDbdF+MBdgn18hP6F+VmhfdNmwK0lue3J/1HQ1UTMuQeQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/promises@5.5.1': + resolution: {integrity: sha512-T9lfuUYkGykJmppEcssNiCf6yiYQxJkhiLPP+pyAc2z84/7r3UVIb2tNJk4A9sucS66pzJnVHZKcZVGUUp6wzA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/promises@6.10.0': + resolution: {integrity: sha512-oJSIn+VBBMWDo8oqw7RV3tI6Jih+Ieup6FcQLYLDUriaeo7+8l1Zdezl8zh7SIfeU4lOfAbRg6mR0huaS/Lltg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-api@5.5.1': + resolution: {integrity: sha512-XWOQQPhKl06Vj0xi3RYHAc6oEQd8B82okYJ04K7N0Vvy3J4PN2cxeK7klwkjgavdcN9EVkYCChm2ADAtnztKnA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-api@6.10.0': + resolution: {integrity: sha512-RjPIVsAb/85P1ptoO3WpC0x7QG6gG/e4q/3lo6gbSznUZOcoM+8sSBnCX7BwP1ZkCDS6NK/ClXLnhhhYZx+OGg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-parsed-types@5.5.1': + resolution: {integrity: sha512-HEi3G2nZqGEsa3vX6U0FrXLaqnUCg4SKIUrOe8CezD+cSFbRTOn3rCLrUmJrhVyXlHoQVaRO9mmeovk31jWxJg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-parsed-types@6.10.0': + resolution: {integrity: sha512-5275mvSV1mxhwvrMVa+K7BU/nAetpHfcb+8Ql9rtA8RRf6DyiimFQFZUukE4Ez6XJihEpCHNy98yhkgai9wytQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec-types@5.5.1': + resolution: {integrity: sha512-6OFKtRpIEJQs8Jb2C4OO8KyP2h2Hy1MFhatMAoXA+0Ik8S3H+CicIuMZvGZ91mIu/tXicuOOsNNLu3HAkrakrw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec-types@6.10.0': + resolution: {integrity: sha512-NDZrKyZrJk4HaMFhTE/lAiMB824cWAodKqDHyKi0UteHU9pyRmil3BN1jt7e+j08mwMWwfklSgyrTaq52g6DIQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec@5.5.1': + resolution: {integrity: sha512-m3LX2bChm3E3by4mQrH4YwCAFY57QBzuUSWqlUw7ChuZ+oLLOq7b2czi4i6L4Vna67j3eCmB3e+4tqy1j5wy7Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-spec@6.10.0': + resolution: {integrity: sha512-yQdbWw5mZEWrwsunHR9NHkuhMXIB9sPOObwm18D53v5tAJnxTB0IcHvO647XqFDLTK/yQ4AdDtlYD1vsY07AMQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-api@5.5.1': + resolution: {integrity: sha512-5Oi7k+GdeS8xR2ly1iuSFkAv6CZqwG0Z6b1QZKbEgxadE1XGSDrhM2cn59l+bqCozUWCqh4c/A2znU/qQjROlw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-api@6.10.0': + resolution: {integrity: sha512-CRPQoTtT1cOwOQUsqS7jgo7wYdAj7jB5ab/UmMPWVpecf2FNMhWhgvxP2s82M7VkDGTGl13qaQ0WySmi7Egrlg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-channel-websocket@5.5.1': + resolution: {integrity: sha512-7tGfBBrYY8TrngOyxSHoCU5shy86iA9SRMRrPSyBhEaZRAk6dnbdpmUTez7gtdVo0BCvh9nzQtUycKWSS7PnFQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-channel-websocket@6.10.0': + resolution: {integrity: sha512-KkqP1186HELPlJftA88SNAT2znR8knCVzsUipXVzY4zfW8sN3LOa0ePMzh9VZ/V+J+raTt55laR87ovAO0n+zw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-spec@5.5.1': + resolution: {integrity: sha512-iq+rGq5fMKP3/mKHPNB6MC8IbVW41KGZg83Us/+LE3AWOTWV1WT20KT2iH1F1ik9roi42COv/TpoZZvhKj45XQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions-spec@6.10.0': + resolution: {integrity: sha512-nWMwGaG4ulzeX2sskY5TywXF3cwEd8FDmUpLe2JBWxE8XDAOGOKcsYPYFcBgb8ee9KqfPT2PTNdcz9jOhJf34w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions@5.5.1': + resolution: {integrity: sha512-CTMy5bt/6mDh4tc6vUJms9EcuZj3xvK0/xq8IQ90rhkpYvate91RjBP+egvjgSayUg9yucU9vNuUpEjz4spM7w==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-subscriptions@6.10.0': + resolution: {integrity: sha512-6mfuHp/K7unFKCOTCCBC9ziEGnxe2tyJ74EbR51QUnBeCUdYD7Hhdpxic1WRSJ3UeNW/mG4OzFM6z8Wi64Eh9Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transformers@5.5.1': + resolution: {integrity: sha512-OsWqLCQdcrRJKvHiMmwFhp9noNZ4FARuMkHT5us3ustDLXaxOjF0gfqZLnMkulSLcKt7TGXqMhBV+HCo7z5M8Q==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transformers@6.10.0': + resolution: {integrity: sha512-2nFUrVTiE720pJOY4XKx3HuYmishw0of/4oScu76YGm6O8wsmvFvPNAkrEinmieWXQkfpBfRvLZmpl8PaAy+ug==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transport-http@5.5.1': + resolution: {integrity: sha512-yv8GoVSHqEV0kUJEIhkdOVkR2SvJ6yoWC51cJn2rSV7plr6huLGe0JgujCmB7uZhhaLbcbP3zxXxu9sOjsi7Fg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-transport-http@6.10.0': + resolution: {integrity: sha512-JrdNuYi0nBbD3X8JUtgX1dQJwIwz/WJvmigDdELysXfGB2bTJpfjqGDLhCLOz2sRl66FASIEqgG/LVa2C9VXcA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-types@5.5.1': + resolution: {integrity: sha512-bibTFQ7PbHJJjGJPmfYC2I+/5CRFS4O2p9WwbFraX1Keeel+nRrt/NBXIy8veP5AEn2sVJIyJPpWBRpCx1oATA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc-types@6.10.0': + resolution: {integrity: sha512-zaSecTfCPvz/vcoAmKD6XoRstGHTr1EKJBD8T9UcpEFFB6CtF6DxerDB+wrzkamuT6msmnR2DWXMrYOGDAsgIg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc@5.5.1': + resolution: {integrity: sha512-ku8zTUMrkCWci66PRIBC+1mXepEnZH/q1f3ck0kJZ95a06bOTl5KU7HeXWtskkyefzARJ5zvCs54AD5nxjQJ+A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/rpc@6.10.0': + resolution: {integrity: sha512-EwxsqoD+NXV+m+iobnWNtATD93gTgaNsOiQOzYB1/2e+8S6fl6obdNPB55yfXgtl4jt6GV6/ae4xuPhLv76vvg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/signers@5.5.1': + resolution: {integrity: sha512-FY0IVaBT2kCAze55vEieR6hag4coqcuJ31Aw3hqRH7mv6sV8oqwuJmUrx+uFwOp1gwd5OEAzlv6N4hOOple4sQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/signers@6.10.0': + resolution: {integrity: sha512-+vtCc+mT1FpGxrA5oL2aaMxSHiMJ2hH5PcDIfjo2XJkHz2klZiCZyT5F9+zpltc9vdi1QTElQq59Sfplmtd33A==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/subscribable@5.5.1': + resolution: {integrity: sha512-9K0PsynFq0CsmK1CDi5Y2vUIJpCqkgSS5yfDN0eKPgHqEptLEaia09Kaxc90cSZDZU5mKY/zv1NBmB6Aro9zQQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/subscribable@6.10.0': + resolution: {integrity: sha512-VsR6XMwkiDBkZJUcoGkEOhf397pOV75gKCL9Bx8bpi2T3Bbs0CxUpMn4yaUgAnRba3eXmjbXMNCXjttfa6sKbw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/sysvars@5.5.1': + resolution: {integrity: sha512-k3Quq87Mm+geGUu1GWv6knPk0ALsfY6EKSJGw9xUJDHzY/RkYSBnh0RiOrUhtFm2TDNjOailg8/m0VHmi3reFA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/sysvars@6.10.0': + resolution: {integrity: sha512-cG13p1+onxz+20iWjwWQr1Z1jQwPm0fnjoW75fqZq7p4rVCie3L2sXvaJsYPjWKrUvpOzOIEHnqZGkG05rCpjg==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-confirmation@5.5.1': + resolution: {integrity: sha512-j4mKlYPHEyu+OD7MBt3jRoX4ScFgkhZC6H65on4Fux6LMScgivPJlwnKoZMnsgxFgWds0pl+BYzSiALDsXlYtw==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-confirmation@6.10.0': + resolution: {integrity: sha512-ULvtg65qfenh4T/GYcIlKSUv5EqDcng9UN0dxbHU4kuZdR2e0B8HN2xDC4WhcFQVeFJSbTZmaYFkeTY/Y4gfGQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-messages@5.5.1': + resolution: {integrity: sha512-aXyhMCEaAp3M/4fP0akwBBQkFPr4pfwoC5CLDq999r/FUwDax2RE/h4Ic7h2Xk+JdcUwsb+rLq85Y52hq84XvQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transaction-messages@6.10.0': + resolution: {integrity: sha512-s7v8G3BTxGlKYIj3eWCG0g1296v+1LBt16mVnlRH5FuyaJ5AdhlhtRho5HUDpdwE8EXun+y1c48V6uhcZ8wdbQ==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transactions@5.5.1': + resolution: {integrity: sha512-8hHtDxtqalZ157pnx6p8k10D7J/KY/biLzfgh9R09VNLLY3Fqi7kJvJCr7M2ik3oRll56pxhraAGCC9yIT6eOA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: ^5.0.0 + peerDependenciesMeta: + typescript: + optional: true + + '@solana/transactions@6.10.0': + resolution: {integrity: sha512-VADSqP9OTYmhrox4pcgDd4+RjVmednXSE0+8Y7SPK4PN1pK5Az2RJ0nSsy0xcTnaOr8mF/crwFktqPrRQwSbQA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.4.0' + peerDependenciesMeta: + typescript: + optional: true + + '@solana/wallet-standard-chains@1.1.2': + resolution: {integrity: sha512-EZobEGclDBAFplpJC5F3d/s8Xnlqc5isNKuPrd5o9ZPZ7tWN84O0e68yIZ8MAOj9V7ieRadNiHtql7uIXCTyXg==} + engines: {node: '>=22'} + + '@solana/wallet-standard-features@1.4.0': + resolution: {integrity: sha512-f0tAdqwM2aL6CiFbIgt9h5zKFp+mgY/iNGwoxPMTj9VSTeQj7d1GGSmWhZw0XWoZ4N/1tnKTKmYFq+Dyq08jRw==} + engines: {node: '>=22'} + + '@solana/wallet-standard-util@1.1.3': + resolution: {integrity: sha512-aweR5y5FjYaeS9TkoqAWERFpGUj2MJepsDhcekCuoPLcNCquJL85Nsnuy01tBybspN5+Y09SWkxwsODOFGSfkg==} + engines: {node: '>=22'} + + '@solana/webcrypto-ed25519-polyfill@4.0.0': + resolution: {integrity: sha512-QHRLO9B50+mj0sazjWJR6MVGO92a56TFjZ2CSql7mzMNy/5s0indlyO+iJmnAHxlzpTwU/ZMCnTkAfA7hg7HmA==} + engines: {node: '>=20.18.0'} + peerDependencies: + typescript: '>=5.3.3' + + '@tailwindcss/node@4.3.1': + resolution: {integrity: sha512-6NDaqRoAMSXD1mr/RXu0HBvNE9a2n5tHPsxu9XHLws8o4Twes5rBM2205SUUiJ9goAtadrN6xTGX0UDEwp/N4A==} + + '@tailwindcss/oxide-android-arm64@4.3.1': + resolution: {integrity: sha512-SVlyf61g374l5cHyg8x9kf5xmLcOaxvOTsbsqDnSsDJaKOEFZ7GCvi84VAVGpxojYOs1+3K6M0UjXfqPU8vmOQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [android] + + '@tailwindcss/oxide-darwin-arm64@4.3.1': + resolution: {integrity: sha512-hVnWLwv+e/l7c4WKyVtHVrIPvYdqWHjRB3MDIqARynzFtnQg85kmQEFCbV9Ja0VVx4xXTIiDWY60Y7iz/iNoDA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [darwin] + + '@tailwindcss/oxide-darwin-x64@4.3.1': + resolution: {integrity: sha512-Cf7abu0WVgbhU7ANgPUnSAvm7nCvMweusHb8FnaHlLfv/Caq4GYaEZg7ZImzzmjx4lIAfuS8q+eLIS7A7IzxIg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [darwin] + + '@tailwindcss/oxide-freebsd-x64@4.3.1': + resolution: {integrity: sha512-ZZqzX2Y+GXtXXfqSfpJhDm60OoZfvLHLCgm+J7NVqgHHJjG/m9ugZI77RwTsVd4fnBJuCFP6Ae6kTJb71UdS8g==} + engines: {node: '>= 20'} + cpu: [x64] + os: [freebsd] + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1': + resolution: {integrity: sha512-/Ah/xik0LaMYfv9DZ0S/t4pBlBNYOcqtRwusjgovHkvT8ixueWCLyJjsaF5kQIckjb4IT8Q6K6p/iPmZMixYgg==} + engines: {node: '>= 20'} + cpu: [arm] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.1': + resolution: {integrity: sha512-gqdFoVJlw444GvpnheZLHmvTzSxI/cOUUh2KSNejQjTcYkW062SVD+En0rUgD+QV91bz1XGIGtt1HJd48xUGbQ==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-arm64-musl@4.3.1': + resolution: {integrity: sha512-Bwv9KwOvE0VKa86xPFif9b9c3Y1NxOV1P0gLti/IYaWEsQYZXDlxfGEtA8mdDZ7SG3wyNXAWYT5SIn3giL57oA==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-gnu@4.3.1': + resolution: {integrity: sha512-Ymi8O8T15HYQdOUWUtTI6ldN0neHP85FC+Qz32xTcZ7iJXtem/x8ITev0o1e9e5rkqj4lONZfTRLvkmin1+tKg==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-linux-x64-musl@4.3.1': + resolution: {integrity: sha512-M+P/91qJ6uILLw4k2G93GMDRAXj61SMvFQYt39AqvUqYgExXpLL5aepfns7sj4HiAQeolirQF9E0lzRvdf4zPQ==} + engines: {node: '>= 20'} + cpu: [x64] + os: [linux] + + '@tailwindcss/oxide-wasm32-wasi@4.3.1': + resolution: {integrity: sha512-zsM8uOeqvVGHsAXsJxsT28ttosFahLJKCLOTUBqRAtKnVgGSRitds9T432QiT8b77Yga7JIBkulIRRlJPtYhRA==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + bundledDependencies: + - '@napi-rs/wasm-runtime' + - '@emnapi/core' + - '@emnapi/runtime' + - '@tybys/wasm-util' + - '@emnapi/wasi-threads' + - tslib + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.1': + resolution: {integrity: sha512-aiNvSq9BsVk8V513lDKlrCFAgf8qBMPZTpgEhInL+NwQqs97mYmupVMrPrgBBSL8Pv/0zXu9MrMF9rMun1ZeNg==} + engines: {node: '>= 20'} + cpu: [arm64] + os: [win32] + + '@tailwindcss/oxide-win32-x64-msvc@4.3.1': + resolution: {integrity: sha512-xDEyu1rg290472FEGaKHnzyDyh5QH+AlWvsU5hMoMtPpzmKlRI0jaYKCgSHDYtaQWZOYbMaduSyCwFwY4n1HmA==} + engines: {node: '>= 20'} + cpu: [x64] + os: [win32] + + '@tailwindcss/oxide@4.3.1': + resolution: {integrity: sha512-yVPyo8RNkabVr3O2EhHEE0Rewu7YKzc1DhIqfL46LKveFrmu9XbDazNOJY7/GRuvw1h6u3utWnR29H/p5JPlgA==} + engines: {node: '>= 20'} + + '@tailwindcss/postcss@4.3.1': + resolution: {integrity: sha512-dNJuNbdEJT/SWRuXTYP1WSamelsz3ztkUsdtWQPjrexysrTpaEPM40P/71knXiXLYEojqPOEGitVLLpPMS5T6A==} + + '@tanstack/query-core@5.101.0': + resolution: {integrity: sha512-cQetA74EB+seWySv1TTKr828TnP0u39m6LykwDXIo84SNortpDkp30TMEjkqtYCNP9c40uT/iwl6MLiufEt0Ow==} + + '@tanstack/react-query@5.101.0': + resolution: {integrity: sha512-rLlJXSpkqfizLWgkR5+eLeIk0MvTx/meEIR7LRjxic+qxiQP8zVjq7BqQkiCMNLQBlLfuOLqqr6KO5GtrDlmSg==} + peerDependencies: + react: ^18 || ^19 + + '@tybys/wasm-util@0.10.2': + resolution: {integrity: sha512-RoBvJ2X0wuKlWFIjrwffGw1IqZHKQqzIchKaadZZfnNpsAYp2mM0h36JtPCjNDAHGgYez/15uMBpfGwchhiMgg==} + + '@types/babel__core@7.20.5': + resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} + + '@types/babel__generator@7.27.0': + resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} + + '@types/babel__template@7.4.4': + resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} + + '@types/babel__traverse@7.28.0': + resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} + + '@types/eslint@9.6.1': + resolution: {integrity: sha512-FXx2pKgId/WyYo2jXw63kk7/+TY7u7AziEJxJAnSFzHlqTAS3Ync6SvgYAN/k4/PQpnnVuzoMuVnByKK2qp0ag==} + + '@types/eslint__js@9.14.0': + resolution: {integrity: sha512-s0jepCjOJWB/GKcuba4jISaVpBudw3ClXJ3fUK4tugChUMQsp6kSwuA8Dcx6wFd/JsJqcY8n4rEpa5RTHs5ypA==} + deprecated: This is a stub types definition. @eslint/js provides its own type definitions, so you do not need this installed. + + '@types/estree@1.0.8': + resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} + + '@types/estree@1.0.9': + resolution: {integrity: sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==} + + '@types/hast@3.0.4': + resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} + + '@types/istanbul-lib-coverage@2.0.6': + resolution: {integrity: sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==} + + '@types/istanbul-lib-report@3.0.3': + resolution: {integrity: sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==} + + '@types/istanbul-reports@3.0.4': + resolution: {integrity: sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==} + + '@types/json-schema@7.0.15': + resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} + + '@types/mdast@4.0.4': + resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} + + '@types/node@25.9.3': + resolution: {integrity: sha512-603BddQMv3pUcr4U2dhujk83N2tTDVr/34wII2B6bJy6g+8WD6yUb11jszNs0gdi4PesVWl7ABt8nYMVpnLUcg==} + + '@types/react-dom@19.2.3': + resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} + peerDependencies: + '@types/react': ^19.2.0 + + '@types/react@19.2.17': + resolution: {integrity: sha512-MXfmqaVPEVgkBT/aY0aGCkRWWtByiYQXo3xdQ8r5RzuFrPiRn8Gar2tQdXSUQ2GKV3bkXckek89V8wQBY2Q/Aw==} + + '@types/semver@7.7.1': + resolution: {integrity: sha512-FmgJfu+MOcQ370SD0ev7EI8TlCAfKYU+B4m5T3yXc1CiRN94g/SZPtsCkk506aUDtlMnFZvasDwHHUcZUEaYuA==} + + '@types/stack-utils@2.0.3': + resolution: {integrity: sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==} + + '@types/unist@3.0.3': + resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} + + '@types/yargs-parser@21.0.3': + resolution: {integrity: sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==} + + '@types/yargs@17.0.35': + resolution: {integrity: sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==} + + '@typescript-eslint/eslint-plugin@8.61.1': + resolution: {integrity: sha512-ZPlVl3PB3et/59Ne0fv/sci6ZXz4T4Hp4nTJ56i/Y0gR89ARb+KphojTq6j+56E5PIezmOIOOWyY+aWQFd+IkQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + '@typescript-eslint/parser': ^8.61.1 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/experimental-utils@5.62.0': + resolution: {integrity: sha512-RTXpeB3eMkpoclG3ZHft6vG/Z30azNHuqY6wKPBHlVMZFuEvrtlEDe8gMqDb+SO+9hjC/pLekeSCryf9vMZlCw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@typescript-eslint/parser@8.61.1': + resolution: {integrity: sha512-PJ5vePq5/ognBbrIcoC5+SHO5dfpeLPzP9FpLkzWrguoYQEeeSjlJpVwOpo1JRSTEi7dRcwNy4h4dzV70PqHcg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/project-service@8.61.1': + resolution: {integrity: sha512-PrC4JYGmR241lYnfhmKGTXkFqv8+ymbTFgSAY0fVXpY82/QkMw5TZPl+vGzuDDU2QYJk9fIDOBTntF+yDv9LEA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/scope-manager@5.62.0': + resolution: {integrity: sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/scope-manager@8.61.1': + resolution: {integrity: sha512-L2bdIeoQS8FlKAvONAr20w6OcLXeB+qiDKbAooS9A0Ben+iSIkBef0FxqwKWYqt5sa0i4KJtxVyVmhMylKzF5w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/tsconfig-utils@8.61.1': + resolution: {integrity: sha512-UN/H4di+OO7EWx2ovME+8t31YO+KVnK0RRKEHR3kOt21/Ay8BOq3M1OMvWs5vNiqcFCYGYoxK3MXPZzmMUE+yg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/type-utils@8.61.1': + resolution: {integrity: sha512-GYRicKmVK0C4fsKgaACaknOUAq9Oa2kwsjnpFhFcS/5p4Ht5IP9OVLbgIgcK4SRk92nVHFluurg1lumD9dBcLw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/types@5.62.0': + resolution: {integrity: sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/types@8.61.1': + resolution: {integrity: sha512-G+CRlPqLv7Bz1IZVs03x5K59F1veqL0EJUROAdGhKsEq8qOiRiZbI+HUojPq5l0fEGOKModD9br6lObhB8zkoA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@typescript-eslint/typescript-estree@5.62.0': + resolution: {integrity: sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + + '@typescript-eslint/typescript-estree@8.61.1': + resolution: {integrity: sha512-u+oQD3BqYWPc8YV9Zab4vaJElJuwOLPRc10Jm1o/qS+6Qwen14HCWwx0Seo4LnSn2wxea2Ik8DxPt2/FHmuhrg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/utils@5.62.0': + resolution: {integrity: sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + peerDependencies: + eslint: ^6.0.0 || ^7.0.0 || ^8.0.0 + + '@typescript-eslint/utils@8.61.1': + resolution: {integrity: sha512-1+P/3Dj6jvtybE1q0HQ6yBt/gq+oKJyLdEv4HdnqasaEXRSYCAsD59mXEVQnM/ULNdQxbX77tdG4jPRjIS6knA==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + '@typescript-eslint/visitor-keys@5.62.0': + resolution: {integrity: sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + '@typescript-eslint/visitor-keys@8.61.1': + resolution: {integrity: sha512-6fJ9MHWtK14C1DSkiMlHUSOmrVebL7150xZJBlJiL62jjhIA4JmOq6flwBgDxIdBKKdoiZRel+dfPD5MLfny3w==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + '@ungap/structured-clone@1.3.1': + resolution: {integrity: sha512-mUFwbeTqrVgDQxFveS+df2yfap6iuP20NAKAsBt5jDEoOTDew+zwLAOilHCeQJOVSvmgCX4ogqIrA0mnyr08yQ==} + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + resolution: {integrity: sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==} + cpu: [arm] + os: [android] + + '@unrs/resolver-binding-android-arm64@1.12.2': + resolution: {integrity: sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==} + cpu: [arm64] + os: [android] + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + resolution: {integrity: sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==} + cpu: [arm64] + os: [darwin] + + '@unrs/resolver-binding-darwin-x64@1.12.2': + resolution: {integrity: sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==} + cpu: [x64] + os: [darwin] + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + resolution: {integrity: sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==} + cpu: [x64] + os: [freebsd] + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + resolution: {integrity: sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + resolution: {integrity: sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==} + cpu: [arm] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + resolution: {integrity: sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + resolution: {integrity: sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==} + cpu: [arm64] + os: [linux] + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + resolution: {integrity: sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==} + cpu: [loong64] + os: [linux] + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + resolution: {integrity: sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==} + cpu: [loong64] + os: [linux] + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + resolution: {integrity: sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==} + cpu: [ppc64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + resolution: {integrity: sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + resolution: {integrity: sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==} + cpu: [riscv64] + os: [linux] + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + resolution: {integrity: sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==} + cpu: [s390x] + os: [linux] + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + resolution: {integrity: sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + resolution: {integrity: sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==} + cpu: [x64] + os: [linux] + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + resolution: {integrity: sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==} + cpu: [arm64] + os: [openharmony] + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + resolution: {integrity: sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==} + engines: {node: '>=14.0.0'} + cpu: [wasm32] + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + resolution: {integrity: sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==} + cpu: [arm64] + os: [win32] + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + resolution: {integrity: sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==} + cpu: [ia32] + os: [win32] + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + resolution: {integrity: sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==} + cpu: [x64] + os: [win32] + + '@vercel/og@0.11.1': + resolution: {integrity: sha512-02rXXRABFq1B03w3aNhcVfxkY+8Ba5QFi4ax0zS0oOiD/LL9WUd/LA7BjVPakrQmVhIBjuo2oBM5U25R9IuXMg==} + engines: {node: '>=16'} + + '@vitejs/plugin-react@6.0.2': + resolution: {integrity: sha512-DlSMqo4WhThw4vB8Mpn0Woe9J+Jfq1geJ61AKW0QEgLzGMNwtIMdxbDUzLxcun8W7NbJO0e2Jg/Nxm3cCSVzzg==} + engines: {node: ^20.19.0 || >=22.12.0} + peerDependencies: + '@rolldown/plugin-babel': ^0.1.7 || ^0.2.0 + babel-plugin-react-compiler: ^1.0.0 + vite: ^8.0.0 + peerDependenciesMeta: + '@rolldown/plugin-babel': + optional: true + babel-plugin-react-compiler: + optional: true + + '@wallet-standard/app@1.1.1': + resolution: {integrity: sha512-WDGwoByhP5gwHH01r5EaLgQdLVkACPCdOMQhmhn8rsm10h/siSgTorShzBxrn0ExSPof+Lu+C3TfgqBrPa1xoQ==} + engines: {node: '>=22'} + + '@wallet-standard/base@1.1.1': + resolution: {integrity: sha512-gggIHTtxicF9XFMQ12DkfS6NAG92Ak795JeSA7f2whAQ6Y3AkMWWuCMxSZXG2NIPN42kEaZSNVjqMsJRaJRxMQ==} + engines: {node: '>=22'} + + '@wallet-standard/core@1.1.2': + resolution: {integrity: sha512-QcVLGDkFtsWjTpkej2jx4FyP2cu+qOAW/lVnvlWjyhCkSEje6z+vEKURV5v+7L6IXjbze5pyFBe24yrPyoUuyw==} + engines: {node: '>=22'} + + '@wallet-standard/errors@0.1.2': + resolution: {integrity: sha512-oEzKUqJefKby6wcIvaJgrSEe/uNn/rnqkJ0P/85K+h0i5Tdo9E3L22VWq/j5K1e8hHMnZd6LgaIr8m/Wn7X/Ng==} + engines: {node: '>=22'} + hasBin: true + + '@wallet-standard/features@1.1.1': + resolution: {integrity: sha512-aCWYmVeSCGViyEU5k7GMoW8zxE4Gs+C1s1Pp2XLesvSNlnZ4PMES9HUnTB3hl0b3RVj7C61yze3IWyrncqg4MA==} + engines: {node: '>=22'} + + '@wallet-standard/wallet@1.1.1': + resolution: {integrity: sha512-8WiRPaKk/wNNRZhB2eVhpR/JW7/aqTCMoZhgVUCujuzDmxxmGvsosMxdCG4NAdYkoyozAHCX8/xLtlWUn5mNdQ==} + engines: {node: '>=22'} + + '@wallet-ui/core@2.2.2': + resolution: {integrity: sha512-Q81TrV0pfGlpzzkt6hYxcDt595VhyIIL+zzyEEZgXu7GpUpK5EencSwGe32tpE8p2ArJunz2jgaxvn4Z9+pTuw==} + engines: {node: '>=20.18.0'} + peerDependencies: + '@solana/kit': ^5.0.0 + + a-sync-waterfall@1.0.1: + resolution: {integrity: sha512-RYTOHHdWipFUliRFMCS4X2Yn2X8M87V/OpSqWzKKOGhzqyUxzyVmhHDH9sAvG+ZuQf/TAOFsLCpMw09I1ufUnA==} + + abort-controller@3.0.0: + resolution: {integrity: sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==} + engines: {node: '>=6.5'} + + accepts@2.0.0: + resolution: {integrity: sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng==} + engines: {node: '>= 0.6'} + + acorn-jsx@5.3.2: + resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} + peerDependencies: + acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 + + acorn@7.4.1: + resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} + engines: {node: '>=0.4.0'} + hasBin: true + + acorn@8.17.0: + resolution: {integrity: sha512-xRQbDb9BnwDafYNn6Vwl839DYVjqXYb1XVGtWAZ1kcDc6iwAL4hg3B1dZlRiuENFeO2H53gFG3in621AdERVAg==} + engines: {node: '>=0.4.0'} + hasBin: true + + agent-base@7.1.4: + resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} + engines: {node: '>= 14'} + + ajv@6.15.0: + resolution: {integrity: sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==} + + anser@1.4.10: + resolution: {integrity: sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==} + + ansi-escapes@4.3.2: + resolution: {integrity: sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==} + engines: {node: '>=8'} + + ansi-regex@5.0.1: + resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} + engines: {node: '>=8'} + + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: + resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} + engines: {node: '>=8'} + + ansi-styles@5.2.0: + resolution: {integrity: sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==} + engines: {node: '>=10'} + + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + any-promise@1.3.0: + resolution: {integrity: sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==} + + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + + anynum@1.0.1: + resolution: {integrity: sha512-N6//FLET/tXYNM/F6ABca1oH6fWB+KlTt909Le28WMDBk8oaT4vY17DCrwg2MvmuqUKt3Ni4N5dGJ/EoBgcO6A==} + + argparse@1.0.10: + resolution: {integrity: sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==} + + argparse@2.0.1: + resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} + + aria-hidden@1.2.6: + resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} + engines: {node: '>=10'} + + array-union@2.1.0: + resolution: {integrity: sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==} + engines: {node: '>=8'} + + asap@2.0.6: + resolution: {integrity: sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==} + + autoprefixer@10.5.0: + resolution: {integrity: sha512-FMhOoZV4+qR6aTUALKX2rEqGG+oyATvwBt9IIzVR5rMa2HRWPkxf+P+PAJLD1I/H5/II+HuZcBJYEFBpq39ong==} + engines: {node: ^10 || ^12 || >=14} + hasBin: true + peerDependencies: + postcss: ^8.1.0 + + babel-jest@30.4.1: + resolution: {integrity: sha512-fATAbM8piYxkiXQp3RBXmZHxZVNJZAVXXfyeyCN2Tida3+qJ8ea9UxhiJ2y4fLO90ZImKt6k9FlcH2+rLkJGhw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 || ^8.0.0-0 + + babel-plugin-istanbul@7.0.1: + resolution: {integrity: sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==} + engines: {node: '>=12'} + + babel-plugin-jest-hoist@30.4.0: + resolution: {integrity: sha512-9EdtWM/sSfXLOGLwSn+GS6pIXyBnL07/8gyJlwFXjWy4DxMOyItqyUT29d4lQiS380EZwYlX7/At4PgBS+m2aA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + babel-plugin-syntax-hermes-parser@0.36.0: + resolution: {integrity: sha512-LhD0xdoedDw7ansQgXbB2DADLZIK/LRXuWNBPuVzMc5S2WK5GyT89tCM+cQzxFGO0mGyLK6D5TrVOJJzAoDy8Q==} + + babel-preset-current-node-syntax@1.2.0: + resolution: {integrity: sha512-E/VlAEzRrsLEb2+dv8yp3bo4scof3l9nR4lrld+Iy5NyVqgVYUJnDAmunkhPMisRI32Qc4iRiz425d8vM++2fg==} + peerDependencies: + '@babel/core': ^7.0.0 || ^8.0.0-0 + + babel-preset-jest@30.4.0: + resolution: {integrity: sha512-lBY4jxsNmCnSiu7kquw8ZC9F4+XLMOKypT3RnNHPvU2Kpd4W0xaPuLr5ZkRyOsvLYAY4yaW1ZwTW4xB7NIiZzg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@babel/core': ^7.11.0 || ^8.0.0-beta.1 + + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + base-x@4.0.1: + resolution: {integrity: sha512-uAZ8x6r6S3aUM9rbHGVOIsR15U/ZSc82b3ymnCPsT45Gk1DDvhDPdIgB5MrhirZWt+5K0EEPQH985kNqZgNPFw==} + + base64-js@0.0.8: + resolution: {integrity: sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==} + engines: {node: '>= 0.4'} + + base64-js@1.5.1: + resolution: {integrity: sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==} + + baseline-browser-mapping@2.10.38: + resolution: {integrity: sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw==} + engines: {node: '>=6.0.0'} + hasBin: true + + bowser@2.14.1: + resolution: {integrity: sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==} + + brace-expansion@2.1.1: + resolution: {integrity: sha512-WR1cURNjuvBLMZBMbqM0UoE+WAfdUcEV1ccD8PVBVOI+Z3ND4+SZbN8RsfT2bMuG1qwz5RFvPukSZm5fF2D5eA==} + + braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + + browserslist@4.28.2: + resolution: {integrity: sha512-48xSriZYYg+8qXna9kwqjIVzuQxi+KYWp2+5nCYnYKPTr0LvD89Jqk2Or5ogxz0NUMfIjhh2lIUX/LyX9B4oIg==} + engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} + hasBin: true + + bs58@5.0.0: + resolution: {integrity: sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==} + + bser@2.1.1: + resolution: {integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==} + + buffer-from@1.1.2: + resolution: {integrity: sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==} + + bundle-require@5.1.0: + resolution: {integrity: sha512-3WrrOuZiyaaZPWiEt4G3+IffISVC9HYlWueJEBWED4ZH4aIAC2PnkdnuRrR94M+w6yGWn4AglWtJtBI8YqvgoA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + peerDependencies: + esbuild: '>=0.18' + + cac@6.7.14: + resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} + engines: {node: '>=8'} + + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + + call-bind@1.0.9: + resolution: {integrity: sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==} + engines: {node: '>= 0.4'} + + call-bound@1.0.4: + resolution: {integrity: sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==} + engines: {node: '>= 0.4'} + + callsites@3.1.0: + resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} + engines: {node: '>=6'} + + camelcase@5.3.1: + resolution: {integrity: sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==} + engines: {node: '>=6'} + + camelcase@6.3.0: + resolution: {integrity: sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==} + engines: {node: '>=10'} + + camelize@1.0.1: + resolution: {integrity: sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==} + + caniuse-lite@1.0.30001799: + resolution: {integrity: sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw==} + + ccount@2.0.1: + resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} + + chalk@4.1.2: + resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} + engines: {node: '>=10'} + + chalk@5.6.2: + resolution: {integrity: sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==} + engines: {node: ^12.17.0 || ^14.13 || >=16.0.0} + + char-regex@1.0.2: + resolution: {integrity: sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==} + engines: {node: '>=10'} + + character-entities-html4@2.1.0: + resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} + + character-entities-legacy@3.0.0: + resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} + + chokidar@4.0.3: + resolution: {integrity: sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==} + engines: {node: '>= 14.16.0'} + + chrome-launcher@0.15.2: + resolution: {integrity: sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==} + engines: {node: '>=12.13.0'} + hasBin: true + + chromium-edge-launcher@0.3.0: + resolution: {integrity: sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==} + + ci-info@2.0.0: + resolution: {integrity: sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==} + + ci-info@3.9.0: + resolution: {integrity: sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==} + engines: {node: '>=8'} + + ci-info@4.4.0: + resolution: {integrity: sha512-77PSwercCZU2Fc4sX94eF8k8Pxte6JAwL4/ICZLFjJLqegs7kCuAsqqj/70NQF6TvDpgFjkubQB2FW2ZZddvQg==} + engines: {node: '>=8'} + + cjs-module-lexer@2.2.0: + resolution: {integrity: sha512-4bHTS2YuzUvtoLjdy+98ykbNB5jS0+07EvFNXerqZQJ89F7DI6ET7OQo/HJuW6K0aVsKA9hj9/RVb2kQVOrPDQ==} + + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + + cliui@6.0.0: + resolution: {integrity: sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==} + + cliui@8.0.1: + resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} + engines: {node: '>=12'} + + clsx@2.1.1: + resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} + engines: {node: '>=6'} + + co@4.6.0: + resolution: {integrity: sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==} + engines: {iojs: '>= 1.0.0', node: '>= 0.12.0'} + + codama@1.8.0: + resolution: {integrity: sha512-P1hctEUpZfgjm3xfosrD4xo/SVnp17ONuGDDtBmkyOaJBBL2JkYXjomZF9xOQqhvlfgcgqRKNB96Lcs4MG/fLQ==} + hasBin: true + + collect-v8-coverage@1.0.3: + resolution: {integrity: sha512-1L5aqIkwPfiodaMgQunkF1zRhNqifHBmtbbbxcr6yVxxBnliw4TDOW6NxpO8DJLgJ16OT+Y4ztZqP6p/FtXnAw==} + + color-convert@2.0.1: + resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} + engines: {node: '>=7.0.0'} + + color-name@1.1.4: + resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} + + comma-separated-tokens@2.0.3: + resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} + + commander@12.1.0: + resolution: {integrity: sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==} + engines: {node: '>=18'} + + commander@13.1.0: + resolution: {integrity: sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==} + engines: {node: '>=18'} + + commander@14.0.2: + resolution: {integrity: sha512-TywoWNNRbhoD0BXs1P3ZEScW8W5iKrnbithIl0YH+uCmBd0QpPOA8yc82DS3BIE5Ma6FnBVUsJ7wVUDz4dvOWQ==} + engines: {node: '>=20'} + + commander@14.0.3: + resolution: {integrity: sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==} + engines: {node: '>=20'} + + commander@15.0.0: + resolution: {integrity: sha512-z67u4ZhzCL/Tydu1lJARtEZYWbWaN7oYLHbsuzocr6y4N6WZAagG3RQ4FW61V1/0+jImpj293XfrcYnd1qxtPg==} + engines: {node: '>=22.12.0'} + + commander@2.20.3: + resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + + commander@4.1.1: + resolution: {integrity: sha512-NOKm8xhkzAjzFx8B2v5OAHT+u5pRQc2UCa2Vq9jYL/31o2wi9mxBA7LIFs3sV5VSC49z6pEhfbMULvShKj26WA==} + engines: {node: '>= 6'} + + commander@5.1.0: + resolution: {integrity: sha512-P0CysNDQ7rtVw4QIQtm+MRxV66vKFSvlsQvGYXZWR3qFU0jlMKHZZZgw8e+8DSah4UDKMqnknRDQz+xuQXQ/Zg==} + engines: {node: '>= 6'} + + confbox@0.1.8: + resolution: {integrity: sha512-RMtmw0iFkeR4YV+fUOSucriAQNb9g8zFR52MWCtl+cCZOFRNL6zeB395vPzFhEjjn4fMxXudmELnl/KF/WrK6w==} + + connect@3.7.0: + resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==} + engines: {node: '>= 0.10.0'} + + consola@3.4.2: + resolution: {integrity: sha512-5IKcdX0nnYavi6G7TtOhwkYzyjfJlatbjMjuLSfE2kYT5pMDOilZ4OvMhi637CcDICTmz3wARPoyhqyX1Y+XvA==} + engines: {node: ^14.18.0 || >=16.10.0} + + convert-source-map@2.0.0: + resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + + cookie@1.1.1: + resolution: {integrity: sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==} + engines: {node: '>=18'} + + country-flag-icons@1.6.17: + resolution: {integrity: sha512-Nmik0289ZVZSI3c7mJR/amg6DyY7Z59b0sTFSKayeX72mHfPzCPJygwJs2pYgQULzuAyWeCUgwAJ+Dq8OR+JFw==} + + cross-spawn@7.0.6: + resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} + engines: {node: '>= 8'} + + css-background-parser@0.1.0: + resolution: {integrity: sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA==} + + css-box-shadow@1.0.0-3: + resolution: {integrity: sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg==} + + css-color-keywords@1.0.0: + resolution: {integrity: sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==} + engines: {node: '>=4'} + + css-gradient-parser@0.0.17: + resolution: {integrity: sha512-w2Xy9UMMwlKtou0vlRnXvWglPAceXCTtcmVSo8ZBUvqCV5aXEFP/PC6d+I464810I9FT++UACwTD5511bmGPUg==} + engines: {node: '>=16'} + + css-to-react-native@3.2.0: + resolution: {integrity: sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==} + + csstype@3.2.3: + resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} + + debug@2.6.9: + resolution: {integrity: sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + debug@4.4.3: + resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + + decamelize@1.2.0: + resolution: {integrity: sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==} + engines: {node: '>=0.10.0'} + + dedent@1.7.2: + resolution: {integrity: sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==} + peerDependencies: + babel-plugin-macros: ^3.1.0 + peerDependenciesMeta: + babel-plugin-macros: + optional: true + + deep-is@0.1.4: + resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} + + deepmerge@4.3.1: + resolution: {integrity: sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==} + engines: {node: '>=0.10.0'} + + define-data-property@1.1.4: + resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} + engines: {node: '>= 0.4'} + + depd@2.0.0: + resolution: {integrity: sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==} + engines: {node: '>= 0.8'} + + dequal@2.0.3: + resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} + engines: {node: '>=6'} + + destroy@1.2.0: + resolution: {integrity: sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==} + engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + + detect-libc@2.1.2: + resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} + engines: {node: '>=8'} + + detect-newline@3.1.0: + resolution: {integrity: sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==} + engines: {node: '>=8'} + + detect-node-es@1.1.0: + resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} + + devlop@1.1.0: + resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} + + dijkstrajs@1.0.3: + resolution: {integrity: sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==} + + dir-glob@3.0.1: + resolution: {integrity: sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==} + engines: {node: '>=8'} + + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + ee-first@1.1.1: + resolution: {integrity: sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==} + + electron-to-chromium@1.5.375: + resolution: {integrity: sha512-ZWP5eB4BVPW/ZYo9252hQZHZ5XavtsTgpbhcmMmRwymavC5AsLWQWBPaKMeNd2LW0KGby5HPXvj7+sr4ta5j/Q==} + + emittery@0.13.1: + resolution: {integrity: sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==} + engines: {node: '>=12'} + + emoji-regex-xs@2.0.1: + resolution: {integrity: sha512-1QFuh8l7LqUcKe24LsPUNzjrzJQ7pgRwp1QMcZ5MX6mFplk2zQ08NVCM84++1cveaUUYtcCYHmeFEuNg16sU4g==} + engines: {node: '>=10.0.0'} + + emoji-regex@8.0.0: + resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} + + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + encodeurl@1.0.2: + resolution: {integrity: sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==} + engines: {node: '>= 0.8'} + + encodeurl@2.0.0: + resolution: {integrity: sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==} + engines: {node: '>= 0.8'} + + enhanced-resolve@5.21.6: + resolution: {integrity: sha512-aNnGCvbJ/RIyWo1IuhNdVjnNF+EjH9wpzpNHt+ci/m9He9LJvUN8wrCcXjp9cWsGNAuvSpVFTx/vraAFQ8qGjQ==} + engines: {node: '>=10.13.0'} + + error-ex@1.3.4: + resolution: {integrity: sha512-sqQamAnR14VgCr1A618A3sGrygcpK+HEbenA/HiEAkkUwcZIIB/tgWqHFxWgOyDh4nB4JCRimh79dR5Ywc9MDQ==} + + error-stack-parser@2.1.4: + resolution: {integrity: sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==} + + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + + es-errors@1.3.0: + resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} + engines: {node: '>= 0.4'} + + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + esbuild@0.27.7: + resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + engines: {node: '>=18'} + hasBin: true + + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} + engines: {node: '>=18'} + hasBin: true + + escalade@3.2.0: + resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} + engines: {node: '>=6'} + + escape-html@1.0.3: + resolution: {integrity: sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==} + + escape-string-regexp@2.0.0: + resolution: {integrity: sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==} + engines: {node: '>=8'} + + escape-string-regexp@4.0.0: + resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} + engines: {node: '>=10'} + + eslint-plugin-jest@29.15.2: + resolution: {integrity: sha512-kEN4r9RZl1xcsb4arGq89LrcVdOUFII/JSCwtTPJyv16mDwmPrcuEQwpxqZHeINvcsd7oK5O/rhdGlxFRaZwvQ==} + engines: {node: ^20.12.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@typescript-eslint/eslint-plugin': ^8.0.0 + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + jest: '*' + typescript: '>=4.8.4 <7.0.0' + peerDependenciesMeta: + '@typescript-eslint/eslint-plugin': + optional: true + jest: + optional: true + typescript: + optional: true + + eslint-plugin-react-hooks@7.1.1: + resolution: {integrity: sha512-f2I7Gw6JbvCexzIInuSbZpfdQ44D7iqdWX01FKLvrPgqxoE7oMj8clOfto8U6vYiz4yd5oKu39rRSVOe1zRu0g==} + engines: {node: '>=18'} + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 || ^10.0.0 + + eslint-plugin-simple-import-sort@12.1.1: + resolution: {integrity: sha512-6nuzu4xwQtE3332Uz0to+TxDQYRLTKRESSc2hefVT48Zc8JthmN23Gx9lnYhu0FtkRSL1oxny3kJ2aveVhmOVA==} + peerDependencies: + eslint: '>=5.0.0' + + eslint-plugin-sort-keys-fix@1.1.2: + resolution: {integrity: sha512-DNPHFGCA0/hZIsfODbeLZqaGY/+q3vgtshF85r+YWDNCQ2apd9PNs/zL6ttKm0nD1IFwvxyg3YOTI7FHl4unrw==} + engines: {node: '>=0.10.0'} + + eslint-plugin-typescript-sort-keys@3.3.0: + resolution: {integrity: sha512-bRW3Rc/VNdrSP9OoY5wgjjaXCOOkZKpzvl/Mk6l8Sg8CMehVIcg9K4y33l+ZcZiknpl0aR6rKusxuCJNGZWmVw==} + engines: {node: '>= 16'} + peerDependencies: + '@typescript-eslint/parser': '>=6' + eslint: ^7 || ^8 + typescript: ^3 || ^4 || ^5 + + eslint-scope@5.1.1: + resolution: {integrity: sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==} + engines: {node: '>=8.0.0'} + + eslint-scope@8.4.0: + resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@1.3.0: + resolution: {integrity: sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==} + engines: {node: '>=4'} + + eslint-visitor-keys@3.4.3: + resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} + engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} + + eslint-visitor-keys@4.2.1: + resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + eslint-visitor-keys@5.0.1: + resolution: {integrity: sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==} + engines: {node: ^20.19.0 || ^22.13.0 || >=24} + + eslint@9.39.4: + resolution: {integrity: sha512-XoMjdBOwe/esVgEvLmNsD3IRHkm7fbKIUGvrleloJXUZgDHig2IPWNniv+GwjyJXzuNqVjlr5+4yVUZjycJwfQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + hasBin: true + peerDependencies: + jiti: '*' + peerDependenciesMeta: + jiti: + optional: true + + espree@10.4.0: + resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + + espree@6.2.1: + resolution: {integrity: sha512-ysCxRQY3WaXJz9tdbWOwuWr5Y/XrPTGX9Kiz3yoUXwW0VZ4w30HTkQLaGx/+ttFjF8i+ACbArnB4ce68a9m5hw==} + engines: {node: '>=6.0.0'} + + esprima@4.0.1: + resolution: {integrity: sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==} + engines: {node: '>=4'} + hasBin: true + + esquery@1.7.0: + resolution: {integrity: sha512-Ap6G0WQwcU/LHsvLwON1fAQX9Zp0A2Y6Y/cJBl9r/JbW90Zyg4/zbG6zzKa2OTALELarYHmKu0GhpM5EO+7T0g==} + engines: {node: '>=0.10'} + + esrecurse@4.3.0: + resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} + engines: {node: '>=4.0'} + + estraverse@4.3.0: + resolution: {integrity: sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==} + engines: {node: '>=4.0'} + + estraverse@5.3.0: + resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} + engines: {node: '>=4.0'} + + esutils@2.0.3: + resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} + engines: {node: '>=0.10.0'} + + etag@1.8.1: + resolution: {integrity: sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==} + engines: {node: '>= 0.6'} + + event-target-shim@5.0.1: + resolution: {integrity: sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==} + engines: {node: '>=6'} + + execa@5.1.1: + resolution: {integrity: sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==} + engines: {node: '>=10'} + + exit-x@0.2.2: + resolution: {integrity: sha512-+I6B/IkJc1o/2tiURyz/ivu/O0nKNEArIUB5O7zBrlDVJr22SCLH3xTeEry428LvFhRzIA1g8izguxJ/gbNcVQ==} + engines: {node: '>= 0.8.0'} + + expect@30.4.1: + resolution: {integrity: sha512-PMARsyh/JtqC20HoGqlFcIlQAyqUtW4PlI1rup1uhYJtKuwAjbvWi3GQMAn+STdHum/dk8xrKfUM1+5SAwpolA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + exponential-backoff@3.1.3: + resolution: {integrity: sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==} + + fast-deep-equal@3.1.3: + resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} + + fast-glob@3.3.3: + resolution: {integrity: sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==} + engines: {node: '>=8.6.0'} + + fast-json-stable-stringify@2.1.0: + resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} + + fast-levenshtein@2.0.6: + resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} + + fast-xml-builder@1.2.0: + resolution: {integrity: sha512-00aAWieqff+ZJhsXA4g1g7M8k+7AYoMUUHF+/zFb5U6Uv/P0Vl4QZo84/IcufzYalLuEj9928bXN9PbbFzMF0Q==} + + fast-xml-parser@5.7.3: + resolution: {integrity: sha512-C0AaNuC+mscy6vrAQKAc/rMq+zAPHodfHGZu4sGVehvAQt/JLG1O5zEcYcXSY5zSqr4YVgxsB+pHXTq0i7eDlg==} + hasBin: true + + fastq@1.20.1: + resolution: {integrity: sha512-GGToxJ/w1x32s/D2EKND7kTil4n8OVk/9mycTc4VDza13lOvpUZTGX3mFSCtV9ksdGBVzvsyAVLM6mHFThxXxw==} + + fb-dotslash@0.5.8: + resolution: {integrity: sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==} + engines: {node: '>=20'} + hasBin: true + + fb-watchman@2.0.2: + resolution: {integrity: sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==} + + fdir@6.5.0: + resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} + engines: {node: '>=12.0.0'} + peerDependencies: + picomatch: 4.0.4 + peerDependenciesMeta: + picomatch: + optional: true + + fflate@0.7.4: + resolution: {integrity: sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw==} + + file-entry-cache@8.0.0: + resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} + engines: {node: '>=16.0.0'} + + fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + + finalhandler@1.1.2: + resolution: {integrity: sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==} + engines: {node: '>= 0.8'} + + find-up@4.1.0: + resolution: {integrity: sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==} + engines: {node: '>=8'} + + find-up@5.0.0: + resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} + engines: {node: '>=10'} + + fix-dts-default-cjs-exports@1.0.1: + resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} + + flat-cache@4.0.1: + resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} + engines: {node: '>=16'} + + flatted@3.4.2: + resolution: {integrity: sha512-PjDse7RzhcPkIJwy5t7KPWQSZ9cAbzQXcafsetQoD7sOJRQlGikNbx7yZp2OotDnJyrDcbyRq3Ttb18iYOqkxA==} + + flow-enums-runtime@0.0.6: + resolution: {integrity: sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==} + + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + fraction.js@5.3.4: + resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} + + framer-motion@12.40.0: + resolution: {integrity: sha512-uaBd3qC1v3KQqBEjwTUd183K6PbS+j0yR9w9VmEOLWA/tnUcSn8Xa3uck7t4dgpDoUss8xQTcj8W2L07lrnLFg==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + + fresh@0.5.2: + resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} + engines: {node: '>= 0.6'} + + fs.realpath@1.0.0: + resolution: {integrity: sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==} + + fsevents@2.3.2: + resolution: {integrity: sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + + function-bind@1.1.2: + resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} + + gensync@1.0.0-beta.2: + resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} + engines: {node: '>=6.9.0'} + + get-caller-file@2.0.5: + resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} + engines: {node: 6.* || 8.* || >= 10.*} + + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-nonce@1.0.1: + resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} + engines: {node: '>=6'} + + get-package-type@0.1.0: + resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==} + engines: {node: '>=8.0.0'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + + get-stream@6.0.1: + resolution: {integrity: sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==} + engines: {node: '>=10'} + + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + + glob-parent@6.0.2: + resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} + engines: {node: '>=10.13.0'} + + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + glob@7.2.3: + resolution: {integrity: sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + + globals@14.0.0: + resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} + engines: {node: '>=18'} + + globals@16.5.0: + resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} + engines: {node: '>=18'} + + globby@11.1.0: + resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} + engines: {node: '>=10'} + + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + + graceful-fs@4.2.11: + resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} + + has-flag@4.0.0: + resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} + engines: {node: '>=8'} + + has-property-descriptors@1.0.2: + resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} + + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + hasown@2.0.4: + resolution: {integrity: sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==} + engines: {node: '>= 0.4'} + + hast-util-to-html@9.0.5: + resolution: {integrity: sha512-OguPdidb+fbHQSU4Q4ZiLKnzWo8Wwsf5bZfbvu7//a9oTYoqD/fWpe96NuHkoS9h0ccGOTe0C4NGXdtS0iObOw==} + + hast-util-whitespace@3.0.0: + resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} + + hermes-compiler@250829098.0.14: + resolution: {integrity: sha512-5meXwsZxgiqFaJjNzwjzI9IyUkuGGBisu+z9BvQWmGVpjH6nz11hgqkyxe4dl8UAdyIV4lTbz91+Dlnjz0VxqA==} + + hermes-estree@0.25.1: + resolution: {integrity: sha512-0wUoCcLp+5Ev5pDW2OriHC2MJCbwLwuRx+gAqMTOkGKJJiBCLjtrvy4PWUGn6MIVefecRpzoOZ/UV6iGdOr+Cw==} + + hermes-estree@0.35.0: + resolution: {integrity: sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==} + + hermes-estree@0.36.0: + resolution: {integrity: sha512-A1+8zn5oss2CFP7pKsOaxorQG6FNIz1WU1VDqruLPPZl3LVgeE2C5xfFg8Ow6/Ow4mSslLLtYP1J3n38eKyW9w==} + + hermes-parser@0.25.1: + resolution: {integrity: sha512-6pEjquH3rqaI6cYAXYPcz9MS4rY6R4ngRgrgfDshRptUZIc3lw0MCIJIGDj9++mfySOuPTHB4nrSW99BCvOPIA==} + + hermes-parser@0.35.0: + resolution: {integrity: sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==} + + hermes-parser@0.36.0: + resolution: {integrity: sha512-GdpwMmH5x6IpC1cijvcvYnlPB60Mh6kTSF/NFdYV/j56gYdi+0RIakYs+eqOV+bbO0SW7mgVVGSsTJxyPQfo3w==} + + hex-rgb@4.3.0: + resolution: {integrity: sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==} + engines: {node: '>=6'} + + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + html-void-elements@3.0.0: + resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} + + http-errors@2.0.1: + resolution: {integrity: sha512-4FbRdAX+bSdmo4AUFuS0WNiPz8NgFt+r8ThgNWmlrjQjt1Q7ZR9+zTlce2859x4KSXrwIsaeTqDoKQmtP8pLmQ==} + engines: {node: '>= 0.8'} + + https-proxy-agent@7.0.6: + resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} + engines: {node: '>= 14'} + + human-signals@2.1.0: + resolution: {integrity: sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==} + engines: {node: '>=10.17.0'} + + ignore@5.3.2: + resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} + engines: {node: '>= 4'} + + ignore@7.0.5: + resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} + engines: {node: '>= 4'} + + image-size@1.2.1: + resolution: {integrity: sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==} + engines: {node: '>=16.x'} + hasBin: true + + import-fresh@3.3.1: + resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} + engines: {node: '>=6'} + + import-local@3.2.0: + resolution: {integrity: sha512-2SPlun1JUPWoM6t3F0dw0FkCF/jWY8kttcY4f599GLTSjh2OCuuhdTkJQsEcZzBqbXZGKMK2OqW1oZsjtf/gQA==} + engines: {node: '>=8'} + hasBin: true + + imurmurhash@0.1.4: + resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} + engines: {node: '>=0.8.19'} + + inflight@1.0.6: + resolution: {integrity: sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==} + deprecated: This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful. + + inherits@2.0.4: + resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} + + invariant@2.2.4: + resolution: {integrity: sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==} + + is-arrayish@0.2.1: + resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==} + + is-docker@2.2.1: + resolution: {integrity: sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==} + engines: {node: '>=8'} + hasBin: true + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-fullwidth-code-point@3.0.0: + resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} + engines: {node: '>=8'} + + is-generator-fn@2.1.0: + resolution: {integrity: sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==} + engines: {node: '>=6'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + is-stream@2.0.1: + resolution: {integrity: sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==} + engines: {node: '>=8'} + + is-wsl@2.2.0: + resolution: {integrity: sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==} + engines: {node: '>=8'} + + isarray@2.0.5: + resolution: {integrity: sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==} + + isexe@2.0.0: + resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} + + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-instrument@6.0.3: + resolution: {integrity: sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==} + engines: {node: '>=10'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jest-changed-files@30.4.1: + resolution: {integrity: sha512-IuctmYrxi21iOSOaIXpJWalHyPAsVv0GeBHKDn8C1CA4W5htHn7INL+wdnL4Bo0+olEndvAFkmb++tIQJG+vvg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-circus@30.4.2: + resolution: {integrity: sha512-rvHH7VlY6LgbJXJTQ87GW62g1FntOtbhh0zT+v04kC+pgL6aBKyYINXxWukCpj3dcIBMw5/XUbtDS9dU9JTXeQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-cli@30.4.2: + resolution: {integrity: sha512-jfA2ocvVHMXS2QijrJ0d31ektP+d/W0T5RpcTX2Pq+3sVqHlsXVCM2+FmwpL+bdY8OfHpIg9xMxLF17Zg0U49Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jest-config@30.4.2: + resolution: {integrity: sha512-rNHAShJQqQwFNoL0hbf3BphSBOWnpOUAKvidLS/AjNVLPfoj5mSf4jQMfW3cYOs6hXeZC7nF7mDHaBnbxELOzg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + peerDependencies: + '@types/node': '*' + esbuild-register: '>=3.4.0' + ts-node: '>=9.0.0' + peerDependenciesMeta: + '@types/node': + optional: true + esbuild-register: + optional: true + ts-node: + optional: true + + jest-diff@30.4.1: + resolution: {integrity: sha512-CRpFK0RtLriVDGcPPAnR6HMVI8bSR2jnUIgralhauzYQZIb4RH9AtEInTuQr65LmmGggGcRT6HIASxwqsVsmlA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-docblock@30.4.0: + resolution: {integrity: sha512-ZPMabUZCx5MpbZ2eBYSvZ0J8fvo3dR9oM+eeUpb3aKNQFuS2tu3Duw1TNlMoP8k3WQgKGJuhcMFvwcVuq6T7oA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-each@30.4.1: + resolution: {integrity: sha512-/8MJbH6fuj48TstjrMf+u/pd06Qezz5xOXvZA6442heNOWr8bdeoGZX2d9fCn028CoMgYmroH9//zky5GfyYmA==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-environment-node@30.4.1: + resolution: {integrity: sha512-4FZYVOk85hz2AyT6BbarKy9u37g6DbrDyCdFhsnDdXqyrueYQvB+0zO4f/kqLCRD0BsPRXPMNJeQwihKZV8naw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-get-type@29.6.3: + resolution: {integrity: sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-haste-map@30.4.1: + resolution: {integrity: sha512-rFrcONd8jeFsyw+Z9CrScJgglRf2+NFmNam8dKu7n+SoHqNYT47mn0DdEcVUZJpvh7Iz6/si7f7yUH7GJHVgnw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-leak-detector@30.4.1: + resolution: {integrity: sha512-IpmyiioeHxiWDhesHnUFmOxcTzwCwKpgACgWajtAP+nYQXiY7DakTxB6Bx9JFiRMljr0AX1PvnQdaU1KFoz6NQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-matcher-utils@30.4.1: + resolution: {integrity: sha512-zvYfX5CaeEkFrrLS9suWe9rvJrm9J1Iv3ua8kIBv9GEPzcnsfBf0bob37la7s67fs0nlBC3EuvkOLnXQKxtx4A==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-message-util@30.4.1: + resolution: {integrity: sha512-kwCKIvq0MCW1HzLoGola9Te6JUdzgV0loyKJ3Qghrkz9i5/RRIHsL95BMQc2HBBhlBKC4j22K9p11TGHH8RBpQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-mock@30.4.1: + resolution: {integrity: sha512-/i8SVb8/NSB7RfNi8gfqu8gxLV23KaL5EpAttyb9iz8qWRIqXRLflycz/32wXsYkOnaUlx8NAKnJYtpsmXUmfw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-pnp-resolver@1.2.3: + resolution: {integrity: sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==} + engines: {node: '>=6'} + peerDependencies: + jest-resolve: '*' + peerDependenciesMeta: + jest-resolve: + optional: true + + jest-regex-util@30.4.0: + resolution: {integrity: sha512-mWlvLviKIgIQ8VCuM1xRdD0TWp3zlzionlmDBjuXVBs+VkmXq6FgW9T4Emr7oGz/Rk6feDCGyiugolcQEyp3mg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve-dependencies@30.4.2: + resolution: {integrity: sha512-gDiVh1I+GxYzz9oXlyw+1wv6VOYX1WYxMOfjsA3iGKePV2oxmbHhwxfkALxNxYy1ciw6APWwkW2zZONwP97aEQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-resolve@30.4.1: + resolution: {integrity: sha512-Zry8Yq/yJcNAZ7dJ5F2heic8AheXvbFZ7XI5V+h28nrYZ7Qoyy4dItq8OodjnYD270mvX+ZudmrNV9cysqhW5Q==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runner@30.4.2: + resolution: {integrity: sha512-2dw0PslVYXxffXGpLo+Ejad+KcI1Qkjn7f4X4619gf21oCUmL+SPfjqIa/losUem3yEOvfNZe/F1HWUcNpODcg==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-runtime@30.4.2: + resolution: {integrity: sha512-3/5e8iPz2k/VLqlr8DgTftYyLUv8Su3FkCAO2/Od81UsUTpSxOrS6O5x5KkoQwyUjmpYyDJKeyAvg2T2nvpNkQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-snapshot@30.4.1: + resolution: {integrity: sha512-tEOkkfOMppUyeiHwjZswOQ3lcnoTnws/q5FnGIaeIh/jmoU0ZlgMYRR8sTlTj+nNGCoJ0RDq6SfxGxCsyMTPmw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-util@29.7.0: + resolution: {integrity: sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-util@30.4.1: + resolution: {integrity: sha512-vjQb1sACEiv13DKJMDToJpzVW0joCsIQrmbg0fi7CyOOt+g9jTuQl2A216pWRBYhOVt53XbL/2LbMKg1BECWOw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-validate@29.7.0: + resolution: {integrity: sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-validate@30.4.1: + resolution: {integrity: sha512-PDWi4SOwLnwqNDfHZjOcsEFyZ4fc/2W2gVL3DEoyqnB6jCQMLRtfBong8s6omIw3lI0HWOus12xfnFmQtjW3fw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-watcher@30.4.1: + resolution: {integrity: sha512-/l9UonmvCwjHH7d2h3iAwIloLc1H0S8mJZ/LNK3i86hqwPAz8otUJjP9MfYtz9Tt77Su5FD2xGjZn8d31IZHlw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest-worker@29.7.0: + resolution: {integrity: sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + jest-worker@30.4.1: + resolution: {integrity: sha512-SHynN/q/QD++iNyvMdy+WMmbCGk8jIsNcRxycXbWubSOhvo6T+j2afcfUSl+3hYsiBebOTo0cT7c2H7CXugu1g==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + jest@30.4.2: + resolution: {integrity: sha512-Yi1jqNC/Oq0N4hBgNH/YvBpP1P57QqundgytzYqy3yqAa7NZPNjSoi4SGbRAXDMdBzNE6xBCi5U7RgfrvMEUVQ==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + hasBin: true + peerDependencies: + node-notifier: ^8.0.1 || ^9.0.0 || ^10.0.0 + peerDependenciesMeta: + node-notifier: + optional: true + + jiti@2.7.0: + resolution: {integrity: sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==} + hasBin: true + + jotai@2.20.1: + resolution: {integrity: sha512-dnuKfU/GLi8B28RRMjQ3AfoN7kfzP8o41+AX2FmITZqEMY8PHnjABq+VkEooomLwYaGjda+pgy0yFSjaHX/ZPg==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@babel/core': '>=7.0.0' + '@babel/template': '>=7.0.0' + '@types/react': '>=17.0.0' + react: '>=17.0.0' + peerDependenciesMeta: + '@babel/core': + optional: true + '@babel/template': + optional: true + '@types/react': + optional: true + react: + optional: true + + joycon@3.1.1: + resolution: {integrity: sha512-34wB/Y7MW7bzjKRjUKTa46I2Z7eV62Rkhva+KkopW7Qvv/OSWBqvkSY7vusOPrNuZcUG3tApvdVgNB8POj3SPw==} + engines: {node: '>=10'} + + js-base64@3.7.8: + resolution: {integrity: sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==} + + js-tokens@4.0.0: + resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} + + js-yaml@3.14.2: + resolution: {integrity: sha512-PMSmkqxr106Xa156c2M265Z+FTrPl+oxd/rgOQy2tijQeK5TxQ43psO1ZCwhVOSdnn+RzkzlRz/eY4BgJBYVpg==} + hasBin: true + + js-yaml@4.2.0: + resolution: {integrity: sha512-ePWsvanv0DWuDRsW8dnt+R4jQ31SCRCQ7hhNcPXZPsoBZiemuZNYGf7adZdqX2D86j6rvKp3RpCxVTSb8WQlOw==} + hasBin: true + + jsc-safe-url@0.2.4: + resolution: {integrity: sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==} + + jsesc@3.1.0: + resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} + engines: {node: '>=6'} + hasBin: true + + json-buffer@3.0.1: + resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} + + json-parse-even-better-errors@2.3.1: + resolution: {integrity: sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==} + + json-schema-traverse@0.4.1: + resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} + + json-schema@0.4.0: + resolution: {integrity: sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==} + + json-stable-stringify-without-jsonify@1.0.1: + resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} + + json-stable-stringify@1.3.0: + resolution: {integrity: sha512-qtYiSSFlwot9XHtF9bD9c7rwKjr+RecWT//ZnPvSmEjpV5mmPOCN4j8UjY5hbjNkOwZ/jQv3J6R1/pL7RwgMsg==} + engines: {node: '>= 0.4'} + + json5@2.2.3: + resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} + engines: {node: '>=6'} + hasBin: true + + jsonify@0.0.1: + resolution: {integrity: sha512-2/Ki0GcmuqSrgFyelQq9M05y7PS0mEwuIzrf3f1fPqkVDVRvZrPZtVSMHxdgo8Aq0sxAOb/cr2aqqA3LeWHVPg==} + + keyv@4.5.4: + resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} + + kleur@3.0.3: + resolution: {integrity: sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==} + engines: {node: '>=6'} + + leven@3.1.0: + resolution: {integrity: sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==} + engines: {node: '>=6'} + + levn@0.4.1: + resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} + engines: {node: '>= 0.8.0'} + + lighthouse-logger@1.4.2: + resolution: {integrity: sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==} + + lightningcss-android-arm64@1.32.0: + resolution: {integrity: sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [android] + + lightningcss-darwin-arm64@1.32.0: + resolution: {integrity: sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [darwin] + + lightningcss-darwin-x64@1.32.0: + resolution: {integrity: sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [darwin] + + lightningcss-freebsd-x64@1.32.0: + resolution: {integrity: sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [freebsd] + + lightningcss-linux-arm-gnueabihf@1.32.0: + resolution: {integrity: sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==} + engines: {node: '>= 12.0.0'} + cpu: [arm] + os: [linux] + + lightningcss-linux-arm64-gnu@1.32.0: + resolution: {integrity: sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-arm64-musl@1.32.0: + resolution: {integrity: sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [linux] + + lightningcss-linux-x64-gnu@1.32.0: + resolution: {integrity: sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-linux-x64-musl@1.32.0: + resolution: {integrity: sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [linux] + + lightningcss-win32-arm64-msvc@1.32.0: + resolution: {integrity: sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==} + engines: {node: '>= 12.0.0'} + cpu: [arm64] + os: [win32] + + lightningcss-win32-x64-msvc@1.32.0: + resolution: {integrity: sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==} + engines: {node: '>= 12.0.0'} + cpu: [x64] + os: [win32] + + lightningcss@1.32.0: + resolution: {integrity: sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==} + engines: {node: '>= 12.0.0'} + + lilconfig@3.1.3: + resolution: {integrity: sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==} + engines: {node: '>=14'} + + linebreak@1.1.0: + resolution: {integrity: sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==} + + lines-and-columns@1.2.4: + resolution: {integrity: sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==} + + load-tsconfig@0.2.5: + resolution: {integrity: sha512-IXO6OCs9yg8tMKzfPZ1YmheJbZCiEsnBdcB03l0OcfK9prKnJb96siuHCr5Fl37/yo9DnKU+TLpxzTUspw9shg==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + + locate-path@5.0.0: + resolution: {integrity: sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==} + engines: {node: '>=8'} + + locate-path@6.0.0: + resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} + engines: {node: '>=10'} + + lodash.merge@4.6.2: + resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} + + lodash.throttle@4.1.1: + resolution: {integrity: sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==} + + loose-envify@1.4.0: + resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} + hasBin: true + + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: + resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} + + lucide-react@0.575.0: + resolution: {integrity: sha512-VuXgKZrk0uiDlWjGGXmKV6MSk9Yy4l10qgVvzGn2AWBx1Ylt0iBexKOAoA6I7JO3m+M9oeovJd3yYENfkUbOeg==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + lucide-react@1.21.0: + resolution: {integrity: sha512-reEZMXq8Qdd5jg5XYkQ5TR1fB/GiQ7ih4vcrthYDtgjSDwh0i6/YLiGjsWsIwgN49gpAnd4J2elSNzncMEEUUQ==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + magic-string@0.30.21: + resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + makeerror@1.0.12: + resolution: {integrity: sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==} + + marky@1.3.0: + resolution: {integrity: sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==} + + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + memoize-one@5.2.1: + resolution: {integrity: sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==} + + merge-stream@2.0.0: + resolution: {integrity: sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==} + + merge2@1.4.1: + resolution: {integrity: sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==} + engines: {node: '>= 8'} + + metro-babel-transformer@0.84.4: + resolution: {integrity: sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-cache-key@0.84.4: + resolution: {integrity: sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-cache@0.84.4: + resolution: {integrity: sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-config@0.84.4: + resolution: {integrity: sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-core@0.84.4: + resolution: {integrity: sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-file-map@0.84.4: + resolution: {integrity: sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-minify-terser@0.84.4: + resolution: {integrity: sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-resolver@0.84.4: + resolution: {integrity: sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-runtime@0.84.4: + resolution: {integrity: sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-source-map@0.84.4: + resolution: {integrity: sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-symbolicate@0.84.4: + resolution: {integrity: sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + + metro-transform-plugins@0.84.4: + resolution: {integrity: sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro-transform-worker@0.84.4: + resolution: {integrity: sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + metro@0.84.4: + resolution: {integrity: sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromatch@4.0.8: + resolution: {integrity: sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==} + engines: {node: '>=8.6'} + + mime-db@1.54.0: + resolution: {integrity: sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==} + engines: {node: '>= 0.6'} + + mime-types@3.0.2: + resolution: {integrity: sha512-Lbgzdk0h4juoQ9fCKXW4by0UJqj+nOOrI9MJ1sSj4nI8aI2eo1qmvQEie4VD1glsS250n15LsWsYtCugiStS5A==} + engines: {node: '>=18'} + + mime@1.6.0: + resolution: {integrity: sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==} + engines: {node: '>=4'} + hasBin: true + + mimic-fn@2.1.0: + resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} + engines: {node: '>=6'} + + minimatch@9.0.9: + resolution: {integrity: sha512-OBwBN9AL4dqmETlpS2zasx+vTeWclWzkblfZk7KTA5j3jeOONz/tRCnZomUyvNg83wL5Zv9Ss6HMJXAgL8R2Yg==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + mkdirp@1.0.4: + resolution: {integrity: sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==} + engines: {node: '>=10'} + hasBin: true + + mlly@1.8.2: + resolution: {integrity: sha512-d+ObxMQFmbt10sretNDytwt85VrbkhhUA/JBGm1MPaWJ65Cl4wOgLaB1NYvJSZ0Ef03MMEU/0xpPMXUIQ29UfA==} + + motion-dom@12.40.0: + resolution: {integrity: sha512-HxU3ZaBwNPVQUBQf1xxgq+7JrPNZvjLVxgbpEZL7RrWJnsxOf0/OM+yrHG9ogLQ31Do/r57Oz2gQWPK+6q62mg==} + + motion-utils@12.39.0: + resolution: {integrity: sha512-8nadJAJjTtqRkmRF36FoJTrywK9nnFmnPwnSMyxaOCU7GDjN9RTMJIxx9De8ErM+vpPhMccr/6fo5WciyQLnMQ==} + + motion@12.40.0: + resolution: {integrity: sha512-yjrHUrBFW6kQvjJwRsoiPSAhC5tRwRqNGJWmiJ4CrGnbKp0V88AdzkhBmDoqIsIPfarOe0Uddd37Xq43/gIocA==} + peerDependencies: + '@emotion/is-prop-valid': '*' + react: ^18.0.0 || ^19.0.0 + react-dom: ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@emotion/is-prop-valid': + optional: true + react: + optional: true + react-dom: + optional: true + + ms@2.0.0: + resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + mz@2.7.0: + resolution: {integrity: sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q==} + + nanoid@3.3.13: + resolution: {integrity: sha512-sPdqC6ByMVVGvF1ynvvMo0/o+oD1VX7DaHhijt1bFgjvBkHBib4t49GoNDhf2NDta4oeUNlaGbSt5K7qjZ955Q==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + nanostores@1.0.1: + resolution: {integrity: sha512-kNZ9xnoJYKg/AfxjrVL4SS0fKX++4awQReGqWnwTRHxeHGZ1FJFVgTqr/eMrNQdp0Tz7M7tG/TDaX8QfHDwVCw==} + engines: {node: ^20.0.0 || >=22.0.0} + + napi-postinstall@0.3.4: + resolution: {integrity: sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==} + engines: {node: ^12.20.0 || ^14.18.0 || >=16.0.0} + hasBin: true + + natural-compare-lite@1.4.0: + resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==} + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + negotiator@1.0.0: + resolution: {integrity: sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg==} + engines: {node: '>= 0.6'} + + next-themes@0.4.6: + resolution: {integrity: sha512-pZvgD5L0IEvX5/9GWyHMf3m8BKiVQwsCMHfoFosXtXBMnaS0ZnIJ9ST4b4NqLVKDEm8QBxoNNGNaBv2JNF6XNA==} + peerDependencies: + react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc + + node-int64@0.4.0: + resolution: {integrity: sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==} + + node-releases@2.0.48: + resolution: {integrity: sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA==} + engines: {node: '>=18'} + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + + npm-run-path@4.0.1: + resolution: {integrity: sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==} + engines: {node: '>=8'} + + nullthrows@1.1.1: + resolution: {integrity: sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==} + + nunjucks@3.2.4: + resolution: {integrity: sha512-26XRV6BhkgK0VOxfbU5cQI+ICFUtMLixv1noZn1tGU38kQH5A5nmmbk/O45xdyBhD1esk47nKrY0mvQpZIhRjQ==} + engines: {node: '>= 6.9.0'} + hasBin: true + peerDependencies: + chokidar: ^3.3.0 + peerDependenciesMeta: + chokidar: + optional: true + + ob1@0.84.4: + resolution: {integrity: sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + + object-assign@4.1.1: + resolution: {integrity: sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==} + engines: {node: '>=0.10.0'} + + object-keys@1.1.1: + resolution: {integrity: sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==} + engines: {node: '>= 0.4'} + + on-finished@2.3.0: + resolution: {integrity: sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==} + engines: {node: '>= 0.8'} + + on-finished@2.4.1: + resolution: {integrity: sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==} + engines: {node: '>= 0.8'} + + once@1.4.0: + resolution: {integrity: sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==} + + onetime@5.1.2: + resolution: {integrity: sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==} + engines: {node: '>=6'} + + oniguruma-parser@0.12.2: + resolution: {integrity: sha512-6HVa5oIrgMC6aA6WF6XyyqbhRPJrKR02L20+2+zpDtO5QAzGHAUGw5TKQvwi5vctNnRHkJYmjAhRVQF2EKdTQw==} + + oniguruma-to-es@4.3.6: + resolution: {integrity: sha512-csuQ9x3Yr0cEIs/Zgx/OEt9iBw9vqIunAPQkx19R/fiMq2oGVTgcMqO/V3Ybqefr1TBvosI6jU539ksaBULJyA==} + + open@7.4.2: + resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==} + engines: {node: '>=8'} + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@2.3.0: + resolution: {integrity: sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==} + engines: {node: '>=6'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@4.1.0: + resolution: {integrity: sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==} + engines: {node: '>=8'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + p-try@2.2.0: + resolution: {integrity: sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==} + engines: {node: '>=6'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + pako@0.2.9: + resolution: {integrity: sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-css-color@0.2.1: + resolution: {integrity: sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==} + + parse-json@5.2.0: + resolution: {integrity: sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==} + engines: {node: '>=8'} + + parseurl@1.3.3: + resolution: {integrity: sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==} + engines: {node: '>= 0.8'} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-expression-matcher@1.5.0: + resolution: {integrity: sha512-cbrerZV+6rvdQrrD+iGMcZFEiiSrbv9Tfdkvnusy6y0x0GKBXREFg/Y65GhIfm0tnLntThhzCnfKwp1WRjeCyQ==} + engines: {node: '>=14.0.0'} + + path-is-absolute@1.0.1: + resolution: {integrity: sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==} + engines: {node: '>=0.10.0'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + path-type@4.0.0: + resolution: {integrity: sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==} + engines: {node: '>=8'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.4: + resolution: {integrity: sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==} + engines: {node: '>=12'} + + pirates@4.0.7: + resolution: {integrity: sha512-TfySrs/5nm8fQJDcBDuUng3VOUKsd7S+zqvbOTiGXHfxX4wK31ard+hoNuvkicM/2YFzlpDgABOevKSsB4G/FA==} + engines: {node: '>= 6'} + + pkg-dir@4.2.0: + resolution: {integrity: sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==} + engines: {node: '>=8'} + + pkg-types@1.3.1: + resolution: {integrity: sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ==} + + playwright-core@1.61.0: + resolution: {integrity: sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==} + engines: {node: '>=18'} + hasBin: true + + playwright@1.61.0: + resolution: {integrity: sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==} + engines: {node: '>=18'} + hasBin: true + + pngjs@5.0.0: + resolution: {integrity: sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==} + engines: {node: '>=10.13.0'} + + postcss-load-config@6.0.1: + resolution: {integrity: sha512-oPtTM4oerL+UXmx+93ytZVN82RrlY/wPUV8IeDxFrzIjXOLF1pN+EmKPLbubvKHT2HC20xXsCAH2Z+CKV6Oz/g==} + engines: {node: '>= 18'} + peerDependencies: + jiti: '>=1.21.0' + postcss: '>=8.0.9' + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + jiti: + optional: true + postcss: + optional: true + tsx: + optional: true + yaml: + optional: true + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.15: + resolution: {integrity: sha512-FfR8sjd4em2T6fb3I2MwAJU7HWVMr9zba+enmQeeWFfCbm+UOC/0X4DS8XtpUTMwWMGbjKYP7xjfNekzyGmB3A==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + prettier@3.8.4: + resolution: {integrity: sha512-N2MylSdi48+5N/6S5j+maeHbUSIzzZ5uOcX5Hm4QpV8Dkb1HFjfAKTKX6yNPJQD9AhcT3ifHNB66tWTTJDi11Q==} + engines: {node: '>=14'} + hasBin: true + + pretty-format@29.7.0: + resolution: {integrity: sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==} + engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} + + pretty-format@30.4.1: + resolution: {integrity: sha512-K6KiKMHTL4jjX4u3Kir2EW07nRfcqVTXIImx50wbjHQTcZPgg+gjVeNTIT3l3L1Rd4UefxfogquC9J37SoFyyw==} + engines: {node: ^18.14.0 || ^20.0.0 || ^22.0.0 || >=24.0.0} + + promise@8.3.0: + resolution: {integrity: sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==} + + prompts@2.4.2: + resolution: {integrity: sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==} + engines: {node: '>= 6'} + + property-information@7.2.0: + resolution: {integrity: sha512-IAtzIB6sUiWaJYrX9smp3V46pBGbBeLFRGdh25kg1334VcBlD8HzhPeNIWQH9zhGmo2itIe25EHt9dQP7G5hmg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + pure-rand@7.0.1: + resolution: {integrity: sha512-oTUZM/NAZS8p7ANR3SHh30kXB+zK2r2BPcEn/awJIbOvq82WoMN4p62AWWp3Hhw50G0xMsw1mhIBLqHw64EcNQ==} + + qrcode@1.5.4: + resolution: {integrity: sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==} + engines: {node: '>=10.13.0'} + hasBin: true + + queue-microtask@1.2.3: + resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} + + queue@6.0.2: + resolution: {integrity: sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==} + + range-parser@1.2.1: + resolution: {integrity: sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==} + engines: {node: '>= 0.6'} + + react-devtools-core@6.1.5: + resolution: {integrity: sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==} + + react-dom@19.2.7: + resolution: {integrity: sha512-t0BRVXvbiE/o20Hfw669rLbMCDWtYZLvmJigy2f0MxsXF+71pxhR3xOkspmsO8h3ZlNzyibAmtCa3l4lYKk6gQ==} + peerDependencies: + react: ^19.2.7 + + react-error-boundary@6.1.2: + resolution: {integrity: sha512-3DpCr5HVdZ0caUjYE/kIHBEJN0mNP3ZCgf16c48uJ5TbWjorKVp+YG8W3XqlJ7vJAVNw6wNIImyPXmFydwmyng==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 + + react-is@18.3.1: + resolution: {integrity: sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==} + + react-is@19.2.7: + resolution: {integrity: sha512-kZFnouyVv7eP/Phmrlo9FK+zcAdriZJvzxXHF1Sl1P377WSGe2G/JxVolhTrB/jeV47lKImhNUsijjHAAbcl/A==} + + react-native@0.86.0: + resolution: {integrity: sha512-17ALh/dd6AO4pgOVmOO5Axll5PbErEo3XFyLokyzW6usyi+OShIEPwUW26wLPlhVifgSOIfECCH0WN+0IqtJ1w==} + engines: {node: ^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0} + hasBin: true + peerDependencies: + '@react-native/jest-preset': 0.86.0 + '@types/react': ^19.1.1 + react: ^19.2.3 + peerDependenciesMeta: + '@react-native/jest-preset': + optional: true + '@types/react': + optional: true + + react-refresh@0.14.2: + resolution: {integrity: sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==} + engines: {node: '>=0.10.0'} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.2: + resolution: {integrity: sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-router@7.18.0: + resolution: {integrity: sha512-pTTGt8J+ji1NOmYnjzT+bAJy/1zD+Jp4ziO6cL7T3ZLvXKtusO7BpFqlRXitqpcPVqllsIXFHRMt+2/k3Xn6HQ==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react@19.2.7: + resolution: {integrity: sha512-HNe9WslTbXmFK8o8cmwgAeJFSBvt1bPdHCVKtaaV+WlAN36mpT4hcRpwbf3fY56ar2oIXzsBpOAiIRHAdY0OlQ==} + engines: {node: '>=0.10.0'} + + readdirp@4.1.2: + resolution: {integrity: sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==} + engines: {node: '>= 14.18.0'} + + regenerator-runtime@0.13.11: + resolution: {integrity: sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==} + + regex-recursion@6.0.2: + resolution: {integrity: sha512-0YCaSCq2VRIebiaUviZNs0cBz1kg5kVS2UKUfNIx8YVs1cN3AV7NTctO5FOKBA+UT2BPJIWZauYHPqJODG50cg==} + + regex-utilities@2.3.0: + resolution: {integrity: sha512-8VhliFJAWRaUiVvREIiW2NXXTmHs4vMNnSzuJVhscgmGav3g9VDxLrQndI3dZZVVdp0ZO/5v0xmX516/7M9cng==} + + regex@6.1.0: + resolution: {integrity: sha512-6VwtthbV4o/7+OaAF9I5L5V3llLEsoPyq9P1JVXkedTP33c7MfCG0/5NOPcSJn0TzXcG9YUrR0gQSWioew3LDg==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-main-filename@2.0.0: + resolution: {integrity: sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==} + + requireindex@1.2.0: + resolution: {integrity: sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww==} + engines: {node: '>=0.10.5'} + + reselect@5.2.0: + resolution: {integrity: sha512-AgZ3UOZm3YndfrJ4OYjgrT7bmCm/1iqkjvEfH/oYjzh6PD2qw4QuT3jjnXIrpdt4MTpMXclMT3lXbmRY+XRakw==} + + resolve-cwd@3.0.0: + resolution: {integrity: sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==} + engines: {node: '>=8'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + resolve-from@5.0.0: + resolution: {integrity: sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==} + engines: {node: '>=8'} + + reusify@1.1.0: + resolution: {integrity: sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==} + engines: {iojs: '>=1.0.0', node: '>=0.10.0'} + + rolldown@1.0.3: + resolution: {integrity: sha512-i00lAJ2ks1BYr7rjNjKC7BcqAS7nVfiT3QX1SI5aY+AFHblCmaUf9OE9dbdzDvW6dJxbi2ZCZiy9v3CcwOiX3g==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + + rollup@4.60.2: + resolution: {integrity: sha512-J9qZyW++QK/09NyN/zeO0dG/1GdGfyp9lV8ajHnRVLfo/uFsbji5mHnDgn/qYdUHyCkM2N+8VyspgZclfAh0eQ==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + run-parallel@1.2.0: + resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + + satori@0.25.0: + resolution: {integrity: sha512-utINfLxrYrmSnLvxFT4ZwgwWa8KOjrz7ans32V5wItgHVmzESl/9i33nE38uG0miycab8hUqQtDlOpqrIpB/iw==} + engines: {node: '>=16'} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.8.4: + resolution: {integrity: sha512-rUCObTnP32Q08R2uuIrt7r9PlEonuTmtuXYcW6s5kjdlj3xbnwe+21yXptAUYcMAABLkYYTtnmzb3w3EDZfueA==} + engines: {node: '>=10'} + hasBin: true + + send@0.19.2: + resolution: {integrity: sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==} + engines: {node: '>= 0.8.0'} + + serialize-error@2.1.0: + resolution: {integrity: sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==} + engines: {node: '>=0.10.0'} + + serve-static@1.16.3: + resolution: {integrity: sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==} + engines: {node: '>= 0.8.0'} + + set-blocking@2.0.0: + resolution: {integrity: sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==} + + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + + set-function-length@1.2.2: + resolution: {integrity: sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==} + engines: {node: '>= 0.4'} + + setprototypeof@1.2.0: + resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==} + + sharp@0.34.5: + resolution: {integrity: sha512-Ou9I5Ft9WNcCbXrU9cMgPBcCK8LiwLqcbywW3t4oDV37n1pzpuNLsYiAV8eODnjbtQlSDwZ2cUEeQz4E54Hltg==} + engines: {node: ^18.17.0 || ^20.3.0 || >=21.0.0} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.4: + resolution: {integrity: sha512-VsC6n6vz1ihYYyZZwX7YZSF5l5x36ca17OC+a69h94YqB7X6XLwf+5MOgynYir2SLFUbl8gIYvBo8K8RoNQ6bQ==} + engines: {node: '>= 0.4'} + + shiki@3.23.0: + resolution: {integrity: sha512-55Dj73uq9ZXL5zyeRPzHQsK7Nbyt6Y10k5s7OjuFZGMhpp4r/rsLBH0o/0fstIzX1Lep9VxefWljK/SKCzygIA==} + + signal-exit@3.0.7: + resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sisteransi@1.0.5: + resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} + + slash@3.0.0: + resolution: {integrity: sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==} + engines: {node: '>=8'} + + sonner@2.0.7: + resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + source-map-support@0.5.13: + resolution: {integrity: sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==} + + source-map-support@0.5.21: + resolution: {integrity: sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==} + + source-map@0.5.7: + resolution: {integrity: sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==} + engines: {node: '>=0.10.0'} + + source-map@0.6.1: + resolution: {integrity: sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==} + engines: {node: '>=0.10.0'} + + source-map@0.7.6: + resolution: {integrity: sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==} + engines: {node: '>= 12'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + sprintf-js@1.0.3: + resolution: {integrity: sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==} + + stack-utils@2.0.6: + resolution: {integrity: sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==} + engines: {node: '>=10'} + + stackframe@1.3.4: + resolution: {integrity: sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==} + + stacktrace-parser@0.1.11: + resolution: {integrity: sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==} + engines: {node: '>=6'} + + statuses@1.5.0: + resolution: {integrity: sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==} + engines: {node: '>= 0.6'} + + statuses@2.0.2: + resolution: {integrity: sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw==} + engines: {node: '>= 0.8'} + + string-length@4.0.2: + resolution: {integrity: sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==} + engines: {node: '>=10'} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + string.prototype.codepointat@0.2.1: + resolution: {integrity: sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg==} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-bom@4.0.0: + resolution: {integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==} + engines: {node: '>=8'} + + strip-final-newline@2.0.0: + resolution: {integrity: sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==} + engines: {node: '>=6'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strnum@2.4.1: + resolution: {integrity: sha512-M9eUSMT2dCB2cTNPG7UYj6KuK7RJR2SN2+yCV/fTW3xzTCS6EaGZ5pSMgDIjB7r8zSfTGk+dvvn9rTjpVS9Mwg==} + + sucrase@3.35.1: + resolution: {integrity: sha512-DhuTmvZWux4H1UOnWMB3sk0sbaCVOoQZjv8u1rDoTV0HTdGem9hkAZtl4JZy8P2z4Bg0nT+YMeOFyVr4zcG5Tw==} + engines: {node: '>=16 || 14 >=14.17'} + hasBin: true + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + synckit@0.11.13: + resolution: {integrity: sha512-eNRKgb3z66Yp3D2CixVujOUvXLFUTij/zVnV8KRyvFdQwpz7I5DS8UfRkTeLzb64u+dkzDSdelE24izu+zSSUg==} + engines: {node: ^14.18.0 || >=16.0.0} + + tailwind-merge@3.6.0: + resolution: {integrity: sha512-uxL7qAVQriqRQPAyK3pj66VqskWqoZ37PW94jwOTwNfq/z9oyu1V+eqrZqtR2+fCiXdYOZe/Modt8GtvqNzu+w==} + + tailwindcss@4.3.1: + resolution: {integrity: sha512-hk+TB1m+K8CYNrP6rjQaq/Y+4Zylwpa87mLYBKCunwnnQ9p+fHb7kmSfGqyEJoxF/O6CDyABWVFEafNSYKll+Q==} + + tapable@2.3.3: + resolution: {integrity: sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==} + engines: {node: '>=6'} + + terser@5.48.0: + resolution: {integrity: sha512-J/9An6vs9Us6wKRriSFXBWdRZapREHqFzdNUKk0pmu804EMR6dr6winwo7e5JDxN4xahxQsuysyYFwlwj4XN/Q==} + engines: {node: '>=10'} + hasBin: true + + test-exclude@6.0.0: + resolution: {integrity: sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==} + engines: {node: '>=8'} + + thenify-all@1.6.0: + resolution: {integrity: sha512-RNxQH/qI8/t3thXJDwcstUO4zeqo64+Uy/+sNVRBx4Xn2OX+OZ9oP+iJnNFqplFra2ZUVeKCSa2oVWi3T4uVmA==} + engines: {node: '>=0.8'} + + thenify@3.3.1: + resolution: {integrity: sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw==} + + throat@5.0.0: + resolution: {integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==} + + tiny-inflate@1.0.3: + resolution: {integrity: sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.17: + resolution: {integrity: sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==} + engines: {node: '>=12.0.0'} + + tmpl@1.0.5: + resolution: {integrity: sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + + toidentifier@1.0.1: + resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} + engines: {node: '>=0.6'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + ts-api-utils@2.5.0: + resolution: {integrity: sha512-OJ/ibxhPlqrMM0UiNHJ/0CKQkoKF243/AEmplt3qpRgkW8VG7IfOS41h7V8TjITqdByHzrjcS/2si+y4lIh8NA==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + ts-interface-checker@0.1.13: + resolution: {integrity: sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==} + + tslib@1.14.1: + resolution: {integrity: sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==} + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + tsup@8.5.1: + resolution: {integrity: sha512-xtgkqwdhpKWr3tKPmCkvYmS9xnQK3m3XgxZHwSUjvfTjp7YfXe5tT3GgWi0F2N+ZSMsOeWeZFh7ZZFg5iPhing==} + engines: {node: '>=18'} + hasBin: true + peerDependencies: + '@microsoft/api-extractor': ^7.36.0 + '@swc/core': ^1 + postcss: ^8.4.12 + typescript: '>=4.5.0' + peerDependenciesMeta: + '@microsoft/api-extractor': + optional: true + '@swc/core': + optional: true + postcss: + optional: true + typescript: + optional: true + + tsutils@3.21.0: + resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==} + engines: {node: '>= 6'} + peerDependencies: + typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta' + + tsx@4.22.4: + resolution: {integrity: sha512-X8EX+XV4QR5xCsrgxaED954zTDfY8KqlDtskKEL0cHhyS/P8b4IFOvGDQpsC9Q1XnLq915wEfwwY/zzskCtmhg==} + engines: {node: '>=18.0.0'} + hasBin: true + + tw-animate-css@1.4.0: + resolution: {integrity: sha512-7bziOlRqH0hJx80h/3mbicLW7o8qLsH5+RaLR2t+OHM3D0JlWGODQKQ4cxbK7WlvmUxpcj6Kgu6EKqjrGFe3QQ==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-detect@4.0.8: + resolution: {integrity: sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==} + engines: {node: '>=4'} + + type-fest@0.21.3: + resolution: {integrity: sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==} + engines: {node: '>=10'} + + type-fest@0.7.1: + resolution: {integrity: sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==} + engines: {node: '>=8'} + + typescript-eslint@8.61.1: + resolution: {integrity: sha512-V7PayAfJokV3pEHgN7/v03D1SpujhRfQtYLbLIiBfDDncdg4PAiRBfoS4cnCANK4jmAPncczi59QO3afiXUlNw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 + typescript: '>=4.8.4 <6.1.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + ufo@1.6.4: + resolution: {integrity: sha512-JFNbkD1Svwe0KvGi8GOeLcP4kAWQ609twvCdcHxq1oSL8svv39ZuSvajcD8B+5D0eL4+s1Is2D/O6KN3qcTeRA==} + + undici-types@7.24.6: + resolution: {integrity: sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==} + + undici-types@8.5.0: + resolution: {integrity: sha512-+FxhD+5RUdCZHlVPt+pd0DaYYHBPsgoHovxhMnFq9R1SOejHGE4ma0swzuRoKhOisEzsjFWdFedyD0JQmftrHg==} + + unicode-trie@2.0.0: + resolution: {integrity: sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.1.0: + resolution: {integrity: sha512-m+vIdyeCOpdr/QeQCu2EzxX/ohgS8KbnPDgFni4dQsfSCtpz8UqDyY5GjRru8PDKuYn7Fq19j1CQ+nJSsGKOzg==} + + unpipe@1.0.0: + resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} + engines: {node: '>= 0.8'} + + unrs-resolver@1.12.2: + resolution: {integrity: sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==} + + update-browserslist-db@1.2.3: + resolution: {integrity: sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sync-external-store@1.6.0: + resolution: {integrity: sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + + utils-merge@1.0.1: + resolution: {integrity: sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==} + engines: {node: '>= 0.4.0'} + + v8-to-istanbul@9.3.0: + resolution: {integrity: sha512-kiGUalWN+rgBJ/1OHZsBtU4rXZOfj/7rKQxULKlIzwzQSvMJUUNgPwJEEh7gU6xEVxC0ahoOBvN2YI8GH6FNgA==} + engines: {node: '>=10.12.0'} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite@8.0.16: + resolution: {integrity: sha512-h9bXPmJichP5fLmVQo3PyaGSDE2n3aPuomeAlVRm0JLmt4rY6zmPKd59HYI4LNW8oTK7tlTsuC7l/m7awx9Jcw==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + '@vitejs/devtools': ^0.1.18 + esbuild: ^0.27.0 || ^0.28.0 + jiti: '>=1.21.0' + less: ^4.0.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + '@vitejs/devtools': + optional: true + esbuild: + optional: true + jiti: + optional: true + less: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vlq@1.0.1: + resolution: {integrity: sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==} + + walker@1.0.8: + resolution: {integrity: sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==} + + whatwg-fetch@3.6.20: + resolution: {integrity: sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==} + + which-module@2.0.1: + resolution: {integrity: sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@6.2.0: + resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} + engines: {node: '>=8'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + wrappy@1.0.2: + resolution: {integrity: sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==} + + write-file-atomic@5.0.1: + resolution: {integrity: sha512-+QU2zd6OTD8XWIJCbffaiQeH9U73qIqafo1x6V1snCWYGJf6cVE0cDR4D8xRzcEnfI21IFrUPzPGtcPf8AC+Rw==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + + ws@7.5.11: + resolution: {integrity: sha512-zS54Oen9bITtp7kp2XM3AydrCIq1D+HwJOuH+c+e4LfpL/lotP5osijd+UoMnxwAam1GN8R4KtLAyIrIcBNpiA==} + engines: {node: '>=8.3.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: ^5.0.2 + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + ws@8.20.1: + resolution: {integrity: sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + + xml-naming@0.1.0: + resolution: {integrity: sha512-k8KO9hrMyNk6tUWqUfkTEZbezRRpONVOzUTnc97VnCvyj6Tf9lyUR9EDAIeiVLv56jsMcoXEwjW8Kv5yPY52lw==} + engines: {node: '>=16.0.0'} + + y18n@4.0.3: + resolution: {integrity: sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml@2.9.0: + resolution: {integrity: sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==} + engines: {node: '>= 14.6'} + hasBin: true + + yargs-parser@18.1.3: + resolution: {integrity: sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==} + engines: {node: '>=6'} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@15.4.1: + resolution: {integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==} + engines: {node: '>=8'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + yoga-layout@3.2.1: + resolution: {integrity: sha512-0LPOt3AxKqMdFBZA3HBAt/t/8vIKq7VaQYbuA8WxCgung+p9TVyKRYdpvCb80HcdTN2NkbIKbhNwKUfm3tQywQ==} + + zod-validation-error@4.0.2: + resolution: {integrity: sha512-Q6/nZLe6jxuU80qb/4uJ4t5v2VEZ44lzQjPDhYJNztRQ4wyWc6VF3D3Kb/fAuPetZQnhS3hnajCf9CsWesghLQ==} + engines: {node: '>=18.0.0'} + peerDependencies: + zod: ^3.25.0 || ^4.0.0 + + zod@4.4.3: + resolution: {integrity: sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==} + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@alloc/quick-lru@5.2.0': {} + + '@aws-crypto/crc32@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + tslib: 2.8.1 + + '@aws-crypto/sha256-browser@5.2.0': + dependencies: + '@aws-crypto/sha256-js': 5.2.0 + '@aws-crypto/supports-web-crypto': 5.2.0 + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + '@aws-sdk/util-locate-window': 3.965.8 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-crypto/sha256-js@5.2.0': + dependencies: + '@aws-crypto/util': 5.2.0 + '@aws-sdk/types': 3.973.13 + tslib: 2.8.1 + + '@aws-crypto/supports-web-crypto@5.2.0': + dependencies: + tslib: 2.8.1 + + '@aws-crypto/util@5.2.0': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/util-utf8': 2.3.0 + tslib: 2.8.1 + + '@aws-sdk/client-kms@3.1072.0': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.22 + '@aws-sdk/credential-provider-node': 3.972.57 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/fetch-http-handler': 5.5.1 + '@smithy/node-http-handler': 4.8.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/core@3.974.22': + dependencies: + '@aws-sdk/types': 3.973.13 + '@aws-sdk/xml-builder': 3.972.30 + '@aws/lambda-invoke-store': 0.2.4 + '@smithy/core': 3.25.1 + '@smithy/signature-v4': 5.5.1 + '@smithy/types': 4.15.0 + bowser: 2.14.1 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-env@3.972.48': + dependencies: + '@aws-sdk/core': 3.974.22 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-http@3.972.50': + dependencies: + '@aws-sdk/core': 3.974.22 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/fetch-http-handler': 5.5.1 + '@smithy/node-http-handler': 4.8.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-ini@3.972.55': + dependencies: + '@aws-sdk/core': 3.974.22 + '@aws-sdk/credential-provider-env': 3.972.48 + '@aws-sdk/credential-provider-http': 3.972.50 + '@aws-sdk/credential-provider-login': 3.972.54 + '@aws-sdk/credential-provider-process': 3.972.48 + '@aws-sdk/credential-provider-sso': 3.972.54 + '@aws-sdk/credential-provider-web-identity': 3.972.54 + '@aws-sdk/nested-clients': 3.997.22 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/credential-provider-imds': 4.4.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-login@3.972.54': + dependencies: + '@aws-sdk/core': 3.974.22 + '@aws-sdk/nested-clients': 3.997.22 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-node@3.972.57': + dependencies: + '@aws-sdk/credential-provider-env': 3.972.48 + '@aws-sdk/credential-provider-http': 3.972.50 + '@aws-sdk/credential-provider-ini': 3.972.55 + '@aws-sdk/credential-provider-process': 3.972.48 + '@aws-sdk/credential-provider-sso': 3.972.54 + '@aws-sdk/credential-provider-web-identity': 3.972.54 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/credential-provider-imds': 4.4.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-process@3.972.48': + dependencies: + '@aws-sdk/core': 3.974.22 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-sso@3.972.54': + dependencies: + '@aws-sdk/core': 3.974.22 + '@aws-sdk/nested-clients': 3.997.22 + '@aws-sdk/token-providers': 3.1071.0 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/credential-provider-web-identity@3.972.54': + dependencies: + '@aws-sdk/core': 3.974.22 + '@aws-sdk/nested-clients': 3.997.22 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/nested-clients@3.997.22': + dependencies: + '@aws-crypto/sha256-browser': 5.2.0 + '@aws-crypto/sha256-js': 5.2.0 + '@aws-sdk/core': 3.974.22 + '@aws-sdk/signature-v4-multi-region': 3.996.35 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/fetch-http-handler': 5.5.1 + '@smithy/node-http-handler': 4.8.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/signature-v4-multi-region@3.996.35': + dependencies: + '@aws-sdk/types': 3.973.13 + '@smithy/signature-v4': 5.5.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/token-providers@3.1071.0': + dependencies: + '@aws-sdk/core': 3.974.22 + '@aws-sdk/nested-clients': 3.997.22 + '@aws-sdk/types': 3.973.13 + '@smithy/core': 3.25.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/types@3.973.13': + dependencies: + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@aws-sdk/util-locate-window@3.965.8': + dependencies: + tslib: 2.8.1 + + '@aws-sdk/xml-builder@3.972.30': + dependencies: + '@smithy/types': 4.15.0 + fast-xml-parser: 5.7.3 + tslib: 2.8.1 + + '@aws/lambda-invoke-store@0.2.4': {} + + '@babel/code-frame@7.29.7': + dependencies: + '@babel/helper-validator-identifier': 7.29.7 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.29.7': {} + + '@babel/core@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-compilation-targets': 7.29.7 + '@babel/helper-module-transforms': 7.29.7(@babel/core@7.29.7) + '@babel/helpers': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3 + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.29.7': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.29.7': + dependencies: + '@babel/compat-data': 7.29.7 + '@babel/helper-validator-option': 7.29.7 + browserslist: 4.28.2 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.29.7': {} + + '@babel/helper-module-imports@7.29.7': + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-module-imports': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + '@babel/traverse': 7.29.7 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.29.7': {} + + '@babel/helper-string-parser@7.29.7': {} + + '@babel/helper-validator-identifier@7.29.7': {} + + '@babel/helper-validator-option@7.29.7': {} + + '@babel/helpers@7.29.7': + dependencies: + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/parser@7.29.7': + dependencies: + '@babel/types': 7.29.7 + + '@babel/plugin-syntax-async-generators@7.8.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-bigint@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-class-properties@7.12.13(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-class-static-block@7.14.5(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-import-attributes@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-json-strings@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-jsx@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-logical-assignment-operators@7.10.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-nullish-coalescing-operator@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-numeric-separator@7.10.4(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-object-rest-spread@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-optional-catch-binding@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-optional-chaining@7.8.3(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-private-property-in-object@7.14.5(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-top-level-await@7.14.5(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/plugin-syntax-typescript@7.29.7(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/helper-plugin-utils': 7.29.7 + + '@babel/runtime@7.29.7': {} + + '@babel/template@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@babel/traverse@7.29.7': + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/helper-globals': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/types': 7.29.7 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + '@babel/types@7.29.7': + dependencies: + '@babel/helper-string-parser': 7.29.7 + '@babel/helper-validator-identifier': 7.29.7 + + '@base-ui/react@1.5.0(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@babel/runtime': 7.29.7 + '@base-ui/utils': 0.2.9(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@floating-ui/utils': 0.2.11 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + use-sync-external-store: 1.6.0(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + + '@base-ui/utils@0.2.9(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@babel/runtime': 7.29.7 + '@floating-ui/utils': 0.2.11 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + reselect: 5.2.0 + use-sync-external-store: 1.6.0(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + + '@bcoe/v8-coverage@0.2.3': {} + + '@codama/cli@1.5.3': + dependencies: + '@codama/nodes': 1.8.0 + '@codama/visitors': 1.8.0 + '@codama/visitors-core': 1.8.0 + commander: 14.0.3 + picocolors: 1.1.1 + prompts: 2.4.2 + + '@codama/errors@1.8.0': + dependencies: + '@codama/node-types': 1.8.0 + commander: 14.0.3 + picocolors: 1.1.1 + + '@codama/fragments@0.1.1': + dependencies: + '@codama/errors': 1.8.0 + + '@codama/node-types@1.8.0': {} + + '@codama/nodes-from-anchor@1.5.1(typescript@5.9.3)': + dependencies: + '@codama/errors': 1.8.0 + '@codama/nodes': 1.8.0 + '@codama/visitors': 1.8.0 + '@noble/hashes': 2.2.0 + '@solana/codecs': 5.5.1(typescript@5.9.3) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@codama/nodes@1.8.0': + dependencies: + '@codama/errors': 1.8.0 + '@codama/node-types': 1.8.0 + + '@codama/renderers-core@1.3.9': + dependencies: + '@codama/errors': 1.8.0 + '@codama/fragments': 0.1.1 + '@codama/nodes': 1.8.0 + '@codama/visitors-core': 1.8.0 + + '@codama/renderers-js@2.3.0(typescript@5.9.3)': + dependencies: + '@codama/errors': 1.8.0 + '@codama/nodes': 1.8.0 + '@codama/renderers-core': 1.3.9 + '@codama/visitors-core': 1.8.0 + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + prettier: 3.8.4 + semver: 7.8.4 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@codama/renderers-rust@3.1.0(typescript@5.9.3)': + dependencies: + '@codama/errors': 1.8.0 + '@codama/nodes': 1.8.0 + '@codama/renderers-core': 1.3.9 + '@codama/visitors-core': 1.8.0 + '@iarna/toml': 2.2.5 + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + nunjucks: 3.2.4 + semver: 7.8.4 + transitivePeerDependencies: + - chokidar + - fastestsmallesttextencoderdecoder + - typescript + + '@codama/validators@1.8.0': + dependencies: + '@codama/errors': 1.8.0 + '@codama/nodes': 1.8.0 + '@codama/visitors-core': 1.8.0 + + '@codama/visitors-core@1.8.0': + dependencies: + '@codama/errors': 1.8.0 + '@codama/nodes': 1.8.0 + json-stable-stringify: 1.3.0 + + '@codama/visitors@1.8.0': + dependencies: + '@codama/errors': 1.8.0 + '@codama/nodes': 1.8.0 + '@codama/visitors-core': 1.8.0 + + '@emnapi/core@1.10.0': + dependencies: + '@emnapi/wasi-threads': 1.2.1 + tslib: 2.8.1 + optional: true + + '@emnapi/runtime@1.10.0': + dependencies: + tslib: 2.8.1 + optional: true + + '@emnapi/wasi-threads@1.2.1': + dependencies: + tslib: 2.8.1 + optional: true + + '@esbuild/aix-ppc64@0.27.7': + optional: true + + '@esbuild/aix-ppc64@0.28.1': + optional: true + + '@esbuild/android-arm64@0.27.7': + optional: true + + '@esbuild/android-arm64@0.28.1': + optional: true + + '@esbuild/android-arm@0.27.7': + optional: true + + '@esbuild/android-arm@0.28.1': + optional: true + + '@esbuild/android-x64@0.27.7': + optional: true + + '@esbuild/android-x64@0.28.1': + optional: true + + '@esbuild/darwin-arm64@0.27.7': + optional: true + + '@esbuild/darwin-arm64@0.28.1': + optional: true + + '@esbuild/darwin-x64@0.27.7': + optional: true + + '@esbuild/darwin-x64@0.28.1': + optional: true + + '@esbuild/freebsd-arm64@0.27.7': + optional: true + + '@esbuild/freebsd-arm64@0.28.1': + optional: true + + '@esbuild/freebsd-x64@0.27.7': + optional: true + + '@esbuild/freebsd-x64@0.28.1': + optional: true + + '@esbuild/linux-arm64@0.27.7': + optional: true + + '@esbuild/linux-arm64@0.28.1': + optional: true + + '@esbuild/linux-arm@0.27.7': + optional: true + + '@esbuild/linux-arm@0.28.1': + optional: true + + '@esbuild/linux-ia32@0.27.7': + optional: true + + '@esbuild/linux-ia32@0.28.1': + optional: true + + '@esbuild/linux-loong64@0.27.7': + optional: true + + '@esbuild/linux-loong64@0.28.1': + optional: true + + '@esbuild/linux-mips64el@0.27.7': + optional: true + + '@esbuild/linux-mips64el@0.28.1': + optional: true + + '@esbuild/linux-ppc64@0.27.7': + optional: true + + '@esbuild/linux-ppc64@0.28.1': + optional: true + + '@esbuild/linux-riscv64@0.27.7': + optional: true + + '@esbuild/linux-riscv64@0.28.1': + optional: true + + '@esbuild/linux-s390x@0.27.7': + optional: true + + '@esbuild/linux-s390x@0.28.1': + optional: true + + '@esbuild/linux-x64@0.27.7': + optional: true + + '@esbuild/linux-x64@0.28.1': + optional: true + + '@esbuild/netbsd-arm64@0.27.7': + optional: true + + '@esbuild/netbsd-arm64@0.28.1': + optional: true + + '@esbuild/netbsd-x64@0.27.7': + optional: true + + '@esbuild/netbsd-x64@0.28.1': + optional: true + + '@esbuild/openbsd-arm64@0.27.7': + optional: true + + '@esbuild/openbsd-arm64@0.28.1': + optional: true + + '@esbuild/openbsd-x64@0.27.7': + optional: true + + '@esbuild/openbsd-x64@0.28.1': + optional: true + + '@esbuild/openharmony-arm64@0.27.7': + optional: true + + '@esbuild/openharmony-arm64@0.28.1': + optional: true + + '@esbuild/sunos-x64@0.27.7': + optional: true + + '@esbuild/sunos-x64@0.28.1': + optional: true + + '@esbuild/win32-arm64@0.27.7': + optional: true + + '@esbuild/win32-arm64@0.28.1': + optional: true + + '@esbuild/win32-ia32@0.27.7': + optional: true + + '@esbuild/win32-ia32@0.28.1': + optional: true + + '@esbuild/win32-x64@0.27.7': + optional: true + + '@esbuild/win32-x64@0.28.1': + optional: true + + '@eslint-community/eslint-utils@4.9.1(eslint@9.39.4(jiti@2.7.0))': + dependencies: + eslint: 9.39.4(jiti@2.7.0) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.2': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3 + minimatch: 9.0.9 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.5': + dependencies: + ajv: 6.15.0 + debug: 4.4.3 + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.2.0 + minimatch: 9.0.9 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.4': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@floating-ui/core@1.7.5': + dependencies: + '@floating-ui/utils': 0.2.11 + + '@floating-ui/dom@1.7.6': + dependencies: + '@floating-ui/core': 1.7.5 + '@floating-ui/utils': 0.2.11 + + '@floating-ui/react-dom@2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@floating-ui/dom': 1.7.6 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + '@floating-ui/utils@0.2.11': {} + + '@heroicons/react@2.2.0(react@19.2.7)': + dependencies: + react: 19.2.7 + + '@humanfs/core@0.19.2': + dependencies: + '@humanfs/types': 0.15.0 + + '@humanfs/node@0.16.8': + dependencies: + '@humanfs/core': 0.19.2 + '@humanfs/types': 0.15.0 + '@humanwhocodes/retry': 0.4.3 + + '@humanfs/types@0.15.0': {} + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@iarna/toml@2.2.5': {} + + '@img/colour@1.1.0': + optional: true + + '@img/sharp-darwin-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-arm64': 1.2.4 + optional: true + + '@img/sharp-darwin-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-darwin-x64': 1.2.4 + optional: true + + '@img/sharp-libvips-darwin-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-darwin-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-arm@1.2.4': + optional: true + + '@img/sharp-libvips-linux-ppc64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-riscv64@1.2.4': + optional: true + + '@img/sharp-libvips-linux-s390x@1.2.4': + optional: true + + '@img/sharp-libvips-linux-x64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-arm64@1.2.4': + optional: true + + '@img/sharp-libvips-linuxmusl-x64@1.2.4': + optional: true + + '@img/sharp-linux-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm64': 1.2.4 + optional: true + + '@img/sharp-linux-arm@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-arm': 1.2.4 + optional: true + + '@img/sharp-linux-ppc64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-ppc64': 1.2.4 + optional: true + + '@img/sharp-linux-riscv64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-riscv64': 1.2.4 + optional: true + + '@img/sharp-linux-s390x@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-s390x': 1.2.4 + optional: true + + '@img/sharp-linux-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linux-x64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-arm64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + optional: true + + '@img/sharp-linuxmusl-x64@0.34.5': + optionalDependencies: + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + optional: true + + '@img/sharp-wasm32@0.34.5': + dependencies: + '@emnapi/runtime': 1.10.0 + optional: true + + '@img/sharp-win32-arm64@0.34.5': + optional: true + + '@img/sharp-win32-ia32@0.34.5': + optional: true + + '@img/sharp-win32-x64@0.34.5': + optional: true + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@isaacs/ttlcache@1.4.1': {} + + '@istanbuljs/load-nyc-config@1.1.0': + dependencies: + camelcase: 5.3.1 + find-up: 4.1.0 + get-package-type: 0.1.0 + js-yaml: 3.14.2 + resolve-from: 5.0.0 + + '@istanbuljs/schema@0.1.6': {} + + '@jest/console@30.4.1': + dependencies: + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + chalk: 4.1.2 + jest-message-util: 30.4.1 + jest-util: 30.4.1 + slash: 3.0.0 + + '@jest/core@30.4.2': + dependencies: + '@jest/console': 30.4.1 + '@jest/pattern': 30.4.0 + '@jest/reporters': 30.4.1 + '@jest/test-result': 30.4.1 + '@jest/transform': 30.4.1 + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + ci-info: 4.4.0 + exit-x: 0.2.2 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-changed-files: 30.4.1 + jest-config: 30.4.2(@types/node@25.9.3) + jest-haste-map: 30.4.1 + jest-message-util: 30.4.1 + jest-regex-util: 30.4.0 + jest-resolve: 30.4.1 + jest-resolve-dependencies: 30.4.2 + jest-runner: 30.4.2 + jest-runtime: 30.4.2 + jest-snapshot: 30.4.1 + jest-util: 30.4.1 + jest-validate: 30.4.1 + jest-watcher: 30.4.1 + pretty-format: 30.4.1 + slash: 3.0.0 + transitivePeerDependencies: + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + '@jest/diff-sequences@30.4.0': {} + + '@jest/environment@30.4.1': + dependencies: + '@jest/fake-timers': 30.4.1 + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + jest-mock: 30.4.1 + + '@jest/expect-utils@30.4.1': + dependencies: + '@jest/get-type': 30.1.0 + + '@jest/expect@30.4.1': + dependencies: + expect: 30.4.1 + jest-snapshot: 30.4.1 + transitivePeerDependencies: + - supports-color + + '@jest/fake-timers@30.4.1': + dependencies: + '@jest/types': 30.4.1 + '@sinonjs/fake-timers': 15.4.0 + '@types/node': 25.9.3 + jest-message-util: 30.4.1 + jest-mock: 30.4.1 + jest-util: 30.4.1 + + '@jest/get-type@30.1.0': {} + + '@jest/globals@30.4.1': + dependencies: + '@jest/environment': 30.4.1 + '@jest/expect': 30.4.1 + '@jest/types': 30.4.1 + jest-mock: 30.4.1 + transitivePeerDependencies: + - supports-color + + '@jest/pattern@30.4.0': + dependencies: + '@types/node': 25.9.3 + jest-regex-util: 30.4.0 + + '@jest/reporters@30.4.1': + dependencies: + '@bcoe/v8-coverage': 0.2.3 + '@jest/console': 30.4.1 + '@jest/test-result': 30.4.1 + '@jest/transform': 30.4.1 + '@jest/types': 30.4.1 + '@jridgewell/trace-mapping': 0.3.31 + '@types/node': 25.9.3 + chalk: 4.1.2 + collect-v8-coverage: 1.0.3 + exit-x: 0.2.2 + glob: 10.5.0 + graceful-fs: 4.2.11 + istanbul-lib-coverage: 3.2.2 + istanbul-lib-instrument: 6.0.3 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + jest-message-util: 30.4.1 + jest-util: 30.4.1 + jest-worker: 30.4.1 + slash: 3.0.0 + string-length: 4.0.2 + v8-to-istanbul: 9.3.0 + transitivePeerDependencies: + - supports-color + + '@jest/schemas@29.6.3': + dependencies: + '@sinclair/typebox': 0.27.10 + + '@jest/schemas@30.4.1': + dependencies: + '@sinclair/typebox': 0.34.49 + + '@jest/snapshot-utils@30.4.1': + dependencies: + '@jest/types': 30.4.1 + chalk: 4.1.2 + graceful-fs: 4.2.11 + natural-compare: 1.4.0 + + '@jest/source-map@30.0.1': + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + callsites: 3.1.0 + graceful-fs: 4.2.11 + + '@jest/test-result@30.4.1': + dependencies: + '@jest/console': 30.4.1 + '@jest/types': 30.4.1 + '@types/istanbul-lib-coverage': 2.0.6 + collect-v8-coverage: 1.0.3 + + '@jest/test-sequencer@30.4.1': + dependencies: + '@jest/test-result': 30.4.1 + graceful-fs: 4.2.11 + jest-haste-map: 30.4.1 + slash: 3.0.0 + + '@jest/transform@30.4.1': + dependencies: + '@babel/core': 7.29.7 + '@jest/types': 30.4.1 + '@jridgewell/trace-mapping': 0.3.31 + babel-plugin-istanbul: 7.0.1 + chalk: 4.1.2 + convert-source-map: 2.0.0 + fast-json-stable-stringify: 2.1.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.4.1 + jest-regex-util: 30.4.0 + jest-util: 30.4.1 + pirates: 4.0.7 + slash: 3.0.0 + write-file-atomic: 5.0.1 + transitivePeerDependencies: + - supports-color + + '@jest/types@29.6.3': + dependencies: + '@jest/schemas': 29.6.3 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 25.9.3 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + + '@jest/types@30.4.1': + dependencies: + '@jest/pattern': 30.4.0 + '@jest/schemas': 30.4.1 + '@types/istanbul-lib-coverage': 2.0.6 + '@types/istanbul-reports': 3.0.4 + '@types/node': 25.9.3 + '@types/yargs': 17.0.35 + chalk: 4.1.2 + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/source-map@0.3.11': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@nanostores/persistent@1.1.0(nanostores@1.0.1)': + dependencies: + nanostores: 1.0.1 + + '@napi-rs/wasm-runtime@1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0)': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@tybys/wasm-util': 0.10.2 + optional: true + + '@noble/curves@1.9.7': + dependencies: + '@noble/hashes': 1.8.0 + + '@noble/curves@2.2.0': + dependencies: + '@noble/hashes': 2.2.0 + + '@noble/ed25519@3.1.0': {} + + '@noble/hashes@1.8.0': {} + + '@noble/hashes@2.2.0': {} + + '@nodable/entities@2.2.0': {} + + '@nodelib/fs.scandir@2.1.5': + dependencies: + '@nodelib/fs.stat': 2.0.5 + run-parallel: 1.2.0 + + '@nodelib/fs.stat@2.0.5': {} + + '@nodelib/fs.walk@1.2.8': + dependencies: + '@nodelib/fs.scandir': 2.1.5 + fastq: 1.20.1 + + '@oxc-project/types@0.133.0': {} + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@pkgr/core@0.3.6': {} + + '@radix-ui/primitive@1.1.4': {} + + '@radix-ui/react-arrow@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-collection@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-compose-refs@1.1.3(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-context@1.1.4(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-dialog@1.1.17(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-portal': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + aria-hidden: 1.2.6 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-direction@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-dismissable-layer@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-escape-keydown': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-dropdown-menu@2.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-menu': 2.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-focus-guards@1.1.4(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-focus-scope@1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-id@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-label@2.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-menu@2.1.18(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collection': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-dismissable-layer': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-focus-guards': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-focus-scope': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-popper': 1.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-portal': 1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-presence': 1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-roving-focus': 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + aria-hidden: 1.2.6 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + react-remove-scroll: 2.7.2(@types/react@19.2.17)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-popper@1.3.1(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@floating-ui/react-dom': 2.1.8(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-arrow': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-rect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-size': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/rect': 1.1.2 + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-portal@1.1.12(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-presence@1.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-primitive@2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/react-slot': 1.3.0(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-roving-focus@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7)': + dependencies: + '@radix-ui/primitive': 1.1.4 + '@radix-ui/react-collection': 1.1.10(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-context': 1.1.4(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-direction': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-id': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-primitive': 2.1.6(@types/react-dom@19.2.3(@types/react@19.2.17))(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-controllable-state': 1.2.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + '@types/react-dom': 19.2.3(@types/react@19.2.17) + + '@radix-ui/react-slot@1.3.0(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.3(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-callback-ref@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-controllable-state@1.2.3(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.3(@types/react@19.2.17)(react@19.2.7) + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-effect-event@0.0.3(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-escape-keydown@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-layout-effect@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-rect@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/rect': 1.1.2 + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/react-use-size@1.1.2(@types/react@19.2.17)(react@19.2.7)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.2(@types/react@19.2.17)(react@19.2.7) + react: 19.2.7 + optionalDependencies: + '@types/react': 19.2.17 + + '@radix-ui/rect@1.1.2': {} + + '@react-native/assets-registry@0.86.0': {} + + '@react-native/codegen@0.86.0(@babel/core@7.29.7)': + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.7 + hermes-parser: 0.36.0 + invariant: 2.2.4 + nullthrows: 1.1.1 + tinyglobby: 0.2.17 + yargs: 17.7.2 + + '@react-native/community-cli-plugin@0.86.0': + dependencies: + '@react-native/dev-middleware': 0.86.0 + debug: 4.4.3 + invariant: 2.2.4 + metro: 0.84.4 + metro-config: 0.84.4 + metro-core: 0.84.4 + semver: 7.8.4 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/debugger-frontend@0.86.0': {} + + '@react-native/debugger-shell@0.86.0': + dependencies: + cross-spawn: 7.0.6 + debug: 4.4.3 + fb-dotslash: 0.5.8 + transitivePeerDependencies: + - supports-color + + '@react-native/dev-middleware@0.86.0': + dependencies: + '@isaacs/ttlcache': 1.4.1 + '@react-native/debugger-frontend': 0.86.0 + '@react-native/debugger-shell': 0.86.0 + chrome-launcher: 0.15.2 + chromium-edge-launcher: 0.3.0 + connect: 3.7.0 + debug: 4.4.3 + invariant: 2.2.4 + nullthrows: 1.1.1 + open: 7.4.2 + serve-static: 1.16.3 + ws: 7.5.11 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + '@react-native/gradle-plugin@0.86.0': {} + + '@react-native/js-polyfills@0.86.0': {} + + '@react-native/normalize-colors@0.86.0': {} + + '@react-native/virtualized-lists@0.86.0(@types/react@19.2.17)(react-native@0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)': + dependencies: + invariant: 2.2.4 + nullthrows: 1.1.1 + react: 19.2.7 + react-native: 0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + + '@resvg/resvg-wasm@2.4.0': {} + + '@rolldown/binding-android-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-arm64@1.0.3': + optional: true + + '@rolldown/binding-darwin-x64@1.0.3': + optional: true + + '@rolldown/binding-freebsd-x64@1.0.3': + optional: true + + '@rolldown/binding-linux-arm-gnueabihf@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-arm64-musl@1.0.3': + optional: true + + '@rolldown/binding-linux-ppc64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-s390x-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-gnu@1.0.3': + optional: true + + '@rolldown/binding-linux-x64-musl@1.0.3': + optional: true + + '@rolldown/binding-openharmony-arm64@1.0.3': + optional: true + + '@rolldown/binding-wasm32-wasi@1.0.3': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@rolldown/binding-win32-arm64-msvc@1.0.3': + optional: true + + '@rolldown/binding-win32-x64-msvc@1.0.3': + optional: true + + '@rolldown/pluginutils@1.0.1': {} + + '@rollup/rollup-android-arm-eabi@4.60.2': + optional: true + + '@rollup/rollup-android-arm64@4.60.2': + optional: true + + '@rollup/rollup-darwin-arm64@4.60.2': + optional: true + + '@rollup/rollup-darwin-x64@4.60.2': + optional: true + + '@rollup/rollup-freebsd-arm64@4.60.2': + optional: true + + '@rollup/rollup-freebsd-x64@4.60.2': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.60.2': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.60.2': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.60.2': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-loong64-musl@4.60.2': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-ppc64-musl@4.60.2': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.60.2': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.60.2': + optional: true + + '@rollup/rollup-linux-x64-musl@4.60.2': + optional: true + + '@rollup/rollup-openbsd-x64@4.60.2': + optional: true + + '@rollup/rollup-openharmony-arm64@4.60.2': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.60.2': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.60.2': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.60.2': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.60.2': + optional: true + + '@shikijs/core@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + hast-util-to-html: 9.0.5 + + '@shikijs/engine-javascript@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + oniguruma-to-es: 4.3.6 + + '@shikijs/engine-oniguruma@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + + '@shikijs/langs@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/themes@3.23.0': + dependencies: + '@shikijs/types': 3.23.0 + + '@shikijs/types@3.23.0': + dependencies: + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + '@shikijs/vscode-textmate@10.0.2': {} + + '@shuding/opentype.js@1.4.0-beta.0': + dependencies: + fflate: 0.7.4 + string.prototype.codepointat: 0.2.1 + + '@sinclair/typebox@0.27.10': {} + + '@sinclair/typebox@0.34.49': {} + + '@sinonjs/commons@3.0.1': + dependencies: + type-detect: 4.0.8 + + '@sinonjs/fake-timers@15.4.0': + dependencies: + '@sinonjs/commons': 3.0.1 + + '@smithy/core@3.25.1': + dependencies: + '@aws-crypto/crc32': 5.2.0 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/credential-provider-imds@4.4.1': + dependencies: + '@smithy/core': 3.25.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/fetch-http-handler@5.5.1': + dependencies: + '@smithy/core': 3.25.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/is-array-buffer@2.2.0': + dependencies: + tslib: 2.8.1 + + '@smithy/node-http-handler@4.8.1': + dependencies: + '@smithy/core': 3.25.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/signature-v4@5.5.1': + dependencies: + '@smithy/core': 3.25.1 + '@smithy/types': 4.15.0 + tslib: 2.8.1 + + '@smithy/types@4.15.0': + dependencies: + tslib: 2.8.1 + + '@smithy/util-buffer-from@2.2.0': + dependencies: + '@smithy/is-array-buffer': 2.2.0 + tslib: 2.8.1 + + '@smithy/util-utf8@2.3.0': + dependencies: + '@smithy/util-buffer-from': 2.2.0 + tslib: 2.8.1 + + '@solana-mobile/mobile-wallet-adapter-protocol@2.2.9(react-native@0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7))(typescript@5.9.3)': + dependencies: + '@solana/kit': 6.10.0(typescript@5.9.3) + '@solana/wallet-standard-features': 1.4.0 + '@solana/wallet-standard-util': 1.1.3 + '@wallet-standard/core': 1.1.2 + react-native: 0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7) + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - typescript + - utf-8-validate + + '@solana-mobile/wallet-standard-mobile@0.4.4(react-native@0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7))(typescript@5.9.3)': + dependencies: + '@solana-mobile/mobile-wallet-adapter-protocol': 2.2.9(react-native@0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7))(typescript@5.9.3) + '@solana/wallet-standard-chains': 1.1.2 + '@solana/wallet-standard-features': 1.4.0 + '@wallet-standard/base': 1.1.1 + '@wallet-standard/features': 1.1.1 + bs58: 5.0.0 + js-base64: 3.7.8 + qrcode: 1.5.4 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - react-native + - typescript + - utf-8-validate + + '@solana-program/system@0.12.2(@solana/kit@6.10.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 6.10.0(typescript@5.9.3) + + '@solana-program/token-2022@0.12.0(@solana/kit@6.10.0(typescript@5.9.3))(@solana/sysvars@6.10.0(typescript@5.9.3))': + dependencies: + '@noble/curves': 1.9.7 + '@solana-program/zk-elgamal-proof': 0.2.0(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana/kit': 6.10.0(typescript@5.9.3) + '@solana/sysvars': 6.10.0(typescript@5.9.3) + + '@solana-program/token-2022@0.9.0(@solana/kit@6.10.0(typescript@5.9.3))(@solana/sysvars@6.10.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 6.10.0(typescript@5.9.3) + '@solana/sysvars': 6.10.0(typescript@5.9.3) + + '@solana-program/token@0.13.0(@solana/kit@6.10.0(typescript@5.9.3))': + dependencies: + '@solana-program/system': 0.12.2(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana/kit': 6.10.0(typescript@5.9.3) + + '@solana-program/token@0.14.0(@solana/kit@6.10.0(typescript@5.9.3))': + dependencies: + '@solana-program/system': 0.12.2(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana/kit': 6.10.0(typescript@5.9.3) + + '@solana-program/zk-elgamal-proof@0.2.0(@solana/kit@6.10.0(typescript@5.9.3))': + dependencies: + '@solana-program/system': 0.12.2(@solana/kit@6.10.0(typescript@5.9.3)) + '@solana/kit': 6.10.0(typescript@5.9.3) + + '@solana/accounts@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/accounts@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/assertions': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/nominal-types': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/addresses@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/assertions@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/assertions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-core@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-core@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-data-structures@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-data-structures@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-numbers@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-numbers@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-strings@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs-strings@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/codecs@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/options': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/codecs@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/fixed-points': 6.10.0(typescript@5.9.3) + '@solana/options': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/connector@0.2.4(@solana/keychain-aws-kms@0.2.1(typescript@5.9.3))(@solana/keychain-turnkey@0.2.1(typescript@5.9.3))(@solana/keychain-vault@0.2.1(typescript@5.9.3))(react-native@0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7))(react@19.2.7)(typescript@5.9.3)': + dependencies: + '@solana-mobile/wallet-standard-mobile': 0.4.4(react-native@0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7))(typescript@5.9.3) + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs': 5.5.1(typescript@5.9.3) + '@solana/keychain-aws-kms': 0.2.1(typescript@5.9.3) + '@solana/keychain-turnkey': 0.2.1(typescript@5.9.3) + '@solana/keychain-vault': 0.2.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/kit': 5.5.1(typescript@5.9.3) + '@solana/signers': 5.5.1(typescript@5.9.3) + '@solana/transaction-messages': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + '@solana/webcrypto-ed25519-polyfill': 4.0.0(typescript@5.9.3) + '@wallet-standard/app': 1.1.1 + '@wallet-standard/base': 1.1.1 + '@wallet-standard/features': 1.1.1 + '@wallet-ui/core': 2.2.2(@solana/kit@5.5.1(typescript@5.9.3)) + zod: 4.4.3 + optionalDependencies: + react: 19.2.7 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - react-native + - typescript + - utf-8-validate + + '@solana/design-system@1.0.1(@base-ui/react@1.5.0(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(motion@12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7))(react-dom@19.2.7(react@19.2.7))(react@19.2.7)(tailwindcss@4.3.1)': + dependencies: + '@base-ui/react': 1.5.0(@types/react@19.2.17)(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + '@heroicons/react': 2.2.0(react@19.2.7) + '@shikijs/core': 3.23.0 + '@shikijs/engine-oniguruma': 3.23.0 + lucide-react: 0.575.0(react@19.2.7) + motion: 12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + shiki: 3.23.0 + tailwindcss: 4.3.1 + + '@solana/errors@5.5.1(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 14.0.2 + optionalDependencies: + typescript: 5.9.3 + + '@solana/errors@6.10.0(typescript@5.9.3)': + dependencies: + chalk: 5.6.2 + commander: 15.0.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/eslint-config-solana@6.0.0(@eslint/js@9.39.4)(@types/eslint@9.6.1)(@types/eslint__js@9.14.0)(eslint-plugin-jest@29.15.2(@typescript-eslint/eslint-plugin@8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(jest@30.4.2(@types/node@25.9.3))(typescript@5.9.3))(eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.4(jiti@2.7.0)))(eslint-plugin-sort-keys-fix@1.1.2)(eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(globals@16.5.0)(jest@30.4.2(@types/node@25.9.3))(typescript-eslint@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(typescript@5.9.3)': + dependencies: + '@eslint/js': 9.39.4 + '@types/eslint': 9.6.1 + '@types/eslint__js': 9.14.0 + eslint: 9.39.4(jiti@2.7.0) + eslint-plugin-jest: 29.15.2(@typescript-eslint/eslint-plugin@8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(jest@30.4.2(@types/node@25.9.3))(typescript@5.9.3) + eslint-plugin-react-hooks: 7.1.1(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-simple-import-sort: 12.1.1(eslint@9.39.4(jiti@2.7.0)) + eslint-plugin-sort-keys-fix: 1.1.2 + eslint-plugin-typescript-sort-keys: 3.3.0(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + globals: 16.5.0 + jest: 30.4.2(@types/node@25.9.3) + typescript: 5.9.3 + typescript-eslint: 8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + + '@solana/fast-stable-stringify@5.5.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/fast-stable-stringify@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/fixed-points@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/functional@5.5.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/functional@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/instruction-plans@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/instructions': 5.5.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/promises': 5.5.1(typescript@5.9.3) + '@solana/transaction-messages': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instruction-plans@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/instructions@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/instructions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/keychain-aws-kms@0.2.1(typescript@5.9.3)': + dependencies: + '@aws-sdk/client-kms': 3.1072.0 + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/keychain-core': 0.2.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/signers': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@solana/keychain-core@0.2.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/signers': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@solana/keychain-turnkey@0.2.1(typescript@5.9.3)': + dependencies: + '@noble/curves': 2.2.0 + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/keychain-core': 0.2.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/signers': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@solana/keychain-vault@0.2.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/keychain-core': 0.2.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/signers': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + - typescript + + '@solana/keys@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/assertions': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/nominal-types': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/keys@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/assertions': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/kit-plugin-instruction-plan@0.10.0(@solana/kit@6.10.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 6.10.0(typescript@5.9.3) + + '@solana/kit-plugin-rpc@0.11.1(@solana/kit@6.10.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 6.10.0(typescript@5.9.3) + '@solana/kit-plugin-instruction-plan': 0.10.0(@solana/kit@6.10.0(typescript@5.9.3)) + + '@solana/kit-plugin-signer@0.10.0(@solana/kit@6.10.0(typescript@5.9.3))': + dependencies: + '@solana/kit': 6.10.0(typescript@5.9.3) + + '@solana/kit@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/accounts': 5.5.1(typescript@5.9.3) + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/functional': 5.5.1(typescript@5.9.3) + '@solana/instruction-plans': 5.5.1(typescript@5.9.3) + '@solana/instructions': 5.5.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/offchain-messages': 5.5.1(typescript@5.9.3) + '@solana/plugin-core': 5.5.1(typescript@5.9.3) + '@solana/programs': 5.5.1(typescript@5.9.3) + '@solana/rpc': 5.5.1(typescript@5.9.3) + '@solana/rpc-api': 5.5.1(typescript@5.9.3) + '@solana/rpc-parsed-types': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3) + '@solana/rpc-subscriptions': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + '@solana/signers': 5.5.1(typescript@5.9.3) + '@solana/sysvars': 5.5.1(typescript@5.9.3) + '@solana/transaction-confirmation': 5.5.1(typescript@5.9.3) + '@solana/transaction-messages': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/kit@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 6.10.0(typescript@5.9.3) + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/instruction-plans': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/offchain-messages': 6.10.0(typescript@5.9.3) + '@solana/plugin-core': 6.10.0(typescript@5.9.3) + '@solana/plugin-interfaces': 6.10.0(typescript@5.9.3) + '@solana/program-client-core': 6.10.0(typescript@5.9.3) + '@solana/programs': 6.10.0(typescript@5.9.3) + '@solana/rpc': 6.10.0(typescript@5.9.3) + '@solana/rpc-api': 6.10.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/signers': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + '@solana/sysvars': 6.10.0(typescript@5.9.3) + '@solana/transaction-confirmation': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/nominal-types@5.5.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/nominal-types@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/offchain-messages@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/nominal-types': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/offchain-messages@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/options@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/plugin-core@5.5.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/plugin-core@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/plugin-interfaces@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/instruction-plans': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/signers': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/prettier-config-solana@0.0.6(prettier@3.8.4)': + dependencies: + prettier: 3.8.4 + + '@solana/program-client-core@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 6.10.0(typescript@5.9.3) + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/instruction-plans': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/plugin-interfaces': 6.10.0(typescript@5.9.3) + '@solana/rpc-api': 6.10.0(typescript@5.9.3) + '@solana/signers': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/programs@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/promises@5.5.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/promises@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-api@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/rpc-parsed-types': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec': 5.5.1(typescript@5.9.3) + '@solana/rpc-transformers': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + '@solana/transaction-messages': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-api@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/rpc-parsed-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-parsed-types@5.5.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-parsed-types@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@5.5.1(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec-types@6.10.0(typescript@5.9.3)': + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-spec@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions-api@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 5.5.1(typescript@5.9.3) + '@solana/rpc-transformers': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + '@solana/transaction-messages': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-api@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-subscriptions-channel-websocket@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/functional': 5.5.1(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 5.5.1(typescript@5.9.3) + '@solana/subscribable': 5.5.1(typescript@5.9.3) + ws: 8.20.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@solana/rpc-subscriptions-channel-websocket@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + ws: 8.20.1 + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + '@solana/rpc-subscriptions-spec@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/promises': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3) + '@solana/subscribable': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions-spec@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-subscriptions@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/fast-stable-stringify': 5.5.1(typescript@5.9.3) + '@solana/functional': 5.5.1(typescript@5.9.3) + '@solana/promises': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 5.5.1(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 5.5.1(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 5.5.1(typescript@5.9.3) + '@solana/rpc-transformers': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + '@solana/subscribable': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/rpc-subscriptions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-api': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-channel-websocket': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/subscribable': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/rpc-transformers@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/functional': 5.5.1(typescript@5.9.3) + '@solana/nominal-types': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transformers@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-transport-http@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3) + undici-types: 7.24.6 + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-transport-http@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + undici-types: 8.5.0 + optionalDependencies: + typescript: 5.9.3 + + '@solana/rpc-types@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/nominal-types': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc-types@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/fixed-points': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/fast-stable-stringify': 5.5.1(typescript@5.9.3) + '@solana/functional': 5.5.1(typescript@5.9.3) + '@solana/rpc-api': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec': 5.5.1(typescript@5.9.3) + '@solana/rpc-spec-types': 5.5.1(typescript@5.9.3) + '@solana/rpc-transformers': 5.5.1(typescript@5.9.3) + '@solana/rpc-transport-http': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/rpc@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/fast-stable-stringify': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/rpc-api': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec': 6.10.0(typescript@5.9.3) + '@solana/rpc-spec-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-transformers': 6.10.0(typescript@5.9.3) + '@solana/rpc-transport-http': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/instructions': 5.5.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/nominal-types': 5.5.1(typescript@5.9.3) + '@solana/offchain-messages': 5.5.1(typescript@5.9.3) + '@solana/transaction-messages': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/signers@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/offchain-messages': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/subscribable@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/errors': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/subscribable@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + + '@solana/sysvars@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/accounts': 5.5.1(typescript@5.9.3) + '@solana/codecs': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/sysvars@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/accounts': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-confirmation@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/promises': 5.5.1(typescript@5.9.3) + '@solana/rpc': 5.5.1(typescript@5.9.3) + '@solana/rpc-subscriptions': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + '@solana/transaction-messages': 5.5.1(typescript@5.9.3) + '@solana/transactions': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/transaction-confirmation@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/promises': 6.10.0(typescript@5.9.3) + '@solana/rpc': 6.10.0(typescript@5.9.3) + '@solana/rpc-subscriptions': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + '@solana/transactions': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - bufferutil + - fastestsmallesttextencoderdecoder + - utf-8-validate + + '@solana/transaction-messages@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/functional': 5.5.1(typescript@5.9.3) + '@solana/instructions': 5.5.1(typescript@5.9.3) + '@solana/nominal-types': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transaction-messages@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@5.5.1(typescript@5.9.3)': + dependencies: + '@solana/addresses': 5.5.1(typescript@5.9.3) + '@solana/codecs-core': 5.5.1(typescript@5.9.3) + '@solana/codecs-data-structures': 5.5.1(typescript@5.9.3) + '@solana/codecs-numbers': 5.5.1(typescript@5.9.3) + '@solana/codecs-strings': 5.5.1(typescript@5.9.3) + '@solana/errors': 5.5.1(typescript@5.9.3) + '@solana/functional': 5.5.1(typescript@5.9.3) + '@solana/instructions': 5.5.1(typescript@5.9.3) + '@solana/keys': 5.5.1(typescript@5.9.3) + '@solana/nominal-types': 5.5.1(typescript@5.9.3) + '@solana/rpc-types': 5.5.1(typescript@5.9.3) + '@solana/transaction-messages': 5.5.1(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/transactions@6.10.0(typescript@5.9.3)': + dependencies: + '@solana/addresses': 6.10.0(typescript@5.9.3) + '@solana/codecs-core': 6.10.0(typescript@5.9.3) + '@solana/codecs-data-structures': 6.10.0(typescript@5.9.3) + '@solana/codecs-numbers': 6.10.0(typescript@5.9.3) + '@solana/codecs-strings': 6.10.0(typescript@5.9.3) + '@solana/errors': 6.10.0(typescript@5.9.3) + '@solana/functional': 6.10.0(typescript@5.9.3) + '@solana/instructions': 6.10.0(typescript@5.9.3) + '@solana/keys': 6.10.0(typescript@5.9.3) + '@solana/nominal-types': 6.10.0(typescript@5.9.3) + '@solana/rpc-types': 6.10.0(typescript@5.9.3) + '@solana/transaction-messages': 6.10.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - fastestsmallesttextencoderdecoder + + '@solana/wallet-standard-chains@1.1.2': + dependencies: + '@wallet-standard/base': 1.1.1 + + '@solana/wallet-standard-features@1.4.0': + dependencies: + '@wallet-standard/base': 1.1.1 + '@wallet-standard/features': 1.1.1 + + '@solana/wallet-standard-util@1.1.3': + dependencies: + '@noble/curves': 1.9.7 + '@solana/wallet-standard-chains': 1.1.2 + '@solana/wallet-standard-features': 1.4.0 + + '@solana/webcrypto-ed25519-polyfill@4.0.0(typescript@5.9.3)': + dependencies: + '@noble/ed25519': 3.1.0 + typescript: 5.9.3 + + '@tailwindcss/node@4.3.1': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.21.6 + jiti: 2.7.0 + lightningcss: 1.32.0 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.3.1 + + '@tailwindcss/oxide-android-arm64@4.3.1': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.3.1': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.3.1': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.3.1': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.3.1': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.3.1': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.3.1': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.3.1': + optional: true + + '@tailwindcss/oxide@4.3.1': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.3.1 + '@tailwindcss/oxide-darwin-arm64': 4.3.1 + '@tailwindcss/oxide-darwin-x64': 4.3.1 + '@tailwindcss/oxide-freebsd-x64': 4.3.1 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.3.1 + '@tailwindcss/oxide-linux-arm64-gnu': 4.3.1 + '@tailwindcss/oxide-linux-arm64-musl': 4.3.1 + '@tailwindcss/oxide-linux-x64-gnu': 4.3.1 + '@tailwindcss/oxide-linux-x64-musl': 4.3.1 + '@tailwindcss/oxide-wasm32-wasi': 4.3.1 + '@tailwindcss/oxide-win32-arm64-msvc': 4.3.1 + '@tailwindcss/oxide-win32-x64-msvc': 4.3.1 + + '@tailwindcss/postcss@4.3.1': + dependencies: + '@alloc/quick-lru': 5.2.0 + '@tailwindcss/node': 4.3.1 + '@tailwindcss/oxide': 4.3.1 + postcss: 8.5.15 + tailwindcss: 4.3.1 + + '@tanstack/query-core@5.101.0': {} + + '@tanstack/react-query@5.101.0(react@19.2.7)': + dependencies: + '@tanstack/query-core': 5.101.0 + react: 19.2.7 + + '@tybys/wasm-util@0.10.2': + dependencies: + tslib: 2.8.1 + optional: true + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.29.7 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.29.7 + + '@types/eslint@9.6.1': + dependencies: + '@types/estree': 1.0.9 + '@types/json-schema': 7.0.15 + + '@types/eslint__js@9.14.0': + dependencies: + '@eslint/js': 9.39.4 + + '@types/estree@1.0.8': {} + + '@types/estree@1.0.9': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/istanbul-lib-coverage@2.0.6': {} + + '@types/istanbul-lib-report@3.0.3': + dependencies: + '@types/istanbul-lib-coverage': 2.0.6 + + '@types/istanbul-reports@3.0.4': + dependencies: + '@types/istanbul-lib-report': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/node@25.9.3': + dependencies: + undici-types: 7.24.6 + + '@types/react-dom@19.2.3(@types/react@19.2.17)': + dependencies: + '@types/react': 19.2.17 + + '@types/react@19.2.17': + dependencies: + csstype: 3.2.3 + + '@types/semver@7.7.1': {} + + '@types/stack-utils@2.0.3': {} + + '@types/unist@3.0.3': {} + + '@types/yargs-parser@21.0.3': {} + + '@types/yargs@17.0.35': + dependencies: + '@types/yargs-parser': 21.0.3 + + '@typescript-eslint/eslint-plugin@8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.61.1 + '@typescript-eslint/type-utils': 8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.61.1 + eslint: 9.39.4(jiti@2.7.0) + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/experimental-utils@5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.61.1 + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.61.1 + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.61.1(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.61.1(typescript@5.9.3) + '@typescript-eslint/types': 8.61.1 + debug: 4.4.3 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@5.62.0': + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + + '@typescript-eslint/scope-manager@8.61.1': + dependencies: + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/visitor-keys': 8.61.1 + + '@typescript-eslint/tsconfig-utils@8.61.1(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + debug: 4.4.3 + eslint: 9.39.4(jiti@2.7.0) + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@5.62.0': {} + + '@typescript-eslint/types@8.61.1': {} + + '@typescript-eslint/typescript-estree@5.62.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/visitor-keys': 5.62.0 + debug: 4.4.3 + globby: 11.1.0 + is-glob: 4.0.3 + semver: 7.8.4 + tsutils: 3.21.0(typescript@5.9.3) + optionalDependencies: + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/typescript-estree@8.61.1(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.61.1(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.61.1(typescript@5.9.3) + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/visitor-keys': 8.61.1 + debug: 4.4.3 + minimatch: 9.0.9 + semver: 7.8.4 + tinyglobby: 0.2.17 + ts-api-utils: 2.5.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@types/json-schema': 7.0.15 + '@types/semver': 7.7.1 + '@typescript-eslint/scope-manager': 5.62.0 + '@typescript-eslint/types': 5.62.0 + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + eslint-scope: 5.1.1 + semver: 7.8.4 + transitivePeerDependencies: + - supports-color + - typescript + + '@typescript-eslint/utils@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@typescript-eslint/scope-manager': 8.61.1 + '@typescript-eslint/types': 8.61.1 + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@5.62.0': + dependencies: + '@typescript-eslint/types': 5.62.0 + eslint-visitor-keys: 3.4.3 + + '@typescript-eslint/visitor-keys@8.61.1': + dependencies: + '@typescript-eslint/types': 8.61.1 + eslint-visitor-keys: 5.0.1 + + '@ungap/structured-clone@1.3.1': {} + + '@unrs/resolver-binding-android-arm-eabi@1.12.2': + optional: true + + '@unrs/resolver-binding-android-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-darwin-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-freebsd-x64@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-gnueabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm-musleabihf@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-arm64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-loong64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-ppc64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-riscv64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-s390x-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-gnu@1.12.2': + optional: true + + '@unrs/resolver-binding-linux-x64-musl@1.12.2': + optional: true + + '@unrs/resolver-binding-openharmony-arm64@1.12.2': + optional: true + + '@unrs/resolver-binding-wasm32-wasi@1.12.2': + dependencies: + '@emnapi/core': 1.10.0 + '@emnapi/runtime': 1.10.0 + '@napi-rs/wasm-runtime': 1.1.5(@emnapi/core@1.10.0)(@emnapi/runtime@1.10.0) + optional: true + + '@unrs/resolver-binding-win32-arm64-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-ia32-msvc@1.12.2': + optional: true + + '@unrs/resolver-binding-win32-x64-msvc@1.12.2': + optional: true + + '@vercel/og@0.11.1': + dependencies: + '@resvg/resvg-wasm': 2.4.0 + satori: 0.25.0 + optionalDependencies: + sharp: 0.34.5 + + '@vitejs/plugin-react@6.0.2(vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0))': + dependencies: + '@rolldown/pluginutils': 1.0.1 + vite: 8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0) + + '@wallet-standard/app@1.1.1': + dependencies: + '@wallet-standard/base': 1.1.1 + + '@wallet-standard/base@1.1.1': {} + + '@wallet-standard/core@1.1.2': + dependencies: + '@wallet-standard/app': 1.1.1 + '@wallet-standard/base': 1.1.1 + '@wallet-standard/errors': 0.1.2 + '@wallet-standard/features': 1.1.1 + '@wallet-standard/wallet': 1.1.1 + + '@wallet-standard/errors@0.1.2': + dependencies: + chalk: 5.6.2 + commander: 13.1.0 + + '@wallet-standard/features@1.1.1': + dependencies: + '@wallet-standard/base': 1.1.1 + + '@wallet-standard/wallet@1.1.1': + dependencies: + '@wallet-standard/base': 1.1.1 + + '@wallet-ui/core@2.2.2(@solana/kit@5.5.1(typescript@5.9.3))': + dependencies: + '@nanostores/persistent': 1.1.0(nanostores@1.0.1) + '@solana/kit': 5.5.1(typescript@5.9.3) + nanostores: 1.0.1 + + a-sync-waterfall@1.0.1: {} + + abort-controller@3.0.0: + dependencies: + event-target-shim: 5.0.1 + + accepts@2.0.0: + dependencies: + mime-types: 3.0.2 + negotiator: 1.0.0 + + acorn-jsx@5.3.2(acorn@7.4.1): + dependencies: + acorn: 7.4.1 + + acorn-jsx@5.3.2(acorn@8.17.0): + dependencies: + acorn: 8.17.0 + + acorn@7.4.1: {} + + acorn@8.17.0: {} + + agent-base@7.1.4: {} + + ajv@6.15.0: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + anser@1.4.10: {} + + ansi-escapes@4.3.2: + dependencies: + type-fest: 0.21.3 + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@5.2.0: {} + + ansi-styles@6.2.3: {} + + any-promise@1.3.0: {} + + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 4.0.4 + + anynum@1.0.1: {} + + argparse@1.0.10: + dependencies: + sprintf-js: 1.0.3 + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + array-union@2.1.0: {} + + asap@2.0.6: {} + + autoprefixer@10.5.0(postcss@8.5.15): + dependencies: + browserslist: 4.28.2 + caniuse-lite: 1.0.30001799 + fraction.js: 5.3.4 + picocolors: 1.1.1 + postcss: 8.5.15 + postcss-value-parser: 4.2.0 + + babel-jest@30.4.1(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@jest/transform': 30.4.1 + '@types/babel__core': 7.20.5 + babel-plugin-istanbul: 7.0.1 + babel-preset-jest: 30.4.0(@babel/core@7.29.7) + chalk: 4.1.2 + graceful-fs: 4.2.11 + slash: 3.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-istanbul@7.0.1: + dependencies: + '@babel/helper-plugin-utils': 7.29.7 + '@istanbuljs/load-nyc-config': 1.1.0 + '@istanbuljs/schema': 0.1.6 + istanbul-lib-instrument: 6.0.3 + test-exclude: 6.0.0 + transitivePeerDependencies: + - supports-color + + babel-plugin-jest-hoist@30.4.0: + dependencies: + '@types/babel__core': 7.20.5 + + babel-plugin-syntax-hermes-parser@0.36.0: + dependencies: + hermes-parser: 0.36.0 + + babel-preset-current-node-syntax@1.2.0(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + '@babel/plugin-syntax-async-generators': 7.8.4(@babel/core@7.29.7) + '@babel/plugin-syntax-bigint': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-class-properties': 7.12.13(@babel/core@7.29.7) + '@babel/plugin-syntax-class-static-block': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-import-attributes': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-json-strings': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-logical-assignment-operators': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-nullish-coalescing-operator': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-numeric-separator': 7.10.4(@babel/core@7.29.7) + '@babel/plugin-syntax-object-rest-spread': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-catch-binding': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-optional-chaining': 7.8.3(@babel/core@7.29.7) + '@babel/plugin-syntax-private-property-in-object': 7.14.5(@babel/core@7.29.7) + '@babel/plugin-syntax-top-level-await': 7.14.5(@babel/core@7.29.7) + + babel-preset-jest@30.4.0(@babel/core@7.29.7): + dependencies: + '@babel/core': 7.29.7 + babel-plugin-jest-hoist: 30.4.0 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + + balanced-match@1.0.2: {} + + base-x@4.0.1: {} + + base64-js@0.0.8: {} + + base64-js@1.5.1: {} + + baseline-browser-mapping@2.10.38: {} + + bowser@2.14.1: {} + + brace-expansion@2.1.1: + dependencies: + balanced-match: 1.0.2 + + braces@3.0.3: + dependencies: + fill-range: 7.1.1 + + browserslist@4.28.2: + dependencies: + baseline-browser-mapping: 2.10.38 + caniuse-lite: 1.0.30001799 + electron-to-chromium: 1.5.375 + node-releases: 2.0.48 + update-browserslist-db: 1.2.3(browserslist@4.28.2) + + bs58@5.0.0: + dependencies: + base-x: 4.0.1 + + bser@2.1.1: + dependencies: + node-int64: 0.4.0 + + buffer-from@1.1.2: {} + + bundle-require@5.1.0(esbuild@0.27.7): + dependencies: + esbuild: 0.27.7 + load-tsconfig: 0.2.5 + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + call-bind@1.0.9: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + get-intrinsic: 1.3.0 + set-function-length: 1.2.2 + + call-bound@1.0.4: + dependencies: + call-bind-apply-helpers: 1.0.2 + get-intrinsic: 1.3.0 + + callsites@3.1.0: {} + + camelcase@5.3.1: {} + + camelcase@6.3.0: {} + + camelize@1.0.1: {} + + caniuse-lite@1.0.30001799: {} + + ccount@2.0.1: {} + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + chalk@5.6.2: {} + + char-regex@1.0.2: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + chokidar@4.0.3: + dependencies: + readdirp: 4.1.2 + + chrome-launcher@0.15.2: + dependencies: + '@types/node': 25.9.3 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + transitivePeerDependencies: + - supports-color + + chromium-edge-launcher@0.3.0: + dependencies: + '@types/node': 25.9.3 + escape-string-regexp: 4.0.0 + is-wsl: 2.2.0 + lighthouse-logger: 1.4.2 + mkdirp: 1.0.4 + transitivePeerDependencies: + - supports-color + + ci-info@2.0.0: {} + + ci-info@3.9.0: {} + + ci-info@4.4.0: {} + + cjs-module-lexer@2.2.0: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + cliui@6.0.0: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 6.2.0 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clsx@2.1.1: {} + + co@4.6.0: {} + + codama@1.8.0: + dependencies: + '@codama/cli': 1.5.3 + '@codama/errors': 1.8.0 + '@codama/nodes': 1.8.0 + '@codama/validators': 1.8.0 + '@codama/visitors': 1.8.0 + + collect-v8-coverage@1.0.3: {} + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + comma-separated-tokens@2.0.3: {} + + commander@12.1.0: {} + + commander@13.1.0: {} + + commander@14.0.2: {} + + commander@14.0.3: {} + + commander@15.0.0: {} + + commander@2.20.3: {} + + commander@4.1.1: {} + + commander@5.1.0: {} + + confbox@0.1.8: {} + + connect@3.7.0: + dependencies: + debug: 2.6.9 + finalhandler: 1.1.2 + parseurl: 1.3.3 + utils-merge: 1.0.1 + transitivePeerDependencies: + - supports-color + + consola@3.4.2: {} + + convert-source-map@2.0.0: {} + + cookie@1.1.1: {} + + country-flag-icons@1.6.17: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + css-background-parser@0.1.0: {} + + css-box-shadow@1.0.0-3: {} + + css-color-keywords@1.0.0: {} + + css-gradient-parser@0.0.17: {} + + css-to-react-native@3.2.0: + dependencies: + camelize: 1.0.1 + css-color-keywords: 1.0.0 + postcss-value-parser: 4.2.0 + + csstype@3.2.3: {} + + debug@2.6.9: + dependencies: + ms: 2.0.0 + + debug@4.4.3: + dependencies: + ms: 2.1.3 + + decamelize@1.2.0: {} + + dedent@1.7.2: {} + + deep-is@0.1.4: {} + + deepmerge@4.3.1: {} + + define-data-property@1.1.4: + dependencies: + es-define-property: 1.0.1 + es-errors: 1.3.0 + gopd: 1.2.0 + + depd@2.0.0: {} + + dequal@2.0.3: {} + + destroy@1.2.0: {} + + detect-libc@2.1.2: {} + + detect-newline@3.1.0: {} + + detect-node-es@1.1.0: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + dijkstrajs@1.0.3: {} + + dir-glob@3.0.1: + dependencies: + path-type: 4.0.0 + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + ee-first@1.1.1: {} + + electron-to-chromium@1.5.375: {} + + emittery@0.13.1: {} + + emoji-regex-xs@2.0.1: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + encodeurl@1.0.2: {} + + encodeurl@2.0.0: {} + + enhanced-resolve@5.21.6: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.3 + + error-ex@1.3.4: + dependencies: + is-arrayish: 0.2.1 + + error-stack-parser@2.1.4: + dependencies: + stackframe: 1.3.4 + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + esbuild@0.27.7: + optionalDependencies: + '@esbuild/aix-ppc64': 0.27.7 + '@esbuild/android-arm': 0.27.7 + '@esbuild/android-arm64': 0.27.7 + '@esbuild/android-x64': 0.27.7 + '@esbuild/darwin-arm64': 0.27.7 + '@esbuild/darwin-x64': 0.27.7 + '@esbuild/freebsd-arm64': 0.27.7 + '@esbuild/freebsd-x64': 0.27.7 + '@esbuild/linux-arm': 0.27.7 + '@esbuild/linux-arm64': 0.27.7 + '@esbuild/linux-ia32': 0.27.7 + '@esbuild/linux-loong64': 0.27.7 + '@esbuild/linux-mips64el': 0.27.7 + '@esbuild/linux-ppc64': 0.27.7 + '@esbuild/linux-riscv64': 0.27.7 + '@esbuild/linux-s390x': 0.27.7 + '@esbuild/linux-x64': 0.27.7 + '@esbuild/netbsd-arm64': 0.27.7 + '@esbuild/netbsd-x64': 0.27.7 + '@esbuild/openbsd-arm64': 0.27.7 + '@esbuild/openbsd-x64': 0.27.7 + '@esbuild/openharmony-arm64': 0.27.7 + '@esbuild/sunos-x64': 0.27.7 + '@esbuild/win32-arm64': 0.27.7 + '@esbuild/win32-ia32': 0.27.7 + '@esbuild/win32-x64': 0.27.7 + + esbuild@0.28.1: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 + + escalade@3.2.0: {} + + escape-html@1.0.3: {} + + escape-string-regexp@2.0.0: {} + + escape-string-regexp@4.0.0: {} + + eslint-plugin-jest@29.15.2(@typescript-eslint/eslint-plugin@8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(jest@30.4.2(@types/node@25.9.3))(typescript@5.9.3): + dependencies: + '@typescript-eslint/utils': 8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + optionalDependencies: + '@typescript-eslint/eslint-plugin': 8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + jest: 30.4.2(@types/node@25.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + eslint-plugin-react-hooks@7.1.1(eslint@9.39.4(jiti@2.7.0)): + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.7 + eslint: 9.39.4(jiti@2.7.0) + hermes-parser: 0.25.1 + zod: 4.4.3 + zod-validation-error: 4.0.2(zod@4.4.3) + transitivePeerDependencies: + - supports-color + + eslint-plugin-simple-import-sort@12.1.1(eslint@9.39.4(jiti@2.7.0)): + dependencies: + eslint: 9.39.4(jiti@2.7.0) + + eslint-plugin-sort-keys-fix@1.1.2: + dependencies: + espree: 6.2.1 + esutils: 2.0.3 + natural-compare: 1.4.0 + requireindex: 1.2.0 + + eslint-plugin-typescript-sort-keys@3.3.0(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + dependencies: + '@typescript-eslint/experimental-utils': 5.62.0(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + json-schema: 0.4.0 + natural-compare-lite: 1.4.0 + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + eslint-scope@5.1.1: + dependencies: + esrecurse: 4.3.0 + estraverse: 4.3.0 + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@1.3.0: {} + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint-visitor-keys@5.0.1: {} + + eslint@9.39.4(jiti@2.7.0): + dependencies: + '@eslint-community/eslint-utils': 4.9.1(eslint@9.39.4(jiti@2.7.0)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.2 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.5 + '@eslint/js': 9.39.4 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.8 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.9 + ajv: 6.15.0 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3 + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.7.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 9.0.9 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.7.0 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.17.0 + acorn-jsx: 5.3.2(acorn@8.17.0) + eslint-visitor-keys: 4.2.1 + + espree@6.2.1: + dependencies: + acorn: 7.4.1 + acorn-jsx: 5.3.2(acorn@7.4.1) + eslint-visitor-keys: 1.3.0 + + esprima@4.0.1: {} + + esquery@1.7.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@4.3.0: {} + + estraverse@5.3.0: {} + + esutils@2.0.3: {} + + etag@1.8.1: {} + + event-target-shim@5.0.1: {} + + execa@5.1.1: + dependencies: + cross-spawn: 7.0.6 + get-stream: 6.0.1 + human-signals: 2.1.0 + is-stream: 2.0.1 + merge-stream: 2.0.0 + npm-run-path: 4.0.1 + onetime: 5.1.2 + signal-exit: 3.0.7 + strip-final-newline: 2.0.0 + + exit-x@0.2.2: {} + + expect@30.4.1: + dependencies: + '@jest/expect-utils': 30.4.1 + '@jest/get-type': 30.1.0 + jest-matcher-utils: 30.4.1 + jest-message-util: 30.4.1 + jest-mock: 30.4.1 + jest-util: 30.4.1 + + exponential-backoff@3.1.3: {} + + fast-deep-equal@3.1.3: {} + + fast-glob@3.3.3: + dependencies: + '@nodelib/fs.stat': 2.0.5 + '@nodelib/fs.walk': 1.2.8 + glob-parent: 5.1.2 + merge2: 1.4.1 + micromatch: 4.0.8 + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-xml-builder@1.2.0: + dependencies: + path-expression-matcher: 1.5.0 + xml-naming: 0.1.0 + + fast-xml-parser@5.7.3: + dependencies: + '@nodable/entities': 2.2.0 + fast-xml-builder: 1.2.0 + path-expression-matcher: 1.5.0 + strnum: 2.4.1 + + fastq@1.20.1: + dependencies: + reusify: 1.1.0 + + fb-dotslash@0.5.8: {} + + fb-watchman@2.0.2: + dependencies: + bser: 2.1.1 + + fdir@6.5.0(picomatch@4.0.4): + optionalDependencies: + picomatch: 4.0.4 + + fflate@0.7.4: {} + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + fill-range@7.1.1: + dependencies: + to-regex-range: 5.0.1 + + finalhandler@1.1.2: + dependencies: + debug: 2.6.9 + encodeurl: 1.0.2 + escape-html: 1.0.3 + on-finished: 2.3.0 + parseurl: 1.3.3 + statuses: 1.5.0 + unpipe: 1.0.0 + transitivePeerDependencies: + - supports-color + + find-up@4.1.0: + dependencies: + locate-path: 5.0.0 + path-exists: 4.0.0 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + fix-dts-default-cjs-exports@1.0.1: + dependencies: + magic-string: 0.30.21 + mlly: 1.8.2 + rollup: 4.60.2 + + flat-cache@4.0.1: + dependencies: + flatted: 3.4.2 + keyv: 4.5.4 + + flatted@3.4.2: {} + + flow-enums-runtime@0.0.6: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + fraction.js@5.3.4: {} + + framer-motion@12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + motion-dom: 12.40.0 + motion-utils: 12.39.0 + tslib: 2.8.1 + optionalDependencies: + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + fresh@0.5.2: {} + + fs.realpath@1.0.0: {} + + fsevents@2.3.2: + optional: true + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-nonce@1.0.1: {} + + get-package-type@0.1.0: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + + get-stream@6.0.1: {} + + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.9 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + glob@7.2.3: + dependencies: + fs.realpath: 1.0.0 + inflight: 1.0.6 + inherits: 2.0.4 + minimatch: 9.0.9 + once: 1.4.0 + path-is-absolute: 1.0.1 + + globals@14.0.0: {} + + globals@16.5.0: {} + + globby@11.1.0: + dependencies: + array-union: 2.1.0 + dir-glob: 3.0.1 + fast-glob: 3.3.3 + ignore: 5.3.2 + merge2: 1.4.1 + slash: 3.0.0 + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + has-flag@4.0.0: {} + + has-property-descriptors@1.0.2: + dependencies: + es-define-property: 1.0.1 + + has-symbols@1.1.0: {} + + hasown@2.0.4: + dependencies: + function-bind: 1.1.2 + + hast-util-to-html@9.0.5: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + ccount: 2.0.1 + comma-separated-tokens: 2.0.3 + hast-util-whitespace: 3.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + property-information: 7.2.0 + space-separated-tokens: 2.0.2 + stringify-entities: 4.0.4 + zwitch: 2.0.4 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hermes-compiler@250829098.0.14: {} + + hermes-estree@0.25.1: {} + + hermes-estree@0.35.0: {} + + hermes-estree@0.36.0: {} + + hermes-parser@0.25.1: + dependencies: + hermes-estree: 0.25.1 + + hermes-parser@0.35.0: + dependencies: + hermes-estree: 0.35.0 + + hermes-parser@0.36.0: + dependencies: + hermes-estree: 0.36.0 + + hex-rgb@4.3.0: {} + + html-escaper@2.0.2: {} + + html-void-elements@3.0.0: {} + + http-errors@2.0.1: + dependencies: + depd: 2.0.0 + inherits: 2.0.4 + setprototypeof: 1.2.0 + statuses: 2.0.2 + toidentifier: 1.0.1 + + https-proxy-agent@7.0.6: + dependencies: + agent-base: 7.1.4 + debug: 4.4.3 + transitivePeerDependencies: + - supports-color + + human-signals@2.1.0: {} + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + image-size@1.2.1: + dependencies: + queue: 6.0.2 + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + import-local@3.2.0: + dependencies: + pkg-dir: 4.2.0 + resolve-cwd: 3.0.0 + + imurmurhash@0.1.4: {} + + inflight@1.0.6: + dependencies: + once: 1.4.0 + wrappy: 1.0.2 + + inherits@2.0.4: {} + + invariant@2.2.4: + dependencies: + loose-envify: 1.4.0 + + is-arrayish@0.2.1: {} + + is-docker@2.2.1: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-generator-fn@2.1.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + is-stream@2.0.1: {} + + is-wsl@2.2.0: + dependencies: + is-docker: 2.2.1 + + isarray@2.0.5: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-instrument@6.0.3: + dependencies: + '@babel/core': 7.29.7 + '@babel/parser': 7.29.7 + '@istanbuljs/schema': 0.1.6 + istanbul-lib-coverage: 3.2.2 + semver: 7.8.4 + transitivePeerDependencies: + - supports-color + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3 + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jest-changed-files@30.4.1: + dependencies: + execa: 5.1.1 + jest-util: 30.4.1 + p-limit: 3.1.0 + + jest-circus@30.4.2: + dependencies: + '@jest/environment': 30.4.1 + '@jest/expect': 30.4.1 + '@jest/test-result': 30.4.1 + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + chalk: 4.1.2 + co: 4.6.0 + dedent: 1.7.2 + is-generator-fn: 2.1.0 + jest-each: 30.4.1 + jest-matcher-utils: 30.4.1 + jest-message-util: 30.4.1 + jest-runtime: 30.4.2 + jest-snapshot: 30.4.1 + jest-util: 30.4.1 + p-limit: 3.1.0 + pretty-format: 30.4.1 + pure-rand: 7.0.1 + slash: 3.0.0 + stack-utils: 2.0.6 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-cli@30.4.2(@types/node@25.9.3): + dependencies: + '@jest/core': 30.4.2 + '@jest/test-result': 30.4.1 + '@jest/types': 30.4.1 + chalk: 4.1.2 + exit-x: 0.2.2 + import-local: 3.2.0 + jest-config: 30.4.2(@types/node@25.9.3) + jest-util: 30.4.1 + jest-validate: 30.4.1 + yargs: 17.7.2 + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + jest-config@30.4.2(@types/node@25.9.3): + dependencies: + '@babel/core': 7.29.7 + '@jest/get-type': 30.1.0 + '@jest/pattern': 30.4.0 + '@jest/test-sequencer': 30.4.1 + '@jest/types': 30.4.1 + babel-jest: 30.4.1(@babel/core@7.29.7) + chalk: 4.1.2 + ci-info: 4.4.0 + deepmerge: 4.3.1 + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-circus: 30.4.2 + jest-docblock: 30.4.0 + jest-environment-node: 30.4.1 + jest-regex-util: 30.4.0 + jest-resolve: 30.4.1 + jest-runner: 30.4.2 + jest-util: 30.4.1 + jest-validate: 30.4.1 + parse-json: 5.2.0 + pretty-format: 30.4.1 + slash: 3.0.0 + strip-json-comments: 3.1.1 + optionalDependencies: + '@types/node': 25.9.3 + transitivePeerDependencies: + - babel-plugin-macros + - supports-color + + jest-diff@30.4.1: + dependencies: + '@jest/diff-sequences': 30.4.0 + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + pretty-format: 30.4.1 + + jest-docblock@30.4.0: + dependencies: + detect-newline: 3.1.0 + + jest-each@30.4.1: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.4.1 + chalk: 4.1.2 + jest-util: 30.4.1 + pretty-format: 30.4.1 + + jest-environment-node@30.4.1: + dependencies: + '@jest/environment': 30.4.1 + '@jest/fake-timers': 30.4.1 + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + jest-mock: 30.4.1 + jest-util: 30.4.1 + jest-validate: 30.4.1 + + jest-get-type@29.6.3: {} + + jest-haste-map@30.4.1: + dependencies: + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + anymatch: 3.1.3 + fb-watchman: 2.0.2 + graceful-fs: 4.2.11 + jest-regex-util: 30.4.0 + jest-util: 30.4.1 + jest-worker: 30.4.1 + picomatch: 4.0.4 + walker: 1.0.8 + optionalDependencies: + fsevents: 2.3.3 + + jest-leak-detector@30.4.1: + dependencies: + '@jest/get-type': 30.1.0 + pretty-format: 30.4.1 + + jest-matcher-utils@30.4.1: + dependencies: + '@jest/get-type': 30.1.0 + chalk: 4.1.2 + jest-diff: 30.4.1 + pretty-format: 30.4.1 + + jest-message-util@30.4.1: + dependencies: + '@babel/code-frame': 7.29.7 + '@jest/types': 30.4.1 + '@types/stack-utils': 2.0.3 + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-util: 30.4.1 + picomatch: 4.0.4 + pretty-format: 30.4.1 + slash: 3.0.0 + stack-utils: 2.0.6 + + jest-mock@30.4.1: + dependencies: + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + jest-util: 30.4.1 + + jest-pnp-resolver@1.2.3(jest-resolve@30.4.1): + optionalDependencies: + jest-resolve: 30.4.1 + + jest-regex-util@30.4.0: {} + + jest-resolve-dependencies@30.4.2: + dependencies: + jest-regex-util: 30.4.0 + jest-snapshot: 30.4.1 + transitivePeerDependencies: + - supports-color + + jest-resolve@30.4.1: + dependencies: + chalk: 4.1.2 + graceful-fs: 4.2.11 + jest-haste-map: 30.4.1 + jest-pnp-resolver: 1.2.3(jest-resolve@30.4.1) + jest-util: 30.4.1 + jest-validate: 30.4.1 + slash: 3.0.0 + unrs-resolver: 1.12.2 + + jest-runner@30.4.2: + dependencies: + '@jest/console': 30.4.1 + '@jest/environment': 30.4.1 + '@jest/test-result': 30.4.1 + '@jest/transform': 30.4.1 + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + chalk: 4.1.2 + emittery: 0.13.1 + exit-x: 0.2.2 + graceful-fs: 4.2.11 + jest-docblock: 30.4.0 + jest-environment-node: 30.4.1 + jest-haste-map: 30.4.1 + jest-leak-detector: 30.4.1 + jest-message-util: 30.4.1 + jest-resolve: 30.4.1 + jest-runtime: 30.4.2 + jest-util: 30.4.1 + jest-watcher: 30.4.1 + jest-worker: 30.4.1 + p-limit: 3.1.0 + source-map-support: 0.5.13 + transitivePeerDependencies: + - supports-color + + jest-runtime@30.4.2: + dependencies: + '@jest/environment': 30.4.1 + '@jest/fake-timers': 30.4.1 + '@jest/globals': 30.4.1 + '@jest/source-map': 30.0.1 + '@jest/test-result': 30.4.1 + '@jest/transform': 30.4.1 + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + chalk: 4.1.2 + cjs-module-lexer: 2.2.0 + collect-v8-coverage: 1.0.3 + glob: 10.5.0 + graceful-fs: 4.2.11 + jest-haste-map: 30.4.1 + jest-message-util: 30.4.1 + jest-mock: 30.4.1 + jest-regex-util: 30.4.0 + jest-resolve: 30.4.1 + jest-snapshot: 30.4.1 + jest-util: 30.4.1 + slash: 3.0.0 + strip-bom: 4.0.0 + transitivePeerDependencies: + - supports-color + + jest-snapshot@30.4.1: + dependencies: + '@babel/core': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/plugin-syntax-jsx': 7.29.7(@babel/core@7.29.7) + '@babel/plugin-syntax-typescript': 7.29.7(@babel/core@7.29.7) + '@babel/types': 7.29.7 + '@jest/expect-utils': 30.4.1 + '@jest/get-type': 30.1.0 + '@jest/snapshot-utils': 30.4.1 + '@jest/transform': 30.4.1 + '@jest/types': 30.4.1 + babel-preset-current-node-syntax: 1.2.0(@babel/core@7.29.7) + chalk: 4.1.2 + expect: 30.4.1 + graceful-fs: 4.2.11 + jest-diff: 30.4.1 + jest-matcher-utils: 30.4.1 + jest-message-util: 30.4.1 + jest-util: 30.4.1 + pretty-format: 30.4.1 + semver: 7.8.4 + synckit: 0.11.13 + transitivePeerDependencies: + - supports-color + + jest-util@29.7.0: + dependencies: + '@jest/types': 29.6.3 + '@types/node': 25.9.3 + chalk: 4.1.2 + ci-info: 3.9.0 + graceful-fs: 4.2.11 + picomatch: 4.0.4 + + jest-util@30.4.1: + dependencies: + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + chalk: 4.1.2 + ci-info: 4.4.0 + graceful-fs: 4.2.11 + picomatch: 4.0.4 + + jest-validate@29.7.0: + dependencies: + '@jest/types': 29.6.3 + camelcase: 6.3.0 + chalk: 4.1.2 + jest-get-type: 29.6.3 + leven: 3.1.0 + pretty-format: 29.7.0 + + jest-validate@30.4.1: + dependencies: + '@jest/get-type': 30.1.0 + '@jest/types': 30.4.1 + camelcase: 6.3.0 + chalk: 4.1.2 + leven: 3.1.0 + pretty-format: 30.4.1 + + jest-watcher@30.4.1: + dependencies: + '@jest/test-result': 30.4.1 + '@jest/types': 30.4.1 + '@types/node': 25.9.3 + ansi-escapes: 4.3.2 + chalk: 4.1.2 + emittery: 0.13.1 + jest-util: 30.4.1 + string-length: 4.0.2 + + jest-worker@29.7.0: + dependencies: + '@types/node': 25.9.3 + jest-util: 29.7.0 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest-worker@30.4.1: + dependencies: + '@types/node': 25.9.3 + '@ungap/structured-clone': 1.3.1 + jest-util: 30.4.1 + merge-stream: 2.0.0 + supports-color: 8.1.1 + + jest@30.4.2(@types/node@25.9.3): + dependencies: + '@jest/core': 30.4.2 + '@jest/types': 30.4.1 + import-local: 3.2.0 + jest-cli: 30.4.2(@types/node@25.9.3) + transitivePeerDependencies: + - '@types/node' + - babel-plugin-macros + - esbuild-register + - supports-color + - ts-node + + jiti@2.7.0: {} + + jotai@2.20.1(@babel/core@7.29.7)(@babel/template@7.29.7)(@types/react@19.2.17)(react@19.2.7): + optionalDependencies: + '@babel/core': 7.29.7 + '@babel/template': 7.29.7 + '@types/react': 19.2.17 + react: 19.2.7 + + joycon@3.1.1: {} + + js-base64@3.7.8: {} + + js-tokens@4.0.0: {} + + js-yaml@3.14.2: + dependencies: + argparse: 1.0.10 + esprima: 4.0.1 + + js-yaml@4.2.0: + dependencies: + argparse: 2.0.1 + + jsc-safe-url@0.2.4: {} + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-parse-even-better-errors@2.3.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema@0.4.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json-stable-stringify@1.3.0: + dependencies: + call-bind: 1.0.9 + call-bound: 1.0.4 + isarray: 2.0.5 + jsonify: 0.0.1 + object-keys: 1.1.1 + + json5@2.2.3: {} + + jsonify@0.0.1: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + kleur@3.0.3: {} + + leven@3.1.0: {} + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lighthouse-logger@1.4.2: + dependencies: + debug: 2.6.9 + marky: 1.3.0 + transitivePeerDependencies: + - supports-color + + lightningcss-android-arm64@1.32.0: + optional: true + + lightningcss-darwin-arm64@1.32.0: + optional: true + + lightningcss-darwin-x64@1.32.0: + optional: true + + lightningcss-freebsd-x64@1.32.0: + optional: true + + lightningcss-linux-arm-gnueabihf@1.32.0: + optional: true + + lightningcss-linux-arm64-gnu@1.32.0: + optional: true + + lightningcss-linux-arm64-musl@1.32.0: + optional: true + + lightningcss-linux-x64-gnu@1.32.0: + optional: true + + lightningcss-linux-x64-musl@1.32.0: + optional: true + + lightningcss-win32-arm64-msvc@1.32.0: + optional: true + + lightningcss-win32-x64-msvc@1.32.0: + optional: true + + lightningcss@1.32.0: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.32.0 + lightningcss-darwin-arm64: 1.32.0 + lightningcss-darwin-x64: 1.32.0 + lightningcss-freebsd-x64: 1.32.0 + lightningcss-linux-arm-gnueabihf: 1.32.0 + lightningcss-linux-arm64-gnu: 1.32.0 + lightningcss-linux-arm64-musl: 1.32.0 + lightningcss-linux-x64-gnu: 1.32.0 + lightningcss-linux-x64-musl: 1.32.0 + lightningcss-win32-arm64-msvc: 1.32.0 + lightningcss-win32-x64-msvc: 1.32.0 + + lilconfig@3.1.3: {} + + linebreak@1.1.0: + dependencies: + base64-js: 0.0.8 + unicode-trie: 2.0.0 + + lines-and-columns@1.2.4: {} + + load-tsconfig@0.2.5: {} + + locate-path@5.0.0: + dependencies: + p-locate: 4.1.0 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + lodash.throttle@4.1.1: {} + + loose-envify@1.4.0: + dependencies: + js-tokens: 4.0.0 + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.575.0(react@19.2.7): + dependencies: + react: 19.2.7 + + lucide-react@1.21.0(react@19.2.7): + dependencies: + react: 19.2.7 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + make-dir@4.0.0: + dependencies: + semver: 7.8.4 + + makeerror@1.0.12: + dependencies: + tmpl: 1.0.5 + + marky@1.3.0: {} + + math-intrinsics@1.1.0: {} + + mdast-util-to-hast@13.2.1: + dependencies: + '@types/hast': 3.0.4 + '@types/mdast': 4.0.4 + '@ungap/structured-clone': 1.3.1 + devlop: 1.1.0 + micromark-util-sanitize-uri: 2.0.1 + trim-lines: 3.0.1 + unist-util-position: 5.0.0 + unist-util-visit: 5.1.0 + vfile: 6.0.3 + + memoize-one@5.2.1: {} + + merge-stream@2.0.0: {} + + merge2@1.4.1: {} + + metro-babel-transformer@0.84.4: + dependencies: + '@babel/core': 7.29.7 + flow-enums-runtime: 0.0.6 + hermes-parser: 0.35.0 + metro-cache-key: 0.84.4 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-cache-key@0.84.4: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-cache@0.84.4: + dependencies: + exponential-backoff: 3.1.3 + flow-enums-runtime: 0.0.6 + https-proxy-agent: 7.0.6 + metro-core: 0.84.4 + transitivePeerDependencies: + - supports-color + + metro-config@0.84.4: + dependencies: + connect: 3.7.0 + flow-enums-runtime: 0.0.6 + jest-validate: 29.7.0 + metro: 0.84.4 + metro-cache: 0.84.4 + metro-core: 0.84.4 + metro-runtime: 0.84.4 + yaml: 2.9.0 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro-core@0.84.4: + dependencies: + flow-enums-runtime: 0.0.6 + lodash.throttle: 4.1.1 + metro-resolver: 0.84.4 + + metro-file-map@0.84.4: + dependencies: + debug: 4.4.3 + fb-watchman: 2.0.2 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + invariant: 2.2.4 + jest-worker: 29.7.0 + micromatch: 4.0.8 + nullthrows: 1.1.1 + walker: 1.0.8 + transitivePeerDependencies: + - supports-color + + metro-minify-terser@0.84.4: + dependencies: + flow-enums-runtime: 0.0.6 + terser: 5.48.0 + + metro-resolver@0.84.4: + dependencies: + flow-enums-runtime: 0.0.6 + + metro-runtime@0.84.4: + dependencies: + '@babel/runtime': 7.29.7 + flow-enums-runtime: 0.0.6 + + metro-source-map@0.84.4: + dependencies: + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-symbolicate: 0.84.4 + nullthrows: 1.1.1 + ob1: 0.84.4 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-symbolicate@0.84.4: + dependencies: + flow-enums-runtime: 0.0.6 + invariant: 2.2.4 + metro-source-map: 0.84.4 + nullthrows: 1.1.1 + source-map: 0.5.7 + vlq: 1.0.1 + transitivePeerDependencies: + - supports-color + + metro-transform-plugins@0.84.4: + dependencies: + '@babel/core': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + flow-enums-runtime: 0.0.6 + nullthrows: 1.1.1 + transitivePeerDependencies: + - supports-color + + metro-transform-worker@0.84.4: + dependencies: + '@babel/core': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/types': 7.29.7 + flow-enums-runtime: 0.0.6 + metro: 0.84.4 + metro-babel-transformer: 0.84.4 + metro-cache: 0.84.4 + metro-cache-key: 0.84.4 + metro-minify-terser: 0.84.4 + metro-source-map: 0.84.4 + metro-transform-plugins: 0.84.4 + nullthrows: 1.1.1 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + metro@0.84.4: + dependencies: + '@babel/code-frame': 7.29.7 + '@babel/core': 7.29.7 + '@babel/generator': 7.29.7 + '@babel/parser': 7.29.7 + '@babel/template': 7.29.7 + '@babel/traverse': 7.29.7 + '@babel/types': 7.29.7 + accepts: 2.0.0 + ci-info: 2.0.0 + connect: 3.7.0 + debug: 4.4.3 + error-stack-parser: 2.1.4 + flow-enums-runtime: 0.0.6 + graceful-fs: 4.2.11 + hermes-parser: 0.35.0 + image-size: 1.2.1 + invariant: 2.2.4 + jest-worker: 29.7.0 + jsc-safe-url: 0.2.4 + lodash.throttle: 4.1.1 + metro-babel-transformer: 0.84.4 + metro-cache: 0.84.4 + metro-cache-key: 0.84.4 + metro-config: 0.84.4 + metro-core: 0.84.4 + metro-file-map: 0.84.4 + metro-resolver: 0.84.4 + metro-runtime: 0.84.4 + metro-source-map: 0.84.4 + metro-symbolicate: 0.84.4 + metro-transform-plugins: 0.84.4 + metro-transform-worker: 0.84.4 + mime-types: 3.0.2 + nullthrows: 1.1.1 + serialize-error: 2.1.0 + source-map: 0.5.7 + throat: 5.0.0 + ws: 7.5.11 + yargs: 17.7.2 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + + micromark-util-character@2.1.1: + dependencies: + micromark-util-symbol: 2.0.1 + micromark-util-types: 2.0.2 + + micromark-util-encode@2.0.1: {} + + micromark-util-sanitize-uri@2.0.1: + dependencies: + micromark-util-character: 2.1.1 + micromark-util-encode: 2.0.1 + micromark-util-symbol: 2.0.1 + + micromark-util-symbol@2.0.1: {} + + micromark-util-types@2.0.2: {} + + micromatch@4.0.8: + dependencies: + braces: 3.0.3 + picomatch: 4.0.4 + + mime-db@1.54.0: {} + + mime-types@3.0.2: + dependencies: + mime-db: 1.54.0 + + mime@1.6.0: {} + + mimic-fn@2.1.0: {} + + minimatch@9.0.9: + dependencies: + brace-expansion: 2.1.1 + + minipass@7.1.3: {} + + mkdirp@1.0.4: {} + + mlly@1.8.2: + dependencies: + acorn: 8.17.0 + pathe: 2.0.3 + pkg-types: 1.3.1 + ufo: 1.6.4 + + motion-dom@12.40.0: + dependencies: + motion-utils: 12.39.0 + + motion-utils@12.39.0: {} + + motion@12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + framer-motion: 12.40.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7) + tslib: 2.8.1 + optionalDependencies: + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + ms@2.0.0: {} + + ms@2.1.3: {} + + mz@2.7.0: + dependencies: + any-promise: 1.3.0 + object-assign: 4.1.1 + thenify-all: 1.6.0 + + nanoid@3.3.13: {} + + nanostores@1.0.1: {} + + napi-postinstall@0.3.4: {} + + natural-compare-lite@1.4.0: {} + + natural-compare@1.4.0: {} + + negotiator@1.0.0: {} + + next-themes@0.4.6(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + node-int64@0.4.0: {} + + node-releases@2.0.48: {} + + normalize-path@3.0.0: {} + + npm-run-path@4.0.1: + dependencies: + path-key: 3.1.1 + + nullthrows@1.1.1: {} + + nunjucks@3.2.4: + dependencies: + a-sync-waterfall: 1.0.1 + asap: 2.0.6 + commander: 5.1.0 + + ob1@0.84.4: + dependencies: + flow-enums-runtime: 0.0.6 + + object-assign@4.1.1: {} + + object-keys@1.1.1: {} + + on-finished@2.3.0: + dependencies: + ee-first: 1.1.1 + + on-finished@2.4.1: + dependencies: + ee-first: 1.1.1 + + once@1.4.0: + dependencies: + wrappy: 1.0.2 + + onetime@5.1.2: + dependencies: + mimic-fn: 2.1.0 + + oniguruma-parser@0.12.2: {} + + oniguruma-to-es@4.3.6: + dependencies: + oniguruma-parser: 0.12.2 + regex: 6.1.0 + regex-recursion: 6.0.2 + + open@7.4.2: + dependencies: + is-docker: 2.2.1 + is-wsl: 2.2.0 + + optionator@0.9.4: + dependencies: + deep-is: 0.1.4 + fast-levenshtein: 2.0.6 + levn: 0.4.1 + prelude-ls: 1.2.1 + type-check: 0.4.0 + word-wrap: 1.2.5 + + p-limit@2.3.0: + dependencies: + p-try: 2.2.0 + + p-limit@3.1.0: + dependencies: + yocto-queue: 0.1.0 + + p-locate@4.1.0: + dependencies: + p-limit: 2.3.0 + + p-locate@5.0.0: + dependencies: + p-limit: 3.1.0 + + p-try@2.2.0: {} + + package-json-from-dist@1.0.1: {} + + pako@0.2.9: {} + + parent-module@1.0.1: + dependencies: + callsites: 3.1.0 + + parse-css-color@0.2.1: + dependencies: + color-name: 1.1.4 + hex-rgb: 4.3.0 + + parse-json@5.2.0: + dependencies: + '@babel/code-frame': 7.29.7 + error-ex: 1.3.4 + json-parse-even-better-errors: 2.3.1 + lines-and-columns: 1.2.4 + + parseurl@1.3.3: {} + + path-exists@4.0.0: {} + + path-expression-matcher@1.5.0: {} + + path-is-absolute@1.0.1: {} + + path-key@3.1.1: {} + + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 + + path-type@4.0.0: {} + + pathe@2.0.3: {} + + picocolors@1.1.1: {} + + picomatch@4.0.4: {} + + pirates@4.0.7: {} + + pkg-dir@4.2.0: + dependencies: + find-up: 4.1.0 + + pkg-types@1.3.1: + dependencies: + confbox: 0.1.8 + mlly: 1.8.2 + pathe: 2.0.3 + + playwright-core@1.61.0: {} + + playwright@1.61.0: + dependencies: + playwright-core: 1.61.0 + optionalDependencies: + fsevents: 2.3.2 + + pngjs@5.0.0: {} + + postcss-load-config@6.0.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(yaml@2.9.0): + dependencies: + lilconfig: 3.1.3 + optionalDependencies: + jiti: 2.7.0 + postcss: 8.5.15 + tsx: 4.22.4 + yaml: 2.9.0 + + postcss-value-parser@4.2.0: {} + + postcss@8.5.15: + dependencies: + nanoid: 3.3.13 + picocolors: 1.1.1 + source-map-js: 1.2.1 + + prelude-ls@1.2.1: {} + + prettier@3.8.4: {} + + pretty-format@29.7.0: + dependencies: + '@jest/schemas': 29.6.3 + ansi-styles: 5.2.0 + react-is: 18.3.1 + + pretty-format@30.4.1: + dependencies: + '@jest/schemas': 30.4.1 + ansi-styles: 5.2.0 + react-is-18: react-is@18.3.1 + react-is-19: react-is@19.2.7 + + promise@8.3.0: + dependencies: + asap: 2.0.6 + + prompts@2.4.2: + dependencies: + kleur: 3.0.3 + sisteransi: 1.0.5 + + property-information@7.2.0: {} + + punycode@2.3.1: {} + + pure-rand@7.0.1: {} + + qrcode@1.5.4: + dependencies: + dijkstrajs: 1.0.3 + pngjs: 5.0.0 + yargs: 15.4.1 + + queue-microtask@1.2.3: {} + + queue@6.0.2: + dependencies: + inherits: 2.0.4 + + range-parser@1.2.1: {} + + react-devtools-core@6.1.5: + dependencies: + shell-quote: 1.8.4 + ws: 7.5.11 + transitivePeerDependencies: + - bufferutil + - utf-8-validate + + react-dom@19.2.7(react@19.2.7): + dependencies: + react: 19.2.7 + scheduler: 0.27.0 + + react-error-boundary@6.1.2(react@19.2.7): + dependencies: + react: 19.2.7 + + react-is@18.3.1: {} + + react-is@19.2.7: {} + + react-native@0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7): + dependencies: + '@react-native/assets-registry': 0.86.0 + '@react-native/codegen': 0.86.0(@babel/core@7.29.7) + '@react-native/community-cli-plugin': 0.86.0 + '@react-native/gradle-plugin': 0.86.0 + '@react-native/js-polyfills': 0.86.0 + '@react-native/normalize-colors': 0.86.0 + '@react-native/virtualized-lists': 0.86.0(@types/react@19.2.17)(react-native@0.86.0(@babel/core@7.29.7)(@types/react@19.2.17)(react@19.2.7))(react@19.2.7) + abort-controller: 3.0.0 + anser: 1.4.10 + ansi-regex: 5.0.1 + babel-plugin-syntax-hermes-parser: 0.36.0 + base64-js: 1.5.1 + commander: 12.1.0 + flow-enums-runtime: 0.0.6 + hermes-compiler: 250829098.0.14 + invariant: 2.2.4 + memoize-one: 5.2.1 + metro-runtime: 0.84.4 + metro-source-map: 0.84.4 + nullthrows: 1.1.1 + pretty-format: 29.7.0 + promise: 8.3.0 + react: 19.2.7 + react-devtools-core: 6.1.5 + react-refresh: 0.14.2 + regenerator-runtime: 0.13.11 + scheduler: 0.27.0 + semver: 7.8.4 + stacktrace-parser: 0.1.11 + tinyglobby: 0.2.17 + whatwg-fetch: 3.6.20 + ws: 7.5.11 + yargs: 17.7.2 + optionalDependencies: + '@types/react': 19.2.17 + transitivePeerDependencies: + - '@babel/core' + - '@react-native-community/cli' + - '@react-native/metro-config' + - bufferutil + - supports-color + - utf-8-validate + + react-refresh@0.14.2: {} + + react-remove-scroll-bar@2.3.8(@types/react@19.2.17)(react@19.2.7): + dependencies: + react: 19.2.7 + react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.7) + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + react-remove-scroll@2.7.2(@types/react@19.2.17)(react@19.2.7): + dependencies: + react: 19.2.7 + react-remove-scroll-bar: 2.3.8(@types/react@19.2.17)(react@19.2.7) + react-style-singleton: 2.2.3(@types/react@19.2.17)(react@19.2.7) + tslib: 2.8.1 + use-callback-ref: 1.3.3(@types/react@19.2.17)(react@19.2.7) + use-sidecar: 1.1.3(@types/react@19.2.17)(react@19.2.7) + optionalDependencies: + '@types/react': 19.2.17 + + react-router@7.18.0(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + cookie: 1.1.1 + react: 19.2.7 + set-cookie-parser: 2.7.2 + optionalDependencies: + react-dom: 19.2.7(react@19.2.7) + + react-style-singleton@2.2.3(@types/react@19.2.17)(react@19.2.7): + dependencies: + get-nonce: 1.0.1 + react: 19.2.7 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + react@19.2.7: {} + + readdirp@4.1.2: {} + + regenerator-runtime@0.13.11: {} + + regex-recursion@6.0.2: + dependencies: + regex-utilities: 2.3.0 + + regex-utilities@2.3.0: {} + + regex@6.1.0: + dependencies: + regex-utilities: 2.3.0 + + require-directory@2.1.1: {} + + require-main-filename@2.0.0: {} + + requireindex@1.2.0: {} + + reselect@5.2.0: {} + + resolve-cwd@3.0.0: + dependencies: + resolve-from: 5.0.0 + + resolve-from@4.0.0: {} + + resolve-from@5.0.0: {} + + reusify@1.1.0: {} + + rolldown@1.0.3: + dependencies: + '@oxc-project/types': 0.133.0 + '@rolldown/pluginutils': 1.0.1 + optionalDependencies: + '@rolldown/binding-android-arm64': 1.0.3 + '@rolldown/binding-darwin-arm64': 1.0.3 + '@rolldown/binding-darwin-x64': 1.0.3 + '@rolldown/binding-freebsd-x64': 1.0.3 + '@rolldown/binding-linux-arm-gnueabihf': 1.0.3 + '@rolldown/binding-linux-arm64-gnu': 1.0.3 + '@rolldown/binding-linux-arm64-musl': 1.0.3 + '@rolldown/binding-linux-ppc64-gnu': 1.0.3 + '@rolldown/binding-linux-s390x-gnu': 1.0.3 + '@rolldown/binding-linux-x64-gnu': 1.0.3 + '@rolldown/binding-linux-x64-musl': 1.0.3 + '@rolldown/binding-openharmony-arm64': 1.0.3 + '@rolldown/binding-wasm32-wasi': 1.0.3 + '@rolldown/binding-win32-arm64-msvc': 1.0.3 + '@rolldown/binding-win32-x64-msvc': 1.0.3 + + rollup@4.60.2: + dependencies: + '@types/estree': 1.0.8 + optionalDependencies: + '@rollup/rollup-android-arm-eabi': 4.60.2 + '@rollup/rollup-android-arm64': 4.60.2 + '@rollup/rollup-darwin-arm64': 4.60.2 + '@rollup/rollup-darwin-x64': 4.60.2 + '@rollup/rollup-freebsd-arm64': 4.60.2 + '@rollup/rollup-freebsd-x64': 4.60.2 + '@rollup/rollup-linux-arm-gnueabihf': 4.60.2 + '@rollup/rollup-linux-arm-musleabihf': 4.60.2 + '@rollup/rollup-linux-arm64-gnu': 4.60.2 + '@rollup/rollup-linux-arm64-musl': 4.60.2 + '@rollup/rollup-linux-loong64-gnu': 4.60.2 + '@rollup/rollup-linux-loong64-musl': 4.60.2 + '@rollup/rollup-linux-ppc64-gnu': 4.60.2 + '@rollup/rollup-linux-ppc64-musl': 4.60.2 + '@rollup/rollup-linux-riscv64-gnu': 4.60.2 + '@rollup/rollup-linux-riscv64-musl': 4.60.2 + '@rollup/rollup-linux-s390x-gnu': 4.60.2 + '@rollup/rollup-linux-x64-gnu': 4.60.2 + '@rollup/rollup-linux-x64-musl': 4.60.2 + '@rollup/rollup-openbsd-x64': 4.60.2 + '@rollup/rollup-openharmony-arm64': 4.60.2 + '@rollup/rollup-win32-arm64-msvc': 4.60.2 + '@rollup/rollup-win32-ia32-msvc': 4.60.2 + '@rollup/rollup-win32-x64-gnu': 4.60.2 + '@rollup/rollup-win32-x64-msvc': 4.60.2 + fsevents: 2.3.3 + + run-parallel@1.2.0: + dependencies: + queue-microtask: 1.2.3 + + satori@0.25.0: + dependencies: + '@shuding/opentype.js': 1.4.0-beta.0 + css-background-parser: 0.1.0 + css-box-shadow: 1.0.0-3 + css-gradient-parser: 0.0.17 + css-to-react-native: 3.2.0 + emoji-regex-xs: 2.0.1 + escape-html: 1.0.3 + linebreak: 1.1.0 + parse-css-color: 0.2.1 + postcss-value-parser: 4.2.0 + yoga-layout: 3.2.1 + + scheduler@0.27.0: {} + + semver@6.3.1: {} + + semver@7.8.4: {} + + send@0.19.2: + dependencies: + debug: 2.6.9 + depd: 2.0.0 + destroy: 1.2.0 + encodeurl: 2.0.0 + escape-html: 1.0.3 + etag: 1.8.1 + fresh: 0.5.2 + http-errors: 2.0.1 + mime: 1.6.0 + ms: 2.1.3 + on-finished: 2.4.1 + range-parser: 1.2.1 + statuses: 2.0.2 + transitivePeerDependencies: + - supports-color + + serialize-error@2.1.0: {} + + serve-static@1.16.3: + dependencies: + encodeurl: 2.0.0 + escape-html: 1.0.3 + parseurl: 1.3.3 + send: 0.19.2 + transitivePeerDependencies: + - supports-color + + set-blocking@2.0.0: {} + + set-cookie-parser@2.7.2: {} + + set-function-length@1.2.2: + dependencies: + define-data-property: 1.1.4 + es-errors: 1.3.0 + function-bind: 1.1.2 + get-intrinsic: 1.3.0 + gopd: 1.2.0 + has-property-descriptors: 1.0.2 + + setprototypeof@1.2.0: {} + + sharp@0.34.5: + dependencies: + '@img/colour': 1.1.0 + detect-libc: 2.1.2 + semver: 7.8.4 + optionalDependencies: + '@img/sharp-darwin-arm64': 0.34.5 + '@img/sharp-darwin-x64': 0.34.5 + '@img/sharp-libvips-darwin-arm64': 1.2.4 + '@img/sharp-libvips-darwin-x64': 1.2.4 + '@img/sharp-libvips-linux-arm': 1.2.4 + '@img/sharp-libvips-linux-arm64': 1.2.4 + '@img/sharp-libvips-linux-ppc64': 1.2.4 + '@img/sharp-libvips-linux-riscv64': 1.2.4 + '@img/sharp-libvips-linux-s390x': 1.2.4 + '@img/sharp-libvips-linux-x64': 1.2.4 + '@img/sharp-libvips-linuxmusl-arm64': 1.2.4 + '@img/sharp-libvips-linuxmusl-x64': 1.2.4 + '@img/sharp-linux-arm': 0.34.5 + '@img/sharp-linux-arm64': 0.34.5 + '@img/sharp-linux-ppc64': 0.34.5 + '@img/sharp-linux-riscv64': 0.34.5 + '@img/sharp-linux-s390x': 0.34.5 + '@img/sharp-linux-x64': 0.34.5 + '@img/sharp-linuxmusl-arm64': 0.34.5 + '@img/sharp-linuxmusl-x64': 0.34.5 + '@img/sharp-wasm32': 0.34.5 + '@img/sharp-win32-arm64': 0.34.5 + '@img/sharp-win32-ia32': 0.34.5 + '@img/sharp-win32-x64': 0.34.5 + optional: true + + shebang-command@2.0.0: + dependencies: + shebang-regex: 3.0.0 + + shebang-regex@3.0.0: {} + + shell-quote@1.8.4: {} + + shiki@3.23.0: + dependencies: + '@shikijs/core': 3.23.0 + '@shikijs/engine-javascript': 3.23.0 + '@shikijs/engine-oniguruma': 3.23.0 + '@shikijs/langs': 3.23.0 + '@shikijs/themes': 3.23.0 + '@shikijs/types': 3.23.0 + '@shikijs/vscode-textmate': 10.0.2 + '@types/hast': 3.0.4 + + signal-exit@3.0.7: {} + + signal-exit@4.1.0: {} + + sisteransi@1.0.5: {} + + slash@3.0.0: {} + + sonner@2.0.7(react-dom@19.2.7(react@19.2.7))(react@19.2.7): + dependencies: + react: 19.2.7 + react-dom: 19.2.7(react@19.2.7) + + source-map-js@1.2.1: {} + + source-map-support@0.5.13: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map-support@0.5.21: + dependencies: + buffer-from: 1.1.2 + source-map: 0.6.1 + + source-map@0.5.7: {} + + source-map@0.6.1: {} + + source-map@0.7.6: {} + + space-separated-tokens@2.0.2: {} + + sprintf-js@1.0.3: {} + + stack-utils@2.0.6: + dependencies: + escape-string-regexp: 2.0.0 + + stackframe@1.3.4: {} + + stacktrace-parser@0.1.11: + dependencies: + type-fest: 0.7.1 + + statuses@1.5.0: {} + + statuses@2.0.2: {} + + string-length@4.0.2: + dependencies: + char-regex: 1.0.2 + strip-ansi: 6.0.1 + + string-width@4.2.3: + dependencies: + emoji-regex: 8.0.0 + is-fullwidth-code-point: 3.0.0 + strip-ansi: 6.0.1 + + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + string.prototype.codepointat@0.2.1: {} + + stringify-entities@4.0.4: + dependencies: + character-entities-html4: 2.1.0 + character-entities-legacy: 3.0.0 + + strip-ansi@6.0.1: + dependencies: + ansi-regex: 5.0.1 + + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 + + strip-bom@4.0.0: {} + + strip-final-newline@2.0.0: {} + + strip-json-comments@3.1.1: {} + + strnum@2.4.1: + dependencies: + anynum: 1.0.1 + + sucrase@3.35.1: + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + commander: 4.1.1 + lines-and-columns: 1.2.4 + mz: 2.7.0 + pirates: 4.0.7 + tinyglobby: 0.2.17 + ts-interface-checker: 0.1.13 + + supports-color@7.2.0: + dependencies: + has-flag: 4.0.0 + + supports-color@8.1.1: + dependencies: + has-flag: 4.0.0 + + synckit@0.11.13: + dependencies: + '@pkgr/core': 0.3.6 + + tailwind-merge@3.6.0: {} + + tailwindcss@4.3.1: {} + + tapable@2.3.3: {} + + terser@5.48.0: + dependencies: + '@jridgewell/source-map': 0.3.11 + acorn: 8.17.0 + commander: 2.20.3 + source-map-support: 0.5.21 + + test-exclude@6.0.0: + dependencies: + '@istanbuljs/schema': 0.1.6 + glob: 7.2.3 + minimatch: 9.0.9 + + thenify-all@1.6.0: + dependencies: + thenify: 3.3.1 + + thenify@3.3.1: + dependencies: + any-promise: 1.3.0 + + throat@5.0.0: {} + + tiny-inflate@1.0.3: {} + + tinyexec@0.3.2: {} + + tinyglobby@0.2.17: + dependencies: + fdir: 6.5.0(picomatch@4.0.4) + picomatch: 4.0.4 + + tmpl@1.0.5: {} + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + + toidentifier@1.0.1: {} + + tree-kill@1.2.2: {} + + trim-lines@3.0.1: {} + + ts-api-utils@2.5.0(typescript@5.9.3): + dependencies: + typescript: 5.9.3 + + ts-interface-checker@0.1.13: {} + + tslib@1.14.1: {} + + tslib@2.8.1: {} + + tsup@8.5.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(typescript@5.9.3)(yaml@2.9.0): + dependencies: + bundle-require: 5.1.0(esbuild@0.27.7) + cac: 6.7.14 + chokidar: 4.0.3 + consola: 3.4.2 + debug: 4.4.3 + esbuild: 0.27.7 + fix-dts-default-cjs-exports: 1.0.1 + joycon: 3.1.1 + picocolors: 1.1.1 + postcss-load-config: 6.0.1(jiti@2.7.0)(postcss@8.5.15)(tsx@4.22.4)(yaml@2.9.0) + resolve-from: 5.0.0 + rollup: 4.60.2 + source-map: 0.7.6 + sucrase: 3.35.1 + tinyexec: 0.3.2 + tinyglobby: 0.2.17 + tree-kill: 1.2.2 + optionalDependencies: + postcss: 8.5.15 + typescript: 5.9.3 + transitivePeerDependencies: + - jiti + - supports-color + - tsx + - yaml + + tsutils@3.21.0(typescript@5.9.3): + dependencies: + tslib: 1.14.1 + typescript: 5.9.3 + + tsx@4.22.4: + dependencies: + esbuild: 0.28.1 + optionalDependencies: + fsevents: 2.3.3 + + tw-animate-css@1.4.0: {} + + type-check@0.4.0: + dependencies: + prelude-ls: 1.2.1 + + type-detect@4.0.8: {} + + type-fest@0.21.3: {} + + type-fest@0.7.1: {} + + typescript-eslint@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3): + dependencies: + '@typescript-eslint/eslint-plugin': 8.61.1(@typescript-eslint/parser@8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3))(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/parser': 8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + '@typescript-eslint/typescript-estree': 8.61.1(typescript@5.9.3) + '@typescript-eslint/utils': 8.61.1(eslint@9.39.4(jiti@2.7.0))(typescript@5.9.3) + eslint: 9.39.4(jiti@2.7.0) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + typescript@5.9.3: {} + + ufo@1.6.4: {} + + undici-types@7.24.6: {} + + undici-types@8.5.0: {} + + unicode-trie@2.0.0: + dependencies: + pako: 0.2.9 + tiny-inflate: 1.0.3 + + unist-util-is@6.0.1: + dependencies: + '@types/unist': 3.0.3 + + unist-util-position@5.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-stringify-position@4.0.0: + dependencies: + '@types/unist': 3.0.3 + + unist-util-visit-parents@6.0.2: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + + unist-util-visit@5.1.0: + dependencies: + '@types/unist': 3.0.3 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + unpipe@1.0.0: {} + + unrs-resolver@1.12.2: + dependencies: + napi-postinstall: 0.3.4 + optionalDependencies: + '@unrs/resolver-binding-android-arm-eabi': 1.12.2 + '@unrs/resolver-binding-android-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-arm64': 1.12.2 + '@unrs/resolver-binding-darwin-x64': 1.12.2 + '@unrs/resolver-binding-freebsd-x64': 1.12.2 + '@unrs/resolver-binding-linux-arm-gnueabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm-musleabihf': 1.12.2 + '@unrs/resolver-binding-linux-arm64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-arm64-musl': 1.12.2 + '@unrs/resolver-binding-linux-loong64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-loong64-musl': 1.12.2 + '@unrs/resolver-binding-linux-ppc64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-riscv64-musl': 1.12.2 + '@unrs/resolver-binding-linux-s390x-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-gnu': 1.12.2 + '@unrs/resolver-binding-linux-x64-musl': 1.12.2 + '@unrs/resolver-binding-openharmony-arm64': 1.12.2 + '@unrs/resolver-binding-wasm32-wasi': 1.12.2 + '@unrs/resolver-binding-win32-arm64-msvc': 1.12.2 + '@unrs/resolver-binding-win32-ia32-msvc': 1.12.2 + '@unrs/resolver-binding-win32-x64-msvc': 1.12.2 + + update-browserslist-db@1.2.3(browserslist@4.28.2): + dependencies: + browserslist: 4.28.2 + escalade: 3.2.0 + picocolors: 1.1.1 + + uri-js@4.4.1: + dependencies: + punycode: 2.3.1 + + use-callback-ref@1.3.3(@types/react@19.2.17)(react@19.2.7): + dependencies: + react: 19.2.7 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + use-sidecar@1.1.3(@types/react@19.2.17)(react@19.2.7): + dependencies: + detect-node-es: 1.1.0 + react: 19.2.7 + tslib: 2.8.1 + optionalDependencies: + '@types/react': 19.2.17 + + use-sync-external-store@1.6.0(react@19.2.7): + dependencies: + react: 19.2.7 + + utils-merge@1.0.1: {} + + v8-to-istanbul@9.3.0: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + '@types/istanbul-lib-coverage': 2.0.6 + convert-source-map: 2.0.0 + + vfile-message@4.0.3: + dependencies: + '@types/unist': 3.0.3 + unist-util-stringify-position: 4.0.0 + + vfile@6.0.3: + dependencies: + '@types/unist': 3.0.3 + vfile-message: 4.0.3 + + vite@8.0.16(@types/node@25.9.3)(esbuild@0.28.1)(jiti@2.7.0)(terser@5.48.0)(tsx@4.22.4)(yaml@2.9.0): + dependencies: + lightningcss: 1.32.0 + picomatch: 4.0.4 + postcss: 8.5.15 + rolldown: 1.0.3 + tinyglobby: 0.2.17 + optionalDependencies: + '@types/node': 25.9.3 + esbuild: 0.28.1 + fsevents: 2.3.3 + jiti: 2.7.0 + terser: 5.48.0 + tsx: 4.22.4 + yaml: 2.9.0 + + vlq@1.0.1: {} + + walker@1.0.8: + dependencies: + makeerror: 1.0.12 + + whatwg-fetch@3.6.20: {} + + which-module@2.0.1: {} + + which@2.0.2: + dependencies: + isexe: 2.0.0 + + word-wrap@1.2.5: {} + + wrap-ansi@6.2.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@7.0.0: + dependencies: + ansi-styles: 4.3.0 + string-width: 4.2.3 + strip-ansi: 6.0.1 + + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 + + wrappy@1.0.2: {} + + write-file-atomic@5.0.1: + dependencies: + imurmurhash: 0.1.4 + signal-exit: 4.1.0 + + ws@7.5.11: {} + + ws@8.20.1: {} + + xml-naming@0.1.0: {} + + y18n@4.0.3: {} + + y18n@5.0.8: {} + + yallist@3.1.1: {} + + yaml@2.9.0: {} + + yargs-parser@18.1.3: + dependencies: + camelcase: 5.3.1 + decamelize: 1.2.0 + + yargs-parser@21.1.1: {} + + yargs@15.4.1: + dependencies: + cliui: 6.0.0 + decamelize: 1.2.0 + find-up: 4.1.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + require-main-filename: 2.0.0 + set-blocking: 2.0.0 + string-width: 4.2.3 + which-module: 2.0.1 + y18n: 4.0.3 + yargs-parser: 18.1.3 + + yargs@17.7.2: + dependencies: + cliui: 8.0.1 + escalade: 3.2.0 + get-caller-file: 2.0.5 + require-directory: 2.1.1 + string-width: 4.2.3 + y18n: 5.0.8 + yargs-parser: 21.1.1 + + yocto-queue@0.1.0: {} + + yoga-layout@3.2.1: {} + + zod-validation-error@4.0.2(zod@4.4.3): + dependencies: + zod: 4.4.3 + + zod@4.4.3: {} + + zwitch@2.0.4: {} diff --git a/games/world-cup/pinocchio/pnpm-workspace.yaml b/games/world-cup/pinocchio/pnpm-workspace.yaml new file mode 100644 index 000000000..bf4095fcc --- /dev/null +++ b/games/world-cup/pinocchio/pnpm-workspace.yaml @@ -0,0 +1,5 @@ +packages: + - 'clients/*' + - 'webapp' + - 'webapp/api' + - 'webapp/scripts' diff --git a/games/world-cup/pinocchio/program/Cargo.toml b/games/world-cup/pinocchio/program/Cargo.toml new file mode 100644 index 000000000..bfa4cc5a9 --- /dev/null +++ b/games/world-cup/pinocchio/program/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "world-cup-program" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } + +[lib] +name = "world_cup_program" +crate-type = ["lib", "cdylib"] + +[lints] +workspace = true + +[features] +no-entrypoint = [] + +[build-dependencies] +codama = { workspace = true } +serde_json = { workspace = true } + +[dependencies] +codama = { workspace = true } +const-crypto = { workspace = true } +pinocchio = { workspace = true } +pinocchio-system = { workspace = true } +pinocchio-token = { workspace = true } +pinocchio-token-2022 = { workspace = true } +solana-address = { workspace = true } +solana-security-txt = { workspace = true } +thiserror = { workspace = true } diff --git a/games/world-cup/pinocchio/program/build.rs b/games/world-cup/pinocchio/program/build.rs new file mode 100644 index 000000000..7327b35e8 --- /dev/null +++ b/games/world-cup/pinocchio/program/build.rs @@ -0,0 +1,38 @@ +//! Codama IDL build script. + +use { + codama::Codama, + std::{env, fs, path::Path}, +}; + +fn main() { + println!("cargo:rerun-if-changed=src/"); + println!("cargo:rerun-if-env-changed=GENERATE_IDL"); + + if let Err(e) = generate_idl() { + println!("cargo:warning=Failed to generate IDL: {}", e) + } +} + +fn generate_idl() -> Result<(), Box> { + let manifest_dir = env::var("CARGO_MANIFEST_DIR")?; + let crate_path = Path::new(&manifest_dir).join("src"); + let codama = Codama::load(&crate_path)?; + let idl_json = codama.get_json_idl()?; + + let mut parsed: serde_json::Value = serde_json::from_str(&idl_json)?; + if let Some(program) = parsed.get_mut("program").and_then(serde_json::Value::as_object_mut) { + program.insert("name".to_string(), serde_json::Value::String("worldCup".to_string())); + } + let mut formatted_json = serde_json::to_string_pretty(&parsed)?; + formatted_json.push('\n'); + + let project_root = Path::new(&manifest_dir).parent().unwrap(); + let idl_dir = project_root.join("idl"); + fs::create_dir_all(&idl_dir)?; + let idl_path = idl_dir.join("world_cup.json"); + fs::write(&idl_path, formatted_json)?; + + println!("cargo:warning=IDL written to: {}", idl_path.display()); + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/entrypoint.rs b/games/world-cup/pinocchio/program/src/entrypoint.rs new file mode 100644 index 000000000..b5d3c0c8d --- /dev/null +++ b/games/world-cup/pinocchio/program/src/entrypoint.rs @@ -0,0 +1,27 @@ +use pinocchio::{account::AccountView, entrypoint, Address, ProgramResult}; + +use crate::instructions::{ + claim, close_bracket, emit_event, finalize, init_config, lock, post_goals, post_result, refresh_score, + submit_bracket, WorldCupInstruction, +}; + +entrypoint!(process_instruction); + +pub fn process_instruction( + program_id: &Address, + accounts: &mut [AccountView], + instruction_data: &[u8], +) -> ProgramResult { + match WorldCupInstruction::from_bytes(instruction_data)? { + WorldCupInstruction::InitConfig(data) => init_config::process(accounts, &data), + WorldCupInstruction::SubmitBracket(data) => submit_bracket::process(accounts, &data), + WorldCupInstruction::Lock => lock::process(accounts), + WorldCupInstruction::PostResult(data) => post_result::process(accounts, &data), + WorldCupInstruction::PostGoals(data) => post_goals::process(accounts, &data), + WorldCupInstruction::RefreshScore => refresh_score::process(accounts), + WorldCupInstruction::Finalize => finalize::process(accounts), + WorldCupInstruction::Claim => claim::process(accounts), + WorldCupInstruction::CloseBracket => close_bracket::process(accounts), + WorldCupInstruction::EmitEvent => emit_event::process(program_id, accounts), + } +} diff --git a/games/world-cup/pinocchio/program/src/errors.rs b/games/world-cup/pinocchio/program/src/errors.rs new file mode 100644 index 000000000..1b3c430a9 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/errors.rs @@ -0,0 +1,145 @@ +use codama::CodamaErrors; +use pinocchio::error::ProgramError; +use thiserror::Error; + +impl From for ProgramError { + fn from(e: WorldCupError) -> Self { + ProgramError::Custom(e as u32) + } +} + +#[cfg(test)] +impl TryFrom for WorldCupError { + type Error = u32; + + fn try_from(code: u32) -> Result { + match code { + 100 => Ok(Self::NotSigner), + 101 => Ok(Self::AccountNotWritable), + 102 => Ok(Self::NotSystemProgram), + 103 => Ok(Self::NotEnoughAccountKeys), + 104 => Ok(Self::InvalidInstruction), + 105 => Ok(Self::InvalidAccountData), + 106 => Ok(Self::InvalidAccountDiscriminator), + 107 => Ok(Self::ArithmeticOverflow), + 108 => Ok(Self::NotProgramOwned), + 200 => Ok(Self::InvalidConfigPda), + 201 => Ok(Self::ConfigAlreadyExists), + 202 => Ok(Self::Unauthorized), + 203 => Ok(Self::InvalidState), + 204 => Ok(Self::RegistrationClosed), + 205 => Ok(Self::NotYetLocked), + 206 => Ok(Self::InvalidLockTs), + 300 => Ok(Self::InvalidBracketPda), + 301 => Ok(Self::BracketAlreadyExists), + 302 => Ok(Self::InvalidPick), + 303 => Ok(Self::AlreadyFolded), + 400 => Ok(Self::InvalidOraclePda), + 401 => Ok(Self::InvalidGame), + 402 => Ok(Self::InvalidResult), + 403 => Ok(Self::FeederNotDecided), + 404 => Ok(Self::ResultAlreadyPosted), + 405 => Ok(Self::GoalsAlreadyPosted), + 500 => Ok(Self::InvalidVaultPda), + 501 => Ok(Self::OracleNotComplete), + 502 => Ok(Self::NotFullyRefreshed), + 503 => Ok(Self::BracketNotBest), + 504 => Ok(Self::NotWinner), + 505 => Ok(Self::AlreadyClaimed), + 600 => Ok(Self::InvalidEventAuthority), + 601 => Ok(Self::InvalidEventData), + _ => Err(code), + } + } +} + +/// Program-specific error codes for the world-cup program. +/// +/// - **100--199**: Generic account and data validation errors. +/// - **200--299**: Config / tournament-lifecycle errors. +/// - **300--399**: Bracket errors. +/// - **400--499**: Oracle errors. +/// - **500--599**: Finalize / claim errors. +/// - **600--699**: Event emission errors. +#[derive(Debug, Copy, Clone, Error, CodamaErrors)] +pub enum WorldCupError { + // --- Generic errors (100--199) --- + #[error("Account must be a signer")] + NotSigner = 100, + #[error("Account must be writable")] + AccountNotWritable, + #[error("Expected system program")] + NotSystemProgram, + #[error("Not enough account keys provided")] + NotEnoughAccountKeys, + #[error("Invalid instruction")] + InvalidInstruction, + #[error("Invalid account data")] + InvalidAccountData, + #[error("Invalid account discriminator")] + InvalidAccountDiscriminator, + #[error("Arithmetic overflow")] + ArithmeticOverflow, + #[error("Account is not owned by this program")] + NotProgramOwned, + + // --- Config / lifecycle errors (200--299) --- + #[error("Invalid config PDA derivation")] + InvalidConfigPda = 200, + #[error("Config account already exists")] + ConfigAlreadyExists, + #[error("Signer is not the tournament admin")] + Unauthorized, + #[error("Instruction not allowed in the current tournament state")] + InvalidState, + #[error("Registration has closed (kickoff reached)")] + RegistrationClosed, + #[error("Lock time has not been reached yet")] + NotYetLocked, + #[error("Lock timestamp must be in the future")] + InvalidLockTs, + + // --- Bracket errors (300--399) --- + #[error("Invalid bracket PDA derivation")] + InvalidBracketPda = 300, + #[error("Bracket already exists for this wallet")] + BracketAlreadyExists, + #[error("Bracket pick is out of range or inconsistent")] + InvalidPick, + #[error("Bracket has already been folded into the final tally")] + AlreadyFolded, + + // --- Oracle errors (400--499) --- + #[error("Invalid oracle PDA derivation")] + InvalidOraclePda = 400, + #[error("Game index is out of range")] + InvalidGame, + #[error("Result is inconsistent with feeder games")] + InvalidResult, + #[error("A feeder game has not been decided yet")] + FeederNotDecided, + #[error("Result for this game has already been posted")] + ResultAlreadyPosted, + #[error("Round-of-32 goal total has already been posted")] + GoalsAlreadyPosted, + + // --- Finalize / claim errors (500--599) --- + #[error("Invalid pot vault PDA derivation")] + InvalidVaultPda = 500, + #[error("Oracle is not complete (all games + goals required)")] + OracleNotComplete, + #[error("Not every bracket has been refreshed at the final state")] + NotFullyRefreshed, + #[error("Provided bracket does not match the winning key")] + BracketNotBest, + #[error("Signer is not the recorded winner")] + NotWinner, + #[error("Pot has already been claimed or released")] + AlreadyClaimed, + + // --- Event errors (600--699) --- + #[error("Invalid event authority PDA")] + InvalidEventAuthority = 600, + #[error("Invalid event data")] + InvalidEventData, +} diff --git a/games/world-cup/pinocchio/program/src/event_engine.rs b/games/world-cup/pinocchio/program/src/event_engine.rs new file mode 100644 index 000000000..9e0928ab6 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/event_engine.rs @@ -0,0 +1,200 @@ +//! Event emission engine using Anchor-compatible self-CPI. +//! +//! Events are emitted by invoking this program's own [`EmitEvent`](crate::instructions::emit_event) +//! instruction via CPI, signed by the event authority PDA. Indexers detect these +//! inner instructions by the 8-byte [`EVENT_IX_TAG`] prefix in the instruction data. + +use core::mem::size_of; + +use alloc::vec::Vec; +use codama::CodamaAccount; +use const_crypto::ed25519; +use pinocchio::cpi::{invoke_signed, Seed, Signer}; +use pinocchio::error::ProgramError; +use pinocchio::instruction::{InstructionAccount, InstructionView}; +use pinocchio::{AccountView, Address, ProgramResult}; + +use crate::errors::WorldCupError; + +/// Event authority PDA — no account data, only used for CPI event emission signing. +#[derive(CodamaAccount)] +#[codama(seed(type = string(utf8), value = "event_authority"))] +pub struct EventAuthority; + +/// PDA seed for the event authority account. +pub const EVENT_AUTHORITY_SEED: &[u8] = b"event_authority"; + +/// Anchor-compatible event tag: `Sha256("anchor:event")[..8]`. +pub const EVENT_IX_TAG: u64 = 0x1d9acb512ea545e4; + +/// Little-endian byte representation of [`EVENT_IX_TAG`]. +pub const EVENT_IX_TAG_LE: [u8; 8] = EVENT_IX_TAG.to_le_bytes(); + +/// Wire format prefix length: 8-byte tag + 1-byte event discriminator. +pub const EVENT_DISCRIMINATOR_LEN: usize = size_of::() + 1; + +/// Instruction discriminator for the EmitEvent no-op instruction. +pub const EMIT_EVENT_IX_DISC: u8 = 228; + +/// Compile-time derived PDA for the event authority. +pub mod event_authority_pda { + use super::*; + + const EVENT_AUTHORITY_AND_BUMP: ([u8; 32], u8) = + ed25519::derive_program_address(&[EVENT_AUTHORITY_SEED], crate::ID.as_array()); + + /// The event authority PDA address, derived at compile time. + pub const ID: Address = Address::new_from_array(EVENT_AUTHORITY_AND_BUMP.0); + + /// The PDA bump seed for the event authority. + pub const BUMP: u8 = EVENT_AUTHORITY_AND_BUMP.1; +} + +/// Defines the event discriminator byte used in the wire format prefix. +pub trait EventDiscriminator { + const DISCRIMINATOR: u8; +} + +#[cfg(test)] +fn discriminator_bytes() -> Vec { + let mut bytes = Vec::with_capacity(EVENT_DISCRIMINATOR_LEN); + bytes.extend_from_slice(&EVENT_IX_TAG_LE); + bytes.push(T::DISCRIMINATOR); + bytes +} + +/// Serializes an event into its wire format: tag + discriminator + field data. +pub trait EventSerialize: EventDiscriminator { + /// The length of the serialized event data (excluding discriminator). + const DATA_LEN: usize; + + /// Appends the event's field data to the given buffer. + fn write_inner(&self, writer: &mut Vec); + + fn load(bytes: &[u8]) -> Result<&Self, ProgramError> + where + Self: Sized, + { + if bytes.len() != Self::DATA_LEN { + return Err(WorldCupError::InvalidEventData.into()); + } + Ok(unsafe { &*bytes.as_ptr().cast::() }) + } + + fn to_bytes(&self) -> Vec { + let mut data = Vec::with_capacity(Self::DATA_LEN + EVENT_DISCRIMINATOR_LEN); + data.extend_from_slice(&EVENT_IX_TAG_LE); + data.push(Self::DISCRIMINATOR); + self.write_inner(&mut data); + data + } +} + +/// Registry of all event discriminator values. +/// +/// Each variant's `u8` value is written as the 9th byte of the event wire format +/// (after the 8-byte [`EVENT_IX_TAG_LE`] prefix), letting indexers identify the +/// event type. +#[repr(u8)] +pub enum EventDiscriminators { + ConfigInitialized = 0, + BracketSubmitted = 1, + TournamentLocked = 2, + ResultPosted = 3, + GoalsPosted = 4, + ScoreRefreshed = 5, + MarketFinalized = 6, + PotClaimed = 7, + BracketClosed = 8, +} + +impl TryFrom for EventDiscriminators { + type Error = u8; + + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::ConfigInitialized), + 1 => Ok(Self::BracketSubmitted), + 2 => Ok(Self::TournamentLocked), + 3 => Ok(Self::ResultPosted), + 4 => Ok(Self::GoalsPosted), + 5 => Ok(Self::ScoreRefreshed), + 6 => Ok(Self::MarketFinalized), + 7 => Ok(Self::PotClaimed), + 8 => Ok(Self::BracketClosed), + _ => Err(value), + } + } +} + +/// Verifies that the given account matches the compile-time event authority PDA. +#[inline(always)] +pub fn verify_event_authority(account: &AccountView) -> Result<(), ProgramError> { + if account.address() != &event_authority_pda::ID { + return Err(WorldCupError::InvalidEventAuthority.into()); + } + Ok(()) +} + +/// Emits an event via self-CPI, recording event data in inner instruction data. +pub fn emit_event( + program_id: &Address, + event_authority: &AccountView, + self_program: &AccountView, + event_data: &[u8], +) -> ProgramResult { + verify_event_authority(event_authority)?; + + let bump = [event_authority_pda::BUMP]; + let signer_seeds: [Seed; 2] = [Seed::from(EVENT_AUTHORITY_SEED), Seed::from(&bump)]; + let signer = Signer::from(&signer_seeds); + + let accounts = [InstructionAccount::readonly_signer(event_authority.address())]; + + let instruction = InstructionView { program_id, data: event_data, accounts: &accounts }; + + invoke_signed::<2, _>(&instruction, &[event_authority, self_program], &[signer]) +} + +#[cfg(test)] +mod tests { + use super::*; + + struct StubEventA { + value: u64, + } + + impl EventDiscriminator for StubEventA { + const DISCRIMINATOR: u8 = 10; + } + + impl EventSerialize for StubEventA { + const DATA_LEN: usize = 8; + fn write_inner(&self, writer: &mut Vec) { + writer.extend_from_slice(&self.value.to_le_bytes()); + } + } + + #[test] + fn constants_are_consistent() { + assert_eq!(EVENT_IX_TAG_LE, EVENT_IX_TAG.to_le_bytes()); + assert_eq!(EVENT_DISCRIMINATOR_LEN, 8 + 1); + } + + #[test] + fn to_bytes_prepends_tag_and_discriminator() { + let event = StubEventA { value: 42 }; + let bytes = event.to_bytes(); + assert_eq!(&bytes[..8], &EVENT_IX_TAG_LE); + assert_eq!(bytes[8], StubEventA::DISCRIMINATOR); + assert_eq!(&bytes[9..], &42u64.to_le_bytes()); + } + + #[test] + fn discriminator_bytes_has_correct_prefix() { + let disc = discriminator_bytes::(); + assert_eq!(disc.len(), EVENT_DISCRIMINATOR_LEN); + assert_eq!(&disc[..8], &EVENT_IX_TAG_LE); + assert_eq!(disc[8], StubEventA::DISCRIMINATOR); + } +} diff --git a/games/world-cup/pinocchio/program/src/events/bracket_closed.rs b/games/world-cup/pinocchio/program/src/events/bracket_closed.rs new file mode 100644 index 000000000..975cd0a32 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/events/bracket_closed.rs @@ -0,0 +1,32 @@ +use core::mem::size_of; + +use alloc::vec::Vec; +use pinocchio::Address; + +use crate::event_engine::{EventDiscriminator, EventDiscriminators, EventSerialize}; + +/// Emitted when an entrant closes their bracket to reclaim its rent. +#[repr(C, packed)] +pub struct BracketClosedEvent { + pub owner: Address, +} + +impl BracketClosedEvent { + pub const DATA_LEN: usize = size_of::(); + + pub fn new(owner: Address) -> Self { + Self { owner } + } +} + +impl EventDiscriminator for BracketClosedEvent { + const DISCRIMINATOR: u8 = EventDiscriminators::BracketClosed as u8; +} + +impl EventSerialize for BracketClosedEvent { + const DATA_LEN: usize = Self::DATA_LEN; + + fn write_inner(&self, writer: &mut Vec) { + writer.extend_from_slice(self.owner.as_ref()); + } +} diff --git a/games/world-cup/pinocchio/program/src/events/bracket_submitted.rs b/games/world-cup/pinocchio/program/src/events/bracket_submitted.rs new file mode 100644 index 000000000..ef2ac6d23 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/events/bracket_submitted.rs @@ -0,0 +1,41 @@ +use core::mem::size_of; + +use alloc::vec::Vec; +use pinocchio::Address; + +use crate::event_engine::{EventDiscriminator, EventDiscriminators, EventSerialize}; + +/// Emitted when an entrant submits a bracket. Carries the full submission (picks + +/// tiebreaker) so it survives in the ledger after the bracket PDA is closed. +#[repr(C, packed)] +pub struct BracketSubmittedEvent { + pub owner: Address, + pub entrant_count: u32, + pub tiebreaker_guess: u16, + pub picks: [u8; 32], +} + +impl BracketSubmittedEvent { + pub const DATA_LEN: usize = size_of::(); + + pub fn new(owner: Address, entrant_count: u32, tiebreaker_guess: u16, picks: [u8; 32]) -> Self { + Self { owner, entrant_count, tiebreaker_guess, picks } + } +} + +impl EventDiscriminator for BracketSubmittedEvent { + const DISCRIMINATOR: u8 = EventDiscriminators::BracketSubmitted as u8; +} + +impl EventSerialize for BracketSubmittedEvent { + const DATA_LEN: usize = Self::DATA_LEN; + + fn write_inner(&self, writer: &mut Vec) { + let entrant_count = self.entrant_count; + let tiebreaker_guess = self.tiebreaker_guess; + writer.extend_from_slice(self.owner.as_ref()); + writer.extend_from_slice(&entrant_count.to_le_bytes()); + writer.extend_from_slice(&tiebreaker_guess.to_le_bytes()); + writer.extend_from_slice(&self.picks); + } +} diff --git a/games/world-cup/pinocchio/program/src/events/config_initialized.rs b/games/world-cup/pinocchio/program/src/events/config_initialized.rs new file mode 100644 index 000000000..3653c7231 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/events/config_initialized.rs @@ -0,0 +1,38 @@ +use core::mem::size_of; + +use alloc::vec::Vec; +use pinocchio::Address; + +use crate::event_engine::{EventDiscriminator, EventDiscriminators, EventSerialize}; + +/// Emitted when the tournament config is initialized. +#[repr(C, packed)] +pub struct ConfigInitializedEvent { + pub admin: Address, + pub lock_ts: i64, + pub entry_fee: u64, +} + +impl ConfigInitializedEvent { + pub const DATA_LEN: usize = size_of::(); + + pub fn new(admin: Address, lock_ts: i64, entry_fee: u64) -> Self { + Self { admin, lock_ts, entry_fee } + } +} + +impl EventDiscriminator for ConfigInitializedEvent { + const DISCRIMINATOR: u8 = EventDiscriminators::ConfigInitialized as u8; +} + +impl EventSerialize for ConfigInitializedEvent { + const DATA_LEN: usize = Self::DATA_LEN; + + fn write_inner(&self, writer: &mut Vec) { + let lock_ts = self.lock_ts; + let entry_fee = self.entry_fee; + writer.extend_from_slice(self.admin.as_ref()); + writer.extend_from_slice(&lock_ts.to_le_bytes()); + writer.extend_from_slice(&entry_fee.to_le_bytes()); + } +} diff --git a/games/world-cup/pinocchio/program/src/events/goals_posted.rs b/games/world-cup/pinocchio/program/src/events/goals_posted.rs new file mode 100644 index 000000000..029f03f8f --- /dev/null +++ b/games/world-cup/pinocchio/program/src/events/goals_posted.rs @@ -0,0 +1,32 @@ +use core::mem::size_of; + +use alloc::vec::Vec; + +use crate::event_engine::{EventDiscriminator, EventDiscriminators, EventSerialize}; + +/// Emitted when the admin posts the Round-of-32 goal total. +#[repr(C, packed)] +pub struct GoalsPostedEvent { + pub total_goals_r32: u16, +} + +impl GoalsPostedEvent { + pub const DATA_LEN: usize = size_of::(); + + pub fn new(total_goals_r32: u16) -> Self { + Self { total_goals_r32 } + } +} + +impl EventDiscriminator for GoalsPostedEvent { + const DISCRIMINATOR: u8 = EventDiscriminators::GoalsPosted as u8; +} + +impl EventSerialize for GoalsPostedEvent { + const DATA_LEN: usize = Self::DATA_LEN; + + fn write_inner(&self, writer: &mut Vec) { + let total = self.total_goals_r32; + writer.extend_from_slice(&total.to_le_bytes()); + } +} diff --git a/games/world-cup/pinocchio/program/src/events/market_finalized.rs b/games/world-cup/pinocchio/program/src/events/market_finalized.rs new file mode 100644 index 000000000..7e5bba76b --- /dev/null +++ b/games/world-cup/pinocchio/program/src/events/market_finalized.rs @@ -0,0 +1,38 @@ +use core::mem::size_of; + +use alloc::vec::Vec; +use pinocchio::Address; + +use crate::event_engine::{EventDiscriminator, EventDiscriminators, EventSerialize}; + +/// Emitted when the admin finalizes a unique winner. +#[repr(C, packed)] +pub struct MarketFinalizedEvent { + pub winner: Address, + pub best_score: u16, + pub best_closeness: u16, +} + +impl MarketFinalizedEvent { + pub const DATA_LEN: usize = size_of::(); + + pub fn new(winner: Address, best_score: u16, best_closeness: u16) -> Self { + Self { winner, best_score, best_closeness } + } +} + +impl EventDiscriminator for MarketFinalizedEvent { + const DISCRIMINATOR: u8 = EventDiscriminators::MarketFinalized as u8; +} + +impl EventSerialize for MarketFinalizedEvent { + const DATA_LEN: usize = Self::DATA_LEN; + + fn write_inner(&self, writer: &mut Vec) { + let best_score = self.best_score; + let best_closeness = self.best_closeness; + writer.extend_from_slice(self.winner.as_ref()); + writer.extend_from_slice(&best_score.to_le_bytes()); + writer.extend_from_slice(&best_closeness.to_le_bytes()); + } +} diff --git a/games/world-cup/pinocchio/program/src/events/mod.rs b/games/world-cup/pinocchio/program/src/events/mod.rs new file mode 100644 index 000000000..bfc46ec8b --- /dev/null +++ b/games/world-cup/pinocchio/program/src/events/mod.rs @@ -0,0 +1,25 @@ +//! Event types emitted by the world-cup program via self-CPI. +//! +//! Each event struct implements [`EventDiscriminator`](crate::event_engine::EventDiscriminator) +//! and [`EventSerialize`](crate::event_engine::EventSerialize): an 8-byte tag prefix, +//! a 1-byte discriminator, then the event-specific payload. + +pub mod bracket_closed; +pub mod bracket_submitted; +pub mod config_initialized; +pub mod goals_posted; +pub mod market_finalized; +pub mod pot_claimed; +pub mod result_posted; +pub mod score_refreshed; +pub mod tournament_locked; + +pub use bracket_closed::BracketClosedEvent; +pub use bracket_submitted::BracketSubmittedEvent; +pub use config_initialized::ConfigInitializedEvent; +pub use goals_posted::GoalsPostedEvent; +pub use market_finalized::MarketFinalizedEvent; +pub use pot_claimed::PotClaimedEvent; +pub use result_posted::ResultPostedEvent; +pub use score_refreshed::ScoreRefreshedEvent; +pub use tournament_locked::TournamentLockedEvent; diff --git a/games/world-cup/pinocchio/program/src/events/pot_claimed.rs b/games/world-cup/pinocchio/program/src/events/pot_claimed.rs new file mode 100644 index 000000000..e14e31c56 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/events/pot_claimed.rs @@ -0,0 +1,35 @@ +use core::mem::size_of; + +use alloc::vec::Vec; +use pinocchio::Address; + +use crate::event_engine::{EventDiscriminator, EventDiscriminators, EventSerialize}; + +/// Emitted when the unique winner claims the pot. +#[repr(C, packed)] +pub struct PotClaimedEvent { + pub winner: Address, + pub amount: u64, +} + +impl PotClaimedEvent { + pub const DATA_LEN: usize = size_of::(); + + pub fn new(winner: Address, amount: u64) -> Self { + Self { winner, amount } + } +} + +impl EventDiscriminator for PotClaimedEvent { + const DISCRIMINATOR: u8 = EventDiscriminators::PotClaimed as u8; +} + +impl EventSerialize for PotClaimedEvent { + const DATA_LEN: usize = Self::DATA_LEN; + + fn write_inner(&self, writer: &mut Vec) { + let amount = self.amount; + writer.extend_from_slice(self.winner.as_ref()); + writer.extend_from_slice(&amount.to_le_bytes()); + } +} diff --git a/games/world-cup/pinocchio/program/src/events/result_posted.rs b/games/world-cup/pinocchio/program/src/events/result_posted.rs new file mode 100644 index 000000000..ed3cd842e --- /dev/null +++ b/games/world-cup/pinocchio/program/src/events/result_posted.rs @@ -0,0 +1,36 @@ +use core::mem::size_of; + +use alloc::vec::Vec; + +use crate::event_engine::{EventDiscriminator, EventDiscriminators, EventSerialize}; + +/// Emitted when the admin posts a game result. +#[repr(C, packed)] +pub struct ResultPostedEvent { + pub game: u8, + pub winner: u8, + pub decided_mask: u32, +} + +impl ResultPostedEvent { + pub const DATA_LEN: usize = size_of::(); + + pub fn new(game: u8, winner: u8, decided_mask: u32) -> Self { + Self { game, winner, decided_mask } + } +} + +impl EventDiscriminator for ResultPostedEvent { + const DISCRIMINATOR: u8 = EventDiscriminators::ResultPosted as u8; +} + +impl EventSerialize for ResultPostedEvent { + const DATA_LEN: usize = Self::DATA_LEN; + + fn write_inner(&self, writer: &mut Vec) { + let decided_mask = self.decided_mask; + writer.push(self.game); + writer.push(self.winner); + writer.extend_from_slice(&decided_mask.to_le_bytes()); + } +} diff --git a/games/world-cup/pinocchio/program/src/events/score_refreshed.rs b/games/world-cup/pinocchio/program/src/events/score_refreshed.rs new file mode 100644 index 000000000..aaec735ef --- /dev/null +++ b/games/world-cup/pinocchio/program/src/events/score_refreshed.rs @@ -0,0 +1,35 @@ +use core::mem::size_of; + +use alloc::vec::Vec; +use pinocchio::Address; + +use crate::event_engine::{EventDiscriminator, EventDiscriminators, EventSerialize}; + +/// Emitted when a bracket's score is refreshed against the oracle. +#[repr(C, packed)] +pub struct ScoreRefreshedEvent { + pub owner: Address, + pub score: u16, +} + +impl ScoreRefreshedEvent { + pub const DATA_LEN: usize = size_of::(); + + pub fn new(owner: Address, score: u16) -> Self { + Self { owner, score } + } +} + +impl EventDiscriminator for ScoreRefreshedEvent { + const DISCRIMINATOR: u8 = EventDiscriminators::ScoreRefreshed as u8; +} + +impl EventSerialize for ScoreRefreshedEvent { + const DATA_LEN: usize = Self::DATA_LEN; + + fn write_inner(&self, writer: &mut Vec) { + let score = self.score; + writer.extend_from_slice(self.owner.as_ref()); + writer.extend_from_slice(&score.to_le_bytes()); + } +} diff --git a/games/world-cup/pinocchio/program/src/events/tournament_locked.rs b/games/world-cup/pinocchio/program/src/events/tournament_locked.rs new file mode 100644 index 000000000..d151bae7e --- /dev/null +++ b/games/world-cup/pinocchio/program/src/events/tournament_locked.rs @@ -0,0 +1,32 @@ +use core::mem::size_of; + +use alloc::vec::Vec; + +use crate::event_engine::{EventDiscriminator, EventDiscriminators, EventSerialize}; + +/// Emitted when the tournament transitions from registration to locked. +#[repr(C, packed)] +pub struct TournamentLockedEvent { + pub lock_ts: i64, +} + +impl TournamentLockedEvent { + pub const DATA_LEN: usize = size_of::(); + + pub fn new(lock_ts: i64) -> Self { + Self { lock_ts } + } +} + +impl EventDiscriminator for TournamentLockedEvent { + const DISCRIMINATOR: u8 = EventDiscriminators::TournamentLocked as u8; +} + +impl EventSerialize for TournamentLockedEvent { + const DATA_LEN: usize = Self::DATA_LEN; + + fn write_inner(&self, writer: &mut Vec) { + let lock_ts = self.lock_ts; + writer.extend_from_slice(&lock_ts.to_le_bytes()); + } +} diff --git a/games/world-cup/pinocchio/program/src/instructions/claim.rs b/games/world-cup/pinocchio/program/src/instructions/claim.rs new file mode 100644 index 000000000..5ba6fdf0b --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/claim.rs @@ -0,0 +1,85 @@ +use pinocchio::{ + error::ProgramError, + sysvars::{rent::Rent, Sysvar}, + AccountView, ProgramResult, +}; + +use crate::{ + event_engine::{self, EventSerialize}, + events::PotClaimedEvent, + instructions::helpers::{check_signer, check_writable}, + state::{ + common::{find_vault_pda, TournamentState}, + config::Config, + }, + WorldCupError, +}; + +/// Instruction discriminator byte for `Claim`. +pub const DISCRIMINATOR: &u8 = &7; + +/// Validated accounts for [`Claim`](crate::WorldCupInstruction::Claim). +pub struct ClaimAccounts<'a> { + pub winner: &'a AccountView, + pub config: &'a mut AccountView, + pub vault: &'a AccountView, + pub event_authority: &'a AccountView, + pub self_program: &'a AccountView, +} + +impl<'a> TryFrom<&'a mut [AccountView]> for ClaimAccounts<'a> { + type Error = ProgramError; + + fn try_from(accounts: &'a mut [AccountView]) -> Result { + let [winner, config, vault, event_authority, self_program] = accounts else { + return Err(WorldCupError::NotEnoughAccountKeys.into()); + }; + + check_signer(winner)?; + check_writable(winner)?; + check_writable(config)?; + Config::check(config)?; + check_writable(vault)?; + + Ok(Self { winner, config, vault, event_authority, self_program }) + } +} + +/// Sweeps the available pot to the recorded unique winner and emits a [`PotClaimedEvent`]. +/// +/// Repeatable: the vault is left alive at its rent floor so bracket rents that flow in +/// via later `close_bracket` calls can be swept by the winner in a follow-up `claim`. +pub fn process(accounts: &mut [AccountView]) -> ProgramResult { + let accounts = ClaimAccounts::try_from(accounts)?; + + { + let config_data = accounts.config.try_borrow()?; + let config = Config::load(&config_data)?; + if TournamentState::try_from(config.state)? != TournamentState::Finalized { + return Err(WorldCupError::InvalidState.into()); + } + let recorded = config.winner; + if recorded != *accounts.winner.address() { + return Err(WorldCupError::NotWinner.into()); + } + } + + if find_vault_pda().0 != *accounts.vault.address() { + return Err(WorldCupError::InvalidVaultPda.into()); + } + + let floor = Rent::get()?.try_minimum_balance(0)?; + let amount = accounts.vault.lamports().saturating_sub(floor); + { + let mut vault = *accounts.vault; + let mut winner = *accounts.winner; + let new_balance = winner.lamports().checked_add(amount).ok_or(WorldCupError::ArithmeticOverflow)?; + winner.set_lamports(new_balance); + vault.set_lamports(floor); + } + + let event = PotClaimedEvent::new(*accounts.winner.address(), amount); + event_engine::emit_event(&crate::ID, accounts.event_authority, accounts.self_program, &event.to_bytes())?; + + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/instructions/close_bracket.rs b/games/world-cup/pinocchio/program/src/instructions/close_bracket.rs new file mode 100644 index 000000000..4e06a0c70 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/close_bracket.rs @@ -0,0 +1,77 @@ +use pinocchio::{error::ProgramError, AccountView, ProgramResult}; + +use crate::{ + event_engine::{self, EventSerialize}, + events::BracketClosedEvent, + instructions::helpers::{check_writable, close_account}, + state::{ + bracket::Bracket, + common::{find_vault_pda, verify_bracket_pda, TournamentState}, + config::Config, + }, + WorldCupError, +}; + +/// Instruction discriminator byte for `CloseBracket`. +pub const DISCRIMINATOR: &u8 = &8; + +/// Validated accounts for [`CloseBracket`](crate::WorldCupInstruction::CloseBracket). +pub struct CloseBracketAccounts<'a> { + pub config: &'a AccountView, + pub bracket: &'a AccountView, + pub vault: &'a AccountView, + pub event_authority: &'a AccountView, + pub self_program: &'a AccountView, +} + +impl<'a> TryFrom<&'a mut [AccountView]> for CloseBracketAccounts<'a> { + type Error = ProgramError; + + fn try_from(accounts: &'a mut [AccountView]) -> Result { + let [config, bracket, vault, event_authority, self_program] = accounts else { + return Err(WorldCupError::NotEnoughAccountKeys.into()); + }; + + Config::check(config)?; + check_writable(bracket)?; + Bracket::check(bracket)?; + check_writable(vault)?; + + Ok(Self { config, bracket, vault, event_authority, self_program }) + } +} + +/// Permissionlessly closes any bracket once the tournament is finalized, rolling its +/// rent into the pot vault, and emits a [`BracketClosedEvent`]. +pub fn process(accounts: &mut [AccountView]) -> ProgramResult { + let accounts = CloseBracketAccounts::try_from(accounts)?; + + { + let config_data = accounts.config.try_borrow()?; + let config = Config::load(&config_data)?; + if TournamentState::try_from(config.state)? != TournamentState::Finalized { + return Err(WorldCupError::InvalidState.into()); + } + } + + let (owner, bump) = { + let bracket_data = accounts.bracket.try_borrow()?; + let bracket = Bracket::load(&bracket_data)?; + (bracket.owner, bracket.bump) + }; + + let expected_pda = verify_bracket_pda(&owner, bump)?; + if expected_pda != *accounts.bracket.address() { + return Err(WorldCupError::InvalidBracketPda.into()); + } + if find_vault_pda().0 != *accounts.vault.address() { + return Err(WorldCupError::InvalidVaultPda.into()); + } + + close_account(accounts.bracket, accounts.vault)?; + + let event = BracketClosedEvent::new(owner); + event_engine::emit_event(&crate::ID, accounts.event_authority, accounts.self_program, &event.to_bytes())?; + + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/instructions/emit_event.rs b/games/world-cup/pinocchio/program/src/instructions/emit_event.rs new file mode 100644 index 000000000..dd3163c03 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/emit_event.rs @@ -0,0 +1,22 @@ +use pinocchio::{error::ProgramError, AccountView, Address, ProgramResult}; + +use crate::event_engine::verify_event_authority; + +/// No-op instruction used as the target of self-CPI event emission. +/// +/// It only verifies that the caller is the event authority PDA. It exists so +/// indexers can detect event data in the inner instruction. It is never invoked +/// directly by external callers. +pub fn process(_program_id: &Address, accounts: &[AccountView]) -> ProgramResult { + let [event_authority] = accounts else { + return Err(ProgramError::NotEnoughAccountKeys); + }; + + if !event_authority.is_signer() { + return Err(ProgramError::MissingRequiredSignature); + } + + verify_event_authority(event_authority)?; + + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/instructions/finalize.rs b/games/world-cup/pinocchio/program/src/instructions/finalize.rs new file mode 100644 index 000000000..888fdd395 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/finalize.rs @@ -0,0 +1,118 @@ +use pinocchio::{error::ProgramError, AccountView, ProgramResult}; + +use crate::{ + event_engine::{self, EventSerialize}, + events::MarketFinalizedEvent, + instructions::helpers::{check_signer, check_writable}, + state::{ + bracket::Bracket, + common::{verify_bracket_pda, TournamentState}, + config::Config, + oracle::Oracle, + }, + tournament::{closeness, ALL_DECIDED}, + WorldCupError, +}; + +/// Instruction discriminator byte for `Finalize`. +pub const DISCRIMINATOR: &u8 = &6; + +/// Validated accounts for [`Finalize`](crate::WorldCupInstruction::Finalize). +pub struct FinalizeAccounts<'a> { + pub admin: &'a AccountView, + pub config: &'a mut AccountView, + pub oracle: &'a AccountView, + pub bracket: &'a AccountView, + pub event_authority: &'a AccountView, + pub self_program: &'a AccountView, +} + +impl<'a> TryFrom<&'a mut [AccountView]> for FinalizeAccounts<'a> { + type Error = ProgramError; + + fn try_from(accounts: &'a mut [AccountView]) -> Result { + let [admin, config, oracle, bracket, event_authority, self_program] = accounts else { + return Err(WorldCupError::NotEnoughAccountKeys.into()); + }; + + check_signer(admin)?; + check_writable(config)?; + Config::check(config)?; + Oracle::check(oracle)?; + Bracket::check(bracket)?; + + Ok(Self { admin, config, oracle, bracket, event_authority, self_program }) + } +} + +/// Records the unique provable winner and emits a [`MarketFinalizedEvent`]. +/// +/// Trust-minimized: the program proves the passed bracket matches the on-chain best +/// `(score, closeness, index)` key and that every bracket has been folded into the +/// tally at the final state. The submission index makes the key total, so exactly one +/// bracket can match it. +pub fn process(accounts: &mut [AccountView]) -> ProgramResult { + let accounts = FinalizeAccounts::try_from(accounts)?; + + let (best_score, best_closeness, best_index, tally_mask, refreshed_count, entrant_count) = { + let config_data = accounts.config.try_borrow()?; + let config = Config::load(&config_data)?; + config.check_admin(accounts.admin.address())?; + if TournamentState::try_from(config.state)? != TournamentState::Locked { + return Err(WorldCupError::InvalidState.into()); + } + ( + config.best_score, + config.best_closeness, + config.best_index, + config.tally_mask, + config.refreshed_count, + config.entrant_count, + ) + }; + + let total_goals = { + let oracle_data = accounts.oracle.try_borrow()?; + let oracle = Oracle::load(&oracle_data)?; + if !oracle.is_complete() { + return Err(WorldCupError::OracleNotComplete.into()); + } + oracle.total_goals_r32 + }; + + if tally_mask != ALL_DECIDED || refreshed_count != entrant_count { + return Err(WorldCupError::NotFullyRefreshed.into()); + } + + let (winner, bracket_bump, bracket_score, bracket_guess, bracket_tally, bracket_index) = { + let bracket_data = accounts.bracket.try_borrow()?; + let bracket = Bracket::load(&bracket_data)?; + (bracket.owner, bracket.bump, bracket.score, bracket.tiebreaker_guess, bracket.tally_mask, bracket.entry_index) + }; + + let expected_pda = verify_bracket_pda(&winner, bracket_bump)?; + if expected_pda != *accounts.bracket.address() { + return Err(WorldCupError::InvalidBracketPda.into()); + } + + let bracket_closeness = closeness(bracket_guess, total_goals); + if bracket_tally != ALL_DECIDED + || bracket_score != best_score + || bracket_closeness != best_closeness + || bracket_index != best_index + { + return Err(WorldCupError::BracketNotBest.into()); + } + + { + let mut config_data = accounts.config.try_borrow_mut()?; + let config = Config::load_mut(&mut config_data)?; + config.winner = winner; + config.state = TournamentState::Finalized as u8; + } + + let event = MarketFinalizedEvent::new(winner, best_score, best_closeness); + event_engine::emit_event(&crate::ID, accounts.event_authority, accounts.self_program, &event.to_bytes())?; + + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/instructions/helpers/mod.rs b/games/world-cup/pinocchio/program/src/instructions/helpers/mod.rs new file mode 100644 index 000000000..8982a7217 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/helpers/mod.rs @@ -0,0 +1,71 @@ +//! Account validation and PDA creation helpers. + +use pinocchio::{ + cpi::{Seed, Signer}, + error::ProgramError, + sysvars::{rent::Rent, Sysvar}, + AccountView, ProgramResult, +}; +use pinocchio_system::instructions::{Allocate, Assign, CreateAccount, Transfer}; + +use crate::WorldCupError; + +/// Returns an error unless `account` is a transaction signer. +pub fn check_signer(account: &AccountView) -> Result<(), ProgramError> { + if !account.is_signer() { + return Err(WorldCupError::NotSigner.into()); + } + Ok(()) +} + +/// Returns an error unless `account` is marked writable. +pub fn check_writable(account: &AccountView) -> Result<(), ProgramError> { + if !account.is_writable() { + return Err(WorldCupError::AccountNotWritable.into()); + } + Ok(()) +} + +/// Returns an error unless `account` is the System Program. +pub fn check_system_program(account: &AccountView) -> Result<(), ProgramError> { + if account.address().ne(&pinocchio_system::ID) { + return Err(WorldCupError::NotSystemProgram.into()); + } + Ok(()) +} + +/// Creates and allocates a program-owned PDA, funding rent from `payer`. +/// +/// `seeds` must include the bump seed as the final element. Idempotent against a +/// pre-funded PDA address: tops up rent then allocates and assigns. +pub fn create_pda_account(payer: &AccountView, account: &AccountView, seeds: &[Seed], space: usize) -> ProgramResult { + let lamports = Rent::get()?.try_minimum_balance(space)?; + let signer = [Signer::from(seeds)]; + + if account.lamports() == 0 { + CreateAccount { from: payer, to: account, lamports, space: space as u64, owner: &crate::ID } + .invoke_signed(&signer)?; + } else { + let required = lamports.saturating_sub(account.lamports()); + if required > 0 { + Transfer { from: payer, to: account, lamports: required }.invoke()?; + } + Allocate { account, space: space as u64 }.invoke_signed(&signer)?; + Assign { account, owner: &crate::ID }.invoke_signed(&signer)?; + } + + Ok(()) +} + +/// Closes a program-owned `account`, transferring its rent lamports to `destination`, +/// zeroing its data, and reassigning it to the system program. +pub fn close_account(account: &AccountView, destination: &AccountView) -> ProgramResult { + let mut account = *account; + let mut destination = *destination; + + let new_balance = + destination.lamports().checked_add(account.lamports()).ok_or(WorldCupError::ArithmeticOverflow)?; + destination.set_lamports(new_balance); + + account.close() +} diff --git a/games/world-cup/pinocchio/program/src/instructions/init_config.rs b/games/world-cup/pinocchio/program/src/instructions/init_config.rs new file mode 100644 index 000000000..b96752b9d --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/init_config.rs @@ -0,0 +1,128 @@ +use core::mem::{size_of, transmute}; + +use codama::CodamaType; +use pinocchio::{ + cpi::Seed, + error::ProgramError, + sysvars::{clock::Clock, Sysvar}, + AccountView, ProgramResult, +}; + +use crate::{ + event_engine::{self, EventSerialize}, + events::ConfigInitializedEvent, + instructions::helpers::{check_signer, check_system_program, check_writable, create_pda_account}, + state::{ + common::{find_config_pda, find_oracle_pda, find_vault_pda, CONFIG_SEED, ENTRY_FEE, ORACLE_SEED, VAULT_SEED}, + config::Config, + oracle::Oracle, + }, + WorldCupError, +}; + +/// Instruction discriminator byte for `InitConfig`. +pub const DISCRIMINATOR: &u8 = &0; + +/// Instruction data for [`InitConfig`](crate::WorldCupInstruction::InitConfig). +#[repr(C, packed)] +#[derive(CodamaType, Debug, Clone)] +pub struct InitConfigData { + /// Unix timestamp at/after which registration closes and `lock` may be called. + pub lock_ts: i64, +} + +impl InitConfigData { + pub const LEN: usize = size_of::(); + + pub fn load(data: &[u8]) -> Result<&Self, ProgramError> { + if data.len() != Self::LEN { + return Err(WorldCupError::InvalidInstruction.into()); + } + Ok(unsafe { &*transmute::<*const u8, *const Self>(data.as_ptr()) }) + } +} + +/// Validated accounts for [`InitConfig`](crate::WorldCupInstruction::InitConfig). +pub struct InitConfigAccounts<'a> { + pub admin: &'a AccountView, + pub config: &'a mut AccountView, + pub oracle: &'a mut AccountView, + pub vault: &'a AccountView, + pub system_program: &'a AccountView, + pub event_authority: &'a AccountView, + pub self_program: &'a AccountView, +} + +impl<'a> TryFrom<&'a mut [AccountView]> for InitConfigAccounts<'a> { + type Error = ProgramError; + + fn try_from(accounts: &'a mut [AccountView]) -> Result { + let [admin, config, oracle, vault, system_program, event_authority, self_program] = accounts else { + return Err(WorldCupError::NotEnoughAccountKeys.into()); + }; + + check_signer(admin)?; + check_writable(admin)?; + check_writable(config)?; + check_writable(oracle)?; + check_writable(vault)?; + check_system_program(system_program)?; + + Ok(Self { admin, config, oracle, vault, system_program, event_authority, self_program }) + } +} + +/// Creates the singleton config, oracle, and pot vault, and emits a [`ConfigInitializedEvent`]. +pub fn process(accounts: &mut [AccountView], data: &InitConfigData) -> ProgramResult { + let accounts = InitConfigAccounts::try_from(accounts)?; + + let now = Clock::get()?.unix_timestamp; + if data.lock_ts <= now { + return Err(WorldCupError::InvalidLockTs.into()); + } + + if accounts.config.data_len() > 0 { + return Err(WorldCupError::ConfigAlreadyExists.into()); + } + + let (config_pda, config_bump) = find_config_pda(); + if config_pda != *accounts.config.address() { + return Err(WorldCupError::InvalidConfigPda.into()); + } + let (oracle_pda, oracle_bump) = find_oracle_pda(); + if oracle_pda != *accounts.oracle.address() { + return Err(WorldCupError::InvalidOraclePda.into()); + } + let (vault_pda, vault_bump) = find_vault_pda(); + if vault_pda != *accounts.vault.address() { + return Err(WorldCupError::InvalidVaultPda.into()); + } + + let lock_ts = data.lock_ts; + + let config_bump_bytes = [config_bump]; + let config_seeds = [Seed::from(CONFIG_SEED), Seed::from(&config_bump_bytes[..])]; + create_pda_account(accounts.admin, accounts.config, &config_seeds, Config::LEN)?; + + let oracle_bump_bytes = [oracle_bump]; + let oracle_seeds = [Seed::from(ORACLE_SEED), Seed::from(&oracle_bump_bytes[..])]; + create_pda_account(accounts.admin, accounts.oracle, &oracle_seeds, Oracle::LEN)?; + + let vault_bump_bytes = [vault_bump]; + let vault_seeds = [Seed::from(VAULT_SEED), Seed::from(&vault_bump_bytes[..])]; + create_pda_account(accounts.admin, accounts.vault, &vault_seeds, 0)?; + + { + let mut config_data = accounts.config.try_borrow_mut()?; + Config::init(&mut config_data, config_bump, accounts.admin.address(), lock_ts, ENTRY_FEE)?; + } + { + let mut oracle_data = accounts.oracle.try_borrow_mut()?; + Oracle::init(&mut oracle_data, oracle_bump)?; + } + + let event = ConfigInitializedEvent::new(*accounts.admin.address(), lock_ts, ENTRY_FEE); + event_engine::emit_event(&crate::ID, accounts.event_authority, accounts.self_program, &event.to_bytes())?; + + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/instructions/lock.rs b/games/world-cup/pinocchio/program/src/instructions/lock.rs new file mode 100644 index 000000000..064905139 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/lock.rs @@ -0,0 +1,66 @@ +use pinocchio::{ + error::ProgramError, + sysvars::{clock::Clock, Sysvar}, + AccountView, ProgramResult, +}; + +use crate::{ + event_engine::{self, EventSerialize}, + events::TournamentLockedEvent, + instructions::helpers::{check_signer, check_writable}, + state::{common::TournamentState, config::Config}, + WorldCupError, +}; + +/// Instruction discriminator byte for `Lock`. +pub const DISCRIMINATOR: &u8 = &2; + +/// Validated accounts for [`Lock`](crate::WorldCupInstruction::Lock). +pub struct LockAccounts<'a> { + pub admin: &'a AccountView, + pub config: &'a mut AccountView, + pub event_authority: &'a AccountView, + pub self_program: &'a AccountView, +} + +impl<'a> TryFrom<&'a mut [AccountView]> for LockAccounts<'a> { + type Error = ProgramError; + + fn try_from(accounts: &'a mut [AccountView]) -> Result { + let [admin, config, event_authority, self_program] = accounts else { + return Err(WorldCupError::NotEnoughAccountKeys.into()); + }; + + check_signer(admin)?; + check_writable(config)?; + Config::check(config)?; + + Ok(Self { admin, config, event_authority, self_program }) + } +} + +/// Transitions the tournament from registration to locked once `lock_ts` is reached. +pub fn process(accounts: &mut [AccountView]) -> ProgramResult { + let accounts = LockAccounts::try_from(accounts)?; + let now = Clock::get()?.unix_timestamp; + + let lock_ts; + { + let mut config_data = accounts.config.try_borrow_mut()?; + let config = Config::load_mut(&mut config_data)?; + config.check_admin(accounts.admin.address())?; + if TournamentState::try_from(config.state)? != TournamentState::Registration { + return Err(WorldCupError::InvalidState.into()); + } + lock_ts = config.lock_ts; + if now < lock_ts { + return Err(WorldCupError::NotYetLocked.into()); + } + config.state = TournamentState::Locked as u8; + } + + let event = TournamentLockedEvent::new(lock_ts); + event_engine::emit_event(&crate::ID, accounts.event_authority, accounts.self_program, &event.to_bytes())?; + + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/instructions/mod.rs b/games/world-cup/pinocchio/program/src/instructions/mod.rs new file mode 100644 index 000000000..665269157 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/mod.rs @@ -0,0 +1,187 @@ +//! Instruction definitions and dispatch for the world-cup program. +//! +//! Each instruction variant carries its own discriminator (the first byte of +//! instruction data). The Codama annotations on each variant describe the required +//! accounts in positional order. + +pub mod claim; +pub mod close_bracket; +pub mod emit_event; +pub mod finalize; +pub mod helpers; +pub mod init_config; +pub mod lock; +pub mod post_goals; +pub mod post_result; +pub mod refresh_score; +pub mod submit_bracket; + +pub use helpers::*; +pub use init_config::InitConfigData; +pub use post_goals::PostGoalsData; +pub use post_result::PostResultData; +pub use submit_bracket::SubmitBracketData; + +use core::fmt; + +use codama::CodamaInstructions; +use pinocchio::error::ProgramError; + +use crate::event_engine::EMIT_EVENT_IX_DISC; +use crate::WorldCupError; + +/// All instructions supported by the world-cup program. +#[derive(Debug, CodamaInstructions)] +#[repr(u8)] +#[allow(clippy::large_enum_variant)] +pub enum WorldCupInstruction { + #[codama(account(name = "admin", signer, writable, docs = "Tournament admin; funds and owns the config"))] + #[codama(account(name = "config", writable, docs = "Singleton config PDA", default_value = pda("config", [])))] + #[codama(account(name = "oracle", writable, docs = "Singleton oracle PDA", default_value = pda("oracle", [])))] + #[codama(account(name = "vault", writable, docs = "Pot vault PDA", default_value = pda("vault", [])))] + #[codama(account(name = "system_program", docs = "The system program", default_value = program("system")))] + #[codama(account(name = "event_authority", docs = "The event authority PDA", default_value = pda("event_authority", [])))] + #[codama(account( + name = "self_program", + docs = "This program (for self-CPI event emission)", + default_value = public_key("wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA") + ))] + InitConfig(#[codama(name = "init_config_data")] InitConfigData) = 0, + + #[codama(account(name = "entrant", signer, writable, docs = "The entrant submitting and paying for a bracket"))] + #[codama(account(name = "config", writable, docs = "Singleton config PDA", default_value = pda("config", [])))] + #[codama(account( + name = "bracket", + writable, + docs = "The bracket PDA being created", + default_value = pda("bracket", [seed("owner", account("entrant"))]) + ))] + #[codama(account(name = "vault", writable, docs = "Pot vault PDA", default_value = pda("vault", [])))] + #[codama(account(name = "system_program", docs = "The system program", default_value = program("system")))] + #[codama(account(name = "event_authority", docs = "The event authority PDA", default_value = pda("event_authority", [])))] + #[codama(account( + name = "self_program", + docs = "This program (for self-CPI event emission)", + default_value = public_key("wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA") + ))] + SubmitBracket(#[codama(name = "submit_bracket_data")] SubmitBracketData) = 1, + + #[codama(account(name = "admin", signer, docs = "Tournament admin"))] + #[codama(account(name = "config", writable, docs = "Singleton config PDA", default_value = pda("config", [])))] + #[codama(account(name = "event_authority", docs = "The event authority PDA", default_value = pda("event_authority", [])))] + #[codama(account( + name = "self_program", + docs = "This program (for self-CPI event emission)", + default_value = public_key("wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA") + ))] + Lock = 2, + + #[codama(account(name = "admin", signer, docs = "Tournament admin (oracle)"))] + #[codama(account(name = "config", docs = "Singleton config PDA", default_value = pda("config", [])))] + #[codama(account(name = "oracle", writable, docs = "Singleton oracle PDA", default_value = pda("oracle", [])))] + #[codama(account(name = "event_authority", docs = "The event authority PDA", default_value = pda("event_authority", [])))] + #[codama(account( + name = "self_program", + docs = "This program (for self-CPI event emission)", + default_value = public_key("wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA") + ))] + PostResult(#[codama(name = "post_result_data")] PostResultData) = 3, + + #[codama(account(name = "admin", signer, docs = "Tournament admin (oracle)"))] + #[codama(account(name = "config", docs = "Singleton config PDA", default_value = pda("config", [])))] + #[codama(account(name = "oracle", writable, docs = "Singleton oracle PDA", default_value = pda("oracle", [])))] + #[codama(account(name = "event_authority", docs = "The event authority PDA", default_value = pda("event_authority", [])))] + #[codama(account( + name = "self_program", + docs = "This program (for self-CPI event emission)", + default_value = public_key("wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA") + ))] + PostGoals(#[codama(name = "post_goals_data")] PostGoalsData) = 4, + + #[codama(account(name = "config", writable, docs = "Singleton config PDA", default_value = pda("config", [])))] + #[codama(account(name = "oracle", docs = "Singleton oracle PDA", default_value = pda("oracle", [])))] + #[codama(account(name = "bracket", writable, docs = "The bracket PDA being scored"))] + #[codama(account(name = "event_authority", docs = "The event authority PDA", default_value = pda("event_authority", [])))] + #[codama(account( + name = "self_program", + docs = "This program (for self-CPI event emission)", + default_value = public_key("wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA") + ))] + RefreshScore = 5, + + #[codama(account(name = "admin", signer, writable, docs = "Tournament admin"))] + #[codama(account(name = "config", writable, docs = "Singleton config PDA", default_value = pda("config", [])))] + #[codama(account(name = "oracle", docs = "Singleton oracle PDA", default_value = pda("oracle", [])))] + #[codama(account(name = "bracket", docs = "The bracket claimed to be the unique winner"))] + #[codama(account(name = "event_authority", docs = "The event authority PDA", default_value = pda("event_authority", [])))] + #[codama(account( + name = "self_program", + docs = "This program (for self-CPI event emission)", + default_value = public_key("wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA") + ))] + Finalize = 6, + + #[codama(account(name = "winner", signer, writable, docs = "The recorded winner claiming the pot"))] + #[codama(account(name = "config", writable, docs = "Singleton config PDA", default_value = pda("config", [])))] + #[codama(account(name = "vault", writable, docs = "Pot vault PDA", default_value = pda("vault", [])))] + #[codama(account(name = "event_authority", docs = "The event authority PDA", default_value = pda("event_authority", [])))] + #[codama(account( + name = "self_program", + docs = "This program (for self-CPI event emission)", + default_value = public_key("wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA") + ))] + Claim = 7, + + #[codama(account(name = "config", docs = "Singleton config PDA", default_value = pda("config", [])))] + #[codama(account(name = "bracket", writable, docs = "The bracket PDA being closed"))] + #[codama(account(name = "vault", writable, docs = "Pot vault PDA", default_value = pda("vault", [])))] + #[codama(account(name = "event_authority", docs = "The event authority PDA", default_value = pda("event_authority", [])))] + #[codama(account( + name = "self_program", + docs = "This program (for self-CPI event emission)", + default_value = public_key("wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA") + ))] + CloseBracket = 8, + + #[codama(skip)] + #[codama(account(name = "event_authority", signer, docs = "The event authority PDA"))] + EmitEvent = 228, +} + +impl WorldCupInstruction { + /// Parse a `WorldCupInstruction` from raw instruction bytes. + pub fn from_bytes(data: &[u8]) -> Result { + let (discriminator, rest) = data.split_first().ok_or(WorldCupError::InvalidInstruction)?; + + match discriminator { + init_config::DISCRIMINATOR => Ok(Self::InitConfig(InitConfigData::load(rest)?.clone())), + submit_bracket::DISCRIMINATOR => Ok(Self::SubmitBracket(SubmitBracketData::load(rest)?.clone())), + lock::DISCRIMINATOR => Ok(Self::Lock), + post_result::DISCRIMINATOR => Ok(Self::PostResult(PostResultData::load(rest)?.clone())), + post_goals::DISCRIMINATOR => Ok(Self::PostGoals(PostGoalsData::load(rest)?.clone())), + refresh_score::DISCRIMINATOR => Ok(Self::RefreshScore), + finalize::DISCRIMINATOR => Ok(Self::Finalize), + claim::DISCRIMINATOR => Ok(Self::Claim), + close_bracket::DISCRIMINATOR => Ok(Self::CloseBracket), + &EMIT_EVENT_IX_DISC => Ok(Self::EmitEvent), + _ => Err(WorldCupError::InvalidInstruction.into()), + } + } +} + +impl fmt::Display for WorldCupInstruction { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::InitConfig(_) => write!(f, "init_config"), + Self::SubmitBracket(_) => write!(f, "submit_bracket"), + Self::Lock => write!(f, "lock"), + Self::PostResult(_) => write!(f, "post_result"), + Self::PostGoals(_) => write!(f, "post_goals"), + Self::RefreshScore => write!(f, "refresh_score"), + Self::Finalize => write!(f, "finalize"), + Self::Claim => write!(f, "claim"), + Self::CloseBracket => write!(f, "close_bracket"), + Self::EmitEvent => write!(f, "emit_event"), + } + } +} diff --git a/games/world-cup/pinocchio/program/src/instructions/post_goals.rs b/games/world-cup/pinocchio/program/src/instructions/post_goals.rs new file mode 100644 index 000000000..46bf81f37 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/post_goals.rs @@ -0,0 +1,95 @@ +use core::mem::{size_of, transmute}; + +use codama::CodamaType; +use pinocchio::{error::ProgramError, AccountView, ProgramResult}; + +use crate::{ + event_engine::{self, EventSerialize}, + events::GoalsPostedEvent, + instructions::helpers::{check_signer, check_writable}, + state::{common::TournamentState, config::Config, oracle::Oracle}, + tournament::ALL_DECIDED, + WorldCupError, +}; + +/// Instruction discriminator byte for `PostGoals`. +pub const DISCRIMINATOR: &u8 = &4; + +/// Instruction data for [`PostGoals`](crate::WorldCupInstruction::PostGoals). +#[repr(C, packed)] +#[derive(CodamaType, Debug, Clone)] +pub struct PostGoalsData { + /// Actual total goals scored across the Round of 32. + pub total_goals_r32: u16, +} + +impl PostGoalsData { + pub const LEN: usize = size_of::(); + + pub fn load(data: &[u8]) -> Result<&Self, ProgramError> { + if data.len() != Self::LEN { + return Err(WorldCupError::InvalidInstruction.into()); + } + Ok(unsafe { &*transmute::<*const u8, *const Self>(data.as_ptr()) }) + } +} + +/// Validated accounts for [`PostGoals`](crate::WorldCupInstruction::PostGoals). +pub struct PostGoalsAccounts<'a> { + pub admin: &'a AccountView, + pub config: &'a AccountView, + pub oracle: &'a mut AccountView, + pub event_authority: &'a AccountView, + pub self_program: &'a AccountView, +} + +impl<'a> TryFrom<&'a mut [AccountView]> for PostGoalsAccounts<'a> { + type Error = ProgramError; + + fn try_from(accounts: &'a mut [AccountView]) -> Result { + let [admin, config, oracle, event_authority, self_program] = accounts else { + return Err(WorldCupError::NotEnoughAccountKeys.into()); + }; + + check_signer(admin)?; + Config::check(config)?; + check_writable(oracle)?; + Oracle::check(oracle)?; + + Ok(Self { admin, config, oracle, event_authority, self_program }) + } +} + +/// Records the Round-of-32 goal total and emits a [`GoalsPostedEvent`]. +pub fn process(accounts: &mut [AccountView], data: &PostGoalsData) -> ProgramResult { + let accounts = PostGoalsAccounts::try_from(accounts)?; + + { + let config_data = accounts.config.try_borrow()?; + let config = Config::load(&config_data)?; + config.check_admin(accounts.admin.address())?; + if TournamentState::try_from(config.state)? != TournamentState::Locked { + return Err(WorldCupError::InvalidState.into()); + } + } + + let total = data.total_goals_r32; + { + let mut oracle_data = accounts.oracle.try_borrow_mut()?; + let oracle = Oracle::load_mut(&mut oracle_data)?; + if oracle.goals_posted != 0 { + return Err(WorldCupError::GoalsAlreadyPosted.into()); + } + let decided_mask = oracle.decided_mask; + if decided_mask != ALL_DECIDED { + return Err(WorldCupError::OracleNotComplete.into()); + } + oracle.total_goals_r32 = total; + oracle.goals_posted = 1; + } + + let event = GoalsPostedEvent::new(total); + event_engine::emit_event(&crate::ID, accounts.event_authority, accounts.self_program, &event.to_bytes())?; + + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/instructions/post_result.rs b/games/world-cup/pinocchio/program/src/instructions/post_result.rs new file mode 100644 index 000000000..5f2b80e46 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/post_result.rs @@ -0,0 +1,105 @@ +use core::mem::{size_of, transmute}; + +use codama::CodamaType; +use pinocchio::{error::ProgramError, AccountView, ProgramResult}; + +use crate::{ + event_engine::{self, EventSerialize}, + events::ResultPostedEvent, + instructions::helpers::{check_signer, check_writable}, + state::{common::TournamentState, config::Config, oracle::Oracle}, + tournament::{validate_result, GAME_COUNT, UNDECIDED}, + WorldCupError, +}; + +/// Instruction discriminator byte for `PostResult`. +pub const DISCRIMINATOR: &u8 = &3; + +/// Instruction data for [`PostResult`](crate::WorldCupInstruction::PostResult). +#[repr(C, packed)] +#[derive(CodamaType, Debug, Clone)] +pub struct PostResultData { + /// Game index `0..32`. + pub game: u8, + /// Winning team (positional id `0..32`). + pub winner: u8, +} + +impl PostResultData { + pub const LEN: usize = size_of::(); + + pub fn load(data: &[u8]) -> Result<&Self, ProgramError> { + if data.len() != Self::LEN { + return Err(WorldCupError::InvalidInstruction.into()); + } + Ok(unsafe { &*transmute::<*const u8, *const Self>(data.as_ptr()) }) + } +} + +/// Validated accounts for [`PostResult`](crate::WorldCupInstruction::PostResult). +pub struct PostResultAccounts<'a> { + pub admin: &'a AccountView, + pub config: &'a AccountView, + pub oracle: &'a mut AccountView, + pub event_authority: &'a AccountView, + pub self_program: &'a AccountView, +} + +impl<'a> TryFrom<&'a mut [AccountView]> for PostResultAccounts<'a> { + type Error = ProgramError; + + fn try_from(accounts: &'a mut [AccountView]) -> Result { + let [admin, config, oracle, event_authority, self_program] = accounts else { + return Err(WorldCupError::NotEnoughAccountKeys.into()); + }; + + check_signer(admin)?; + Config::check(config)?; + check_writable(oracle)?; + Oracle::check(oracle)?; + + Ok(Self { admin, config, oracle, event_authority, self_program }) + } +} + +/// Records a single game result on the oracle and emits a [`ResultPostedEvent`]. +pub fn process(accounts: &mut [AccountView], data: &PostResultData) -> ProgramResult { + let accounts = PostResultAccounts::try_from(accounts)?; + + { + let config_data = accounts.config.try_borrow()?; + let config = Config::load(&config_data)?; + config.check_admin(accounts.admin.address())?; + if TournamentState::try_from(config.state)? != TournamentState::Locked { + return Err(WorldCupError::InvalidState.into()); + } + } + + let game = data.game; + let winner = data.winner; + + let decided_mask; + { + let mut oracle_data = accounts.oracle.try_borrow_mut()?; + let oracle = Oracle::load_mut(&mut oracle_data)?; + + if (game as usize) >= GAME_COUNT { + return Err(WorldCupError::InvalidGame.into()); + } + if oracle.results[game as usize] != UNDECIDED { + return Err(WorldCupError::ResultAlreadyPosted.into()); + } + + validate_result(&oracle.results, game, winner)?; + + oracle.results[game as usize] = winner; + let current_mask = oracle.decided_mask; + decided_mask = current_mask | (1u32 << game); + oracle.decided_mask = decided_mask; + } + + let event = ResultPostedEvent::new(game, winner, decided_mask); + event_engine::emit_event(&crate::ID, accounts.event_authority, accounts.self_program, &event.to_bytes())?; + + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/instructions/refresh_score.rs b/games/world-cup/pinocchio/program/src/instructions/refresh_score.rs new file mode 100644 index 000000000..249d3f9fb --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/refresh_score.rs @@ -0,0 +1,114 @@ +use pinocchio::{error::ProgramError, AccountView, ProgramResult}; + +use crate::{ + event_engine::{self, EventSerialize}, + events::ScoreRefreshedEvent, + instructions::helpers::check_writable, + state::{bracket::Bracket, common::TournamentState, config::Config, oracle::Oracle}, + tournament::{closeness, score_bracket, ALL_DECIDED}, + WorldCupError, +}; + +/// Instruction discriminator byte for `RefreshScore`. +pub const DISCRIMINATOR: &u8 = &5; + +/// Validated accounts for [`RefreshScore`](crate::WorldCupInstruction::RefreshScore). +pub struct RefreshScoreAccounts<'a> { + pub config: &'a mut AccountView, + pub oracle: &'a AccountView, + pub bracket: &'a mut AccountView, + pub event_authority: &'a AccountView, + pub self_program: &'a AccountView, +} + +impl<'a> TryFrom<&'a mut [AccountView]> for RefreshScoreAccounts<'a> { + type Error = ProgramError; + + fn try_from(accounts: &'a mut [AccountView]) -> Result { + let [config, oracle, bracket, event_authority, self_program] = accounts else { + return Err(WorldCupError::NotEnoughAccountKeys.into()); + }; + + check_writable(config)?; + Config::check(config)?; + Oracle::check(oracle)?; + check_writable(bracket)?; + Bracket::check(bracket)?; + + Ok(Self { config, oracle, bracket, event_authority, self_program }) + } +} + +/// Scores a bracket against the oracle and, once the oracle is complete, folds it +/// exactly once into the provable global tally. Permissionless and idempotent. +pub fn process(accounts: &mut [AccountView]) -> ProgramResult { + let accounts = RefreshScoreAccounts::try_from(accounts)?; + + { + let config_data = accounts.config.try_borrow()?; + let config = Config::load(&config_data)?; + if TournamentState::try_from(config.state)? != TournamentState::Locked { + return Err(WorldCupError::InvalidState.into()); + } + } + + let (results, total_goals) = { + let oracle_data = accounts.oracle.try_borrow()?; + let oracle = Oracle::load(&oracle_data)?; + if !oracle.is_complete() { + return Err(WorldCupError::OracleNotComplete.into()); + } + (oracle.results, oracle.total_goals_r32) + }; + + let owner; + let score; + { + let mut bracket_data = accounts.bracket.try_borrow_mut()?; + let bracket = Bracket::load_mut(&mut bracket_data)?; + + if bracket.tally_mask == ALL_DECIDED { + return Err(WorldCupError::AlreadyFolded.into()); + } + + score = score_bracket(&bracket.picks, &results); + bracket.score = score; + owner = bracket.owner; + + let guess = bracket.tiebreaker_guess; + let close = closeness(guess, total_goals); + let index = bracket.entry_index; + + let mut config_data = accounts.config.try_borrow_mut()?; + let config = Config::load_mut(&mut config_data)?; + + let config_tally_mask = config.tally_mask; + if config_tally_mask != ALL_DECIDED { + config.best_score = 0; + config.best_closeness = u16::MAX; + config.best_index = u32::MAX; + config.refreshed_count = 0; + config.tally_mask = ALL_DECIDED; + } + + let best_score = config.best_score; + let best_closeness = config.best_closeness; + let best_index = config.best_index; + let better = score > best_score + || (score == best_score && close < best_closeness) + || (score == best_score && close == best_closeness && index < best_index); + if better { + config.best_score = score; + config.best_closeness = close; + config.best_index = index; + } + bracket.tally_mask = ALL_DECIDED; + let refreshed = config.refreshed_count; + config.refreshed_count = refreshed.checked_add(1).ok_or(WorldCupError::ArithmeticOverflow)?; + } + + let event = ScoreRefreshedEvent::new(owner, score); + event_engine::emit_event(&crate::ID, accounts.event_authority, accounts.self_program, &event.to_bytes())?; + + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/instructions/submit_bracket.rs b/games/world-cup/pinocchio/program/src/instructions/submit_bracket.rs new file mode 100644 index 000000000..f8a570a49 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/instructions/submit_bracket.rs @@ -0,0 +1,152 @@ +use core::mem::{size_of, transmute}; + +use codama::CodamaType; +use pinocchio::{ + cpi::Seed, + error::ProgramError, + sysvars::{clock::Clock, rent::Rent, Sysvar}, + AccountView, ProgramResult, +}; +use pinocchio_system::instructions::Transfer; + +use crate::{ + event_engine::{self, EventSerialize}, + events::BracketSubmittedEvent, + instructions::helpers::{check_signer, check_system_program, check_writable}, + state::{ + bracket::Bracket, + common::{find_bracket_pda, find_vault_pda, TournamentState, BRACKET_SEED}, + config::Config, + }, + tournament::validate_bracket, + WorldCupError, +}; + +/// Instruction discriminator byte for `SubmitBracket`. +pub const DISCRIMINATOR: &u8 = &1; + +/// Instruction data for [`SubmitBracket`](crate::WorldCupInstruction::SubmitBracket). +#[repr(C, packed)] +#[derive(CodamaType, Debug, Clone)] +pub struct SubmitBracketData { + /// Winner pick per game (positional team id `0..32`). + pub picks: [u8; 32], + /// Predicted total Round-of-32 goals (tiebreaker guess). + pub tiebreaker_guess: u16, +} + +impl SubmitBracketData { + pub const LEN: usize = size_of::(); + + pub fn load(data: &[u8]) -> Result<&Self, ProgramError> { + if data.len() != Self::LEN { + return Err(WorldCupError::InvalidInstruction.into()); + } + Ok(unsafe { &*transmute::<*const u8, *const Self>(data.as_ptr()) }) + } +} + +/// Validated accounts for [`SubmitBracket`](crate::WorldCupInstruction::SubmitBracket). +pub struct SubmitBracketAccounts<'a> { + pub entrant: &'a AccountView, + pub config: &'a mut AccountView, + pub bracket: &'a mut AccountView, + pub vault: &'a AccountView, + pub system_program: &'a AccountView, + pub event_authority: &'a AccountView, + pub self_program: &'a AccountView, +} + +impl<'a> TryFrom<&'a mut [AccountView]> for SubmitBracketAccounts<'a> { + type Error = ProgramError; + + fn try_from(accounts: &'a mut [AccountView]) -> Result { + let [entrant, config, bracket, vault, system_program, event_authority, self_program] = accounts else { + return Err(WorldCupError::NotEnoughAccountKeys.into()); + }; + + check_signer(entrant)?; + check_writable(entrant)?; + check_writable(config)?; + Config::check(config)?; + check_writable(bracket)?; + check_writable(vault)?; + check_system_program(system_program)?; + + Ok(Self { entrant, config, bracket, vault, system_program, event_authority, self_program }) + } +} + +/// Creates a [`Bracket`] for the entrant, escrows the stake, and emits a [`BracketSubmittedEvent`]. +pub fn process(accounts: &mut [AccountView], data: &SubmitBracketData) -> ProgramResult { + let accounts = SubmitBracketAccounts::try_from(accounts)?; + let now = Clock::get()?.unix_timestamp; + + let entry_fee; + let entry_index; + { + let config_data = accounts.config.try_borrow()?; + let config = Config::load(&config_data)?; + if TournamentState::try_from(config.state)? != TournamentState::Registration { + return Err(WorldCupError::InvalidState.into()); + } + let lock_ts = config.lock_ts; + if now >= lock_ts { + return Err(WorldCupError::RegistrationClosed.into()); + } + entry_fee = config.entry_fee; + entry_index = config.entrant_count; + } + + if accounts.bracket.data_len() > 0 { + return Err(WorldCupError::BracketAlreadyExists.into()); + } + + let (bracket_pda, bump) = find_bracket_pda(accounts.entrant.address()); + if bracket_pda != *accounts.bracket.address() { + return Err(WorldCupError::InvalidBracketPda.into()); + } + + if find_vault_pda().0 != *accounts.vault.address() { + return Err(WorldCupError::InvalidVaultPda.into()); + } + + validate_bracket(&data.picks)?; + + let bracket_rent = Rent::get()?.try_minimum_balance(Bracket::LEN)?; + let pot_contribution = entry_fee.checked_sub(bracket_rent).ok_or(WorldCupError::ArithmeticOverflow)?; + + let bump_bytes = [bump]; + let seeds = + [Seed::from(BRACKET_SEED), Seed::from(accounts.entrant.address().as_ref()), Seed::from(&bump_bytes[..])]; + crate::instructions::helpers::create_pda_account(accounts.entrant, accounts.bracket, &seeds, Bracket::LEN)?; + + Transfer { from: accounts.entrant, to: accounts.vault, lamports: pot_contribution }.invoke()?; + + { + let mut bracket_data = accounts.bracket.try_borrow_mut()?; + Bracket::init( + &mut bracket_data, + bump, + accounts.entrant.address(), + &data.picks, + data.tiebreaker_guess, + entry_index, + )?; + } + + let entrant_count; + { + let mut config_data = accounts.config.try_borrow_mut()?; + let config = Config::load_mut(&mut config_data)?; + let current = config.entrant_count; + entrant_count = current.checked_add(1).ok_or(WorldCupError::ArithmeticOverflow)?; + config.entrant_count = entrant_count; + } + + let event = + BracketSubmittedEvent::new(*accounts.entrant.address(), entrant_count, data.tiebreaker_guess, data.picks); + event_engine::emit_event(&crate::ID, accounts.event_authority, accounts.self_program, &event.to_bytes())?; + + Ok(()) +} diff --git a/games/world-cup/pinocchio/program/src/lib.rs b/games/world-cup/pinocchio/program/src/lib.rs new file mode 100644 index 000000000..ad43fdf83 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/lib.rs @@ -0,0 +1,55 @@ +//! World Cup Solana Program. +//! +//! A bracket-prediction game starting at the Round of 32. Entrants pay a fixed fee +//! to submit a consistency-checked bracket; an admin oracle records results; a +//! permissionless, idempotent `refresh_score` folds each bracket into a provable +//! global tally; the unique winner claims the pot. The ranking key is total +//! (score, then goal-closeness, then earliest submission), so a winner always exists. +//! +//! Built on the [Pinocchio](https://docs.rs/pinocchio) runtime; uses +//! [Codama](https://github.com/codama-idl/codama) for IDL generation. + +#![no_std] + +extern crate alloc; + +#[cfg(test)] +#[macro_use] +extern crate std; + +use pinocchio::address::declare_id; + +pub mod errors; +pub use errors::*; + +pub mod event_engine; +pub mod events; + +pub mod instructions; +pub use instructions::*; + +pub mod state; +pub use state::*; + +pub mod tournament; +pub use tournament::*; + +#[cfg(not(feature = "no-entrypoint"))] +pub mod entrypoint; + +#[cfg(test)] +mod tests; + +declare_id!("wCupoZtR1g1NXRRVELe5KqFgayyEteVKKxEerxugvxA"); + +#[cfg(not(feature = "no-entrypoint"))] +use solana_security_txt::security_txt; + +#[cfg(not(feature = "no-entrypoint"))] +security_txt! { + name: "World Cup Program", + project_url: "https://github.com/solana-foundation/world-cup", + contacts: "link:https://github.com/solana-foundation/world-cup/security/advisories/new", + policy: "https://github.com/solana-foundation/world-cup/security/policy", + source_code: "https://github.com/solana-foundation/world-cup" +} diff --git a/games/world-cup/pinocchio/program/src/state/bracket.rs b/games/world-cup/pinocchio/program/src/state/bracket.rs new file mode 100644 index 000000000..3ead0b6f9 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/state/bracket.rs @@ -0,0 +1,104 @@ +//! Per-wallet bracket account: the entrant's 32 picks, tiebreaker, and cached score. + +use codama::CodamaAccount; +use core::mem::{size_of, transmute}; +use pinocchio::{error::ProgramError, AccountView, Address}; + +use crate::{state::common::AccountDiscriminator, tournament::GAME_COUNT, WorldCupError}; + +/// One entrant's bracket. +/// +/// `score` is the cached weighted score from the last `refresh_score`. `tally_mask` +/// is the oracle `decided_mask` this bracket was last folded into the global tally +/// at, making the fold idempotent (a bracket already folded at the current mask is +/// skipped) and self-invalidating when the oracle advances. +/// +/// **PDA seeds:** `["bracket", owner]` +#[repr(C, packed)] +#[derive(CodamaAccount)] +#[codama(seed(type = string(utf8), value = "bracket"))] +#[codama(seed(name = "owner", type = public_key))] +pub struct Bracket { + /// Account type discriminator ([`AccountDiscriminator::Bracket`]). + pub discriminator: u8, + /// PDA bump seed. + pub bump: u8, + /// Wallet that submitted (and owns) this bracket. + pub owner: Address, + /// Winner pick per game (positional team id `0..32`). + pub picks: [u8; 32], + /// Predicted total Round-of-32 goals (tiebreaker guess). + pub tiebreaker_guess: u16, + /// Cached weighted score from the last refresh. + pub score: u16, + /// Oracle `decided_mask` this bracket was last folded into the tally at. + pub tally_mask: u32, + /// Zero-based submission order, assigned at submit. Final ranking tiebreaker. + pub entry_index: u32, +} + +impl Bracket { + /// Total serialized size in bytes. + pub const LEN: usize = size_of::(); + + /// PDA seed prefix. + pub const SEED: &'static [u8] = b"bracket"; + + /// Initializes a freshly created account. + #[inline(always)] + pub fn init( + bytes: &mut [u8], + bump: u8, + owner: &Address, + picks: &[u8; GAME_COUNT], + tiebreaker_guess: u16, + entry_index: u32, + ) -> Result<(), ProgramError> { + if bytes.len() != Self::LEN { + return Err(WorldCupError::InvalidAccountData.into()); + } + let account = unsafe { &mut *transmute::<*mut u8, *mut Self>(bytes.as_mut_ptr()) }; + account.discriminator = AccountDiscriminator::Bracket as u8; + account.bump = bump; + account.owner = *owner; + account.picks = *picks; + account.tiebreaker_guess = tiebreaker_guess; + account.score = 0; + account.tally_mask = 0; + account.entry_index = entry_index; + Ok(()) + } + + /// Deserializes a mutable reference from raw account data. + #[inline(always)] + pub fn load_mut(bytes: &mut [u8]) -> Result<&mut Self, ProgramError> { + Self::validate(bytes)?; + Ok(unsafe { &mut *transmute::<*mut u8, *mut Self>(bytes.as_mut_ptr()) }) + } + + /// Deserializes an immutable reference from raw account data. + #[inline(always)] + pub fn load(bytes: &[u8]) -> Result<&Self, ProgramError> { + Self::validate(bytes)?; + Ok(unsafe { &*transmute::<*const u8, *const Self>(bytes.as_ptr()) }) + } + + /// Verifies an account is a genuine bracket: owned by this program, correctly + /// sized, and carrying the bracket discriminator. Call in account validation. + pub fn check(account: &AccountView) -> Result<(), ProgramError> { + if !account.owned_by(&crate::ID) { + return Err(WorldCupError::NotProgramOwned.into()); + } + Self::validate(&account.try_borrow()?) + } + + fn validate(bytes: &[u8]) -> Result<(), ProgramError> { + if bytes.len() != Self::LEN { + return Err(WorldCupError::InvalidAccountData.into()); + } + if bytes[0] != AccountDiscriminator::Bracket as u8 { + return Err(WorldCupError::InvalidAccountDiscriminator.into()); + } + Ok(()) + } +} diff --git a/games/world-cup/pinocchio/program/src/state/common.rs b/games/world-cup/pinocchio/program/src/state/common.rs new file mode 100644 index 000000000..c6b5d2e60 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/state/common.rs @@ -0,0 +1,101 @@ +//! Shared account discriminator, tournament state, PDA seeds, and derivation helpers. + +use codama::CodamaType; +use pinocchio::{error::ProgramError, Address}; + +use crate::WorldCupError; + +/// Entry fee per bracket, in lamports (0.1 SOL). Covers the bracket account rent; +/// the remainder is escrowed into the pot vault. +pub const ENTRY_FEE: u64 = 100_000_000; + +/// PDA seed for the singleton config account. +pub const CONFIG_SEED: &[u8] = b"config"; +/// PDA seed for the singleton oracle account. +pub const ORACLE_SEED: &[u8] = b"oracle"; +/// PDA seed for the singleton pot vault. +pub const VAULT_SEED: &[u8] = b"vault"; +/// PDA seed prefix for per-wallet bracket accounts. +pub const BRACKET_SEED: &[u8] = b"bracket"; + +/// One-byte discriminator identifying the type of a program-owned account. +/// +/// Stored at byte offset 0 of every data-carrying account created by this program. +#[repr(u8)] +#[derive(Clone, Copy, PartialEq, Debug, CodamaType)] +pub enum AccountDiscriminator { + /// [`Config`](super::config::Config) account. + Config = 0, + /// [`Oracle`](super::oracle::Oracle) account. + Oracle = 1, + /// [`Bracket`](super::bracket::Bracket) account. + Bracket = 2, +} + +impl TryFrom for AccountDiscriminator { + type Error = ProgramError; + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::Config), + 1 => Ok(Self::Oracle), + 2 => Ok(Self::Bracket), + _ => Err(WorldCupError::InvalidAccountDiscriminator.into()), + } + } +} + +impl From for u8 { + fn from(val: AccountDiscriminator) -> Self { + val as u8 + } +} + +/// Lifecycle state of the tournament, stored in [`Config`](super::config::Config). +#[repr(u8)] +#[derive(Clone, Copy, PartialEq, Debug, CodamaType)] +pub enum TournamentState { + /// Accepting new brackets. + Registration = 0, + /// Kickoff passed: no new brackets; oracle posting + scoring. + Locked = 1, + /// Winner set (or tie routed to admin); claim phase. + Finalized = 2, +} + +impl TryFrom for TournamentState { + type Error = ProgramError; + fn try_from(value: u8) -> Result { + match value { + 0 => Ok(Self::Registration), + 1 => Ok(Self::Locked), + 2 => Ok(Self::Finalized), + _ => Err(WorldCupError::InvalidState.into()), + } + } +} + +/// Finds the singleton config PDA and bump. +pub fn find_config_pda() -> (Address, u8) { + Address::find_program_address(&[CONFIG_SEED], &crate::ID) +} + +/// Finds the singleton oracle PDA and bump. +pub fn find_oracle_pda() -> (Address, u8) { + Address::find_program_address(&[ORACLE_SEED], &crate::ID) +} + +/// Finds the singleton pot vault PDA and bump. +pub fn find_vault_pda() -> (Address, u8) { + Address::find_program_address(&[VAULT_SEED], &crate::ID) +} + +/// Finds the bracket PDA and bump for a wallet. +pub fn find_bracket_pda(owner: &Address) -> (Address, u8) { + Address::find_program_address(&[BRACKET_SEED, owner.as_ref()], &crate::ID) +} + +/// Verifies a bracket PDA by re-deriving with the given owner and bump. +pub fn verify_bracket_pda(owner: &Address, bump: u8) -> Result { + Address::create_program_address(&[BRACKET_SEED, owner.as_ref(), &[bump]], &crate::ID) + .map_err(|_| WorldCupError::InvalidBracketPda.into()) +} diff --git a/games/world-cup/pinocchio/program/src/state/config.rs b/games/world-cup/pinocchio/program/src/state/config.rs new file mode 100644 index 000000000..cd55adc6c --- /dev/null +++ b/games/world-cup/pinocchio/program/src/state/config.rs @@ -0,0 +1,123 @@ +//! Singleton config account: tournament admin, lifecycle state, and the global tally. + +use codama::CodamaAccount; +use core::mem::{size_of, transmute}; +use pinocchio::{error::ProgramError, AccountView, Address}; + +use crate::{ + state::common::{AccountDiscriminator, TournamentState}, + WorldCupError, +}; + +/// The singleton tournament config and provable global tally. +/// +/// `best_score`/`best_closeness`/`best_index` form the on-chain ranking key: the +/// highest score, tiebroken by the smallest `|guess - actual_goals|`, and finally by +/// the smallest submission index (earliest entrant wins). Because the index is unique +/// per bracket, the key is total — exactly one bracket can match it. The key is only +/// meaningful once the oracle is complete and `refreshed_count == entrant_count`. +/// +/// **PDA seeds:** `["config"]` +#[repr(C, packed)] +#[derive(CodamaAccount)] +#[codama(seed(type = string(utf8), value = "config"))] +pub struct Config { + /// Account type discriminator ([`AccountDiscriminator::Config`]). + pub discriminator: u8, + /// PDA bump seed. + pub bump: u8, + /// Current [`TournamentState`]. + pub state: u8, + /// Authority that posts oracle results and finalizes. + pub admin: Address, + /// Unix timestamp at/after which registration closes and `lock` may be called. + pub lock_ts: i64, + /// Entry fee per bracket, in lamports. + pub entry_fee: u64, + /// Number of brackets submitted. + pub entrant_count: u32, + /// Number of brackets folded into the tally at [`tally_mask`](Self::tally_mask). + pub refreshed_count: u32, + /// `decided_mask` the current tally corresponds to (0 until the first fold). + pub tally_mask: u32, + /// Best (highest) weighted score seen. + pub best_score: u16, + /// Tiebreaker closeness of the best key (smaller is better). + pub best_closeness: u16, + /// Submission index of the best key (smaller is better; final tiebreaker). + pub best_index: u32, + /// Recorded unique winner (zeroed until `finalize`). + pub winner: Address, +} + +impl Config { + /// Total serialized size in bytes. + pub const LEN: usize = size_of::(); + + /// PDA seed prefix. + pub const SEED: &'static [u8] = b"config"; + + /// Initializes a freshly created account. + #[inline(always)] + pub fn init(bytes: &mut [u8], bump: u8, admin: &Address, lock_ts: i64, entry_fee: u64) -> Result<(), ProgramError> { + if bytes.len() != Self::LEN { + return Err(WorldCupError::InvalidAccountData.into()); + } + let account = unsafe { &mut *transmute::<*mut u8, *mut Self>(bytes.as_mut_ptr()) }; + account.discriminator = AccountDiscriminator::Config as u8; + account.bump = bump; + account.state = TournamentState::Registration as u8; + account.admin = *admin; + account.lock_ts = lock_ts; + account.entry_fee = entry_fee; + account.entrant_count = 0; + account.refreshed_count = 0; + account.tally_mask = 0; + account.best_score = 0; + account.best_closeness = u16::MAX; + account.best_index = u32::MAX; + account.winner = Address::default(); + Ok(()) + } + + /// Deserializes a mutable reference from raw account data. + #[inline(always)] + pub fn load_mut(bytes: &mut [u8]) -> Result<&mut Self, ProgramError> { + Self::validate(bytes)?; + Ok(unsafe { &mut *transmute::<*mut u8, *mut Self>(bytes.as_mut_ptr()) }) + } + + /// Deserializes an immutable reference from raw account data. + #[inline(always)] + pub fn load(bytes: &[u8]) -> Result<&Self, ProgramError> { + Self::validate(bytes)?; + Ok(unsafe { &*transmute::<*const u8, *const Self>(bytes.as_ptr()) }) + } + + /// Verifies an account is a genuine config: owned by this program, correctly + /// sized, and carrying the config discriminator. Call in account validation. + pub fn check(account: &AccountView) -> Result<(), ProgramError> { + if !account.owned_by(&crate::ID) { + return Err(WorldCupError::NotProgramOwned.into()); + } + Self::validate(&account.try_borrow()?) + } + + fn validate(bytes: &[u8]) -> Result<(), ProgramError> { + if bytes.len() != Self::LEN { + return Err(WorldCupError::InvalidAccountData.into()); + } + if bytes[0] != AccountDiscriminator::Config as u8 { + return Err(WorldCupError::InvalidAccountDiscriminator.into()); + } + Ok(()) + } + + /// Asserts `signer` is the recorded admin. + pub fn check_admin(&self, signer: &Address) -> Result<(), ProgramError> { + if self.admin != *signer { + return Err(WorldCupError::Unauthorized.into()); + } + Ok(()) + } +} diff --git a/games/world-cup/pinocchio/program/src/state/mod.rs b/games/world-cup/pinocchio/program/src/state/mod.rs new file mode 100644 index 000000000..9d163cfcf --- /dev/null +++ b/games/world-cup/pinocchio/program/src/state/mod.rs @@ -0,0 +1,20 @@ +//! On-chain account state types for the world-cup program. +//! +//! Each data-carrying account is stored as a packed C struct in a Program Derived +//! Account (PDA), with a one-byte discriminator at offset 0. The pot [`Vault`] is a +//! zero-data PDA. + +pub mod bracket; +pub mod common; +pub mod config; +pub mod oracle; +pub mod vault; + +pub use bracket::Bracket; +pub use common::{ + find_bracket_pda, find_config_pda, find_oracle_pda, find_vault_pda, verify_bracket_pda, AccountDiscriminator, + TournamentState, ENTRY_FEE, +}; +pub use config::Config; +pub use oracle::Oracle; +pub use vault::Vault; diff --git a/games/world-cup/pinocchio/program/src/state/oracle.rs b/games/world-cup/pinocchio/program/src/state/oracle.rs new file mode 100644 index 000000000..1b81c2957 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/state/oracle.rs @@ -0,0 +1,99 @@ +//! Singleton oracle account: admin-posted game results and Round-of-32 goal total. + +use codama::CodamaAccount; +use core::mem::{size_of, transmute}; +use pinocchio::{error::ProgramError, AccountView}; + +use crate::{ + state::common::AccountDiscriminator, + tournament::{ALL_DECIDED, GAME_COUNT, UNDECIDED}, + WorldCupError, +}; + +/// The singleton oracle: the recorded truth of the tournament. +/// +/// `results[g]` is the winning team of game `g`, or [`UNDECIDED`] until posted. +/// Results are immutable once set. `total_goals_r32` is posted separately (it is not +/// derivable from winners) and drives the tiebreaker. +/// +/// **PDA seeds:** `["oracle"]` +#[repr(C, packed)] +#[derive(CodamaAccount)] +#[codama(seed(type = string(utf8), value = "oracle"))] +pub struct Oracle { + /// Account type discriminator ([`AccountDiscriminator::Oracle`]). + pub discriminator: u8, + /// PDA bump seed. + pub bump: u8, + /// `1` once [`total_goals_r32`](Self::total_goals_r32) has been posted. + pub goals_posted: u8, + /// Winning team per game; [`UNDECIDED`] until posted. + pub results: [u8; 32], + /// Bitmap of decided games; `ALL_DECIDED` when every game is in. + pub decided_mask: u32, + /// Actual total goals scored across the Round of 32 (the tiebreaker target). + pub total_goals_r32: u16, +} + +impl Oracle { + /// Total serialized size in bytes. + pub const LEN: usize = size_of::(); + + /// PDA seed prefix. + pub const SEED: &'static [u8] = b"oracle"; + + /// Initializes a freshly created account with all games undecided. + #[inline(always)] + pub fn init(bytes: &mut [u8], bump: u8) -> Result<(), ProgramError> { + if bytes.len() != Self::LEN { + return Err(WorldCupError::InvalidAccountData.into()); + } + let account = unsafe { &mut *transmute::<*mut u8, *mut Self>(bytes.as_mut_ptr()) }; + account.discriminator = AccountDiscriminator::Oracle as u8; + account.bump = bump; + account.goals_posted = 0; + account.results = [UNDECIDED; GAME_COUNT]; + account.decided_mask = 0; + account.total_goals_r32 = 0; + Ok(()) + } + + /// Deserializes a mutable reference from raw account data. + #[inline(always)] + pub fn load_mut(bytes: &mut [u8]) -> Result<&mut Self, ProgramError> { + Self::validate(bytes)?; + Ok(unsafe { &mut *transmute::<*mut u8, *mut Self>(bytes.as_mut_ptr()) }) + } + + /// Deserializes an immutable reference from raw account data. + #[inline(always)] + pub fn load(bytes: &[u8]) -> Result<&Self, ProgramError> { + Self::validate(bytes)?; + Ok(unsafe { &*transmute::<*const u8, *const Self>(bytes.as_ptr()) }) + } + + /// Verifies an account is a genuine oracle: owned by this program, correctly + /// sized, and carrying the oracle discriminator. Call in account validation. + pub fn check(account: &AccountView) -> Result<(), ProgramError> { + if !account.owned_by(&crate::ID) { + return Err(WorldCupError::NotProgramOwned.into()); + } + Self::validate(&account.try_borrow()?) + } + + fn validate(bytes: &[u8]) -> Result<(), ProgramError> { + if bytes.len() != Self::LEN { + return Err(WorldCupError::InvalidAccountData.into()); + } + if bytes[0] != AccountDiscriminator::Oracle as u8 { + return Err(WorldCupError::InvalidAccountDiscriminator.into()); + } + Ok(()) + } + + /// Whether every game is decided and the goal total has been posted. + #[inline] + pub fn is_complete(&self) -> bool { + self.decided_mask == ALL_DECIDED && self.goals_posted != 0 + } +} diff --git a/games/world-cup/pinocchio/program/src/state/vault.rs b/games/world-cup/pinocchio/program/src/state/vault.rs new file mode 100644 index 000000000..9027a0260 --- /dev/null +++ b/games/world-cup/pinocchio/program/src/state/vault.rs @@ -0,0 +1,12 @@ +//! Pot vault marker for client PDA derivation. + +use codama::CodamaAccount; + +/// The pot vault — a program-owned, zero-data PDA that escrows pooled entry +/// lamports. It carries no account data; this marker exists only so the generated +/// client can derive its address. +/// +/// **PDA seeds:** `["vault"]` +#[derive(CodamaAccount)] +#[codama(seed(type = string(utf8), value = "vault"))] +pub struct Vault; diff --git a/games/world-cup/pinocchio/program/src/tests.rs b/games/world-cup/pinocchio/program/src/tests.rs new file mode 100644 index 000000000..8c4da20fb --- /dev/null +++ b/games/world-cup/pinocchio/program/src/tests.rs @@ -0,0 +1,182 @@ +//! Host unit tests for pure (runtime-independent) logic. + +use pinocchio::Address; + +use crate::{ + event_engine::{event_authority_pda, EVENT_AUTHORITY_SEED}, + state::{bracket::Bracket, common::AccountDiscriminator, config::Config, oracle::Oracle}, + tournament::{ + children, closeness, r32_slots, round_of, score_bracket, third_place_slots, validate_bracket, validate_result, + Round, GAME_COUNT, UNDECIDED, + }, + WorldCupError, +}; + +/// A "chalk" bracket where the lower-id team always advances. Champion is team 0. +fn chalk_bracket() -> [u8; GAME_COUNT] { + let mut p = [0u8; GAME_COUNT]; + for g in 0..16u8 { + p[g as usize] = 2 * g; + } + for g in 16..=30u8 { + let (c0, c1) = children(g); + p[g as usize] = p[c0 as usize].min(p[c1 as usize]); + } + let (l0, l1) = third_place_slots(&p); + p[31] = l0.min(l1); + p +} + +#[test] +fn account_discriminator_maps_known_values_and_rejects_unknown() { + assert_eq!(AccountDiscriminator::try_from(0u8).unwrap(), AccountDiscriminator::Config); + assert_eq!(AccountDiscriminator::try_from(1u8).unwrap(), AccountDiscriminator::Oracle); + assert_eq!(AccountDiscriminator::try_from(2u8).unwrap(), AccountDiscriminator::Bracket); + assert!(AccountDiscriminator::try_from(3u8).is_err()); +} + +#[test] +fn account_sizes_are_fixed() { + assert_eq!(Config::LEN, 103); + assert_eq!(Oracle::LEN, 41); + assert_eq!(Bracket::LEN, 78); +} + +#[test] +fn round_of_partitions_all_games() { + assert_eq!(round_of(0), Round::R32); + assert_eq!(round_of(15), Round::R32); + assert_eq!(round_of(16), Round::R16); + assert_eq!(round_of(23), Round::R16); + assert_eq!(round_of(24), Round::Qf); + assert_eq!(round_of(27), Round::Qf); + assert_eq!(round_of(28), Round::Sf); + assert_eq!(round_of(29), Round::Sf); + assert_eq!(round_of(30), Round::Final); + assert_eq!(round_of(31), Round::ThirdPlace); +} + +#[test] +fn tree_topology_matches_prd() { + assert_eq!(children(16), (0, 1)); + assert_eq!(children(23), (14, 15)); + assert_eq!(children(24), (16, 17)); + assert_eq!(children(28), (24, 25)); + assert_eq!(children(30), (28, 29)); + assert_eq!(r32_slots(0), (0, 1)); + assert_eq!(r32_slots(15), (30, 31)); +} + +#[test] +fn chalk_bracket_is_consistent() { + let p = chalk_bracket(); + assert!(validate_bracket(&p).is_ok()); + assert_eq!(p[30], 0, "chalk champion is team 0"); +} + +#[test] +fn rejects_pick_out_of_range() { + let mut p = chalk_bracket(); + p[0] = 99; + assert!(matches!(validate_bracket(&p), Err(WorldCupError::InvalidPick))); +} + +#[test] +fn rejects_r32_pick_not_in_its_two_slots() { + let mut p = chalk_bracket(); + // game 0 is contested by teams 0,1; team 5 cannot win it. + p[0] = 5; + assert!(matches!(validate_bracket(&p), Err(WorldCupError::InvalidPick))); +} + +#[test] +fn rejects_advancing_a_team_that_was_not_advanced_from_a_feeder() { + let mut p = chalk_bracket(); + // game 16 is fed by games 0,1 (teams 0 and 2 under chalk); team 8 never reached it. + p[16] = 8; + assert!(matches!(validate_bracket(&p), Err(WorldCupError::InvalidPick))); +} + +#[test] +fn rejects_third_place_pick_that_is_not_a_semifinal_loser() { + let mut p = chalk_bracket(); + let (l0, l1) = third_place_slots(&p); + // pick a team that is neither semifinal loser. + let bogus = (0..32u8).find(|t| *t != l0 && *t != l1).unwrap(); + p[31] = bogus; + assert!(matches!(validate_bracket(&p), Err(WorldCupError::InvalidPick))); +} + +#[test] +fn result_requires_feeders_decided_first() { + let results = [UNDECIDED; GAME_COUNT]; + // game 16 feeds from 0,1 which are still undecided. + assert!(matches!(validate_result(&results, 16, 0), Err(WorldCupError::FeederNotDecided))); +} + +#[test] +fn result_rejects_winner_not_in_contest() { + let results = [UNDECIDED; GAME_COUNT]; + // game 0 is teams 0,1; team 4 cannot win it. + assert!(matches!(validate_result(&results, 0, 4), Err(WorldCupError::InvalidResult))); +} + +#[test] +fn result_accepts_consistent_chain() { + let mut results = [UNDECIDED; GAME_COUNT]; + assert!(validate_result(&results, 0, 0).is_ok()); + results[0] = 0; + assert!(validate_result(&results, 1, 2).is_ok()); + results[1] = 2; + // game 16 fed by 0,1 → winner must be 0 or 2. + assert!(validate_result(&results, 16, 0).is_ok()); + assert!(matches!(validate_result(&results, 16, 1), Err(WorldCupError::InvalidResult))); +} + +#[test] +fn score_is_weighted_sum_of_correct_picks() { + let chalk = chalk_bracket(); + // Full chalk results: lower team wins every game. + let results = chalk; + // 16*1 + 8*2 + 4*4 + 2*8 + 1*16 + 1*8 = 16+16+16+16+16+8 = 88. + assert_eq!(score_bracket(&chalk, &results), 88); +} + +#[test] +fn score_ignores_undecided_and_wrong_picks() { + let chalk = chalk_bracket(); + let mut results = [UNDECIDED; GAME_COUNT]; + // Only the Round of 32 is decided, all chalk → 16 points. + results[..16].copy_from_slice(&chalk[..16]); + assert_eq!(score_bracket(&chalk, &results), 16); + + // Flip the final's result so the champion pick is wrong: lose the 16-pt game. + let mut full = chalk; + let mut full_results = chalk; + full_results[30] = 1; // some other finalist won + full[30] = 0; + assert_eq!(score_bracket(&full, &full_results), 88 - 16); +} + +#[test] +fn closeness_is_absolute_difference() { + assert_eq!(closeness(10, 7), 3); + assert_eq!(closeness(7, 10), 3); + assert_eq!(closeness(5, 5), 0); +} + +#[test] +fn event_authority_pda_is_off_curve_with_valid_bump() { + let (expected, bump) = Address::find_program_address(&[EVENT_AUTHORITY_SEED], &crate::ID); + assert_eq!(event_authority_pda::ID, expected); + assert_eq!(event_authority_pda::BUMP, bump); +} + +#[test] +fn error_codes_are_stable() { + assert_eq!(WorldCupError::try_from(100).unwrap() as u32, WorldCupError::NotSigner as u32); + assert_eq!(WorldCupError::try_from(202).unwrap() as u32, WorldCupError::Unauthorized as u32); + assert_eq!(WorldCupError::try_from(302).unwrap() as u32, WorldCupError::InvalidPick as u32); + assert_eq!(WorldCupError::try_from(503).unwrap() as u32, WorldCupError::BracketNotBest as u32); + assert!(WorldCupError::try_from(999).is_err()); +} diff --git a/games/world-cup/pinocchio/program/src/tournament.rs b/games/world-cup/pinocchio/program/src/tournament.rs new file mode 100644 index 000000000..12a49d21c --- /dev/null +++ b/games/world-cup/pinocchio/program/src/tournament.rs @@ -0,0 +1,166 @@ +//! Pure tournament logic: bracket tree topology, scoring, and consistency rules. +//! +//! Runtime-independent and `no_std`-friendly so it can be unit-tested on the host. +//! The bracket is a perfect binary tree stored leaves-first (Round of 32 at indices +//! `0..=15`), plus a third-place playoff at index `31` contested by the two semifinal +//! losers. Real-world team names are a client concern — on-chain a team is just a +//! positional id `0..32`. + +use crate::WorldCupError; + +/// Total games: 31 knockout games + the third-place playoff. +pub const GAME_COUNT: usize = 32; + +/// Number of competing teams (positional identities `0..32`). +pub const TEAM_COUNT: u8 = 32; + +/// `decided_mask`/`tally_mask` value once all 32 games are recorded. +pub const ALL_DECIDED: u32 = u32::MAX; + +/// Sentinel for an undecided game result in the oracle. +pub const UNDECIDED: u8 = 0xFF; + +/// Index of the third-place playoff game. +pub const THIRD_PLACE_GAME: u8 = 31; + +/// Round a game belongs to. Derived from the game index, never stored. +#[derive(Clone, Copy, PartialEq, Debug)] +#[repr(u8)] +pub enum Round { + R32 = 0, + R16 = 1, + Qf = 2, + Sf = 3, + Final = 4, + ThirdPlace = 5, +} + +/// Per-round score weight (classic doubling); the third-place playoff is a bonus +/// game weighted like a semifinal. Index by `round_of(game) as usize`. +pub const ROUND_WEIGHT: [u16; 6] = [1, 2, 4, 8, 16, 8]; + +/// The round a game index belongs to. +#[inline] +pub fn round_of(game: u8) -> Round { + match game { + 0..=15 => Round::R32, + 16..=23 => Round::R16, + 24..=27 => Round::Qf, + 28..=29 => Round::Sf, + 30 => Round::Final, + 31 => Round::ThirdPlace, + _ => Round::Final, + } +} + +/// The two feeder games for a non-leaf knockout game (`g` in `16..=30`). +#[inline] +pub fn children(g: u8) -> (u8, u8) { + let base = (g - 16) * 2; + (base, base + 1) +} + +/// The two team slots contesting a Round-of-32 game (`g` in `0..=15`). +#[inline] +pub fn r32_slots(g: u8) -> (u8, u8) { + (2 * g, 2 * g + 1) +} + +/// The two competitors of the third-place game: the losers of the two semifinals. +/// +/// SF game 28 has children `(24,25)`; SF game 29 has children `(26,27)`. The loser +/// of a semifinal is the child winner that the semifinal pick did *not* advance. +/// For any bracket that passes [`validate_bracket`], `slots[24] != slots[25]` and +/// `slots[26] != slots[27]` (winners come from disjoint subtrees), so each loser is +/// unambiguous. Works identically on a picks array or an oracle results array. +#[inline] +pub fn third_place_slots(slots: &[u8; GAME_COUNT]) -> (u8, u8) { + let loser_28 = if slots[28] == slots[24] { slots[25] } else { slots[24] }; + let loser_29 = if slots[29] == slots[26] { slots[27] } else { slots[26] }; + (loser_28, loser_29) +} + +/// Verifies a full bracket is internally consistent: every pick is a team that the +/// bracket itself advanced from one of the game's two feeders. +pub fn validate_bracket(picks: &[u8; GAME_COUNT]) -> Result<(), WorldCupError> { + for (g, &pick) in picks.iter().enumerate() { + if pick >= TEAM_COUNT { + return Err(WorldCupError::InvalidPick); + } + let g = g as u8; + if g < 16 { + let (a, b) = r32_slots(g); + if pick != a && pick != b { + return Err(WorldCupError::InvalidPick); + } + } else if g <= 30 { + let (c0, c1) = children(g); + if pick != picks[c0 as usize] && pick != picks[c1 as usize] { + return Err(WorldCupError::InvalidPick); + } + } else { + let (l0, l1) = third_place_slots(picks); + if pick != l0 && pick != l1 { + return Err(WorldCupError::InvalidPick); + } + } + } + Ok(()) +} + +/// Verifies a single oracle result is consistent with the already-decided feeders, +/// enforcing that feeder games are posted before the games they feed. +/// +/// `results` is the current oracle array (with [`UNDECIDED`] for unposted games). +pub fn validate_result(results: &[u8; GAME_COUNT], game: u8, winner: u8) -> Result<(), WorldCupError> { + if game as usize >= GAME_COUNT { + return Err(WorldCupError::InvalidGame); + } + if winner >= TEAM_COUNT { + return Err(WorldCupError::InvalidResult); + } + if game < 16 { + let (a, b) = r32_slots(game); + if winner != a && winner != b { + return Err(WorldCupError::InvalidResult); + } + } else if game <= 30 { + let (c0, c1) = children(game); + let f0 = results[c0 as usize]; + let f1 = results[c1 as usize]; + if f0 == UNDECIDED || f1 == UNDECIDED { + return Err(WorldCupError::FeederNotDecided); + } + if winner != f0 && winner != f1 { + return Err(WorldCupError::InvalidResult); + } + } else { + for feeder in [24u8, 25, 26, 27, 28, 29] { + if results[feeder as usize] == UNDECIDED { + return Err(WorldCupError::FeederNotDecided); + } + } + let (l0, l1) = third_place_slots(results); + if winner != l0 && winner != l1 { + return Err(WorldCupError::InvalidResult); + } + } + Ok(()) +} + +/// Sums a bracket's weighted score against the decided games in `results`. +pub fn score_bracket(picks: &[u8; GAME_COUNT], results: &[u8; GAME_COUNT]) -> u16 { + let mut score = 0u16; + for g in 0..GAME_COUNT { + if results[g] != UNDECIDED && picks[g] == results[g] { + score += ROUND_WEIGHT[round_of(g as u8) as usize]; + } + } + score +} + +/// Absolute difference between a tiebreaker guess and the actual Round-of-32 goal total. +#[inline] +pub fn closeness(guess: u16, actual: u16) -> u16 { + guess.abs_diff(actual) +} diff --git a/games/world-cup/pinocchio/rust-toolchain.toml b/games/world-cup/pinocchio/rust-toolchain.toml new file mode 100644 index 000000000..50b3f5d47 --- /dev/null +++ b/games/world-cup/pinocchio/rust-toolchain.toml @@ -0,0 +1,2 @@ +[toolchain] +channel = "1.92" diff --git a/games/world-cup/pinocchio/rustfmt.toml b/games/world-cup/pinocchio/rustfmt.toml new file mode 100644 index 000000000..5e1292f3e --- /dev/null +++ b/games/world-cup/pinocchio/rustfmt.toml @@ -0,0 +1,5 @@ +edition = "2021" +max_width = 120 +tab_spaces = 4 +use_small_heuristics = "Max" +reorder_imports = true diff --git a/games/world-cup/pinocchio/scripts/create-bracket.ts b/games/world-cup/pinocchio/scripts/create-bracket.ts new file mode 100644 index 000000000..5d59332bc --- /dev/null +++ b/games/world-cup/pinocchio/scripts/create-bracket.ts @@ -0,0 +1,147 @@ +/** + * Demo: submits a full, consistency-checked 32-game bracket on-chain. + * + * Real-world teams are mapped onto the program's positional team ids (0..31). + * The bracket is simulated by team strength, with one thumb on the scale: the + * USA wins every game it plays and lifts the trophy. 🇺🇸 + * + * Env: + * ENTRANT - entrant keypair secret as a JSON [u8] array (defaults to ADMIN) + * ADMIN - admin keypair secret as a JSON [u8] array (fallback entrant) + * RPC_URL - cluster endpoint (default: http://127.0.0.1:8899) + */ + +import { createClient, createKeyPairSignerFromBytes } from '@solana/kit'; +import { solanaRpc } from '@solana/kit-plugin-rpc'; +import { signer } from '@solana/kit-plugin-signer'; +import { getSubmitBracketInstructionAsync } from '@solana/world-cup'; + +const RPC_URL = process.env.RPC_URL ?? 'http://127.0.0.1:8899'; + +const THIRD_PLACE_GAME = 31; +const USA = 'USA'; + +/** + * 32 teams in seeded slot order (slot 0 is the strongest bracket position). + * The USA sits in slot 0 so its path to the final is the top line of the tree. + * `strength` breaks every other game; higher wins. + */ +const TEAMS: { name: string; strength: number }[] = [ + { name: USA, strength: 999 }, // slot 0 — host, destined champion + { name: 'Ghana', strength: 71 }, + { name: 'Argentina', strength: 96 }, + { name: 'Australia', strength: 74 }, + { name: 'France', strength: 95 }, + { name: 'Ecuador', strength: 77 }, + { name: 'England', strength: 92 }, + { name: 'Senegal', strength: 80 }, + { name: 'Brazil', strength: 94 }, + { name: 'South Korea', strength: 76 }, + { name: 'Portugal', strength: 91 }, + { name: 'Japan', strength: 81 }, + { name: 'Spain', strength: 93 }, + { name: 'Morocco', strength: 84 }, + { name: 'Netherlands', strength: 90 }, + { name: 'Mexico', strength: 79 }, + { name: 'Germany', strength: 89 }, + { name: 'Uruguay', strength: 82 }, + { name: 'Belgium', strength: 88 }, + { name: 'Switzerland', strength: 78 }, + { name: 'Croatia', strength: 87 }, + { name: 'Denmark', strength: 83 }, + { name: 'Italy', strength: 86 }, + { name: 'Canada', strength: 72 }, + { name: 'Colombia', strength: 85 }, + { name: 'Poland', strength: 73 }, + { name: 'Norway', strength: 80 }, + { name: 'Nigeria', strength: 75 }, + { name: 'Austria', strength: 79 }, + { name: 'Serbia', strength: 74 }, + { name: 'Ivory Coast', strength: 70 }, + { name: 'Saudi Arabia', strength: 68 }, // slot 31 +]; + +const FINAL_GAME = 30; +const usaSlot = TEAMS.findIndex(t => t.name === USA); + +/** Team in a slot; throws on an out-of-range id so the result is never undefined. */ +function team(slot: number): { name: string; strength: number } { + const t = TEAMS[slot]; + if (!t) throw new Error(`no team in slot ${slot}`); + return t; +} + +/** Two R32 slots contesting game `g` (0..15). */ +const r32Slots = (g: number): [number, number] => [2 * g, 2 * g + 1]; + +/** Two feeder games for a non-leaf knockout game (16..30). */ +const children = (g: number): [number, number] => [(g - 16) * 2, (g - 16) * 2 + 1]; + +/** The team that should win a contest between two slots: USA always, else strength. */ +function winner(a: number, b: number): number { + if (a === usaSlot || b === usaSlot) return usaSlot; + return team(a).strength >= team(b).strength ? a : b; +} + +/** Winning slot of any knockout game (0..30), computed down the tree. */ +function advance(game: number): number { + if (game < 16) { + const [a, b] = r32Slots(game); + return winner(a, b); + } + const [c0, c1] = children(game); + return winner(advance(c0), advance(c1)); +} + +/** Loser of a semifinal: the feeder winner the semifinal did not advance. */ +function semifinalLoser(sf: number): number { + const [c0, c1] = children(sf); + const w0 = advance(c0); + const w1 = advance(c1); + return winner(w0, w1) === w0 ? w1 : w0; +} + +/** Builds a fully consistent bracket where the USA wins it all. */ +function buildPicks(): number[] { + const picks: number[] = []; + for (let g = 0; g <= FINAL_GAME; g++) picks.push(advance(g)); + picks[THIRD_PLACE_GAME] = winner(semifinalLoser(28), semifinalLoser(29)); + return picks; +} + +function entrantSecret(): Uint8Array { + const raw = process.env.ENTRANT ?? process.env.ADMIN; + if (!raw) throw new Error('ENTRANT (or ADMIN) env var is required (JSON [u8] array of the keypair secret)'); + return Uint8Array.from(JSON.parse(raw) as number[]); +} + +async function main() { + const entrant = await createKeyPairSignerFromBytes(entrantSecret()); + const client = createClient() + .use(signer(entrant)) + .use(solanaRpc({ rpcUrl: RPC_URL })); + + const picks = buildPicks(); + const tiebreakerGuess = 84; // predicted Round-of-32 total goals + + const champion = advance(FINAL_GAME); + console.log(`Entrant: ${entrant.address}`); + console.log(`RPC: ${RPC_URL}`); + console.log(`Champion: ${team(champion).name} 🏆`); + console.log(`Final: ${team(champion).name} def. ${team(semifinalLoser(29)).name}`); + console.log(`3rd: ${team(winner(semifinalLoser(28), semifinalLoser(29))).name}`); + console.log(`Tiebreaker (R32 goals): ${tiebreakerGuess}`); + + const instruction = await getSubmitBracketInstructionAsync({ + entrant, + submitBracketData: { picks, tiebreakerGuess }, + }); + + const { context } = await client.sendTransaction([instruction]); + console.log(`Bracket submitted: ${context.signature}`); +} + +main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/games/world-cup/pinocchio/scripts/generate-clients.ts b/games/world-cup/pinocchio/scripts/generate-clients.ts new file mode 100644 index 000000000..1389d0113 --- /dev/null +++ b/games/world-cup/pinocchio/scripts/generate-clients.ts @@ -0,0 +1,34 @@ +import type { AnchorIdl } from '@codama/nodes-from-anchor'; +import { renderVisitor as renderJavaScriptVisitor } from '@codama/renderers-js'; +import { renderVisitor as renderRustVisitor } from '@codama/renderers-rust'; +import { createFromJson } from 'codama'; +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +const projectRoot = path.join(__dirname, '..'); +const idlPath = path.join(projectRoot, 'idl', 'world_cup.json'); +const idl = JSON.parse(fs.readFileSync(idlPath, 'utf-8')) as AnchorIdl; +const rustClientsDir = path.join(projectRoot, 'clients', 'rust'); +const typescriptClientsDir = path.join(projectRoot, 'clients', 'typescript'); + +const codama = createFromJson(JSON.stringify(idl)); + +void codama.accept( + renderRustVisitor(rustClientsDir, { + anchorTraits: false, + deleteFolderBeforeRendering: true, + formatCode: true, + generatedFolder: 'src/generated', + }), +); + +void codama.accept( + renderJavaScriptVisitor(typescriptClientsDir, { + deleteFolderBeforeRendering: true, + formatCode: true, + generatedFolder: 'src/generated', + }), +); diff --git a/games/world-cup/pinocchio/scripts/generate-ts-client.ts b/games/world-cup/pinocchio/scripts/generate-ts-client.ts new file mode 100644 index 000000000..7d61aecd1 --- /dev/null +++ b/games/world-cup/pinocchio/scripts/generate-ts-client.ts @@ -0,0 +1,25 @@ +import type { AnchorIdl } from '@codama/nodes-from-anchor'; +import { renderVisitor as renderJavaScriptVisitor } from '@codama/renderers-js'; +import { createFromJson } from 'codama'; +import fs from 'fs'; +import path from 'path'; +import { fileURLToPath } from 'url'; + +const __dirname = path.dirname(fileURLToPath(import.meta.url)); + +const projectRoot = path.join(__dirname, '..'); +const idlPath = path.join(projectRoot, 'idl', 'world_cup.json'); +const idl = JSON.parse(fs.readFileSync(idlPath, 'utf-8')) as AnchorIdl; +const typescriptClientsDir = path.join(projectRoot, 'clients', 'typescript'); + +const codama = createFromJson(JSON.stringify(idl)); + +await Promise.resolve( + codama.accept( + renderJavaScriptVisitor(typescriptClientsDir, { + deleteFolderBeforeRendering: true, + formatCode: true, + generatedFolder: 'src/generated', + }), + ), +); diff --git a/games/world-cup/pinocchio/scripts/init.ts b/games/world-cup/pinocchio/scripts/init.ts new file mode 100644 index 000000000..3235ab53d --- /dev/null +++ b/games/world-cup/pinocchio/scripts/init.ts @@ -0,0 +1,49 @@ +/** + * Initializes the World Cup config, oracle, and vault on-chain. + * + * Env: + * ADMIN - admin keypair secret as a JSON [u8] array (64 bytes) + * RPC_URL - cluster endpoint (default: http://127.0.0.1:8899) + */ + +import { createClient, createKeyPairSignerFromBytes } from '@solana/kit'; +import { solanaRpc } from '@solana/kit-plugin-rpc'; +import { signer } from '@solana/kit-plugin-signer'; +import { getInitConfigInstructionAsync } from '@solana/world-cup'; + +const RPC_URL = process.env.RPC_URL ?? 'http://127.0.0.1:8899'; + +const REGISTRATION_WINDOW_SECONDS = 5 * 24 * 60 * 60; + +function adminSecret(): Uint8Array { + const raw = process.env.ADMIN; + if (!raw) throw new Error('ADMIN env var is required (JSON [u8] array of the keypair secret)'); + return Uint8Array.from(JSON.parse(raw) as number[]); +} + +function lockTs(): bigint { + return BigInt(Math.floor(Date.now() / 1000) + REGISTRATION_WINDOW_SECONDS); +} + +async function main() { + const admin = await createKeyPairSignerFromBytes(adminSecret()); + const client = createClient() + .use(signer(admin)) + .use(solanaRpc({ rpcUrl: RPC_URL })); + + console.log(`Admin: ${admin.address}`); + console.log(`RPC: ${RPC_URL}`); + + const instruction = await getInitConfigInstructionAsync({ + admin, + initConfigData: { lockTs: lockTs() }, + }); + + const { context } = await client.sendTransaction([instruction]); + console.log(`Config initialized: ${context.signature}`); +} + +main().catch(err => { + console.error(err); + process.exit(1); +}); diff --git a/games/world-cup/pinocchio/tests/integration-tests/Cargo.toml b/games/world-cup/pinocchio/tests/integration-tests/Cargo.toml new file mode 100644 index 000000000..095030c8e --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/Cargo.toml @@ -0,0 +1,24 @@ +[package] +name = "tests-world-cup" +version = { workspace = true } +edition = { workspace = true } +license = { workspace = true } +repository = { workspace = true } + +[lints] +workspace = true + +[dependencies] +world_cup = { package = "world-cup-program", path = "../../program", features = ["no-entrypoint"] } +litesvm = "^0.12" +serde_json = "1" +solana-account = "~3.4" +solana-clock = "^3" +solana-instruction = "^3" +solana-keypair = "=3.1.0" +solana-message = "^3.1" +solana-native-token = "^3" +solana-pubkey = "^4" +solana-signer = "^3" +solana-transaction = "^3" +solana-transaction-error = "^3.2" diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/lib.rs b/games/world-cup/pinocchio/tests/integration-tests/src/lib.rs new file mode 100644 index 000000000..46acdc091 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/lib.rs @@ -0,0 +1,32 @@ +pub use world_cup::*; + +pub mod utils; + +pub mod tests { + pub use crate::utils::{asserts, constants, idl, pda}; + + pub mod utils { + pub use crate::utils::test_helpers::*; + } +} + +#[cfg(test)] +mod test_account_meta; +#[cfg(test)] +mod test_claim; +#[cfg(test)] +mod test_close_bracket; +#[cfg(test)] +mod test_finalize; +#[cfg(test)] +mod test_init_config; +#[cfg(test)] +mod test_lock; +#[cfg(test)] +mod test_post_goals; +#[cfg(test)] +mod test_post_result; +#[cfg(test)] +mod test_refresh_score; +#[cfg(test)] +mod test_submit_bracket; diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/test_account_meta.rs b/games/world-cup/pinocchio/tests/integration-tests/src/test_account_meta.rs new file mode 100644 index 000000000..2ff4ee588 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/test_account_meta.rs @@ -0,0 +1,66 @@ +use solana_instruction::{AccountMeta, Instruction}; +use solana_pubkey::Pubkey; +use solana_signer::Signer; + +use crate::{ + tests::{ + asserts::TransactionResultExt, + constants::{EVENT_AUTHORITY, PROGRAM_ID, SYSTEM_PROGRAM_ID}, + idl, + pda::{get_config_pda, get_oracle_pda, get_vault_pda}, + utils::{build_and_send, funded_keypair, setup, LOCK_TS}, + }, + WorldCupError, +}; + +fn init_config_metas(admin: &Pubkey) -> Vec { + let (config, _) = get_config_pda(); + let (oracle, _) = get_oracle_pda(); + let (vault, _) = get_vault_pda(); + vec![ + AccountMeta::new(*admin, true), + AccountMeta::new(config, false), + AccountMeta::new(oracle, false), + AccountMeta::new(vault, false), + AccountMeta::new_readonly(SYSTEM_PROGRAM_ID, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ] +} + +fn init_config_data() -> Vec { + let mut data = vec![0u8]; + data.extend_from_slice(&LOCK_TS.to_le_bytes()); + data +} + +#[test] +fn idl_writable_accounts_are_enforced() { + let writable: Vec = + idl::instruction_accounts("initConfig").into_iter().filter(|a| a.is_writable).collect(); + assert!(!writable.is_empty(), "IDL declares writable accounts"); + + for account in writable { + if account.index == 0 { + continue; // admin is the fee payer: runtime forces it writable, can't demote + } + let (mut litesvm, admin) = setup(); + let mut metas = init_config_metas(&admin.pubkey()); + let demoted = &metas[account.index]; + metas[account.index] = AccountMeta::new_readonly(demoted.pubkey, demoted.is_signer); + let ix = Instruction { program_id: PROGRAM_ID, accounts: metas, data: init_config_data() }; + build_and_send(&mut litesvm, &[&admin], &admin.pubkey(), &ix).assert_err(WorldCupError::AccountNotWritable); + } +} + +#[test] +fn admin_must_sign_init_config() { + let (mut litesvm, admin) = setup(); + let fee_payer = funded_keypair(&mut litesvm); + + let mut metas = init_config_metas(&admin.pubkey()); + metas[0] = AccountMeta::new(admin.pubkey(), false); // admin present but not a signer + let ix = Instruction { program_id: PROGRAM_ID, accounts: metas, data: init_config_data() }; + + build_and_send(&mut litesvm, &[&fee_payer], &fee_payer.pubkey(), &ix).assert_err(WorldCupError::NotSigner); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/test_claim.rs b/games/world-cup/pinocchio/tests/integration-tests/src/test_claim.rs new file mode 100644 index 000000000..ddad5c5ae --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/test_claim.rs @@ -0,0 +1,117 @@ +use solana_account::Account; +use solana_instruction::{AccountMeta, Instruction}; +use solana_keypair::Keypair; +use solana_signer::Signer; + +use crate::{ + tests::{ + asserts::TransactionResultExt, + constants::{EVENT_AUTHORITY, PROGRAM_ID, SYSTEM_PROGRAM_ID}, + pda::get_vault_pda, + utils::{ + build_and_send, chalk_bracket, claim, finalize, funded_keypair, init_config, lock, post_full_chalk_oracle, + refresh_score, set_unix_timestamp, setup, submit_bracket, vault_balance, LOCK_TS, + }, + }, + Config, WorldCupError, +}; + +/// Runs a single-entrant tournament through finalize; returns the winner keypair. +fn finalized_single_winner(litesvm: &mut litesvm::LiteSVM, admin: &Keypair) -> Keypair { + init_config(litesvm, admin, LOCK_TS).assert_ok(); + let winner = funded_keypair(litesvm); + submit_bracket(litesvm, &winner, &chalk_bracket(), 87).0.assert_ok(); + set_unix_timestamp(litesvm, LOCK_TS); + lock(litesvm, admin).assert_ok(); + post_full_chalk_oracle(litesvm, admin, 87); + let cranker = funded_keypair(litesvm); + refresh_score(litesvm, &cranker, &winner.pubkey()).assert_ok(); + finalize(litesvm, admin, &winner.pubkey()).assert_ok(); + winner +} + +#[test] +fn winner_claims_the_whole_pot() { + let (mut litesvm, admin) = setup(); + let winner = finalized_single_winner(&mut litesvm, &admin); + + let pot = vault_balance(&litesvm); + assert!(pot > 0); + let before = litesvm.get_balance(&winner.pubkey()).unwrap(); + + claim(&mut litesvm, &winner).assert_ok(); + + let after = litesvm.get_balance(&winner.pubkey()).unwrap(); + assert!(after > before, "winner received the pot"); + let remaining = vault_balance(&litesvm); + assert!(remaining > 0 && remaining < pot, "vault swept down to its rent floor"); +} + +#[test] +fn non_winner_cannot_claim() { + let (mut litesvm, admin) = setup(); + let _winner = finalized_single_winner(&mut litesvm, &admin); + + let stranger = funded_keypair(&mut litesvm); + claim(&mut litesvm, &stranger).assert_err(WorldCupError::NotWinner); +} + +#[test] +fn claim_is_repeatable() { + let (mut litesvm, admin) = setup(); + let winner = finalized_single_winner(&mut litesvm, &admin); + + claim(&mut litesvm, &winner).assert_ok(); + let after_first = litesvm.get_balance(&winner.pubkey()).unwrap(); + // Vault is already swept to its floor; a second claim sweeps ~nothing but still succeeds. + claim(&mut litesvm, &winner).assert_ok(); + let after_second = litesvm.get_balance(&winner.pubkey()).unwrap(); + assert!(after_second <= after_first, "second claim pays no additional pot"); +} + +#[test] +fn counterfeit_config_is_rejected() { + let (mut litesvm, admin) = setup(); + let _winner = finalized_single_winner(&mut litesvm, &admin); + let pot_before = vault_balance(&litesvm); + assert!(pot_before > 0); + + let attacker = funded_keypair(&mut litesvm); + let fake_config = Keypair::new(); + let mut data = vec![0u8; Config::LEN]; + data[2] = 2; // wire offset: state = TournamentState::Finalized + data[71..103].copy_from_slice(&attacker.pubkey().to_bytes()); // wire offset: winner + litesvm + .set_account( + fake_config.pubkey(), + Account { lamports: 1_000_000, data, owner: SYSTEM_PROGRAM_ID, executable: false, rent_epoch: 0 }, + ) + .unwrap(); + + let (vault, _) = get_vault_pda(); + let accounts = vec![ + AccountMeta::new(attacker.pubkey(), true), + AccountMeta::new(fake_config.pubkey(), false), + AccountMeta::new(vault, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ]; + let ix = Instruction { program_id: PROGRAM_ID, accounts, data: vec![*crate::claim::DISCRIMINATOR] }; + build_and_send(&mut litesvm, &[&attacker], &attacker.pubkey(), &ix).assert_err(WorldCupError::NotProgramOwned); + + assert_eq!(vault_balance(&litesvm), pot_before, "pot untouched"); +} + +#[test] +fn cannot_claim_before_finalize() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 87).0.assert_ok(); + set_unix_timestamp(&mut litesvm, LOCK_TS); + lock(&mut litesvm, &admin).assert_ok(); + post_full_chalk_oracle(&mut litesvm, &admin, 87); + + claim(&mut litesvm, &entrant).assert_err(WorldCupError::InvalidState); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/test_close_bracket.rs b/games/world-cup/pinocchio/tests/integration-tests/src/test_close_bracket.rs new file mode 100644 index 000000000..bd9f680c1 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/test_close_bracket.rs @@ -0,0 +1,64 @@ +use solana_keypair::Keypair; +use solana_signer::Signer; + +use crate::{ + tests::{ + asserts::TransactionResultExt, + pda::get_bracket_pda, + utils::{ + chalk_bracket, chalk_bracket_wrong_third, close_bracket, finalize, funded_keypair, init_config, lock, + post_full_chalk_oracle, refresh_score, set_unix_timestamp, setup, submit_bracket, vault_balance, LOCK_TS, + }, + }, + WorldCupError, +}; + +/// Winner (perfect chalk) + loser (misses third place), oracle posted, both refreshed, +/// winner finalized. +fn finalized_winner_and_loser(litesvm: &mut litesvm::LiteSVM, admin: &Keypair) -> (Keypair, Keypair) { + init_config(litesvm, admin, LOCK_TS).assert_ok(); + let winner = funded_keypair(litesvm); + let loser = funded_keypair(litesvm); + submit_bracket(litesvm, &winner, &chalk_bracket(), 87).0.assert_ok(); + submit_bracket(litesvm, &loser, &chalk_bracket_wrong_third(), 87).0.assert_ok(); + set_unix_timestamp(litesvm, LOCK_TS); + lock(litesvm, admin).assert_ok(); + post_full_chalk_oracle(litesvm, admin, 87); + let cranker = funded_keypair(litesvm); + refresh_score(litesvm, &cranker, &winner.pubkey()).assert_ok(); + refresh_score(litesvm, &cranker, &loser.pubkey()).assert_ok(); + finalize(litesvm, admin, &winner.pubkey()).assert_ok(); + (winner, loser) +} + +#[test] +fn close_bracket_rolls_rent_into_pot() { + let (mut litesvm, admin) = setup(); + let (_winner, loser) = finalized_winner_and_loser(&mut litesvm, &admin); + + let (bracket_pda, _) = get_bracket_pda(&loser.pubkey()); + assert!(litesvm.get_account(&bracket_pda).is_some()); + let vault_before = vault_balance(&litesvm); + + // Permissionless: any cranker can close any bracket once finalized. + let cranker = funded_keypair(&mut litesvm); + close_bracket(&mut litesvm, &cranker, &loser.pubkey()).assert_ok(); + + assert!(vault_balance(&litesvm) > vault_before, "rent rolled into the pot"); + let after = litesvm.get_account(&bracket_pda); + assert!(after.is_none() || after.unwrap().lamports == 0, "bracket account closed"); +} + +#[test] +fn cannot_close_before_finalize() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 87).0.assert_ok(); + set_unix_timestamp(&mut litesvm, LOCK_TS); + lock(&mut litesvm, &admin).assert_ok(); + + let cranker = funded_keypair(&mut litesvm); + close_bracket(&mut litesvm, &cranker, &entrant.pubkey()).assert_err(WorldCupError::InvalidState); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/test_finalize.rs b/games/world-cup/pinocchio/tests/integration-tests/src/test_finalize.rs new file mode 100644 index 000000000..395649031 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/test_finalize.rs @@ -0,0 +1,118 @@ +use solana_signer::Signer; + +use crate::{ + tests::{ + asserts::TransactionResultExt, + utils::{ + chalk_bracket, chalk_bracket_wrong_third, finalize, funded_keypair, init_config, lock, + post_full_chalk_oracle, read_config, refresh_score, set_unix_timestamp, setup, submit_bracket, LOCK_TS, + }, + }, + TournamentState, WorldCupError, +}; + +/// Two entrants: `winner` plays perfect chalk (88), `runner_up` misses only the +/// third-place game (80). Returns both keypairs with the oracle fully posted. +fn two_entrant_tournament( + litesvm: &mut litesvm::LiteSVM, + admin: &solana_keypair::Keypair, +) -> (solana_keypair::Keypair, solana_keypair::Keypair) { + init_config(litesvm, admin, LOCK_TS).assert_ok(); + + let winner = funded_keypair(litesvm); + let runner_up = funded_keypair(litesvm); + submit_bracket(litesvm, &winner, &chalk_bracket(), 87).0.assert_ok(); + submit_bracket(litesvm, &runner_up, &chalk_bracket_wrong_third(), 87).0.assert_ok(); + + set_unix_timestamp(litesvm, LOCK_TS); + lock(litesvm, admin).assert_ok(); + post_full_chalk_oracle(litesvm, admin, 87); + (winner, runner_up) +} + +#[test] +fn finalize_records_unique_winner() { + let (mut litesvm, admin) = setup(); + let (winner, runner_up) = two_entrant_tournament(&mut litesvm, &admin); + + let cranker = funded_keypair(&mut litesvm); + refresh_score(&mut litesvm, &cranker, &winner.pubkey()).assert_ok(); + refresh_score(&mut litesvm, &cranker, &runner_up.pubkey()).assert_ok(); + + let view = read_config(&litesvm); + assert_eq!(view.best_score, 88); + assert_eq!(view.best_index, 0, "winner is the first submission"); + + finalize(&mut litesvm, &admin, &winner.pubkey()).assert_ok(); + + let view = read_config(&litesvm); + assert_eq!(view.state, TournamentState::Finalized as u8); + assert_eq!(view.winner, winner.pubkey().to_bytes()); +} + +#[test] +fn finalize_with_a_non_winning_bracket_fails() { + let (mut litesvm, admin) = setup(); + let (winner, runner_up) = two_entrant_tournament(&mut litesvm, &admin); + + let cranker = funded_keypair(&mut litesvm); + refresh_score(&mut litesvm, &cranker, &winner.pubkey()).assert_ok(); + refresh_score(&mut litesvm, &cranker, &runner_up.pubkey()).assert_ok(); + + // runner_up scored 80, the best is 88 — cannot be finalized as the winner. + finalize(&mut litesvm, &admin, &runner_up.pubkey()).assert_err(WorldCupError::BracketNotBest); +} + +#[test] +fn finalize_requires_every_bracket_refreshed() { + let (mut litesvm, admin) = setup(); + let (winner, _runner_up) = two_entrant_tournament(&mut litesvm, &admin); + + let cranker = funded_keypair(&mut litesvm); + // Only one of the two brackets refreshed. + refresh_score(&mut litesvm, &cranker, &winner.pubkey()).assert_ok(); + + finalize(&mut litesvm, &admin, &winner.pubkey()).assert_err(WorldCupError::NotFullyRefreshed); +} + +#[test] +fn finalize_requires_complete_oracle() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 87).0.assert_ok(); + set_unix_timestamp(&mut litesvm, LOCK_TS); + lock(&mut litesvm, &admin).assert_ok(); + + // No results posted at all. + finalize(&mut litesvm, &admin, &entrant.pubkey()).assert_err(WorldCupError::OracleNotComplete); +} + +#[test] +fn earliest_submission_breaks_an_otherwise_identical_key() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let first = funded_keypair(&mut litesvm); + let second = funded_keypair(&mut litesvm); + // Identical brackets and identical tiebreaker: only submission order separates them. + submit_bracket(&mut litesvm, &first, &chalk_bracket(), 87).0.assert_ok(); + submit_bracket(&mut litesvm, &second, &chalk_bracket(), 87).0.assert_ok(); + + set_unix_timestamp(&mut litesvm, LOCK_TS); + lock(&mut litesvm, &admin).assert_ok(); + post_full_chalk_oracle(&mut litesvm, &admin, 87); + + let cranker = funded_keypair(&mut litesvm); + // Refresh out of submission order to prove the fold is order-independent. + refresh_score(&mut litesvm, &cranker, &second.pubkey()).assert_ok(); + refresh_score(&mut litesvm, &cranker, &first.pubkey()).assert_ok(); + + assert_eq!(read_config(&litesvm).best_index, 0, "the earlier submission holds the best key"); + + // The later submitter cannot finalize; the earlier one can. + finalize(&mut litesvm, &admin, &second.pubkey()).assert_err(WorldCupError::BracketNotBest); + finalize(&mut litesvm, &admin, &first.pubkey()).assert_ok(); + assert_eq!(read_config(&litesvm).winner, first.pubkey().to_bytes()); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/test_init_config.rs b/games/world-cup/pinocchio/tests/integration-tests/src/test_init_config.rs new file mode 100644 index 000000000..2fa083e31 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/test_init_config.rs @@ -0,0 +1,56 @@ +use crate::{ + state::common::AccountDiscriminator, + tests::{ + asserts::TransactionResultExt, + constants::PROGRAM_ID, + pda::{get_config_pda, get_oracle_pda, get_vault_pda}, + utils::{init_config, read_config, setup, BASE_TS, LOCK_TS}, + }, + Oracle, TournamentState, WorldCupError, ENTRY_FEE, +}; + +#[test] +fn init_config_creates_singletons() { + let (mut litesvm, admin) = setup(); + + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let (config_pda, _) = get_config_pda(); + let config = litesvm.get_account(&config_pda).unwrap(); + assert_eq!(config.owner, PROGRAM_ID); + assert_eq!(config.data[0], AccountDiscriminator::Config as u8); + + let view = read_config(&litesvm); + assert_eq!(view.state, TournamentState::Registration as u8); + assert_eq!(view.entrant_count, 0); + assert_eq!(view.winner, [0u8; 32]); + + let (oracle_pda, _) = get_oracle_pda(); + let oracle_account = litesvm.get_account(&oracle_pda).unwrap(); + assert_eq!(oracle_account.data[0], AccountDiscriminator::Oracle as u8); + let oracle = Oracle::load(&oracle_account.data).unwrap(); + let decided = oracle.decided_mask; + assert_eq!(decided, 0, "no games decided at init"); + assert!(oracle.results.iter().all(|&r| r == 0xFF), "all games undecided"); + + let (vault_pda, _) = get_vault_pda(); + let vault = litesvm.get_account(&vault_pda).unwrap(); + assert_eq!(vault.owner, PROGRAM_ID, "vault is program-owned"); + assert!(vault.lamports > 0, "vault is rent-funded"); + + // Entry fee is the fixed protocol constant. + assert_eq!(ENTRY_FEE, 100_000_000); +} + +#[test] +fn init_config_twice_fails() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_err(crate::WorldCupError::ConfigAlreadyExists); +} + +#[test] +fn init_config_rejects_past_lock_ts() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, BASE_TS).assert_err(WorldCupError::InvalidLockTs); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/test_lock.rs b/games/world-cup/pinocchio/tests/integration-tests/src/test_lock.rs new file mode 100644 index 000000000..7c8381766 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/test_lock.rs @@ -0,0 +1,61 @@ +use crate::{ + tests::{ + asserts::TransactionResultExt, + utils::{ + chalk_bracket, funded_keypair, init_config, lock, read_config, set_unix_timestamp, setup, submit_bracket, + LOCK_TS, + }, + }, + TournamentState, WorldCupError, +}; + +#[test] +fn lock_before_kickoff_fails() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + // Still at BASE_TS, well before LOCK_TS. + lock(&mut litesvm, &admin).assert_err(WorldCupError::NotYetLocked); +} + +#[test] +fn lock_after_kickoff_transitions_state() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + set_unix_timestamp(&mut litesvm, LOCK_TS); + lock(&mut litesvm, &admin).assert_ok(); + assert_eq!(read_config(&litesvm).state, TournamentState::Locked as u8); +} + +#[test] +fn lock_by_non_admin_fails() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + set_unix_timestamp(&mut litesvm, LOCK_TS); + let stranger = funded_keypair(&mut litesvm); + lock(&mut litesvm, &stranger).assert_err(WorldCupError::Unauthorized); +} + +#[test] +fn submit_after_lock_is_rejected() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + set_unix_timestamp(&mut litesvm, LOCK_TS); + lock(&mut litesvm, &admin).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 100).0.assert_err(WorldCupError::InvalidState); +} + +#[test] +fn lock_twice_fails() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + set_unix_timestamp(&mut litesvm, LOCK_TS); + lock(&mut litesvm, &admin).assert_ok(); + lock(&mut litesvm, &admin).assert_err(WorldCupError::InvalidState); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/test_post_goals.rs b/games/world-cup/pinocchio/tests/integration-tests/src/test_post_goals.rs new file mode 100644 index 000000000..14066e808 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/test_post_goals.rs @@ -0,0 +1,46 @@ +use crate::{ + tests::{ + asserts::TransactionResultExt, + utils::{funded_keypair, init_and_lock, init_config, post_all_chalk_results, post_goals, setup, LOCK_TS}, + }, + WorldCupError, +}; + +#[test] +fn admin_posts_goal_total() { + let (mut litesvm, admin) = setup(); + init_and_lock(&mut litesvm, &admin); + post_all_chalk_results(&mut litesvm, &admin); + post_goals(&mut litesvm, &admin, 87).assert_ok(); +} + +#[test] +fn goal_total_is_immutable() { + let (mut litesvm, admin) = setup(); + init_and_lock(&mut litesvm, &admin); + post_all_chalk_results(&mut litesvm, &admin); + post_goals(&mut litesvm, &admin, 87).assert_ok(); + post_goals(&mut litesvm, &admin, 90).assert_err(WorldCupError::GoalsAlreadyPosted); +} + +#[test] +fn cannot_post_goals_before_all_results() { + let (mut litesvm, admin) = setup(); + init_and_lock(&mut litesvm, &admin); + post_goals(&mut litesvm, &admin, 87).assert_err(WorldCupError::OracleNotComplete); +} + +#[test] +fn non_admin_cannot_post_goals() { + let (mut litesvm, admin) = setup(); + init_and_lock(&mut litesvm, &admin); + let stranger = funded_keypair(&mut litesvm); + post_goals(&mut litesvm, &stranger, 87).assert_err(WorldCupError::Unauthorized); +} + +#[test] +fn cannot_post_goals_before_lock() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + post_goals(&mut litesvm, &admin, 87).assert_err(WorldCupError::InvalidState); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/test_post_result.rs b/games/world-cup/pinocchio/tests/integration-tests/src/test_post_result.rs new file mode 100644 index 000000000..e2a7ffb1b --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/test_post_result.rs @@ -0,0 +1,64 @@ +use crate::{ + tests::{ + asserts::TransactionResultExt, + utils::{funded_keypair, init_and_lock, init_config, oracle_decided_mask, post_result, setup, LOCK_TS}, + }, + WorldCupError, +}; + +#[test] +fn admin_posts_result_and_sets_decided_bit() { + let (mut litesvm, admin) = setup(); + init_and_lock(&mut litesvm, &admin); + + // Round-of-32 game 0 is contested by teams 0 and 1. + post_result(&mut litesvm, &admin, 0, 0).assert_ok(); + assert_eq!(oracle_decided_mask(&litesvm), 1, "bit 0 set"); + + post_result(&mut litesvm, &admin, 1, 2).assert_ok(); + assert_eq!(oracle_decided_mask(&litesvm), 0b11, "bits 0 and 1 set"); +} + +#[test] +fn non_admin_cannot_post() { + let (mut litesvm, admin) = setup(); + init_and_lock(&mut litesvm, &admin); + + let stranger = funded_keypair(&mut litesvm); + post_result(&mut litesvm, &stranger, 0, 0).assert_err(WorldCupError::Unauthorized); +} + +#[test] +fn cannot_post_dependent_before_feeders() { + let (mut litesvm, admin) = setup(); + init_and_lock(&mut litesvm, &admin); + + // Game 16 is fed by games 0 and 1, neither decided yet. + post_result(&mut litesvm, &admin, 16, 0).assert_err(WorldCupError::FeederNotDecided); +} + +#[test] +fn rejects_winner_not_in_the_contest() { + let (mut litesvm, admin) = setup(); + init_and_lock(&mut litesvm, &admin); + + // Game 0 is teams 0,1; team 5 cannot win it. + post_result(&mut litesvm, &admin, 0, 5).assert_err(WorldCupError::InvalidResult); +} + +#[test] +fn results_are_immutable() { + let (mut litesvm, admin) = setup(); + init_and_lock(&mut litesvm, &admin); + + post_result(&mut litesvm, &admin, 0, 0).assert_ok(); + post_result(&mut litesvm, &admin, 0, 1).assert_err(WorldCupError::ResultAlreadyPosted); +} + +#[test] +fn cannot_post_before_lock() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + post_result(&mut litesvm, &admin, 0, 0).assert_err(WorldCupError::InvalidState); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/test_refresh_score.rs b/games/world-cup/pinocchio/tests/integration-tests/src/test_refresh_score.rs new file mode 100644 index 000000000..02b465ed0 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/test_refresh_score.rs @@ -0,0 +1,81 @@ +use solana_signer::Signer; + +use crate::{ + tests::{ + asserts::TransactionResultExt, + utils::{ + chalk_bracket, funded_keypair, init_config, lock, post_full_chalk_oracle, post_result, read_bracket, + read_config, refresh_score, set_unix_timestamp, setup, submit_bracket, LOCK_TS, + }, + }, + WorldCupError, ALL_DECIDED, +}; + +#[test] +fn refresh_folds_into_tally_once_oracle_complete() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 87).0.assert_ok(); + + set_unix_timestamp(&mut litesvm, LOCK_TS); + lock(&mut litesvm, &admin).assert_ok(); + post_full_chalk_oracle(&mut litesvm, &admin, 87); + + let cranker = funded_keypair(&mut litesvm); + refresh_score(&mut litesvm, &cranker, &entrant.pubkey()).assert_ok(); + + let (score, tally_mask) = read_bracket(&litesvm, &entrant.pubkey()); + assert_eq!(score, 88, "perfect chalk bracket scores the maximum"); + assert_eq!(tally_mask, ALL_DECIDED); + + let view = read_config(&litesvm); + assert_eq!(view.best_score, 88); + assert_eq!(view.best_closeness, 0, "guess matched the actual goal total"); + assert_eq!(view.best_index, 0, "the sole entrant is the first submission"); + assert_eq!(view.refreshed_count, 1); +} + +#[test] +fn refreshing_an_already_folded_bracket_fails() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 87).0.assert_ok(); + + set_unix_timestamp(&mut litesvm, LOCK_TS); + lock(&mut litesvm, &admin).assert_ok(); + post_full_chalk_oracle(&mut litesvm, &admin, 87); + + let cranker = funded_keypair(&mut litesvm); + refresh_score(&mut litesvm, &cranker, &entrant.pubkey()).assert_ok(); + // Re-folding the same bracket is rejected (no double-count). + refresh_score(&mut litesvm, &cranker, &entrant.pubkey()).assert_err(WorldCupError::AlreadyFolded); + + let view = read_config(&litesvm); + assert_eq!(view.best_index, 0); + assert_eq!(view.refreshed_count, 1); +} + +#[test] +fn refresh_before_oracle_complete_fails() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 87).0.assert_ok(); + + set_unix_timestamp(&mut litesvm, LOCK_TS); + lock(&mut litesvm, &admin).assert_ok(); + + // Only the Round of 32 is decided; the oracle is not yet complete. + let chalk = chalk_bracket(); + for g in 0..16u8 { + post_result(&mut litesvm, &admin, g, chalk[g as usize]).assert_ok(); + } + + let cranker = funded_keypair(&mut litesvm); + refresh_score(&mut litesvm, &cranker, &entrant.pubkey()).assert_err(WorldCupError::OracleNotComplete); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/test_submit_bracket.rs b/games/world-cup/pinocchio/tests/integration-tests/src/test_submit_bracket.rs new file mode 100644 index 000000000..526870e21 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/test_submit_bracket.rs @@ -0,0 +1,86 @@ +use solana_signer::Signer; + +use crate::{ + state::common::AccountDiscriminator, + tests::{ + asserts::TransactionResultExt, + constants::PROGRAM_ID, + pda::get_bracket_pda, + utils::{ + chalk_bracket, funded_keypair, init_config, read_config, set_unix_timestamp, setup, submit_bracket, + vault_balance, LOCK_TS, + }, + }, + WorldCupError, ENTRY_FEE, +}; + +#[test] +fn submit_creates_bracket_and_escrows_stake() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + let vault_before = vault_balance(&litesvm); + + let (result, bracket_pda) = submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 120); + result.assert_ok(); + + let bracket = litesvm.get_account(&bracket_pda).unwrap(); + assert_eq!(bracket.owner, PROGRAM_ID); + assert_eq!(bracket.data[0], AccountDiscriminator::Bracket as u8); + + assert_eq!(read_config(&litesvm).entrant_count, 1); + + // The vault receives the entry fee minus the bracket account rent. + let escrowed = vault_balance(&litesvm) - vault_before; + assert!(escrowed > 0 && escrowed < ENTRY_FEE, "escrowed {escrowed} should be fee minus rent"); + assert!(escrowed > ENTRY_FEE - 5_000_000, "rent should be a small slice of the fee"); +} + +#[test] +fn submit_rejects_inconsistent_bracket() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + let mut picks = chalk_bracket(); + picks[16] = 9; // game 16 is fed by games 0,1; team 9 never reached it. + submit_bracket(&mut litesvm, &entrant, &picks, 100).0.assert_err(WorldCupError::InvalidPick); +} + +#[test] +fn submit_twice_for_same_wallet_fails() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 100).0.assert_ok(); + submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 100).0.assert_err(WorldCupError::BracketAlreadyExists); +} + +#[test] +fn prefunded_bracket_pda_does_not_block_submit() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + let (bracket_pda, _) = get_bracket_pda(&entrant.pubkey()); + litesvm.airdrop(&bracket_pda, 1_000_000).unwrap(); + + let (result, _) = submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 100); + result.assert_ok(); + + let bracket = litesvm.get_account(&bracket_pda).unwrap(); + assert_eq!(bracket.owner, PROGRAM_ID); + assert_eq!(bracket.data[0], AccountDiscriminator::Bracket as u8); +} + +#[test] +fn submit_after_kickoff_is_rejected() { + let (mut litesvm, admin) = setup(); + init_config(&mut litesvm, &admin, LOCK_TS).assert_ok(); + + let entrant = funded_keypair(&mut litesvm); + set_unix_timestamp(&mut litesvm, LOCK_TS); + submit_bracket(&mut litesvm, &entrant, &chalk_bracket(), 100).0.assert_err(WorldCupError::RegistrationClosed); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/utils/asserts.rs b/games/world-cup/pinocchio/tests/integration-tests/src/utils/asserts.rs new file mode 100644 index 000000000..64a485ad7 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/utils/asserts.rs @@ -0,0 +1,52 @@ +use std::string::String; + +use litesvm::types::{FailedTransactionMetadata, TransactionMetadata, TransactionResult}; +use solana_instruction::error::InstructionError; +use solana_transaction_error::TransactionError; + +use crate::errors::WorldCupError; + +pub trait TransactionResultExt { + /// Assert the transaction succeeded and return its metadata. + fn assert_ok(self) -> TransactionMetadata; + + /// Assert the transaction failed with the expected program error. + fn assert_err(self, expected: WorldCupError); +} + +impl TransactionResultExt for TransactionResult { + fn assert_ok(self) -> TransactionMetadata { + match self { + Ok(meta) => meta, + Err(failed_tx) => panic!( + "Expected transaction to succeed, but got: {}\nLogs:\n{}", + format_error(&failed_tx), + failed_tx.meta.logs.join("\n") + ), + } + } + + fn assert_err(self, expected: WorldCupError) { + match self { + Ok(_) => panic!("Expected transaction to fail with {:?}", expected), + Err(failed_tx) => { + let expected_err = TransactionError::InstructionError(0, InstructionError::Custom(expected as u32)); + if failed_tx.err != expected_err { + panic!( + "Expected {:?}, got: {}\nLogs:\n{}", + expected, + format_error(&failed_tx), + failed_tx.meta.logs.join("\n") + ); + } + } + } + } +} + +fn format_error(failed_tx: &FailedTransactionMetadata) -> String { + match &failed_tx.err { + TransactionError::InstructionError(_, InstructionError::Custom(code)) => format!("Custom error code: {}", code), + other => format!("{:?}", other), + } +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/utils/constants.rs b/games/world-cup/pinocchio/tests/integration-tests/src/utils/constants.rs new file mode 100644 index 000000000..d24a89887 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/utils/constants.rs @@ -0,0 +1,5 @@ +use solana_pubkey::Pubkey; + +pub static PROGRAM_ID: Pubkey = Pubkey::new_from_array(crate::ID.to_bytes()); +pub static SYSTEM_PROGRAM_ID: Pubkey = Pubkey::new_from_array([0u8; 32]); +pub static EVENT_AUTHORITY: Pubkey = Pubkey::new_from_array(crate::event_engine::event_authority_pda::ID.to_bytes()); diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/utils/cu_tracker.rs b/games/world-cup/pinocchio/tests/integration-tests/src/utils/cu_tracker.rs new file mode 100644 index 000000000..06311a448 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/utils/cu_tracker.rs @@ -0,0 +1,36 @@ +//! Opt-in compute-unit tracking. Enable with `CU_REPORT=1 cargo test`; the minimum +//! CU observed per instruction is written to `cu_report.md`. Off by default (and in +//! CI), so it adds no overhead to normal runs. + +use std::{ + collections::BTreeMap, + fs, + sync::{Mutex, OnceLock}, +}; + +fn enabled() -> bool { + static ENABLED: OnceLock = OnceLock::new(); + *ENABLED.get_or_init(|| std::env::var("CU_REPORT").is_ok()) +} + +fn tracker() -> &'static Mutex> { + static TRACKER: OnceLock>> = OnceLock::new(); + TRACKER.get_or_init(|| Mutex::new(BTreeMap::new())) +} + +/// Records the minimum compute units seen for an instruction. +pub fn record_cu(instruction: &str, cus: u64) { + if !enabled() { + return; + } + let mut map = tracker().lock().unwrap(); + let entry = map.entry(instruction.to_string()).or_insert(u64::MAX); + if cus < *entry { + *entry = cus; + } + let mut out = String::from("# Compute Unit Report\n\n| Instruction | Min CU |\n| --- | --- |\n"); + for (name, cu) in map.iter() { + out.push_str(&format!("| {name} | {cu} |\n")); + } + let _ = fs::write("cu_report.md", out); +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/utils/idl.rs b/games/world-cup/pinocchio/tests/integration-tests/src/utils/idl.rs new file mode 100644 index 000000000..0ce87350f --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/utils/idl.rs @@ -0,0 +1,34 @@ +//! Reads the generated IDL so tests can assert on-chain account requirements +//! (writable/signer flags) match what the program enforces. + +const IDL: &str = include_str!("../../../../idl/world_cup.json"); + +pub struct IdlAccount { + pub index: usize, + pub name: String, + pub is_writable: bool, + pub is_signer: bool, +} + +/// The ordered account metas the IDL declares for an instruction. +pub fn instruction_accounts(instruction: &str) -> Vec { + let value: serde_json::Value = serde_json::from_str(IDL).expect("valid IDL json"); + let program = value.get("program").unwrap_or(&value); + let instructions = program["instructions"].as_array().expect("instructions array"); + let ix = instructions + .iter() + .find(|i| i["name"].as_str() == Some(instruction)) + .unwrap_or_else(|| panic!("instruction {instruction} not in IDL")); + ix["accounts"] + .as_array() + .expect("accounts array") + .iter() + .enumerate() + .map(|(index, a)| IdlAccount { + index, + name: a["name"].as_str().unwrap_or_default().to_string(), + is_writable: a.get("isWritable").and_then(|v| v.as_bool()).unwrap_or(false), + is_signer: a.get("isSigner").and_then(|v| v.as_bool()).unwrap_or(false), + }) + .collect() +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/utils/mod.rs b/games/world-cup/pinocchio/tests/integration-tests/src/utils/mod.rs new file mode 100644 index 000000000..9bc077f35 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/utils/mod.rs @@ -0,0 +1,8 @@ +pub mod asserts; +pub mod constants; +pub mod cu_tracker; +pub mod idl; +pub mod pda; +pub mod test_helpers; + +pub use test_helpers::*; diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/utils/pda.rs b/games/world-cup/pinocchio/tests/integration-tests/src/utils/pda.rs new file mode 100644 index 000000000..1f77bb009 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/utils/pda.rs @@ -0,0 +1,23 @@ +use solana_pubkey::Pubkey; + +use crate::{ + state::common::{CONFIG_SEED, ORACLE_SEED, VAULT_SEED}, + tests::constants::PROGRAM_ID, + Bracket, +}; + +pub fn get_config_pda() -> (Pubkey, u8) { + Pubkey::find_program_address(&[CONFIG_SEED], &PROGRAM_ID) +} + +pub fn get_oracle_pda() -> (Pubkey, u8) { + Pubkey::find_program_address(&[ORACLE_SEED], &PROGRAM_ID) +} + +pub fn get_vault_pda() -> (Pubkey, u8) { + Pubkey::find_program_address(&[VAULT_SEED], &PROGRAM_ID) +} + +pub fn get_bracket_pda(owner: &Pubkey) -> (Pubkey, u8) { + Pubkey::find_program_address(&[Bracket::SEED, owner.as_ref()], &PROGRAM_ID) +} diff --git a/games/world-cup/pinocchio/tests/integration-tests/src/utils/test_helpers.rs b/games/world-cup/pinocchio/tests/integration-tests/src/utils/test_helpers.rs new file mode 100644 index 000000000..405b3af46 --- /dev/null +++ b/games/world-cup/pinocchio/tests/integration-tests/src/utils/test_helpers.rs @@ -0,0 +1,323 @@ +use litesvm::{types::TransactionResult, LiteSVM}; +use solana_clock::Clock; +use solana_instruction::{AccountMeta, Instruction}; +use solana_keypair::Keypair; +use solana_message::Message; +use solana_native_token::LAMPORTS_PER_SOL; +use solana_pubkey::Pubkey; +use solana_signer::Signer; +use solana_transaction::Transaction; + +use crate::{ + children, + tests::{ + constants::{EVENT_AUTHORITY, PROGRAM_ID, SYSTEM_PROGRAM_ID}, + pda::{get_bracket_pda, get_config_pda, get_oracle_pda, get_vault_pda}, + }, + third_place_slots, + utils::cu_tracker::record_cu, + Bracket, Config, Oracle, WorldCupInstruction, +}; + +/// Baseline wall-clock the test SVM starts at. +pub const BASE_TS: i64 = 1_700_000_000; +/// Lock timestamp used by the helpers (kickoff one day after the baseline). +pub const LOCK_TS: i64 = BASE_TS + 86_400; + +pub fn setup() -> (LiteSVM, Keypair) { + let mut litesvm = LiteSVM::new(); + + let so_path = std::path::Path::new(env!("CARGO_MANIFEST_DIR")).join("../../target/deploy/world_cup_program.so"); + litesvm.add_program_from_file(PROGRAM_ID.to_bytes(), so_path).unwrap(); + + let admin = Keypair::new(); + litesvm.airdrop(&admin.pubkey(), LAMPORTS_PER_SOL * 100).unwrap(); + set_unix_timestamp(&mut litesvm, BASE_TS); + + (litesvm, admin) +} + +pub fn set_unix_timestamp(litesvm: &mut LiteSVM, ts: i64) { + let mut clock: Clock = litesvm.get_sysvar(); + clock.unix_timestamp = ts; + litesvm.set_sysvar(&clock); +} + +pub fn funded_keypair(litesvm: &mut LiteSVM) -> Keypair { + let kp = Keypair::new(); + litesvm.airdrop(&kp.pubkey(), LAMPORTS_PER_SOL * 100).unwrap(); + kp +} + +#[allow(clippy::result_large_err)] +pub fn build_and_send( + litesvm: &mut LiteSVM, + signers: &[&Keypair], + payer: &Pubkey, + ix: &Instruction, +) -> TransactionResult { + let tx = Transaction::new(signers, Message::new(std::slice::from_ref(ix), Some(payer)), litesvm.latest_blockhash()); + let result = litesvm.send_transaction(tx); + if let Ok(meta) = &result { + if let Ok(parsed) = WorldCupInstruction::from_bytes(&ix.data) { + record_cu(&parsed.to_string(), meta.compute_units_consumed); + } + } + litesvm.expire_blockhash(); + result +} + +/// A "chalk" bracket where the lower-id team always advances (champion = team 0). +/// Identical shape to a full chalk oracle result array. +pub fn chalk_bracket() -> [u8; 32] { + let mut p = [0u8; 32]; + for g in 0..16u8 { + p[g as usize] = 2 * g; + } + for g in 16..=30u8 { + let (c0, c1) = children(g); + p[g as usize] = p[c0 as usize].min(p[c1 as usize]); + } + let (l0, l1) = third_place_slots(&p); + p[31] = l0.min(l1); + p +} + +/// A valid bracket identical to chalk except the third-place pick is the *other* +/// semifinal loser — so against a chalk oracle it loses exactly the third-place game. +pub fn chalk_bracket_wrong_third() -> [u8; 32] { + let mut p = chalk_bracket(); + let (l0, l1) = third_place_slots(&p); + p[31] = l0.max(l1); + p +} + +#[allow(clippy::result_large_err)] +pub fn init_config(litesvm: &mut LiteSVM, admin: &Keypair, lock_ts: i64) -> TransactionResult { + let (config, _) = get_config_pda(); + let (oracle, _) = get_oracle_pda(); + let (vault, _) = get_vault_pda(); + + let mut data = vec![*crate::init_config::DISCRIMINATOR]; + data.extend_from_slice(&lock_ts.to_le_bytes()); + + let accounts = vec![ + AccountMeta::new(admin.pubkey(), true), + AccountMeta::new(config, false), + AccountMeta::new(oracle, false), + AccountMeta::new(vault, false), + AccountMeta::new_readonly(SYSTEM_PROGRAM_ID, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ]; + + let ix = Instruction { program_id: PROGRAM_ID, accounts, data }; + build_and_send(litesvm, &[admin], &admin.pubkey(), &ix) +} + +#[allow(clippy::result_large_err)] +pub fn submit_bracket( + litesvm: &mut LiteSVM, + entrant: &Keypair, + picks: &[u8; 32], + tiebreaker_guess: u16, +) -> (TransactionResult, Pubkey) { + let (config, _) = get_config_pda(); + let (vault, _) = get_vault_pda(); + let (bracket, _) = get_bracket_pda(&entrant.pubkey()); + + let mut data = vec![*crate::submit_bracket::DISCRIMINATOR]; + data.extend_from_slice(picks); + data.extend_from_slice(&tiebreaker_guess.to_le_bytes()); + + let accounts = vec![ + AccountMeta::new(entrant.pubkey(), true), + AccountMeta::new(config, false), + AccountMeta::new(bracket, false), + AccountMeta::new(vault, false), + AccountMeta::new_readonly(SYSTEM_PROGRAM_ID, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ]; + + let ix = Instruction { program_id: PROGRAM_ID, accounts, data }; + (build_and_send(litesvm, &[entrant], &entrant.pubkey(), &ix), bracket) +} + +#[allow(clippy::result_large_err)] +pub fn lock(litesvm: &mut LiteSVM, admin: &Keypair) -> TransactionResult { + let (config, _) = get_config_pda(); + let accounts = vec![ + AccountMeta::new_readonly(admin.pubkey(), true), + AccountMeta::new(config, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ]; + let ix = Instruction { program_id: PROGRAM_ID, accounts, data: vec![*crate::lock::DISCRIMINATOR] }; + build_and_send(litesvm, &[admin], &admin.pubkey(), &ix) +} + +#[allow(clippy::result_large_err)] +pub fn post_result(litesvm: &mut LiteSVM, admin: &Keypair, game: u8, winner: u8) -> TransactionResult { + let (config, _) = get_config_pda(); + let (oracle, _) = get_oracle_pda(); + let accounts = vec![ + AccountMeta::new_readonly(admin.pubkey(), true), + AccountMeta::new_readonly(config, false), + AccountMeta::new(oracle, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ]; + let ix = + Instruction { program_id: PROGRAM_ID, accounts, data: vec![*crate::post_result::DISCRIMINATOR, game, winner] }; + build_and_send(litesvm, &[admin], &admin.pubkey(), &ix) +} + +#[allow(clippy::result_large_err)] +pub fn post_goals(litesvm: &mut LiteSVM, admin: &Keypair, total: u16) -> TransactionResult { + let (config, _) = get_config_pda(); + let (oracle, _) = get_oracle_pda(); + let mut data = vec![*crate::post_goals::DISCRIMINATOR]; + data.extend_from_slice(&total.to_le_bytes()); + let accounts = vec![ + AccountMeta::new_readonly(admin.pubkey(), true), + AccountMeta::new_readonly(config, false), + AccountMeta::new(oracle, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ]; + let ix = Instruction { program_id: PROGRAM_ID, accounts, data }; + build_and_send(litesvm, &[admin], &admin.pubkey(), &ix) +} + +#[allow(clippy::result_large_err)] +pub fn refresh_score(litesvm: &mut LiteSVM, payer: &Keypair, bracket_owner: &Pubkey) -> TransactionResult { + let (config, _) = get_config_pda(); + let (oracle, _) = get_oracle_pda(); + let (bracket, _) = get_bracket_pda(bracket_owner); + let accounts = vec![ + AccountMeta::new(config, false), + AccountMeta::new_readonly(oracle, false), + AccountMeta::new(bracket, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ]; + let ix = Instruction { program_id: PROGRAM_ID, accounts, data: vec![*crate::refresh_score::DISCRIMINATOR] }; + build_and_send(litesvm, &[payer], &payer.pubkey(), &ix) +} + +#[allow(clippy::result_large_err)] +pub fn finalize(litesvm: &mut LiteSVM, admin: &Keypair, winning_bracket_owner: &Pubkey) -> TransactionResult { + let (config, _) = get_config_pda(); + let (oracle, _) = get_oracle_pda(); + let (bracket, _) = get_bracket_pda(winning_bracket_owner); + let accounts = vec![ + AccountMeta::new(admin.pubkey(), true), + AccountMeta::new(config, false), + AccountMeta::new_readonly(oracle, false), + AccountMeta::new_readonly(bracket, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ]; + let ix = Instruction { program_id: PROGRAM_ID, accounts, data: vec![*crate::finalize::DISCRIMINATOR] }; + build_and_send(litesvm, &[admin], &admin.pubkey(), &ix) +} + +#[allow(clippy::result_large_err)] +pub fn claim(litesvm: &mut LiteSVM, winner: &Keypair) -> TransactionResult { + let (config, _) = get_config_pda(); + let (vault, _) = get_vault_pda(); + let accounts = vec![ + AccountMeta::new(winner.pubkey(), true), + AccountMeta::new(config, false), + AccountMeta::new(vault, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ]; + let ix = Instruction { program_id: PROGRAM_ID, accounts, data: vec![*crate::claim::DISCRIMINATOR] }; + build_and_send(litesvm, &[winner], &winner.pubkey(), &ix) +} + +/// Snapshot of the config fields tests assert on (copied out of the packed struct). +pub struct ConfigView { + pub state: u8, + pub entrant_count: u32, + pub refreshed_count: u32, + pub tally_mask: u32, + pub best_score: u16, + pub best_closeness: u16, + pub best_index: u32, + pub winner: [u8; 32], +} + +pub fn read_config(litesvm: &LiteSVM) -> ConfigView { + let (config, _) = get_config_pda(); + let account = litesvm.get_account(&config).expect("config exists"); + let c = Config::load(&account.data).expect("valid config"); + ConfigView { + state: c.state, + entrant_count: c.entrant_count, + refreshed_count: c.refreshed_count, + tally_mask: c.tally_mask, + best_score: c.best_score, + best_closeness: c.best_closeness, + best_index: c.best_index, + winner: c.winner.to_bytes(), + } +} + +pub fn oracle_decided_mask(litesvm: &LiteSVM) -> u32 { + let (oracle, _) = get_oracle_pda(); + let account = litesvm.get_account(&oracle).expect("oracle exists"); + Oracle::load(&account.data).expect("valid oracle").decided_mask +} + +/// Returns `(score, tally_mask)` for a bracket. +pub fn read_bracket(litesvm: &LiteSVM, owner: &Pubkey) -> (u16, u32) { + let (bracket, _) = get_bracket_pda(owner); + let account = litesvm.get_account(&bracket).expect("bracket exists"); + let b = Bracket::load(&account.data).expect("valid bracket"); + (b.score, b.tally_mask) +} + +pub fn vault_balance(litesvm: &LiteSVM) -> u64 { + let (vault, _) = get_vault_pda(); + litesvm.get_account(&vault).map(|a| a.lamports).unwrap_or(0) +} + +/// Initializes the tournament and advances to the locked (oracle-posting) phase. +pub fn init_and_lock(litesvm: &mut LiteSVM, admin: &Keypair) { + init_config(litesvm, admin, LOCK_TS).expect("init_config should succeed"); + set_unix_timestamp(litesvm, LOCK_TS); + lock(litesvm, admin).expect("lock should succeed"); +} + +#[allow(clippy::result_large_err)] +pub fn close_bracket(litesvm: &mut LiteSVM, payer: &Keypair, owner: &Pubkey) -> TransactionResult { + let (config, _) = get_config_pda(); + let (bracket, _) = get_bracket_pda(owner); + let (vault, _) = get_vault_pda(); + let accounts = vec![ + AccountMeta::new_readonly(config, false), + AccountMeta::new(bracket, false), + AccountMeta::new(vault, false), + AccountMeta::new_readonly(EVENT_AUTHORITY, false), + AccountMeta::new_readonly(PROGRAM_ID, false), + ]; + let ix = Instruction { program_id: PROGRAM_ID, accounts, data: vec![*crate::close_bracket::DISCRIMINATOR] }; + build_and_send(litesvm, &[payer], &payer.pubkey(), &ix) +} + +/// Posts every chalk game result in feeder-before-dependent order (no goal total). +pub fn post_all_chalk_results(litesvm: &mut LiteSVM, admin: &Keypair) { + let results = chalk_bracket(); + for game in 0..32u8 { + post_result(litesvm, admin, game, results[game as usize]).expect("post_result should succeed"); + } +} + +/// Posts every chalk game result and then the goal total. +pub fn post_full_chalk_oracle(litesvm: &mut LiteSVM, admin: &Keypair, total_goals: u16) { + post_all_chalk_results(litesvm, admin); + post_goals(litesvm, admin, total_goals).expect("post_goals should succeed"); +} diff --git a/games/world-cup/pinocchio/tsconfig.json b/games/world-cup/pinocchio/tsconfig.json new file mode 100644 index 000000000..a12667ce8 --- /dev/null +++ b/games/world-cup/pinocchio/tsconfig.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ESNext", + "lib": ["DOM", "DOM.Iterable", "ESNext"], + "module": "ESNext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "strict": true, + "skipLibCheck": true, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true, + "noUncheckedIndexedAccess": true + } +} diff --git a/games/world-cup/pinocchio/webapp/.env.example b/games/world-cup/pinocchio/webapp/.env.example new file mode 100644 index 000000000..b53921fbe --- /dev/null +++ b/games/world-cup/pinocchio/webapp/.env.example @@ -0,0 +1,8 @@ +# Show a "Preview" toggle on a submitted bracket that scores it against fake +# game results (wins/losses/points) before real oracle results exist. When set, +# the bracket display opens in preview mode and can be toggled back to "Live". +VITE_PREVIEW=true + +# RPC the /api/og social-card function uses to fetch a bracket server-side. +# Defaults to devnet when unset. +OG_RPC_URL=https://api.devnet.solana.com diff --git a/games/world-cup/pinocchio/webapp/.gitignore b/games/world-cup/pinocchio/webapp/.gitignore new file mode 100644 index 000000000..7823f49f4 --- /dev/null +++ b/games/world-cup/pinocchio/webapp/.gitignore @@ -0,0 +1,32 @@ +# Logs +logs +*.log +npm-debug.log* +yarn-debug.log* +yarn-error.log* +pnpm-debug.log* +lerna-debug.log* + +node_modules +dist +dist-ssr +*.local + +# Editor directories and files +.vscode/* +!.vscode/extensions.json +.idea +.DS_Store +*.suo +*.ntvs* +*.njsproj +*.sln +*.sw? + +# Environment variables +.env +.env.local + +# Generated code +src/generated/ +.vercel diff --git a/games/world-cup/pinocchio/webapp/README.md b/games/world-cup/pinocchio/webapp/README.md new file mode 100644 index 000000000..d53479a76 --- /dev/null +++ b/games/world-cup/pinocchio/webapp/README.md @@ -0,0 +1,26 @@ +# World Cup Webapp + +A generic Solana app shell connected to the World Cup on-chain program. Provides wallet connection, cluster switching, program deploy/status tooling, token management, and a dev faucet. + +## Features + +- **Wallet Connection** - Solana wallet integration (tested with Phantom) with real-time SOL and token balance display +- **Cluster Switching** - Switch between localnet, devnet, testnet, mainnet, or a custom RPC endpoint +- **Program Deploy & Status** - Deploy and inspect the on-chain program (dev only) +- **Token Management** - Add and select tokens, view balances +- **Dev Faucet** - Request SOL/USDC airdrops for local testing (hidden on mainnet) +- **Theme Support** - Dark/light mode toggle + +## Scripts + +| Script | Description | +| ----------------- | ----------------------------------------------------- | +| `npm run dev` | Start the Vite dev server with hot module replacement | +| `npm run build` | Type-check with TypeScript and build for production | +| `npm run preview` | Preview the production build locally | + +From the project root, `just webapp-run` builds the program and clients, starts a local validator + API, and launches the webapp. + +## Tech Stack + +React 19, TypeScript, Vite, Tailwind CSS, Radix UI, jotai (state), TanStack Query (data fetching), Solana Kit, ConnectorKit. diff --git a/games/world-cup/pinocchio/webapp/api/lib/bpf-loader.ts b/games/world-cup/pinocchio/webapp/api/lib/bpf-loader.ts new file mode 100644 index 000000000..8a896e45b --- /dev/null +++ b/games/world-cup/pinocchio/webapp/api/lib/bpf-loader.ts @@ -0,0 +1,143 @@ +import { + type Address, + type Instruction, + type AccountMeta, + address, + getAddressEncoder, + getProgramDerivedAddress, +} from '@solana/kit'; + +export const BPF_LOADER_UPGRADEABLE = address('BPFLoaderUpgradeab1e11111111111111111111111'); +export const SYSTEM_PROGRAM = address('11111111111111111111111111111111'); +export const SYSVAR_RENT = address('SysvarRent111111111111111111111111111111111'); +export const SYSVAR_CLOCK = address('SysvarC1ock11111111111111111111111111111111'); +export const CHUNK_SIZE = 900; + +function u32LE(value: number): Uint8Array { + const buf = new Uint8Array(4); + const view = new DataView(buf.buffer); + view.setUint32(0, value, true); + return buf; +} + +function u64LE(value: number | bigint): Uint8Array { + const buf = new Uint8Array(8); + const view = new DataView(buf.buffer); + view.setBigUint64(0, BigInt(value), true); + return buf; +} + +const AccountRole = { READONLY: 0, WRITABLE: 1, SIGNER: 2, WRITABLE_SIGNER: 3 } as const; + +function writable(addr: Address): AccountMeta { + return { address: addr, role: AccountRole.WRITABLE }; +} + +function writableSigner(addr: Address): AccountMeta { + return { address: addr, role: AccountRole.WRITABLE_SIGNER }; +} + +function signer(addr: Address): AccountMeta { + return { address: addr, role: AccountRole.SIGNER }; +} + +function readonly(addr: Address): AccountMeta { + return { address: addr, role: AccountRole.READONLY }; +} + +export function buildInitializeBufferIx(buffer: Address, authority: Address): Instruction { + return { + programAddress: BPF_LOADER_UPGRADEABLE, + accounts: [writable(buffer), readonly(authority)], + data: u32LE(0), + }; +} + +export function buildWriteIx(buffer: Address, authority: Address, offset: number, chunk: Uint8Array): Instruction { + const data = new Uint8Array(4 + 4 + 8 + chunk.length); + data.set(u32LE(1), 0); + data.set(u32LE(offset), 4); + data.set(u64LE(chunk.length), 8); + data.set(chunk, 16); + return { + programAddress: BPF_LOADER_UPGRADEABLE, + accounts: [writable(buffer), signer(authority)], + data, + }; +} + +export function buildDeployIx( + payer: Address, + programDataPDA: Address, + program: Address, + buffer: Address, + authority: Address, + maxDataLen: number | bigint, +): Instruction { + const data = new Uint8Array(4 + 8); + data.set(u32LE(2), 0); + data.set(u64LE(maxDataLen), 4); + return { + programAddress: BPF_LOADER_UPGRADEABLE, + accounts: [ + writableSigner(payer), + writable(programDataPDA), + writableSigner(program), + writable(buffer), + readonly(SYSVAR_RENT), + readonly(SYSVAR_CLOCK), + readonly(SYSTEM_PROGRAM), + signer(authority), + ], + data, + }; +} + +export function buildUpgradeIx( + programDataPDA: Address, + program: Address, + buffer: Address, + spill: Address, + authority: Address, +): Instruction { + return { + programAddress: BPF_LOADER_UPGRADEABLE, + accounts: [ + writable(programDataPDA), + writable(program), + writable(buffer), + writable(spill), + readonly(SYSVAR_RENT), + readonly(SYSVAR_CLOCK), + signer(authority), + ], + data: u32LE(3), + }; +} + +export function buildSetAuthorityIx(account: Address, currentAuth: Address, newAuth: Address | null): Instruction { + const accounts = [writable(account), signer(currentAuth)]; + if (newAuth) accounts.push(readonly(newAuth)); + return { + programAddress: BPF_LOADER_UPGRADEABLE, + accounts, + data: u32LE(4), + }; +} + +export function buildCloseBufferIx(buffer: Address, recipient: Address, authority: Address): Instruction { + return { + programAddress: BPF_LOADER_UPGRADEABLE, + accounts: [writable(buffer), writable(recipient), signer(authority)], + data: u32LE(5), + }; +} + +export async function deriveProgramDataAddress(programId: Address): Promise
{ + const pubkeyEncoder = getAddressEncoder(); + const [pda] = await getProgramDerivedAddress({ + programAddress: BPF_LOADER_UPGRADEABLE, + seeds: [pubkeyEncoder.encode(programId)], + }); + return pda; +} diff --git a/games/world-cup/pinocchio/webapp/api/lib/deploy-builder.ts b/games/world-cup/pinocchio/webapp/api/lib/deploy-builder.ts new file mode 100644 index 000000000..f3dcd59a0 --- /dev/null +++ b/games/world-cup/pinocchio/webapp/api/lib/deploy-builder.ts @@ -0,0 +1,80 @@ +import { getAddressFromPublicKey, createKeyPairFromPrivateKeyBytes } from '@solana/kit'; +import crypto from 'node:crypto'; +import { CHUNK_SIZE } from './bpf-loader.js'; + +export { CHUNK_SIZE }; + +/** + * Generate a fresh ed25519 keypair and serialize it as the 64-byte + * `[priv(32) | pub(32)]` Solana keypair format that `createKeyPairFromBytes` + * expects on the client side. Replaces the removed kit helpers + * `generateExtractableKeyPair` + `extractBytesFromKeyPair`. + */ +async function generateKeypairBytes(): Promise<{ keypairBytes: Uint8Array; publicKey: CryptoKey }> { + const privBytes = crypto.getRandomValues(new Uint8Array(32)); + const kp = await createKeyPairFromPrivateKeyBytes(privBytes, true); + const pubBytes = new Uint8Array(await crypto.subtle.exportKey('raw', kp.publicKey)); + const keypairBytes = new Uint8Array(64); + keypairBytes.set(privBytes, 0); + keypairBytes.set(pubBytes, 32); + return { keypairBytes, publicKey: kp.publicKey }; +} + +export interface DeployPlan { + bufferKeypair: number[]; + bufferAddress: string; + chunks: string[]; + totalChunks: number; + programAddress: string; + soHash: string; + soSize: number; +} + +function chunkSoBytes(soBytes: Uint8Array): string[] { + const totalChunks = Math.ceil(soBytes.length / CHUNK_SIZE); + const chunks: string[] = []; + for (let i = 0; i < totalChunks; i++) { + const offset = i * CHUNK_SIZE; + const chunk = soBytes.slice(offset, offset + CHUNK_SIZE); + chunks.push(Buffer.from(chunk).toString('base64')); + } + return chunks; +} + +export async function buildDeployPlan(soBytes: Uint8Array, programAddress: string): Promise { + const soHash = crypto.createHash('sha256').update(soBytes).digest('hex'); + + const { keypairBytes: bufferKeypairBytes, publicKey: bufferPubKey } = await generateKeypairBytes(); + const bufferAddress = await getAddressFromPublicKey(bufferPubKey); + + const chunks = chunkSoBytes(soBytes); + + return { + bufferKeypair: Array.from(bufferKeypairBytes), + bufferAddress: bufferAddress.toString(), + chunks, + totalChunks: chunks.length, + programAddress, + soHash, + soSize: soBytes.length, + }; +} + +export async function buildUpgradePlan(soBytes: Uint8Array, programAddress: string): Promise { + const soHash = crypto.createHash('sha256').update(soBytes).digest('hex'); + + const { keypairBytes: bufferKeypairBytes, publicKey: bufferPubKey } = await generateKeypairBytes(); + const bufferAddress = await getAddressFromPublicKey(bufferPubKey); + + const chunks = chunkSoBytes(soBytes); + + return { + bufferKeypair: Array.from(bufferKeypairBytes), + bufferAddress: bufferAddress.toString(), + chunks, + totalChunks: chunks.length, + programAddress, + soHash, + soSize: soBytes.length, + }; +} diff --git a/games/world-cup/pinocchio/webapp/api/lib/program-status.ts b/games/world-cup/pinocchio/webapp/api/lib/program-status.ts new file mode 100644 index 000000000..bb9fa5192 --- /dev/null +++ b/games/world-cup/pinocchio/webapp/api/lib/program-status.ts @@ -0,0 +1,118 @@ +import { getAddressDecoder } from '@solana/kit'; + +const PROGRAM_ACCOUNT_TAG = 2; +const PROGRAM_DATA_OFFSET = 4; +const PROGRAM_DATA_PUBKEY_LEN = 32; +const PROGRAM_ACCOUNT_MIN_LEN = PROGRAM_DATA_OFFSET + PROGRAM_DATA_PUBKEY_LEN; +const SLOT_OFFSET = 4; +const SLOT_SIZE = 8; +const AUTHORITY_FLAG_OFFSET = 12; +const AUTHORITY_PUBKEY_OFFSET = 13; +const AUTHORITY_PUBKEY_LEN = 32; +const HEADER_SIZE = AUTHORITY_PUBKEY_OFFSET + AUTHORITY_PUBKEY_LEN; + +export interface ProgramStatus { + deployed: boolean; + upgradeable: boolean; + upgradeAuthority: string | null; + lastDeploySlot: number | null; + lastDeployTime: number | null; + programDataAddress: string | null; + dataSize: number | null; +} + +interface RpcAccountInfo { + value: { + data: [string, string]; + executable: boolean; + lamports: number; + owner: string; + rentEpoch: number; + } | null; +} + +async function rpcCall(rpcUrl: string, method: string, params: unknown[], timeoutMs = 15_000): Promise { + const controller = new AbortController(); + const timeout = setTimeout(() => controller.abort(), timeoutMs); + try { + const res = await fetch(rpcUrl, { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ jsonrpc: '2.0', id: 1, method, params }), + signal: controller.signal, + }); + const json = (await res.json()) as { result?: unknown; error?: { message: string } }; + if (json.error) throw new Error(json.error.message); + return json.result; + } finally { + clearTimeout(timeout); + } +} + +export async function checkProgramStatus(rpcUrl: string, programAddress: string): Promise { + const notDeployed: ProgramStatus = { + deployed: false, + upgradeable: false, + upgradeAuthority: null, + lastDeploySlot: null, + lastDeployTime: null, + programDataAddress: null, + dataSize: null, + }; + + const accountResult = (await rpcCall(rpcUrl, 'getAccountInfo', [ + programAddress, + { encoding: 'base64' }, + ])) as RpcAccountInfo; + + if (!accountResult.value || !accountResult.value.executable) return notDeployed; + + const data = Buffer.from(accountResult.value.data[0], 'base64'); + if (data.length < PROGRAM_ACCOUNT_MIN_LEN || data[0] !== PROGRAM_ACCOUNT_TAG) return notDeployed; + + const addressDecoder = getAddressDecoder(); + const programDataBytes = data.slice(PROGRAM_DATA_OFFSET, PROGRAM_DATA_OFFSET + PROGRAM_DATA_PUBKEY_LEN); + const programDataAddress = addressDecoder.decode(programDataBytes); + + const pdResult = (await rpcCall(rpcUrl, 'getAccountInfo', [ + programDataAddress, + { encoding: 'base64' }, + ])) as RpcAccountInfo; + + if (!pdResult.value) return { ...notDeployed, deployed: true, programDataAddress }; + + const pdData = Buffer.from(pdResult.value.data[0], 'base64'); + + const slotBytes = pdData.slice(SLOT_OFFSET, SLOT_OFFSET + SLOT_SIZE); + const lastDeploySlot = Number(slotBytes.reduce((acc, b, i) => acc + BigInt(b) * 256n ** BigInt(i), 0n)); + + let lastDeployTime: number | null = null; + if (lastDeploySlot > 0) { + try { + const blockTime = (await rpcCall(rpcUrl, 'getBlockTime', [lastDeploySlot])) as number | null; + lastDeployTime = blockTime; + } catch { + // block time not available for this slot + } + } + + const hasAuthority = pdData[AUTHORITY_FLAG_OFFSET] === 1; + let upgradeAuthority: string | null = null; + if (hasAuthority && pdData.length >= HEADER_SIZE) { + upgradeAuthority = addressDecoder.decode( + pdData.slice(AUTHORITY_PUBKEY_OFFSET, AUTHORITY_PUBKEY_OFFSET + AUTHORITY_PUBKEY_LEN), + ); + } + + const dataSize = pdData.length - HEADER_SIZE; + + return { + deployed: true, + upgradeable: hasAuthority, + upgradeAuthority, + lastDeploySlot, + lastDeployTime, + programDataAddress, + dataSize: dataSize > 0 ? dataSize : null, + }; +} diff --git a/games/world-cup/pinocchio/webapp/api/og.tsx b/games/world-cup/pinocchio/webapp/api/og.tsx new file mode 100644 index 000000000..36a17beee --- /dev/null +++ b/games/world-cup/pinocchio/webapp/api/og.tsx @@ -0,0 +1,303 @@ +/** @jsxImportSource react */ +import { type ReactNode } from 'react'; +import { ImageResponse } from '@vercel/og'; +import { address, createSolanaRpc } from '@solana/kit'; +import { + FINAL_GAME, + GAME_COUNT, + TEAM_NAMES, + THIRD_PLACE_GAME, + children, + fetchMaybeBracketFromSeeds, +} from '@solana/world-cup'; + +import { displayTeam } from '../src/components/bracket/teams'; +import { PROJECT_HANDLE, SHARE_HASHTAG, bracketHighlights, flagEmoji } from '../src/lib/share'; + +export const config = { runtime: 'edge' }; + +const WIDTH = 1200; +const HEIGHT = 630; +const RPC_URL = process.env.OG_RPC_URL ?? 'https://api.devnet.solana.com'; + +/** A bracket's podium never changes once submitted, so the rendered card caches hard at the edge. */ +const CACHE_HEADERS = { 'cache-control': 'public, max-age=3600, s-maxage=86400, stale-while-revalidate=604800' }; + +const INK = '#0A0A0F'; +const SOLANA_PURPLE = '#9945FF'; +const SOLANA_GREEN = '#14F195'; +const GOLD = '#F5C451'; + +/** + * `@vercel/og` ships a single Geist weight, so `fontWeight` alone renders flat. + * Loading static-weight Inter from a CDN restores real typographic hierarchy. + * Each fetch is independent and best-effort: any failure drops that weight and + * the card still renders with whatever loaded (including none). + */ +const FONT_URLS: ReadonlyArray<{ weight: 400 | 600 | 800; url: string }> = [ + { weight: 400, url: 'https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/latin-400-normal.ttf' }, + { weight: 600, url: 'https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/latin-600-normal.ttf' }, + { weight: 800, url: 'https://cdn.jsdelivr.net/fontsource/fonts/inter@latest/latin-800-normal.ttf' }, +]; + +type LoadedFont = { name: 'Inter'; data: ArrayBuffer; weight: 400 | 600 | 800; style: 'normal' }; + +async function loadFonts(): Promise { + const results = await Promise.all( + FONT_URLS.map(async ({ weight, url }) => { + try { + const res = await fetch(url); + if (!res.ok) return null; + const data = await res.arrayBuffer(); + return { name: 'Inter', data, weight, style: 'normal' } satisfies LoadedFont; + } catch { + return null; + } + }), + ); + return results.filter((f): f is LoadedFont => f !== null); +} + +/** A polished placeholder pill for a slot that has no decided nation yet. */ +function PlaceholderChip({ code, size }: { code: string; size: number }) { + return ( +
+ {code} +
+ ); +} + +function Header() { + return ( +
+
+
+ + 2026 WORLD CUP + + + BRACKET + +
+ {PROJECT_HANDLE} +
+ ); +} + +function ChampionRow({ slot }: { slot: number }) { + const { name } = displayTeam(slot); + const emoji = flagEmoji(slot); + return ( +
+
+ {emoji || '🏆'} +
+
+ CHAMPION + + {emoji ? name : 'To be decided'} + +
+
+ ); +} + +function MinorRow({ medal, label, slot }: { medal: string; label: string; slot: number }) { + const { name } = displayTeam(slot); + const emoji = flagEmoji(slot); + return ( +
+ {medal} + + {label} + + {emoji ? ( + <> + {emoji} + {name} + + ) : ( + + )} +
+ ); +} + +function Card({ children }: { children: ReactNode }) { + return ( +
+
+
+
+ {children} +
+ ); +} + +function Footer({ label }: { label: string }) { + return ( +
+ {label} +
+ {SHARE_HASHTAG} +
+
+ ); +} + +function podiumImage(picks: ReadonlyArray, fonts: LoadedFont[]): ImageResponse { + const { championSlot, runnerUpSlot, thirdSlot } = bracketHighlights(picks); + return new ImageResponse( + +
+
+ +
+ + +
+
+