From 3f177c16013df872df708cd2244099028735b076 Mon Sep 17 00:00:00 2001 From: Tommaso Casaburi Date: Tue, 2 Jun 2026 20:02:49 +0700 Subject: [PATCH] chore: extract hosted web app to a private repo; mixed-license monorepo The hosted MintPass web app (web/) is the SMS-OTP + NFT-mint service for mintpass.org -- abuse-sensitive, cost-bearing, and intended to be closed-source. It was inheriting the repo-root MIT license while sitting in a public repo (anyone could legally clone the whole service). Moved to the private repo bitsocialnet/mintpass-web (full history preserved via subtree split, proprietary LICENSE). This repo now ships only the open-source packages: - challenge -> GPL-3.0-or-later - contracts -> MIT Changes: - remove web/ (80 files) - LICENSE: MIT -> mixed-license explainer - package.json: license MIT -> UNLICENSED (private monorepo root) - README + scripts/llms-config.json: drop web/ references Authorized by cofounder / copyright holder. --- LICENSE | 23 +- README.md | 11 +- package.json | 2 +- scripts/llms-config.json | 7 +- web/.env.example | 36 - web/.gitignore | 42 - web/.yarnrc.yml | 1 - web/README.md | 178 - web/components.json | 32 - web/eslint.config.mjs | 3 - web/lib/abi.ts | 5 - web/lib/admin-auth-edge.ts | 85 - web/lib/admin-auth.ts | 109 - web/lib/cooldowns.ts | 76 - web/lib/env.ts | 112 - web/lib/hash.ts | 14 - web/lib/ip-reputation.ts | 51 - web/lib/kv.ts | 137 - web/lib/phone-intel.ts | 53 - web/lib/policy.ts | 24 - web/lib/rate-limit.ts | 35 - web/lib/request-ip.ts | 14 - web/lib/session.ts | 38 - web/lib/sms.ts | 340 - web/middleware.ts | 71 - web/next.config.ts | 30 - web/package.json | 74 - web/postcss.config.mjs | 8 - web/public/android-chrome-192x192.png | Bin 38619 -> 0 bytes web/public/android-chrome-512x512.png | Bin 168439 -> 0 bytes web/public/apple-touch-icon.png | Bin 35048 -> 0 bytes web/public/favicon-16x16.png | Bin 2049 -> 0 bytes web/public/favicon-32x32.png | Bin 3412 -> 0 bytes web/public/favicon.ico | Bin 14790 -> 0 bytes web/public/favicon.png | Bin 30663 -> 0 bytes web/public/llms-full.txt | 3251 ------- web/public/llms.txt | 49 - web/public/mintpass.png | Bin 73109 -> 0 bytes web/public/site.webmanifest | 19 - web/scripts/smoke-test.sh | 251 - web/scripts/start-dev.mjs | 152 - web/src/components/confetti-celebration.tsx | 59 - web/src/components/footer.tsx | 45 - web/src/components/header.tsx | 49 - .../magicui/animated-theme-toggler.tsx | 109 - web/src/components/magicui/confetti.tsx | 171 - web/src/components/magicui/rainbow-button.tsx | 59 - web/src/components/page-card.tsx | 63 - web/src/components/ui/button.tsx | 58 - web/src/components/ui/card.tsx | 76 - web/src/components/ui/command.tsx | 153 - web/src/components/ui/dialog.tsx | 120 - web/src/components/ui/dropdown-menu.tsx | 199 - web/src/components/ui/input-otp.tsx | 75 - web/src/components/ui/input.tsx | 22 - web/src/components/ui/label.tsx | 24 - web/src/components/ui/phone-input.tsx | 298 - web/src/components/ui/popover.tsx | 31 - web/src/components/ui/scroll-area.tsx | 46 - .../ui/shadcn-io/hexagon-background/index.tsx | 250 - web/src/lib/utils.ts | 6 - web/src/pages/404.tsx | 50 - web/src/pages/_app.tsx | 21 - web/src/pages/_document.tsx | 40 - web/src/pages/admin.tsx | 327 - web/src/pages/api/admin/clear-user.ts | 180 - web/src/pages/api/admin/login.ts | 47 - web/src/pages/api/admin/logout.ts | 25 - web/src/pages/api/check-eligibility.ts | 40 - web/src/pages/api/debug/code.ts | 25 - web/src/pages/api/mint.ts | 131 - web/src/pages/api/pre-check-eligibility.ts | 45 - web/src/pages/api/sms/send.ts | 174 - web/src/pages/api/sms/verify.ts | 120 - web/src/pages/index.tsx | 37 - web/src/pages/privacy-policy.tsx | 114 - web/src/pages/request/[eth-address].tsx | 20 - web/src/pages/request/index.tsx | 501 -- web/src/pages/terms-and-conditions.tsx | 75 - web/src/styles/globals.css | 86 - web/src/types/view-transitions.d.ts | 29 - web/tailwind.config.ts | 75 - web/tsconfig.json | 37 - web/yarn.lock | 7542 ----------------- 84 files changed, 15 insertions(+), 16972 deletions(-) delete mode 100644 web/.env.example delete mode 100644 web/.gitignore delete mode 100644 web/.yarnrc.yml delete mode 100644 web/README.md delete mode 100644 web/components.json delete mode 100644 web/eslint.config.mjs delete mode 100644 web/lib/abi.ts delete mode 100644 web/lib/admin-auth-edge.ts delete mode 100644 web/lib/admin-auth.ts delete mode 100644 web/lib/cooldowns.ts delete mode 100644 web/lib/env.ts delete mode 100644 web/lib/hash.ts delete mode 100644 web/lib/ip-reputation.ts delete mode 100644 web/lib/kv.ts delete mode 100644 web/lib/phone-intel.ts delete mode 100644 web/lib/policy.ts delete mode 100644 web/lib/rate-limit.ts delete mode 100644 web/lib/request-ip.ts delete mode 100644 web/lib/session.ts delete mode 100644 web/lib/sms.ts delete mode 100644 web/middleware.ts delete mode 100644 web/next.config.ts delete mode 100644 web/package.json delete mode 100644 web/postcss.config.mjs delete mode 100644 web/public/android-chrome-192x192.png delete mode 100644 web/public/android-chrome-512x512.png delete mode 100644 web/public/apple-touch-icon.png delete mode 100644 web/public/favicon-16x16.png delete mode 100644 web/public/favicon-32x32.png delete mode 100644 web/public/favicon.ico delete mode 100644 web/public/favicon.png delete mode 100644 web/public/llms-full.txt delete mode 100644 web/public/llms.txt delete mode 100644 web/public/mintpass.png delete mode 100644 web/public/site.webmanifest delete mode 100755 web/scripts/smoke-test.sh delete mode 100644 web/scripts/start-dev.mjs delete mode 100644 web/src/components/confetti-celebration.tsx delete mode 100644 web/src/components/footer.tsx delete mode 100644 web/src/components/header.tsx delete mode 100644 web/src/components/magicui/animated-theme-toggler.tsx delete mode 100644 web/src/components/magicui/confetti.tsx delete mode 100644 web/src/components/magicui/rainbow-button.tsx delete mode 100644 web/src/components/page-card.tsx delete mode 100644 web/src/components/ui/button.tsx delete mode 100644 web/src/components/ui/card.tsx delete mode 100644 web/src/components/ui/command.tsx delete mode 100644 web/src/components/ui/dialog.tsx delete mode 100644 web/src/components/ui/dropdown-menu.tsx delete mode 100644 web/src/components/ui/input-otp.tsx delete mode 100644 web/src/components/ui/input.tsx delete mode 100644 web/src/components/ui/label.tsx delete mode 100644 web/src/components/ui/phone-input.tsx delete mode 100644 web/src/components/ui/popover.tsx delete mode 100644 web/src/components/ui/scroll-area.tsx delete mode 100644 web/src/components/ui/shadcn-io/hexagon-background/index.tsx delete mode 100644 web/src/lib/utils.ts delete mode 100644 web/src/pages/404.tsx delete mode 100644 web/src/pages/_app.tsx delete mode 100644 web/src/pages/_document.tsx delete mode 100644 web/src/pages/admin.tsx delete mode 100644 web/src/pages/api/admin/clear-user.ts delete mode 100644 web/src/pages/api/admin/login.ts delete mode 100644 web/src/pages/api/admin/logout.ts delete mode 100644 web/src/pages/api/check-eligibility.ts delete mode 100644 web/src/pages/api/debug/code.ts delete mode 100644 web/src/pages/api/mint.ts delete mode 100644 web/src/pages/api/pre-check-eligibility.ts delete mode 100644 web/src/pages/api/sms/send.ts delete mode 100644 web/src/pages/api/sms/verify.ts delete mode 100644 web/src/pages/index.tsx delete mode 100644 web/src/pages/privacy-policy.tsx delete mode 100644 web/src/pages/request/[eth-address].tsx delete mode 100644 web/src/pages/request/index.tsx delete mode 100644 web/src/pages/terms-and-conditions.tsx delete mode 100644 web/src/styles/globals.css delete mode 100644 web/src/types/view-transitions.d.ts delete mode 100644 web/tailwind.config.ts delete mode 100644 web/tsconfig.json delete mode 100644 web/yarn.lock diff --git a/LICENSE b/LICENSE index 9e69d0f..4732fe2 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,8 @@ -MIT License +MintPass is a mixed-license monorepo for the public, open-source MintPass packages. -Copyright (c) 2025 Bitsocial +The controlling license depends on the package you are using: -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: +- `challenge` (`@bitsocial/mintpass-challenge`): `GPL-3.0-or-later`. See `challenge/LICENSE`. +- `contracts` (`@bitsocial/mintpass-contracts`): `MIT`. See `contracts/LICENSE`. -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. \ No newline at end of file +The hosted MintPass web app (the SMS-OTP and minting service for mintpass.org) is proprietary and maintained separately in a private repository; it is not included here. Unless a subdirectory says otherwise, root workspace files are provided for monorepo development only and are not offered as a separate redistributable package. diff --git a/README.md b/README.md index 56b147b..9737202 100644 --- a/README.md +++ b/README.md @@ -32,7 +32,6 @@ MintPass integrates as a challenge so Bitsocial communities can distinguish real mintpass/ ├── contracts/ # MintPassV1 smart contract and tooling ├── challenge/ # Bitsocial challenge implementation (“mintpass”) -├── web/ # Next.js website + API (mintpass.org) ├── docs/ # Documentation and specifications ├── tests/ # Cross‑component integration tests └── scripts/ # Deployment and utilities @@ -42,7 +41,7 @@ mintpass/ - `contracts/`: Solidity contracts (MintPassV1). Versioned, role‑based minting, token types per NFT (type 0 = SMS). See `contracts/README.md`. - `challenge/`: The Bitsocial challenge that checks for a MintPass NFT and applies additional rules (e.g., transfer cooldowns) to resist sybils. -- `web/`: The user‑facing site and serverless backend. Sends SMS codes, verifies OTP, and mints or records successful verification. See `web/README.md`. +- The hosted MintPass web app (the `mintpass.org` site + SMS-OTP / minting API) is **proprietary** and maintained in a separate private repository; it is not part of this public monorepo. ## Privacy and anti‑sybil design (high level) @@ -59,7 +58,6 @@ mintpass/ - Contracts: `cd contracts && yarn install && yarn test` - Challenge: `cd challenge && yarn install && yarn test` -- Web: `cd web && yarn install && yarn dev` then open `https://mintpass.localhost/request` ## Using MintPass in your community @@ -195,6 +193,9 @@ These items are exploratory; concrete work will land incrementally and stay conf ## License -MIT License — see [LICENSE](LICENSE). +MintPass is a mixed-license monorepo — see [LICENSE](LICENSE): -Open source and commercial‑friendly. A hosted version is available at [mintpass.org](https://mintpass.org). +- `challenge/` (`@bitsocial/mintpass-challenge`): GPL-3.0-or-later +- `contracts/` (`@bitsocial/mintpass-contracts`): MIT + +The hosted MintPass web app is proprietary and maintained in a separate private repository. A hosted version is available at [mintpass.org](https://mintpass.org). diff --git a/package.json b/package.json index 4d6e349..e3e3df3 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,7 @@ "type": "module", "description": "NFT-based authentication system for PKC communities", "author": "Bitsocial", - "license": "MIT", + "license": "UNLICENSED", "exports": { "./challenge": { "types": "./dist/challenge/index.d.ts", diff --git a/scripts/llms-config.json b/scripts/llms-config.json index 1626857..7da0b4a 100644 --- a/scripts/llms-config.json +++ b/scripts/llms-config.json @@ -4,8 +4,8 @@ "repoUrl": "https://github.com/bitsocialnet/mintpass", "llmsUrl": "https://mintpass.org/llms.txt", "llmsFullUrl": "https://mintpass.org/llms-full.txt", - "shortOutputs": ["llms.txt", "web/public/llms.txt"], - "fullOutputs": ["llms-full.txt", "web/public/llms-full.txt"], + "shortOutputs": ["llms.txt"], + "fullOutputs": ["llms-full.txt"], "links": [ ["Website", "https://mintpass.org"], ["Repository", "https://github.com/bitsocialnet/mintpass"], @@ -13,14 +13,13 @@ ["Bitsocial protocol", "https://bitsocial.net"] ], "notes": [ - "This is a multi-project repo: web, contracts, challenge, docs, and generated challenge artifacts.", + "This is a multi-project repo: contracts, challenge, docs, and generated challenge artifacts.", "Secrets and private deployment values belong in environment variables or private operator files, never in committed docs.", "Generated llms files are compiled context for AI contributors and deployed site readers; verify behavior against source." ], "docs": [ "README.md", "AGENTS.md", - "web/README.md", "challenge/README.md", "contracts/README.md", "docs/pkc-info.md", diff --git a/web/.env.example b/web/.env.example deleted file mode 100644 index fc50575..0000000 --- a/web/.env.example +++ /dev/null @@ -1,36 +0,0 @@ -# Vercel KV / Upstash Redis -KV_REST_API_URL="" -KV_REST_API_TOKEN="" - -# Server-held minter private key (DO NOT COMMIT REAL KEY) -MINTER_PRIVATE_KEY="" - -# Twilio Verify (Verify-first OTP; required in production for Verify mode) -TWILIO_ACCOUNT_SID="" -TWILIO_AUTH_TOKEN="" -TWILIO_VERIFY_SERVICE_SID="" - -# Legacy SMS sender envs (deprecated for OTP path) -# TWILIO_MESSAGING_SERVICE_SID="" -# SMS_SENDER_ID="MintPass" -SMS_PROVIDER_API_KEY="" - -# Preview/local smoke fallback token -SMOKE_TEST_TOKEN="" - -# Optional security policy -BLOCKED_COUNTRIES="" - -# Rate limiting -RATE_LIMIT_WINDOW_SECONDS="60" -RATE_LIMIT_MAX_REQUESTS="10" - -# Cooldowns -SMS_SEND_COOLDOWN_SECONDS="120" -MINT_IP_COOLDOWN_SECONDS="604800" # 7 days - -# Optional external intelligence providers -# IPQS for VPN/proxy/cloud detection -IPQS_API_KEY="" -# AbstractAPI (or similar) for phone risk and disposable detection -ABSTRACTAPI_PHONE_KEY="" \ No newline at end of file diff --git a/web/.gitignore b/web/.gitignore deleted file mode 100644 index 7b8da95..0000000 --- a/web/.gitignore +++ /dev/null @@ -1,42 +0,0 @@ -# See https://help.github.com/articles/ignoring-files/ for more about ignoring files. - -# dependencies -/node_modules -/.pnp -.pnp.* -.yarn/* -!.yarn/patches -!.yarn/plugins -!.yarn/releases -!.yarn/versions - -# testing -/coverage - -# next.js -/.next/ -/out/ - -# production -/build - -# misc -.DS_Store -*.pem - -# debug -npm-debug.log* -yarn-debug.log* -yarn-error.log* -.pnpm-debug.log* - -# env files (can opt-in for committing if needed) -.env* -!.env.example - -# vercel -.vercel - -# typescript -*.tsbuildinfo -next-env.d.ts diff --git a/web/.yarnrc.yml b/web/.yarnrc.yml deleted file mode 100644 index 3186f3f..0000000 --- a/web/.yarnrc.yml +++ /dev/null @@ -1 +0,0 @@ -nodeLinker: node-modules diff --git a/web/README.md b/web/README.md deleted file mode 100644 index f8b613a..0000000 --- a/web/README.md +++ /dev/null @@ -1,178 +0,0 @@ -## MintPass Web - -Serverless website and API that power the SMS verification flow and NFT minting at `mintpass.org`. - -### How it works (code map) -- UI: `src/pages/request/` — phone + OTP form, error handling, and success state -- API routes: - - `POST /api/sms/send` → rate-limit, optional IP/phone risk checks, then start Twilio Verify SMS (or non-prod smoke `kv-fallback`); returns `mode` (`verify` | `kv-fallback`) - - `POST /api/sms/verify` → verify OTP, mark phone as verified - - `POST /api/pre-check-eligibility` → quick check before sending code - - `POST /api/check-eligibility` → final eligibility check before mint - - `POST /api/mint` → on‑chain mint (when envs set) or record as minted -- Libraries and helpers: `lib/` — KV (Upstash), rate‑limits, cooldowns, hashing, SMS provider adapter, IP/phone intelligence, and admin auth/session utilities - -### Anti-Sybil and Security Requirements -- **Phone number database**: Track used numbers; prevent reuse for minting. -- **IP address tracking**: Rate limit per IP; detect abuse patterns. -- **SMS verification state**: Verify with Twilio Verify; keep short-lived fallback codes only for smoke flow. -- **Minter key security**: Private key only in Vercel env vars; never in code or logs. -- **Rate limiting**: Global and per-route limits to mitigate spam. -- **Geolocation filtering**: Optional country blocking via `middleware.ts`. -- **Audit trail (optional)**: Log key events to a separate store with redaction. - - **VPN/Proxy detection (optional)**: If `IPQS_API_KEY` is set, block VPNs/proxies/cloud provider IPs. - - **Disposable/VOIP phone detection (optional)**: If `ABSTRACTAPI_PHONE_KEY` is set, block disposable/VOIP/high-risk numbers. - - **Cooldowns**: Per-IP mint cooldown and per-IP/phone SMS send cooldowns configurable via env. - - **Keyed hashing (pepper)**: If `HASH_PEPPER` is set, phone numbers and IPs are stored as HMAC-SHA256 digests (domain-separated) in KV keys to reduce offline brute-force risk if a DB-only leak occurs. - -#### Preview-only testing behavior -- In Vercel Preview deployments (`VERCEL_ENV=preview`), the disposable/VOIP/high-risk phone check is bypassed in `POST /api/sms/send` to allow testing with temporary numbers. Production (`VERCEL_ENV=production`) remains strict and continues to block such numbers. - -### Vercel Setup (exact steps) -1. Create a new Vercel project and select this repo. Set root directory to `web`. -2. Add storage via Marketplace: Upstash → Redis. Create separate databases per environment (recommended): - - `mintpass-kv-prod` (Production) - - `mintpass-kv-preview` (Preview) - - `mintpass-kv-dev` (optional local) - Settings for each DB: Plan = Pay as You Go, Primary Region = `iad1` (US‑East), Read Regions = none, Eviction = off, Auto‑upgrade = on. -3. In Project Settings → Environment Variables, add: - - `MINTER_PRIVATE_KEY` (server only) - - `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_VERIFY_SERVICE_SID` (Verify mode; recommended for OTP) - - `BLOCKED_COUNTRIES` (comma-separated ISO codes if needed) - - `RATE_LIMIT_WINDOW_SECONDS`, `RATE_LIMIT_MAX_REQUESTS` (optional) - - `IPQS_API_KEY` (optional) to enable IP reputation checks - - `ABSTRACTAPI_PHONE_KEY` (optional) to enable disposable/VOIP phone checks - - `SMS_SEND_COOLDOWN_SECONDS` (optional) default 120 - - `MINT_IP_COOLDOWN_SECONDS` (optional) default 604800 (7 days) - - Map Upstash credentials to app envs per environment: - - Production: `KV_REST_API_URL` = Upstash prod REST URL; `KV_REST_API_TOKEN` = Upstash prod REST token - - Preview: `KV_REST_API_URL` = Upstash preview REST URL; `KV_REST_API_TOKEN` = Upstash preview REST token - - Local dev (optional): set the same in `.env.local` pointing to `mintpass-kv-dev` -4. Deploy. After first deploy, add the domain `mintpass.org` in Domains, set as primary. -5. Ensure the KV database is scoped to the production environment and not shared with preview. - -### Runtime regions -- Vercel Project → Settings → Functions → Region: set to `iad1` to co‑locate with Redis and reduce latency. - -### Storage notes -- Why Redis/KV: fast TTL keys for OTPs and cooldowns, atomic counters, and simple idempotency. -- Cost model (Pay as You Go): ~$0.20 per 100k commands. Typical flow is ~20 commands per successful mint. - -### Environments and KV mapping (prod/preview/local) -- **Databases to create**: - - `mintpass-kv-prod` → used by Vercel Production - - `mintpass-kv-preview` → used by Vercel Preview (and local dev by default) - - Optional later: `mintpass-kv-dev` → used only for local dev - -- **Vercel → Project → Settings → Environment Variables**: - - Production: set `KV_REST_API_URL` and `KV_REST_API_TOKEN` from `mintpass-kv-prod` - - Preview: set `KV_REST_API_URL` and `KV_REST_API_TOKEN` from `mintpass-kv-preview` - - Do not point local or preview to prod. - -- **Local development**: - - Copy `.env.example` to `.env.local` - - Set `KV_REST_API_URL` and `KV_REST_API_TOKEN` to the preview DB (or to `mintpass-kv-dev` if you created it) - - Run `yarn dev` - -### API Routes -- `POST /api/sms/send` → request SMS code (rate-limited; Verify-first with non-prod smoke fallback) -- `POST /api/sms/verify` → verify code and mark phone as verified -- `POST /api/check-eligibility` → confirm address + phone can mint -- `POST /api/mint` → on-chain mint on Base Sepolia when envs are set; otherwise records local minted state. Requires `authorAddress` string; country is derived from `x-vercel-ip-country` header. - -### Local Development - -Requires [Portless](https://github.com/vercel-labs/portless), installed with project dependencies via `corepack yarn install` - -```bash -corepack enable -corepack yarn install -corepack yarn dev # https://mintpass.localhost -``` - -The dev server runs at https://mintpass.localhost via [Portless](https://github.com/vercel-labs/portless), which gives each Bitsocial project a stable, named URL instead of a random port. To bypass Portless: `PORTLESS=0 yarn dev` - -To test API calls locally, use `curl` or your preferred REST client. - -### Smoke test (prod/preview) -Create local env files (not committed) with the target base URL and test identifiers. Include Upstash REST URL/Token when you need `kv-fallback` full E2E: - -- `.env.smoke.prod` (for Production) -``` -BASE_URL=https://mintpass.org -PHONE=+15555550123 -ADDR=0x1111111111111111111111111111111111111111 -``` - -- `.env.smoke.preview` (for Preview) -``` -KV_REST_API_URL= -KV_REST_API_TOKEN= -PREVIEW_BASE_URL=https://.vercel.app -PHONE=+15555550123 -ADDR=0x1111111111111111111111111111111111111111 -BYPASS_TOKEN=... -SMOKE_TEST_TOKEN=... -``` - -Run the script: -```bash -yarn smoke:prod -# or -yarn smoke:preview -``` - -Notes: -- The script inspects `POST /api/sms/send` response JSON for `mode` (`verify` | `kv-fallback`). -- **mode=kv-fallback**: runs full E2E (fetch code from KV/debug → verify → eligibility → mint). -- **mode=verify + prod**: send-health (send ok) + eligibility check only; OTP verify/mint skipped by design. -- **mode=verify + preview**: full E2E only when fallback is used; otherwise OTP verify/mint skipped with clear message. -- `KV_REST_API_URL` and `KV_REST_API_TOKEN` are required only when `mode=kv-fallback`. -- `BYPASS_TOKEN` and `SMOKE_TEST_TOKEN` supported. -- The script loads ENVFILE (if provided), then `.env.smoke.{prod|preview}`, then `.env.local`, then `.env`. -- No SMS provider needed for kv-fallback; OTP is read from KV via REST for testing. -- Cooldowns and rate limits apply; you may need to wait 120s for repeated runs. - - If your Preview custom domain is protected via Vercel Auth and proxied by Cloudflare, prefer the vercel.app URL for smoke tests. - -### Contributor quickstart: Preview smoke test -- Create/connect a Preview Upstash KV to this project and ensure the Preview env has `KV_REST_API_URL` and `KV_REST_API_TOKEN` (use the plain names; avoid double prefixes). Optionally set `SMOKE_TEST_TOKEN` to enable a debug echo of the OTP. -- If Deployment Protection is enabled, create a Protection Bypass token and use it as `BYPASS_TOKEN` in the `.env.smoke.preview` file. The script will set the bypass cookie and header automatically. -- Trigger a new Preview deployment and copy its per-deployment vercel.app URL from Vercel → Deployments. Use that URL as `PREVIEW_BASE_URL`. -- Create `web/.env.smoke.preview` with: - - `KV_REST_API_URL`, `KV_REST_API_TOKEN` - - `PREVIEW_BASE_URL`, `PHONE`, `ADDR` - - `BYPASS_TOKEN` (only if protection is enabled) - - `SMOKE_TEST_TOKEN` (optional; returns `debugCode` during send) -- Run `corepack yarn install` then `corepack yarn smoke:preview`. -- Expected: send → verify → eligibility=true → mint ok (stubbed unless on-chain envs are set). - -### Environment Variables -Copy `.env.example` to `.env.local` and fill in values. Do not commit `.env.local`. - -Required for runtime: -- `KV_REST_API_URL`, `KV_REST_API_TOKEN` -- `HASH_PEPPER` (optional; HMAC key for hashing identifiers used in KV keys) - -Optional for SMS provider (Twilio Verify preferred): -- `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_VERIFY_SERVICE_SID` — required in production for Verify mode. Create a Verify Service in Twilio Console and use its SID. -- Legacy (kv-fallback only; deprecated for OTP): `TWILIO_MESSAGING_SERVICE_SID` or `SMS_SENDER_ID` - -Optional for on-chain mint (Base Sepolia): -- `MINTER_PRIVATE_KEY` -- `MINTPASSV1_ADDRESS_BASE_SEPOLIA` -- `BASE_SEPOLIA_RPC_URL` - -Optional for smoke testing (Preview only): -- `SMOKE_TEST_TOKEN` (debug-only echo of OTP when `x-smoke-test-token` header is present) -- `HASH_PEPPER` (optional; if set, `scripts/smoke-test.sh` derives the hashed OTP KV key via OpenSSL when available) - -### Next Steps -- Add additional authentication methods beyond SMS (e.g., pay‑to‑mint, others). -- Add abuse heuristics (velocity checks per phone/IP, lightweight device signals if needed). -- Continue UI polish and success animations; broaden admin tooling and observability. - -This project includes both backend APIs and frontend UI components built with shadcn/ui and mobile-first responsive design. - -### Operational recommendations -- Put Cloudflare in front of Vercel for additional DDoS protection and WAF/challenge. Set `CF-Connecting-IP` pass-through so backend uses real client IP. -- Monitor rate-limit headers (`X-RateLimit-*`) and adjust envs based on traffic. diff --git a/web/components.json b/web/components.json deleted file mode 100644 index 81e9184..0000000 --- a/web/components.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "$schema": "https://ui.shadcn.com/schema.json", - "style": "new-york", - "rsc": false, - "tsx": true, - "tailwind": { - "config": "tailwind.config.ts", - "css": "src/styles/globals.css", - "baseColor": "neutral", - "cssVariables": true, - "prefix": "" - }, - "iconLibrary": "lucide", - "aliases": { - "components": "@/components", - "utils": "@/lib/utils", - "ui": "@/components/ui", - "lib": "@/lib", - "hooks": "@/hooks" - }, - "registries": { - "@alpine": "https://alpine-registry.vercel.app/r/{name}.json", - "@tailark": "https://tailark.com/r/{name}.json", - "@magicui": "https://magicui.dev/r/{name}.json", - "@shadcn-form": "https://www.shadcn-form.com/r/{name}.json", - "@kokonutui": "https://kokonutui.com/r/{name}.json", - "@diceui": "https://diceui.com/r/{name}.json", - "@basecn": "https://basecn.dev/r/{name}.json", - "@animateui": "https://animate-ui.com/r/{name}.json", - "@fancycomponents": "https://fancycomponents.dev/r/{name}.json" - } -} diff --git a/web/eslint.config.mjs b/web/eslint.config.mjs deleted file mode 100644 index fcbac3c..0000000 --- a/web/eslint.config.mjs +++ /dev/null @@ -1,3 +0,0 @@ -import nextConfig from "eslint-config-next"; - -export default nextConfig; diff --git a/web/lib/abi.ts b/web/lib/abi.ts deleted file mode 100644 index 10d6f79..0000000 --- a/web/lib/abi.ts +++ /dev/null @@ -1,5 +0,0 @@ -// Minimal ABIs used by the backend -export const MintPassV1Abi = [ - 'function mint(address to, uint16 tokenTypeValue) external', -]; - diff --git a/web/lib/admin-auth-edge.ts b/web/lib/admin-auth-edge.ts deleted file mode 100644 index dcea47a..0000000 --- a/web/lib/admin-auth-edge.ts +++ /dev/null @@ -1,85 +0,0 @@ -// Edge-safe admin token verification using Web Crypto API - -function toHex(buffer: ArrayBuffer): string { - const bytes = new Uint8Array(buffer); - let out = ''; - for (let i = 0; i < bytes.length; i++) { - const h = bytes[i].toString(16).padStart(2, '0'); - out += h; - } - return out; -} - -async function hmacSha256Hex(message: string, secret: string): Promise { - const enc = new TextEncoder(); - const key = await crypto.subtle.importKey( - 'raw', - enc.encode(secret), - { name: 'HMAC', hash: 'SHA-256' }, - false, - ['sign'] - ); - const sig = await crypto.subtle.sign('HMAC', key, enc.encode(message)); - return toHex(sig); -} - -export async function verifyAdminTokenEdge(token: string | undefined, secret: string | undefined): Promise { - if (!token || !secret) return false; - const parts = token.split('.'); - if (parts.length !== 2) return false; - const [payloadB64, sig] = parts; - try { - // Validate formats up-front - const isBase64Url = /^[A-Za-z0-9_-]+$/.test(payloadB64); - // sha256 HMAC hex digest should be 64 lowercase hex chars - const isHexSig = /^[0-9a-f]{64}$/.test(sig); - if (!isBase64Url || !isHexSig) return false; - - const expected = await hmacSha256Hex(payloadB64, secret); - if (expected.length !== sig.length) return false; - // timing-safe equal polyfill - let mismatch = 0; - for (let i = 0; i < expected.length; i++) { - mismatch |= expected.charCodeAt(i) ^ sig.charCodeAt(i); - } - if (mismatch !== 0) return false; - - // Verify payload with robust validation - try { - // Normalize base64url and add required padding for robust decoding - const normalized = payloadB64.replace(/-/g, '+').replace(/_/g, '/'); - const paddingLen = (4 - (normalized.length % 4)) % 4; - const padded = normalized + '='.repeat(paddingLen); - const json = atob(padded); - const payload = JSON.parse(json); - - // Validate payload structure - if (!payload || typeof payload !== 'object') return false; - const { v, iat, exp } = payload as { v: unknown; iat: unknown; exp: unknown }; - if (!Number.isFinite(v as number) || (v as number) !== 1) return false; - if (!Number.isFinite(iat as number) || !Number.isFinite(exp as number)) return false; - - const now = Math.floor(Date.now() / 1000); - const iatNum = Math.floor(iat as number); - const expNum = Math.floor(exp as number); - - // iat must be in the past (<= now) but not older than 1 day - const maxIatSkewSeconds = 24 * 60 * 60; // 1 day - if (iatNum > now) return false; - if (iatNum < now - maxIatSkewSeconds) return false; - - // exp must be in the future and not farther than 30 days from now - const maxTtlSeconds = 30 * 24 * 60 * 60; // 30 days - if (expNum <= now) return false; - if (expNum > now + maxTtlSeconds) return false; - - return true; - } catch { - return false; - } - } catch { - return false; - } -} - - diff --git a/web/lib/admin-auth.ts b/web/lib/admin-auth.ts deleted file mode 100644 index f5a90cd..0000000 --- a/web/lib/admin-auth.ts +++ /dev/null @@ -1,109 +0,0 @@ -import { createHmac, timingSafeEqual } from 'crypto'; -import type { NextApiRequest, NextApiResponse } from 'next'; -import { getAdminSessionSecret, getAdminSessionMaxLifetimeSeconds } from './env'; - -const ADMIN_COOKIE_NAME = 'admin_session'; -const DEFAULT_SESSION_TTL_SECONDS = getAdminSessionMaxLifetimeSeconds(); - -type AdminTokenPayload = { - v: 1; - iat: number; // seconds since epoch - exp: number; // seconds since epoch -}; - -function base64urlEncode(input: string): string { - return Buffer.from(input) - .toString('base64') - .replace(/=/g, '') - .replace(/\+/g, '-') - .replace(/\//g, '_'); -} - -function sign(data: string, secret: string): string { - return createHmac('sha256', secret).update(data).digest('hex'); -} - -export function createAdminToken(expiresInSeconds = DEFAULT_SESSION_TTL_SECONDS): string { - const secret = getAdminSessionSecret(); - if (!secret) throw new Error('ADMIN_SESSION_SECRET not configured'); - const now = Math.floor(Date.now() / 1000); - const payload: AdminTokenPayload = { v: 1, iat: now, exp: now + expiresInSeconds }; - const payloadB64 = base64urlEncode(JSON.stringify(payload)); - const sig = sign(payloadB64, secret); - return `${payloadB64}.${sig}`; -} - -export function verifyAdminToken(token: string | undefined): boolean { - if (!token) return false; - const secret = getAdminSessionSecret(); - if (!secret) return false; - const parts = token.split('.'); - if (parts.length !== 2) return false; - const [payloadB64, sig] = parts; - // Pre-validate signature format to fixed-length hex (64 chars for sha256) - if (!/^[0-9a-fA-F]{64}$/.test(sig)) return false; - // Validate payload base64url characters to avoid decode work on malformed input - if (!/^[A-Za-z0-9_-]+$/.test(payloadB64)) return false; - const expected = sign(payloadB64, secret); - const a = Buffer.from(sig, 'hex'); - const b = Buffer.from(expected, 'hex'); - // Use timingSafeEqual on same-length buffers - if (!timingSafeEqual(a, b)) return false; - try { - // Decode base64url with padding - const base64 = payloadB64.replace(/-/g, '+').replace(/_/g, '/'); - const pad = (4 - (base64.length % 4)) % 4; - const padded = base64 + '='.repeat(pad); - const json = Buffer.from(padded, 'base64').toString('utf8'); - const payload = JSON.parse(json) as AdminTokenPayload; - if (payload.v !== 1) return false; - const now = Math.floor(Date.now() / 1000); - return now < payload.exp; - } catch { - return false; - } -} - -function appendSetCookie(res: NextApiResponse, newCookie: string) { - const existing = res.getHeader('Set-Cookie'); - const existingCookies = existing - ? (Array.isArray(existing) ? existing.map(String) : [String(existing)]) - : []; - res.setHeader('Set-Cookie', [...existingCookies, newCookie]); -} - -export function setAdminSessionCookie(res: NextApiResponse, token: string, maxAgeSeconds = DEFAULT_SESSION_TTL_SECONDS) { - const isProd = process.env.NODE_ENV === 'production'; - const cookie = `${ADMIN_COOKIE_NAME}=${token}; Path=/; HttpOnly; SameSite=Strict; Max-Age=${maxAgeSeconds};${isProd ? ' Secure;' : ''}`; - appendSetCookie(res, cookie); -} - -export function clearAdminSessionCookie(res: NextApiResponse) { - const isProd = process.env.NODE_ENV === 'production'; - const cookie = `${ADMIN_COOKIE_NAME}=; Path=/; HttpOnly; SameSite=Strict; Max-Age=0;${isProd ? ' Secure;' : ''}`; - appendSetCookie(res, cookie); -} - -export function isAdminRequest(req: NextApiRequest): boolean { - const token = req.cookies?.[ADMIN_COOKIE_NAME]; - return verifyAdminToken(token); -} - -export function requireAdmin(req: NextApiRequest, res: NextApiResponse): boolean { - if (isAdminRequest(req)) return true; - res.status(401).json({ error: 'Unauthorized' }); - return false; -} - -export const AdminAuth = { - ADMIN_COOKIE_NAME, - DEFAULT_SESSION_TTL_SECONDS, - createAdminToken, - verifyAdminToken, - setAdminSessionCookie, - clearAdminSessionCookie, - isAdminRequest, - requireAdmin, -}; - - diff --git a/web/lib/cooldowns.ts b/web/lib/cooldowns.ts deleted file mode 100644 index 6453ca6..0000000 --- a/web/lib/cooldowns.ts +++ /dev/null @@ -1,76 +0,0 @@ -import { kv } from '@vercel/kv'; -import { policy } from './policy'; -import { hashIdentifier } from './hash'; - -function smsPhoneCooldownKey(phoneE164: string) { - const h = hashIdentifier('phone', phoneE164); - return `cd:sms:phone:${h}`; -} - -function smsIpCooldownKey(ip: string) { - const h = hashIdentifier('ip', ip); - return `cd:sms:ip:${h}`; -} - -function mintIpCooldownKey(ip: string) { - const h = hashIdentifier('ip', ip); - return `cd:mint:ip:${h}`; -} - -export async function isSmsSendInCooldown(ip: string, phoneE164: string) { - const [p, i] = await Promise.all([ - kv.get(smsPhoneCooldownKey(phoneE164)), - kv.get(smsIpCooldownKey(ip)), - ]); - if (p || i) return true; - // Legacy plaintext keys fallback - const legacyP = await kv.get(`cd:sms:phone:${phoneE164}`); - const legacyI = await kv.get(`cd:sms:ip:${ip}`); - return Boolean(legacyP || legacyI); -} - -export async function getSmsSendCooldownRemaining(ip: string, phoneE164: string): Promise { - // Check TTL for both phone and IP cooldown keys - const [phoneTtl, ipTtl] = await Promise.all([ - kv.ttl(smsPhoneCooldownKey(phoneE164)), - kv.ttl(smsIpCooldownKey(ip)), - ]); - - // Also check legacy plaintext keys - const [legacyPhoneTtl, legacyIpTtl] = await Promise.all([ - kv.ttl(`cd:sms:phone:${phoneE164}`), - kv.ttl(`cd:sms:ip:${ip}`), - ]); - - // Return the maximum TTL (whichever cooldown has more time remaining) - // TTL returns -1 if key doesn't exist, -2 if key exists but has no expiry - const validTtls = [phoneTtl, ipTtl, legacyPhoneTtl, legacyIpTtl].filter(ttl => ttl > 0); - - return validTtls.length > 0 ? Math.max(...validTtls) : 0; -} - -export async function setSmsSendCooldown(ip: string, phoneE164: string) { - const ttl = Number.isFinite(policy.SMS_SEND_COOLDOWN_SECONDS) && policy.SMS_SEND_COOLDOWN_SECONDS > 0 - ? policy.SMS_SEND_COOLDOWN_SECONDS - : 120; - await Promise.all([ - kv.set(smsPhoneCooldownKey(phoneE164), '1', { ex: ttl }), - kv.set(smsIpCooldownKey(ip), '1', { ex: ttl }), - ]); -} - -export async function isMintIpInCooldown(ip: string) { - const v = await kv.get(mintIpCooldownKey(ip)); - if (v) return true; - const legacy = await kv.get(`cd:mint:ip:${ip}`); - return Boolean(legacy); -} - -export async function setMintIpCooldown(ip: string) { - const ttl = Number.isFinite(policy.MINT_IP_COOLDOWN_SECONDS) && policy.MINT_IP_COOLDOWN_SECONDS > 0 - ? policy.MINT_IP_COOLDOWN_SECONDS - : 7 * 24 * 60 * 60; // default 7 days - await kv.set(mintIpCooldownKey(ip), '1', { ex: ttl }); -} - - diff --git a/web/lib/env.ts b/web/lib/env.ts deleted file mode 100644 index f02dbf9..0000000 --- a/web/lib/env.ts +++ /dev/null @@ -1,112 +0,0 @@ -import { z } from "zod"; - -// Guard against accidental client bundling of this module -if (typeof window !== "undefined") { - throw new Error("env.ts must not be imported on the client"); -} - -const ethAddress = z - .string() - .regex(/^0x[a-fA-F0-9]{40}$/, "Must be a valid 0x-prefixed Ethereum address"); - -const envSchema = z.object({ - // Vercel KV / Upstash Redis - KV_REST_API_URL: z.string().url(), - KV_REST_API_TOKEN: z.string().min(1), - - // Secrets and provider keys (server-only) - MINTER_PRIVATE_KEY: z.string().min(1).optional(), - SMS_PROVIDER_API_KEY: z.string().optional(), // legacy/generic - // Legacy sender ID env (deprecated for OTP Verify flow): 1-11 chars, - // must have at least one letter, only letters/digits/spaces allowed. - SMS_SENDER_ID: z - .string() - .refine((val) => { - if (!val) return true; // optional - // If it starts with + it's a phone number, skip alphanumeric validation - if (val.startsWith("+")) return true; - // Alphanumeric: max 11 chars, at least one letter, only [A-Za-z0-9 ] - return val.length <= 11 && /[A-Za-z]/.test(val) && /^[A-Za-z0-9 ]+$/.test(val); - }, "Alphanumeric sender ID must be 1-11 characters, contain at least one letter, and only use letters, digits, or spaces") - .optional(), // generic sender id/from - - // Twilio Verify (preferred OTP path) - TWILIO_ACCOUNT_SID: z.string().optional(), - TWILIO_AUTH_TOKEN: z.string().optional(), - TWILIO_VERIFY_SERVICE_SID: z.string().optional(), - // Legacy Twilio Messaging env (deprecated for OTP Verify flow) - TWILIO_MESSAGING_SERVICE_SID: z.string().optional(), - - // On-chain Mint (Base Sepolia) - MINTPASSV1_ADDRESS_BASE_SEPOLIA: ethAddress.optional(), - BASE_SEPOLIA_RPC_URL: z.string().url().optional(), - - // Preview-only smoke test helper - SMOKE_TEST_TOKEN: z.string().optional(), - // Keyed hashing pepper for identifiers (HMAC key) - HASH_PEPPER: z.string().optional(), - - // Admin credentials (server-only) - ADMIN_PASSWORD: z.string().min(12, "Admin password must be at least 12 characters").optional(), - ADMIN_SESSION_SECRET: z - .string() - .min(32, "Admin session secret must be at least 32 characters") - .optional(), - ADMIN_SESSION_MAX_LIFETIME_SECONDS: z.string().optional(), -}); - -const parsed = envSchema.safeParse(process.env as Record); - -if (!parsed.success) { - // Do not crash builds in early scaffolding if envs are missing; warn instead - // Runtime handlers will validate critical vars per-route. - console.warn( - "[env] Missing or invalid environment variables:", - parsed.error.flatten().fieldErrors, - ); -} - -export const env = { - KV_REST_API_URL: process.env.KV_REST_API_URL, - KV_REST_API_TOKEN: process.env.KV_REST_API_TOKEN, - MINTER_PRIVATE_KEY: process.env.MINTER_PRIVATE_KEY, - SMS_PROVIDER_API_KEY: process.env.SMS_PROVIDER_API_KEY, - SMS_SENDER_ID: process.env.SMS_SENDER_ID, - TWILIO_ACCOUNT_SID: process.env.TWILIO_ACCOUNT_SID, - TWILIO_AUTH_TOKEN: process.env.TWILIO_AUTH_TOKEN, - TWILIO_VERIFY_SERVICE_SID: process.env.TWILIO_VERIFY_SERVICE_SID, - TWILIO_MESSAGING_SERVICE_SID: process.env.TWILIO_MESSAGING_SERVICE_SID, - MINTPASSV1_ADDRESS_BASE_SEPOLIA: process.env.MINTPASSV1_ADDRESS_BASE_SEPOLIA, - BASE_SEPOLIA_RPC_URL: process.env.BASE_SEPOLIA_RPC_URL, - SMOKE_TEST_TOKEN: process.env.SMOKE_TEST_TOKEN, - HASH_PEPPER: process.env.HASH_PEPPER, - ADMIN_PASSWORD: process.env.ADMIN_PASSWORD, - ADMIN_SESSION_SECRET: process.env.ADMIN_SESSION_SECRET, - ADMIN_SESSION_MAX_LIFETIME_SECONDS: process.env.ADMIN_SESSION_MAX_LIFETIME_SECONDS, -}; - -// Server-only accessors for secrets - use validated schema values -export function getAdminPassword(): string | undefined { - return env.ADMIN_PASSWORD; -} - -export function getAdminSessionSecret(): string | undefined { - return env.ADMIN_SESSION_SECRET; -} - -export function getAdminSessionMaxLifetimeSeconds(): number { - const raw = env.ADMIN_SESSION_MAX_LIFETIME_SECONDS; - const n = raw ? Number(raw) : NaN; - // Default to 8 hours if unset or invalid - if (!Number.isFinite(n) || n <= 0) return 8 * 60 * 60; - // Cap to 24 hours - return Math.min(n, 24 * 60 * 60); -} - -export function requireEnv(key: K): NonNullable<(typeof env)[K]> { - const value = env[key]; - if (value === undefined || value === null || (typeof value === "string" && value.length === 0)) { - throw new Error(`Missing required env: ${String(key)}`); - } - return value as NonNullable<(typeof env)[K]>; -} diff --git a/web/lib/hash.ts b/web/lib/hash.ts deleted file mode 100644 index 93807a5..0000000 --- a/web/lib/hash.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { createHmac } from 'crypto'; -import { env } from './env'; - -// Deterministic keyed hashing for identifiers with domain separation. -// If HASH_PEPPER is not set, returns the original value for backward compatibility. -export function hashIdentifier(kind: 'phone' | 'ip' | 'addr' | 'generic', value: string): string { - const pepper = env.HASH_PEPPER; - if (pepper && pepper.length > 0) { - return createHmac('sha256', pepper).update(`${kind}:${value}`).digest('hex'); - } - return value; -} - - diff --git a/web/lib/ip-reputation.ts b/web/lib/ip-reputation.ts deleted file mode 100644 index b26fb28..0000000 --- a/web/lib/ip-reputation.ts +++ /dev/null @@ -1,51 +0,0 @@ -import type { NextApiRequest } from 'next'; - -export type IpReputation = { - ip: string; - isVpnOrProxy: boolean; - isCloudProvider: boolean; - riskScore?: number; - provider?: 'ipqs' | 'none'; -}; - -function getClientIp(req: NextApiRequest): string { - const xf = (req.headers['x-forwarded-for'] as string) || ''; - const first = xf.split(',')[0]?.trim(); - return first || req.socket.remoteAddress || 'unknown'; -} - -export async function assessIpReputation(req: NextApiRequest): Promise { - const ip = getClientIp(req); - - // If IPQS is configured, use it. Otherwise, return neutral assessment. - const ipqsKey = process.env.IPQS_API_KEY; - if (ipqsKey && ip && ip !== 'unknown') { - try { - const url = `https://ipqualityscore.com/api/json/ip/${encodeURIComponent(ipqsKey)}/${encodeURIComponent(ip)}?strictness=1&allow_public_access_points=false`; - const controller = new AbortController(); - const timer = setTimeout(() => controller.abort(), 3000); - const res = await fetch(url, { method: 'GET', signal: controller.signal }); - clearTimeout(timer); - const data = (await res.json()) as { - vpn?: boolean; - proxy?: boolean; - tor?: boolean; - relay?: boolean; - active_vpn?: boolean; - active_tor?: boolean; - cloud_provider?: boolean; - fraud_score?: number; - }; - const isVpnOrProxy = Boolean(data.vpn || data.proxy || data.tor || data.relay || data.active_vpn || data.active_tor); - const isCloudProvider = Boolean(data.cloud_provider); - const riskScore = typeof data.fraud_score === 'number' ? data.fraud_score : undefined; - return { ip, isVpnOrProxy, isCloudProvider, riskScore, provider: 'ipqs' }; - } catch { - return { ip, isVpnOrProxy: false, isCloudProvider: false, provider: 'ipqs' }; - } - } - - return { ip, isVpnOrProxy: false, isCloudProvider: false, provider: 'none' }; -} - - diff --git a/web/lib/kv.ts b/web/lib/kv.ts deleted file mode 100644 index 53bf021..0000000 --- a/web/lib/kv.ts +++ /dev/null @@ -1,137 +0,0 @@ -import { kv } from "@vercel/kv"; -import { hashIdentifier } from "./hash"; - -const CODE_TTL_SECONDS = 5 * 60; // 5 minutes - -function codeKey(phoneE164: string) { - const h = hashIdentifier("phone", phoneE164); - return `sms:code:${h}`; -} - -function verifiedKey(phoneE164: string) { - const h = hashIdentifier("phone", phoneE164); - return `sms:verified:${h}`; -} - -function mintedKey(address: string) { - const lower = address.toLowerCase(); - const h = hashIdentifier("addr", lower); - return `mint:address:${h}`; -} - -function phoneMintedKey(phoneE164: string) { - const h = hashIdentifier("phone", phoneE164); - return `mint:phone:${h}`; -} - -export async function saveSmsCode(phoneE164: string, code: string) { - await kv.set(codeKey(phoneE164), code, { ex: CODE_TTL_SECONDS }); -} - -export async function readSmsCode(phoneE164: string) { - // Try hashed key; if missing, fall back to legacy plaintext key for backwards compatibility - const primary = await kv.get(codeKey(phoneE164)); - if (primary !== null && primary !== undefined) return primary; - const legacyKey = `sms:code:${phoneE164}`; - return kv.get(legacyKey); -} - -export async function clearSmsCode(phoneE164: string) { - await kv.del(codeKey(phoneE164)); - // Also remove legacy key if present - await kv.del(`sms:code:${phoneE164}`); -} - -export async function markPhoneVerified(phoneE164: string) { - await kv.set(verifiedKey(phoneE164), "1", { ex: CODE_TTL_SECONDS }); -} - -export async function isPhoneVerified(phoneE164: string) { - let v = await kv.get(verifiedKey(phoneE164)); - if (v === null || v === undefined) { - v = await kv.get(`sms:verified:${phoneE164}`); - } - // Normalize potential numeric deserialization from KV - return String(v) === "1"; -} - -export async function markMinted(address: string, phoneE164: string) { - // Persist indefinitely to prevent reuse; can add TTL policy later if needed - await kv.set(mintedKey(address), phoneE164); - await kv.set(phoneMintedKey(phoneE164), address.toLowerCase()); - // Optionally, we could migrate legacy keys here, but we avoid writing plaintext keys. -} - -export async function hasMinted(address: string) { - let v = await kv.get(mintedKey(address)); - if (!(typeof v === "string" && v.length > 0)) { - v = await kv.get(`mint:address:${address.toLowerCase()}`); - } - return typeof v === "string" && v.length > 0; -} - -export async function hasPhoneMinted(phoneE164: string) { - let v = await kv.get(phoneMintedKey(phoneE164)); - if (!(typeof v === "string" && v.length > 0)) { - v = await kv.get(`mint:phone:${phoneE164}`); - } - return typeof v === "string" && v.length > 0; -} - -// --- Associations: phone/address -> hashed IPs --- -function phoneIpsKey(phoneE164: string) { - const h = hashIdentifier("phone", phoneE164); - return `assoc:phone:ips:${h}`; -} - -function addressIpsKey(address: string) { - const lower = address.toLowerCase(); - const h = hashIdentifier("addr", lower); - return `assoc:addr:ips:${h}`; -} - -/** - * Record the hashed IP used with a given phone number. - * Stores only the hashed IP to avoid retaining plaintext IPs. - */ -export async function addIpAssociationForPhone(phoneE164: string, ip: string) { - const ipHash = hashIdentifier("ip", ip); - try { - await kv.sadd(phoneIpsKey(phoneE164), ipHash); - } catch {} -} - -/** - * Record the hashed IP used with a given wallet address. - * Stores only the hashed IP to avoid retaining plaintext IPs. - */ -export async function addIpAssociationForAddress(address: string, ip: string) { - const ipHash = hashIdentifier("ip", ip); - try { - await kv.sadd(addressIpsKey(address), ipHash); - } catch {} -} - -/** Get all hashed IPs associated with a given phone number. */ -export async function getHashedIpsForPhone(phoneE164: string): Promise { - try { - const ips = await kv.smembers(phoneIpsKey(phoneE164)); - return Array.isArray(ips) - ? ips.filter((v): v is string => typeof v === "string" && v.length > 0) - : []; - } catch { - return []; - } -} - -/** Get all hashed IPs associated with a given wallet address. */ -export async function getHashedIpsForAddress(address: string): Promise { - try { - const ips = await kv.smembers(addressIpsKey(address)); - return Array.isArray(ips) - ? ips.filter((v): v is string => typeof v === "string" && v.length > 0) - : []; - } catch { - return []; - } -} diff --git a/web/lib/phone-intel.ts b/web/lib/phone-intel.ts deleted file mode 100644 index 3ac279c..0000000 --- a/web/lib/phone-intel.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { z } from 'zod'; - -export type PhoneCheck = { - phoneE164: string; - isDisposable: boolean; - isVoip: boolean; - isHighRisk: boolean; - carrierType?: string; - provider?: 'abstractapi' | 'none'; -}; - -const AbstractPhoneResp = z.object({ - valid: z.boolean().optional(), - number: z.string().optional(), - disposable: z.boolean().optional(), - type: z.string().optional(), // e.g., 'mobile', 'voip' - risk: z.number().optional(), -}); - -export async function analyzePhone(phoneE164: string): Promise { - const key = process.env.ABSTRACTAPI_PHONE_KEY; - if (key) { - try { - const url = `https://phonevalidation.abstractapi.com/v1/?api_key=${encodeURIComponent(key)}&phone=${encodeURIComponent(phoneE164)}`; - const controller = new AbortController(); - const timer = setTimeout(() => controller.abort(), 3000); - const res = await fetch(url, { signal: controller.signal }); - clearTimeout(timer); - const data = await res.json(); - const parsed = AbstractPhoneResp.safeParse(data); - if (parsed.success) { - const t = (parsed.data.type || '').toLowerCase(); - const isVoip = t.includes('voip'); - const isDisposable = Boolean(parsed.data.disposable); - const risk = parsed.data.risk ?? 0; - const isHighRisk = isVoip || isDisposable || risk >= 70; - return { - phoneE164, - isDisposable, - isVoip, - isHighRisk, - carrierType: parsed.data.type, - provider: 'abstractapi', - }; - } - } catch { - // fall through to default - } - } - return { phoneE164, isDisposable: false, isVoip: false, isHighRisk: false, provider: 'none' }; -} - - diff --git a/web/lib/policy.ts b/web/lib/policy.ts deleted file mode 100644 index 2b7c387..0000000 --- a/web/lib/policy.ts +++ /dev/null @@ -1,24 +0,0 @@ -export type Policy = { - // Country codes (ISO alpha-2) that are blocked at the edge middleware - BLOCKED_COUNTRIES: string[]; - - // Global rate limit window and allowance per IP - RATE_LIMIT_WINDOW_SECONDS: number; - RATE_LIMIT_MAX_REQUESTS: number; - - // Cooldowns - SMS_SEND_COOLDOWN_SECONDS: number; // per-IP and per-phone cooldown for requesting SMS - MINT_IP_COOLDOWN_SECONDS: number; // per-IP cooldown after a successful mint -}; - -// Non-secret anti-abuse policy (committed defaults). -// Adjust these values via code review; secrets remain in env variables. -export const policy: Policy = { - BLOCKED_COUNTRIES: [], - RATE_LIMIT_WINDOW_SECONDS: 60, - RATE_LIMIT_MAX_REQUESTS: 10, - SMS_SEND_COOLDOWN_SECONDS: 120, - MINT_IP_COOLDOWN_SECONDS: 7 * 24 * 60 * 60, // 7 days -}; - - diff --git a/web/lib/rate-limit.ts b/web/lib/rate-limit.ts deleted file mode 100644 index a862144..0000000 --- a/web/lib/rate-limit.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { Ratelimit } from '@upstash/ratelimit'; -import { Redis } from '@upstash/redis'; -import { requireEnv } from './env'; -import { policy } from './policy'; -import { hashIdentifier } from './hash'; - -// Single Redis instance for the app using Vercel KV credentials -const redis = new Redis({ - url: requireEnv('KV_REST_API_URL'), - token: requireEnv('KV_REST_API_TOKEN'), -}); - -// Global IP rate limiter (used as default) -export const globalIpRatelimit = new Ratelimit({ - redis, - limiter: Ratelimit.slidingWindow(policy.RATE_LIMIT_MAX_REQUESTS, `${policy.RATE_LIMIT_WINDOW_SECONDS} s`), - analytics: true, - prefix: 'rl:ip', -}); - -export function createRatelimit(prefix: string, maxRequests: number, windowSeconds: number) { - return new Ratelimit({ - redis, - limiter: Ratelimit.slidingWindow(maxRequests, `${windowSeconds} s`), - analytics: true, - prefix, - }); -} - -// Helper to normalize IP key before rate limiting if callers forget to hash. -export function ratelimitKeyForIp(rawIp: string): string { - return hashIdentifier('ip', rawIp); -} - - diff --git a/web/lib/request-ip.ts b/web/lib/request-ip.ts deleted file mode 100644 index eb3043d..0000000 --- a/web/lib/request-ip.ts +++ /dev/null @@ -1,14 +0,0 @@ -import type { NextApiRequest } from 'next'; - -// Prefer Cloudflare/Vercel headers if present -export function getClientIp(req: NextApiRequest): string { - const cf = (req.headers['cf-connecting-ip'] as string) || ''; - if (cf) return cf; - const vercel = (req.headers['x-real-ip'] as string) || ''; - if (vercel) return vercel; - const xf = (req.headers['x-forwarded-for'] as string) || ''; - const first = xf.split(',')[0]?.trim(); - return first || req.socket.remoteAddress || 'unknown'; -} - - diff --git a/web/lib/session.ts b/web/lib/session.ts deleted file mode 100644 index a19abad..0000000 --- a/web/lib/session.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { randomBytes } from 'crypto'; - -// Generate a unique session ID for grouping related database entries -export function generateSessionId(): string { - return randomBytes(16).toString('hex'); -} - -// Session-aware key generation for better data management -export function sessionKey(sessionId: string, type: string, identifier: string): string { - const values = { sessionId, type, identifier } as const; - for (const [k, v] of Object.entries(values)) { - if (typeof v !== 'string') throw new TypeError(`sessionKey: ${k} must be a string`); - if (v.trim().length === 0) throw new TypeError(`sessionKey: ${k} must be non-empty`); - if (!/^[^\s:]+$/.test(v)) throw new TypeError(`sessionKey: ${k} contains invalid characters`); - } - return `session:${sessionId}:${type}:${identifier}`; -} - -// Extract session ID from a session key with DoS protection -export function extractSessionId(sessionKey: string): string | null { - // Validate input - if (typeof sessionKey !== 'string') return null; - if (sessionKey.length > 1024) return null; // Prevent extremely long inputs - - // Use simple string operations instead of regex - if (!sessionKey.startsWith('session:')) return null; - - const parts = sessionKey.split(':'); - if (parts.length < 3) return null; // Should have at least "session", sessionId, and type - - const sessionId = parts[1]; - - // Validate session ID format (alphanumeric, reasonable length) - if (!sessionId || sessionId.length === 0 || sessionId.length > 64) return null; - if (!/^[a-zA-Z0-9]+$/.test(sessionId)) return null; - - return sessionId; -} diff --git a/web/lib/sms.ts b/web/lib/sms.ts deleted file mode 100644 index 97c4886..0000000 --- a/web/lib/sms.ts +++ /dev/null @@ -1,340 +0,0 @@ -import { env } from "./env"; - -const VERIFY_PROVIDER = "twilio-verify" as const; - -export type SmsProviderError = { - provider: typeof VERIFY_PROVIDER; - status?: number; - errorCode?: number | string; - errorMessage?: string; -}; - -type VerifyRequestOptions = { - timeoutMs?: number; - maxRetries?: number; - baseDelayMs?: number; - deviceIp?: string; -}; - -export type StartSmsVerificationResult = { - ok: boolean; - sid?: string; - status?: string; - providerError?: SmsProviderError; -}; - -export type SmsVerificationFailureReason = "invalid_code" | "expired_or_invalid" | "provider_error"; - -export type CheckSmsVerificationResult = { - ok: boolean; - sid?: string; - status?: string; - valid?: boolean; - reason?: SmsVerificationFailureReason; - providerError?: SmsProviderError; -}; - -type TwilioVerifyResponse = { - sid?: unknown; - status?: unknown; - valid?: unknown; -}; - -type VerifyPostResult = - | { ok: true; status: number; data: TwilioVerifyResponse } - | { ok: false; providerError: SmsProviderError }; - -const EXPIRED_OR_INVALID_ERROR_CODES = new Set([20404, 60202, 60203, 60212, 60213, 60224]); -const INVALID_CODE_ERROR_CODES = new Set([60200]); -const EXPIRED_OR_INVALID_STATUS = new Set([ - "canceled", - "expired", - "max_attempts_reached", - "denied", -]); - -function toUrlEncoded(params: Record): string { - return Object.entries(params) - .filter(([, value]) => typeof value === "string" && value.length > 0) - .map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v as string)}`) - .join("&"); -} - -function sleep(ms: number) { - return new Promise((resolve) => setTimeout(resolve, ms)); -} - -function asString(value: unknown): string | undefined { - return typeof value === "string" && value.length > 0 ? value : undefined; -} - -function asBoolean(value: unknown): boolean | undefined { - return typeof value === "boolean" ? value : undefined; -} - -function getNumericCode(value: number | string | undefined): number | undefined { - if (typeof value === "number" && Number.isFinite(value)) return value; - if (typeof value === "string" && value.length > 0) { - const parsed = Number(value); - return Number.isFinite(parsed) ? parsed : undefined; - } - return undefined; -} - -function normalizeProviderError( - status: number | undefined, - details: { errorCode?: number | string; errorMessage?: string } = {}, -): SmsProviderError { - return { - provider: VERIFY_PROVIDER, - status, - errorCode: details.errorCode, - errorMessage: details.errorMessage, - }; -} - -export function isProductionRuntime(): boolean { - return (process.env.VERCEL_ENV || "").toLowerCase() === "production"; -} - -export function isVerifyConfigured(): boolean { - return Boolean(env.TWILIO_ACCOUNT_SID && env.TWILIO_AUTH_TOKEN && env.TWILIO_VERIFY_SERVICE_SID); -} - -export function shouldUseKvFallback(smokeTokenHeader: string | undefined): boolean { - if (isProductionRuntime()) return false; - if (!env.SMOKE_TEST_TOKEN) return false; - const incoming = (smokeTokenHeader || "").trim(); - return incoming.length > 0 && incoming === env.SMOKE_TEST_TOKEN; -} - -async function parseProviderErrorDetails( - res: Response, -): Promise<{ errorCode?: number | string; errorMessage?: string }> { - try { - const contentType = res.headers.get("content-type") || ""; - if (contentType.includes("application/json")) { - const json = (await res.json()) as Record; - const rawCode = json.code; - const rawMessage = json.message; - const errorCode = - typeof rawCode === "number" || typeof rawCode === "string" - ? (rawCode as number | string) - : undefined; - const errorMessage = typeof rawMessage === "string" ? rawMessage : undefined; - return { errorCode, errorMessage }; - } - - const text = await res.text(); - return { - errorMessage: typeof text === "string" && text.length > 0 ? text.slice(0, 300) : undefined, - }; - } catch { - return {}; - } -} - -async function twilioVerifyPost( - resource: "Verifications" | "VerificationCheck", - bodyParams: Record, - options: VerifyRequestOptions = {}, -): Promise { - if (!isVerifyConfigured()) { - return { - ok: false, - providerError: normalizeProviderError(undefined, { - errorMessage: "Twilio Verify is not configured", - }), - }; - } - - const accountSid = env.TWILIO_ACCOUNT_SID as string; - const authToken = env.TWILIO_AUTH_TOKEN as string; - const verifyServiceSid = env.TWILIO_VERIFY_SERVICE_SID as string; - const url = `https://verify.twilio.com/v2/Services/${encodeURIComponent(verifyServiceSid)}/${resource}`; - const authorization = Buffer.from(`${accountSid}:${authToken}`).toString("base64"); - - const timeoutMs = - Number.isFinite(options.timeoutMs) && (options.timeoutMs as number) > 0 - ? (options.timeoutMs as number) - : 6000; - const maxRetries = - Number.isFinite(options.maxRetries) && (options.maxRetries as number) >= 0 - ? (options.maxRetries as number) - : 2; - const baseDelayMs = - Number.isFinite(options.baseDelayMs) && (options.baseDelayMs as number) >= 0 - ? (options.baseDelayMs as number) - : 300; - - let attempt = 0; - let lastProviderError: SmsProviderError | undefined; - - while (attempt <= maxRetries) { - const controller = new AbortController(); - const timer = setTimeout(() => controller.abort(), timeoutMs); - try { - const res = await fetch(url, { - method: "POST", - headers: { - Authorization: `Basic ${authorization}`, - "Content-Type": "application/x-www-form-urlencoded", - }, - body: toUrlEncoded(bodyParams), - signal: controller.signal, - }); - - if (res.ok) { - let data: TwilioVerifyResponse = {}; - try { - const contentType = res.headers.get("content-type") || ""; - if (contentType.includes("application/json")) { - data = (await res.json()) as TwilioVerifyResponse; - } - } catch { - data = {}; - } - return { ok: true, status: res.status, data }; - } - - const details = await parseProviderErrorDetails(res); - const providerError = normalizeProviderError(res.status, details); - if (res.status >= 400 && res.status < 500) { - return { ok: false, providerError }; - } - - lastProviderError = providerError; - } catch { - lastProviderError = normalizeProviderError(undefined, { - errorMessage: "Twilio Verify request failed", - }); - } finally { - clearTimeout(timer); - } - - attempt += 1; - if (attempt > maxRetries) break; - - const backoff = baseDelayMs * 2 ** (attempt - 1); - const jitter = Math.floor(Math.random() * (baseDelayMs / 2)); - await sleep(backoff + jitter); - } - - return { - ok: false, - providerError: - lastProviderError || - normalizeProviderError(undefined, { - errorMessage: "Twilio Verify request failed after retries", - }), - }; -} - -function classifyProviderFailure(providerError: SmsProviderError): SmsVerificationFailureReason { - const code = getNumericCode(providerError.errorCode); - const message = (providerError.errorMessage || "").toLowerCase(); - - if (providerError.status === 404) return "expired_or_invalid"; - if (code !== undefined && EXPIRED_OR_INVALID_ERROR_CODES.has(code)) return "expired_or_invalid"; - if (code !== undefined && INVALID_CODE_ERROR_CODES.has(code)) return "invalid_code"; - - if ( - message.includes("expired") || - message.includes("not found") || - message.includes("max check attempts") || - message.includes("maximum check attempts") || - message.includes("too many check") || - message.includes("already canceled") || - message.includes("already cancelled") - ) { - return "expired_or_invalid"; - } - - if ( - message.includes("invalid code") || - message.includes("incorrect") || - message.includes("does not match") || - message.includes("mismatch") || - message.includes("wrong code") - ) { - return "invalid_code"; - } - - return "provider_error"; -} - -export async function startSmsVerification( - phoneE164: string, - options: VerifyRequestOptions = {}, -): Promise { - const result = await twilioVerifyPost( - "Verifications", - { - To: phoneE164, - Channel: "sms", - DeviceIp: options.deviceIp, - }, - options, - ); - - if (!result.ok) { - return { - ok: false, - providerError: result.providerError, - }; - } - - return { - ok: true, - sid: asString(result.data.sid), - status: asString(result.data.status), - }; -} - -export async function checkSmsVerification( - phoneE164: string, - code: string, - options: VerifyRequestOptions = {}, -): Promise { - const result = await twilioVerifyPost( - "VerificationCheck", - { - To: phoneE164, - Code: code, - DeviceIp: options.deviceIp, - }, - options, - ); - - if (!result.ok) { - return { - ok: false, - reason: classifyProviderFailure(result.providerError), - providerError: result.providerError, - }; - } - - const status = asString(result.data.status); - const valid = asBoolean(result.data.valid); - const normalizedStatus = (status || "").toLowerCase(); - const isApproved = normalizedStatus === "approved" || valid === true; - if (isApproved) { - return { - ok: true, - sid: asString(result.data.sid), - status, - valid, - }; - } - - const reason = EXPIRED_OR_INVALID_STATUS.has(normalizedStatus) - ? "expired_or_invalid" - : "invalid_code"; - return { - ok: false, - sid: asString(result.data.sid), - status, - valid, - reason, - }; -} diff --git a/web/middleware.ts b/web/middleware.ts deleted file mode 100644 index 1d9a203..0000000 --- a/web/middleware.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { NextRequest, NextResponse } from 'next/server'; -import { policy } from './lib/policy'; -import { verifyAdminTokenEdge } from './lib/admin-auth-edge'; - -// Helper functions to reduce duplication -function sendUnauthorizedApi(): NextResponse { - return new NextResponse(JSON.stringify({ error: 'Unauthorized' }), { - status: 401, - headers: { 'content-type': 'application/json' }, - }); -} - -function redirectToHome(req: NextRequest): NextResponse { - const url = req.nextUrl.clone(); - url.pathname = '/'; - return NextResponse.redirect(url); -} - -export async function middleware(req: NextRequest) { - // Block by country if configured (prefer Vercel header at edge) - const headerCountry = req.headers.get('x-vercel-ip-country') || ''; - const country = headerCountry.toUpperCase(); - if (country && policy.BLOCKED_COUNTRIES.includes(country)) { - return new NextResponse(JSON.stringify({ error: 'Access blocked in your region' }), { - status: 451, - headers: { 'content-type': 'application/json' }, - }); - } - - // Protect admin routes both API and page access at the edge where possible - const { pathname } = req.nextUrl; - const isAdminApi = pathname.startsWith('/api/admin'); - const isAdminPage = pathname === '/admin' || pathname.startsWith('/admin/'); - if (isAdminApi || isAdminPage) { - const token = req.cookies.get('admin_session')?.value; - const secret = process.env.ADMIN_SESSION_SECRET; // Use direct access since requireEnv is not edge-compatible - try { - // Fail fast on server misconfiguration (missing secret) - if (!secret) { - console.error('[middleware] ADMIN_SESSION_SECRET is not set. Blocking admin route access.'); - return isAdminApi - ? new NextResponse(JSON.stringify({ error: 'Server error' }), { - status: 500, - headers: { 'content-type': 'application/json' }, - }) - : redirectToHome(req); - } - - if (!token) { - return isAdminApi ? sendUnauthorizedApi() : redirectToHome(req); - } - // Edge-safe verification - const ok = await verifyAdminTokenEdge(token, secret); - if (!ok) { - return isAdminApi ? sendUnauthorizedApi() : redirectToHome(req); - } - } catch (err) { - const path = req.nextUrl.pathname; - console.warn(`[middleware] Admin auth failure on ${path} (isAdminApi=${isAdminApi})`, err); - return isAdminApi ? sendUnauthorizedApi() : redirectToHome(req); - } - } - - return NextResponse.next(); -} - -export const config = { - matcher: ['/api/:path*', '/admin', '/admin/:path*'], -}; - - diff --git a/web/next.config.ts b/web/next.config.ts deleted file mode 100644 index b1ec640..0000000 --- a/web/next.config.ts +++ /dev/null @@ -1,30 +0,0 @@ -import type { NextConfig } from "next"; - -const nextConfig: NextConfig = { - /* config options here */ - reactStrictMode: true, - images: { - // Enable static image optimization for better caching - unoptimized: false, - // Set cache time for optimized images (1 year) - minimumCacheTTL: 31536000, - }, - // Add cache headers for static assets - async headers() { - return [ - { - // Cache all static image assets under `public/`. Use a long max-age without `immutable` - // since filenames are not fingerprinted with hashes. - source: '/:all*\\.(jpg|jpeg|png|svg|ico|webp)', - headers: [ - { - key: 'Cache-Control', - value: 'public, max-age=31536000', - }, - ], - }, - ]; - }, -}; - -export default nextConfig; diff --git a/web/package.json b/web/package.json deleted file mode 100644 index 3571be4..0000000 --- a/web/package.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "name": "web", - "version": "0.1.0", - "private": true, - "scripts": { - "dev": "node scripts/start-dev.mjs", - "build": "next build", - "start": "next start", - "lint": "eslint .", - "smoke:prod": "bash scripts/smoke-test.sh prod", - "smoke:preview": "bash scripts/smoke-test.sh preview", - "doctor": "react-doctor . -y", - "doctor:score": "react-doctor . --score -y", - "doctor:verbose": "react-doctor . --verbose -y" - }, - "dependencies": { - "@radix-ui/react-dialog": "^1.1.15", - "@radix-ui/react-dropdown-menu": "^2.1.16", - "@radix-ui/react-label": "^2.1.7", - "@radix-ui/react-popover": "^1.1.15", - "@radix-ui/react-scroll-area": "^1.2.10", - "@radix-ui/react-slot": "^1.2.3", - "@radix-ui/react-toast": "^1.2.15", - "@types/canvas-confetti": "^1.9.0", - "@upstash/ratelimit": "2.0.6", - "@upstash/redis": "1.35.3", - "@vercel/analytics": "^1.5.0", - "@vercel/kv": "3.0.0", - "canvas-confetti": "^1.9.3", - "class-variance-authority": "^0.7.1", - "clsx": "^2.1.1", - "cmdk": "^1.1.1", - "ethers": "6.13.4", - "input-otp": "^1.4.2", - "lucide-react": "^0.543.0", - "next": "16.2.3", - "next-themes": "^0.4.6", - "react": "19.2.3", - "react-dom": "19.2.3", - "react-phone-number-input": "^3.4.12", - "tailwind-merge": "^3.3.1", - "zod": "4.0.15" - }, - "devDependencies": { - "@eslint/eslintrc": "^3", - "@types/minimatch": "^6.0.0", - "@types/node": "^20", - "@types/react": "^19.2.7", - "@types/react-dom": "^19.2.3", - "autoprefixer": "^10.4.21", - "eslint": "^9.39.2", - "eslint-config-next": "16.2.3", - "portless": "0.11.1", - "postcss": "^8.5.6", - "react-doctor": "0.2.6", - "tailwindcss": "^3.4.19", - "typescript": "^6.0.2" - }, - "packageManager": "yarn@4.13.0", - "resolutions": { - "brace-expansion@npm:^1.1.7": "1.1.13", - "flatted@npm:^3.2.9": "3.4.2", - "js-yaml": ">=4.1.1", - "minimatch@npm:^3.1.2": "3.1.4", - "minimatch@npm:^9.0.4": "9.0.7", - "minimatch@npm:*": "10.2.4", - "picomatch@npm:^2.0.4": "2.3.2", - "picomatch@npm:^2.2.1": "2.3.2", - "picomatch@npm:^2.3.1": "2.3.2", - "picomatch@npm:^4.0.1": "4.0.4", - "picomatch@npm:^4.0.2": "4.0.4", - "picomatch@npm:^4.0.3": "4.0.4" - } -} diff --git a/web/postcss.config.mjs b/web/postcss.config.mjs deleted file mode 100644 index a982c64..0000000 --- a/web/postcss.config.mjs +++ /dev/null @@ -1,8 +0,0 @@ -const config = { - plugins: { - tailwindcss: {}, - autoprefixer: {}, - }, -}; - -export default config; diff --git a/web/public/android-chrome-192x192.png b/web/public/android-chrome-192x192.png deleted file mode 100644 index 028c25a69744415c850853cdcdeba1580ad5fd12..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 38619 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 diff --git a/web/public/android-chrome-512x512.png b/web/public/android-chrome-512x512.png deleted file mode 100644 index 63f61899eefb4f81139fd2f7a7f1aabff997f33a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 168439 zcmXV12Q*yY*VPH4_Y#a=M~mK#7D5CO5hc1`^b$lF-RME0M~j|>DA9ZGC4{J>6K(Xt zn3-?n|1HZJ>%E0{@7?E|efHTe_L;ucLt-XkEG(>tI@+M;SXeliAF+>!2rwV+PX^>M zAMCc;&!1vpz30Kg3XR0Vy2V@y-NVB26~)5Zx5mPf%f!N>_sDHARKVOIu+h~5VWIE8 z3fjxkFjpRUXq$OsVX?5^e`Al6=j35768h*o)gb))fP`FJ>_ZUUA?9CZy*Ga8^Zbn; zyN8#%gR_f0yH9|JJ-ffF2Nsr0VwACAdIUS^-6a1NQD!7w@+R@!Q6Qpu5Q_KpW##v_ z$|yY^35s>tE`7%xm1cnnwQx4q+Yds9W;~=Qs~7xFIy4y#dEQinQ#mi}B=5yRu-`M~ z+`ZG*%eC$5;xc&%3Bx0ax>6T-)4kUFL`7Gm9%M(59tJkQU`nk`REhU|;Yv^UlU*oL zt>zb~j{KWS*c8vyae%Ik!LNm1uNJaJ<->sRR|9dG+~KJoo{l|TbP=KXdO~U4QQ(pf#_tIZS4SweawGTq9UoXz;eS_V|eLgbwI?*PCUBCN~(=wB& ze-zTq;S}p#FS)Pt0&ee}K$*e=f<^+VH>?-|!Jk3Tz7 z^jykSQFmpn|4HE{kT)9+{rWhe*GpH8kaAI#OuxZ)O=9oW3*K!9JpXx6?L@xI%%;eH zq|9F|(|W%b-)K@L8#5CetJ=ofC`$kR^Ti`NHv-AryYbfbYI}26@PxbpDT>}~t#!qm z8@9WbzA^S>kzY0j16VpBRb&6fLu5dki`lz*!jSnzgdU|QEEu+}VC-N&S3sr7fJgMT zrZ0in_M240hlfqr5&c>NQhx}RgOsL3a0zl$t;ek25HP#!X%djMFype>eTY(3>tWAP zrAn<*!N-${@QguS)DrrzGs+!3diN1}mETiZND?-=EWfFRzG$>Ag9>(TPNMMP zyPfcu+T;~Q!O4SC2!|chxO_Y@@gd9>mUX2WlRAmOp+(! zl}qgY`)IWVH3@}J`vtyr7|T4B5_81DEO+ObPF|2`L>(+*$$jtWQi^=~Mdk{YTc{A8 zpbk2Je)XK3;Gu_`2SF~=vTKXTRKGS^p#dIbY`O=thR0)MT?vfyEa<(uYTdB2o-z#+iBuASBwovLLxF)u%!4N}KRy@o*;qV&FQK=lVr4aUph~$-|*Jlu+V> z2yqVIdmyCE9^ejHa12VwAGQsuqtQ1tYY1^@F7LdH%~@f)3s9CH0bgp#isQFiHdpX9l;ZTOO>{QMyTUxGl1wKsowKT4WfM z(2L4rNjSX54f1W&RJu((c|WR*UeCDhbHDx>v<GUQ_H)4H1c|xNmvsT_=`UTz&W~(Jq5u=x(SZ#f=?}*<;PC7fXMk?cVSS zgS#u(ABFbUQc$FAr_ddJ{w)`HPa;2{vC$p_%zRu2t&o9)K_V;kQ>f%BI?C!6fbKCx zT3sh~A}oTo!FOeaW9vT~ud}UgXD-}BHWF=?qBVGyg-k4mK�MqZSZggN1*UM4(*P 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 TL4J8GPzi<Dnm{r-UW|9NOx9 diff --git a/web/public/favicon-16x16.png b/web/public/favicon-16x16.png deleted file mode 100644 index 29aa4004aa1f8b0649585ff8ec9ccd44872eb7c9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2049 zcmb7Fd010d7QX=mSz>@7Yn31nmOyw3iAqFAFi=utla#F*6Clx4AR!3^M3G%okbPgW zvJ=37SkX}|UB-Sh%79~qe&1-vVFafLwlh?wAai3Ky8SixefOPn&-wk%IrqHx?z<2f z{w~_Y-UI-EW`xj>KxqyqW~)BD&uVV(fC85kawH6Z(|7>#iU9ZzH08|$kbwa3oDBf2 z5da%u>sXXO0D9QS!^|KEz^0wuE-i2n=h+I*8nc9^u_6nG+CtPgcMbf^UEly0=?*y_PM3OOEW_o8`B#b2c|!@JyVPf_Tn3wtiW`}ADXWU;4G;USY*v&A6bm~&kNNvk0Z^*Prxz_Q;dF7p}ag;m+*mAce7 zlCKUrRn&sOqi!v&u1zh#Ki2L{iF;c+j6hH-aOKrLnjWI22P$4FrH4Y{*4k#BUAVKP z+^f6OtE*#2Q5m5_?OM~|)8FIM-@U7{RxkKC?oySfO6lF(1&z)%^bn|4*z?JTQ8v>IfvZ)fRc z5Sr-L-cA}Gz_+#m^lnJ>?&=_@Rpuw9gbo#qPx(2`s&Ru z?sqXzTeh2Jt#i;=eF;10+kaAxT3=V_TlaTbon_IV!y-_Lq3_a%4kZtK0vE=@ka#hC z2XMNH`V*$59U6@!jIbc11!GeT+0)+cv5wPpni(fK!ja;HA_0$|!o^9lg8t;t|SoM$GqIahVDK ztIHQ266dJ)E6bYc^7EhJ*Rbf=Wlh7Yz0|f7<{$r?Hh>*(`ub6otKq)*yLo-o zvI$XWppnIFz_#$wq$j@f2{CSSJcFz+>Dqg;lp%_;SYYn{Pfy*zu0v9e-llPS%00(TABQY;sWnP8>sv zC{k?twafPg(xk>1hKHdcKf*`gc>H!daU*YB{>0p_WOC@Qw_Y1#-NM?*S8osQ@h@;X zGpkRa0xPvgFc>tdXp{5AI?+iETqEtIEc>l8;^$eWLz*?e?1J=_z0G zu+}blP9*y7+t`7GW07&pqq_#j<=yIjWx`mecyWwO%|M5FSAI2;@de@GwV0TNkJpv4 z$D(iC9AG&T+3ZJ?j~=8Xn z*z!gP-~h^DQx87R2L^BL;ZW*E2%M1dR_e=9KSh!2ZK6Bm`kT5;N0VtJb5OWSg5o5} z90`|}B;rB=$OxJ0jre(!NK6uyMxoLW5&=PI2r~Y=Yq~;zBBTnE`Mm636DTw)`A33V zw=fD4+&42w_^Dj6gabdrUnZd=W7Ci=Z zT5dXnAR>at6LTeC&)&Naa@?TTcGDZl&*G-U(P7dwF<+1dNV}iiqP{KL{_tn$v-zLz*9DLfgq1UV b{Wp-G%O1+eV*%jzwf%9H_g$(l8;A{2LJ#* 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 V)?~<3o?@o}*5(dowOH?je*w)B!P)=- diff --git a/web/public/favicon.ico b/web/public/favicon.ico deleted file mode 100644 index f68fa6792b20ae5241e4cecac7bbbe00bccf29bb..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14790 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 diff --git a/web/public/favicon.png b/web/public/favicon.png deleted file mode 100644 index 2e7ee8b2816adc9c13853dec5802f047b803d3da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 30663 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

TK?zzeG#sQo`~`Ev18lpn$J5| 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 BAM*eJ diff --git a/web/public/llms-full.txt b/web/public/llms-full.txt deleted file mode 100644 index 8364f36..0000000 --- a/web/public/llms-full.txt +++ /dev/null @@ -1,3251 +0,0 @@ -# MintPass Full LLM Context - -> MintPass is an NFT-based authentication and anti-sybil system for Bitsocial communities and other decentralized apps. - -This file is generated by `scripts/generate-llms-files.mjs`. Do not hand-edit it; update the source docs or generator config, then run `yarn llms:generate`. - -Use this as compiled context only. Source files, tests, manifests, and live/runtime evidence remain authoritative. - -## Index - -- [README.md](#readmemd) -- [AGENTS.md](#agentsmd) -- [web/README.md](#webreadmemd) -- [challenge/README.md](#challengereadmemd) -- [contracts/README.md](#contractsreadmemd) -- [docs/pkc-info.md](#docspkc-infomd) -- [docs/challenges/README.md](#docschallengesreadmemd) -- [docs/challenges/question.md](#docschallengesquestionmd) -- [docs/challenges/evm-contract-call.md](#docschallengesevm-contract-callmd) -- [docs/challenges/publication-match.md](#docschallengespublication-matchmd) -- [challenge/TESTING.md](#challengetestingmd) -- [challenge/AUTOMATED_TESTING.md](#challengeautomatedtestingmd) -- [contracts/DEPLOYMENT.md](#contractsdeploymentmd) -- [contracts/security-checklist.md](#contractssecurity-checklistmd) -- [docs/challenges/blacklist.md](#docschallengesblacklistmd) -- [docs/challenges/captcha-canvas.md](#docschallengescaptcha-canvasmd) -- [docs/challenges/fail.md](#docschallengesfailmd) -- [docs/challenges/text-math.md](#docschallengestext-mathmd) - ---- - -## README.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/README.md - -```markdown -[![Commitizen friendly](https://img.shields.io/badge/commitizen-friendly-brightgreen.svg)](http://commitizen.github.io/cz-cli/) - -# MintPass - NFT Authentication Middleware for Bitsocial - -MintPass Logo - -MintPass is an NFT-based authentication system that provides verified identity proofs for decentralized communities. It began as an anti‑spam challenge for Bitsocial communities, and it works equally well for other protocols and social applications. Users mint a non‑transferable verification NFT (e.g., after SMS OTP) that communities can check to reduce sybil attacks, such as fake upvotes/downvotes, fake conversations, and users evading bans. - -
- -## How people use MintPass - -1) Visit `mintpass.org/request`, enter a phone number, and complete SMS OTP. -2) MintPass mints an NFT (on testnet in this reference deployment) to your wallet or records an equivalent “verified” state when on‑chain minting is disabled. -3) Communities (e.g., Bitsocial communities) check ownership of the NFT to treat you as authenticated for anti‑spam. - -The request form looks like this: - -

- MintPass request form screenshot -

- -## What is Bitsocial? - -Bitsocial is p2p and decentralized social media protocol built completely with IPFS/IPNS/pubsub. It doesn't use any central server, central database, public HTTP endpoint or DNS, it is pure peer to peer (except for the web client that can't join a P2P swarm directly, web clients use interchangeable HTTP providers). It allows community owners to retain full ownership over their community. Whitepaper [here](https://github.com/pkc/whitepaper/discussions/2). - -MintPass integrates as a challenge so Bitsocial communities can distinguish real users and limit abuse without central servers. Because the artifact is an NFT, other decentralized apps can use the same credential to authenticate users. - -## Project Structure - -``` -mintpass/ -├── contracts/ # MintPassV1 smart contract and tooling -├── challenge/ # Bitsocial challenge implementation (“mintpass”) -├── web/ # Next.js website + API (mintpass.org) -├── docs/ # Documentation and specifications -├── tests/ # Cross‑component integration tests -└── scripts/ # Deployment and utilities -``` - -### Subprojects - -- `contracts/`: Solidity contracts (MintPassV1). Versioned, role‑based minting, token types per NFT (type 0 = SMS). See `contracts/README.md`. -- `challenge/`: The Bitsocial challenge that checks for a MintPass NFT and applies additional rules (e.g., transfer cooldowns) to resist sybils. -- `web/`: The user‑facing site and serverless backend. Sends SMS codes, verifies OTP, and mints or records successful verification. See `web/README.md`. - -## Privacy and anti‑sybil design (high level) - -- Short‑lived operational data (OTP codes, verification markers, rate‑limit state) stored in Redis with TTLs. -- Persistent “mint association” between wallet and phone to prevent duplicate mints. -- Optional IP reputation (VPN/proxy) and phone‑risk checks, optional geoblocking, and per‑IP cooldowns. -- Secrets live only in environment variables; logs avoid PII and never include OTPs or private keys. - -## Getting started - -1. Run `nvm install && nvm use` -2. Run `corepack enable` once per machine so `yarn` resolves to the pinned Yarn 4 release -3. Use plain `yarn install`, `yarn build`, and `yarn test` - -- Contracts: `cd contracts && yarn install && yarn test` -- Challenge: `cd challenge && yarn install && yarn test` -- Web: `cd web && yarn install && yarn dev` then open `https://mintpass.localhost/request` - -## Using MintPass in your community - -Community owners add the MintPass challenge to their community settings. When enabled, every publication (post, reply, vote) requires the author to hold a valid MintPass NFT. The challenge is published as [`@bitsocial/mintpass-challenge`](https://www.npmjs.com/package/@bitsocial/mintpass-challenge) on npm. - -### With pkc-js over RPC - -If your RPC server is already running, first install the challenge on the server: - -```bash -bitsocial challenge install @bitsocial/mintpass-challenge -``` - -Then from your RPC client, connect and set the challenge on your community by name — no npm install or challenge registration needed on the client side: - -```ts -import PKC from "@pkcprotocol/pkc-js"; - -const pkc = await PKC({ - pkcRpcClientsOptions: ["ws://localhost:9138"] -}); - -const community = await pkc.createCommunity({ address: "your-community-address.bso" }); - -await community.edit({ - settings: { - challenges: [ - { - name: "@bitsocial/mintpass-challenge", - options: { - chainTicker: "base", - contractAddress: "0x13d41d6B8EA5C86096bb7a94C3557FCF184491b9", - requiredTokenType: "0", - transferCooldownSeconds: "604800" - } - } - ] - } -}); -``` - -### With pkc-js (TypeScript) - -Install the challenge package: - -```bash -npm install @bitsocial/mintpass-challenge -``` - -Register the challenge and configure your community: - -```typescript -import PKC from '@pkcprotocol/pkc-js' -import mintpassChallenge from '@bitsocial/mintpass-challenge' - -// Register the challenge so it can be referenced by name -PKC.challenges['@bitsocial/mintpass-challenge'] = mintpassChallenge - -const pkc = await PKC({ /* your pkc options */ }) -const community = await pkc.createCommunity({ address: 'your-community.bso' }) - -await community.edit({ - settings: { - challenges: [{ - name: '@bitsocial/mintpass-challenge', - options: { - chainTicker: 'base', - contractAddress: '0x13d41d6B8EA5C86096bb7a94C3557FCF184491b9', - requiredTokenType: '0', - bindToFirstAuthor: 'true', - transferCooldownSeconds: '604800', - } - }] - } -}) -``` - -#### Challenge options - -All option values must be strings (pkc-js challenge convention). - -| Option | Default | Description | -|--------|---------|-------------| -| `chainTicker` | `"base"` | Chain where MintPass is deployed | -| `contractAddress` | Base Sepolia default | Contract address (auto-detected for supported chains) | -| `requiredTokenType` | `"0"` | Token type (0 = SMS, 1 = Email) | -| `bindToFirstAuthor` | `"true"` | Bind NFT to first author per community | -| `transferCooldownSeconds` | `"604800"` | Cooldown after NFT transfer (1 week) | -| `error` | Default message | Custom error (`{authorAddress}` placeholder supported) | -| `rpcUrl` | Chain default | Optional custom RPC URL | - -### With bitsocial-cli - -Install the challenge package: - -```bash -bitsocial challenge install @bitsocial/mintpass-challenge -``` - -Edit your community to use the challenge: - -```bash -bitsocial community edit your-community.bso \ - '--settings.challenges[0].name' @bitsocial/mintpass-challenge \ - '--settings.challenges[0].options.chainTicker' base \ - '--settings.challenges[0].options.contractAddress' '0x13d41d6B8EA5C86096bb7a94C3557FCF184491b9' \ - '--settings.challenges[0].options.requiredTokenType' '0' \ - '--settings.challenges[0].options.bindToFirstAuthor' 'true' \ - '--settings.challenges[0].options.transferCooldownSeconds' '604800' -``` - -See the [bitsocial-cli documentation](https://github.com/bitsocial/bitsocial-cli) for full CLI reference. - -## Where MintPass is useful - -While designed for Bitsocial, any decentralized or serverless social app can use MintPass NFTs as a lightweight proof‑of‑personhood. Apps only need to check ownership of a token type (e.g., type 0 for SMS) to gate actions or increase trust in votes and reports. - -## Roadmap and considerations - -We plan to support multiple authentication methods alongside SMS OTP to fit different threat models and UX constraints: -- Add a “pay‑to‑mint” option with a small fee that is high enough to deter bulk purchases but low enough for regular users. -- Add additional human‑verification signals (e.g., email, government‑backed KYC providers, or proofs such as biometrics/world‑ID systems) when they can be integrated without compromising decentralization goals. -- Expand admin tooling, heuristics, and optional device signals to further reduce abuse. - -These items are exploratory; concrete work will land incrementally and stay configurable so communities can choose what they trust. - -## Technology Stack - -- **Smart Contracts**: Solidity, Hardhat/Foundry -- **Website**: Next.js, React, Ethereum (ethers) -- **Challenges**: TypeScript, pkc-js integration -- **Deployment**: Base network (L2) - -## License - -MIT License — see [LICENSE](LICENSE). - -Open source and commercial‑friendly. A hosted version is available at [mintpass.org](https://mintpass.org). -``` - ---- - -## AGENTS.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/AGENTS.md - -```markdown -# AGENTS.md - -## Project Overview - -MintPass is a multi-part authentication system for Bitsocial and other decentralized apps: -- `web/`: Next.js site + API for SMS verification and mint flow -- `contracts/`: Solidity contracts for MintPass NFTs -- `challenge/`: PKC challenge module that verifies NFT ownership - -This is not a single app repo. Treat it as a coordinated multi-project codebase. - -## Agent Operating Principles - -- Before editing, state important assumptions when the task is ambiguous. Ask instead of silently choosing between materially different interpretations. -- Prefer the smallest implementation that solves the requested problem. Do not add speculative abstractions, configurability, or features. -- Keep diffs surgical. Do not refactor, reformat, rename, or "improve" adjacent code unless it is necessary for the task. -- Clean up only artifacts created by the current change, such as newly unused imports or dead helper code. -- For non-trivial work, define success criteria and verify them with the narrowest reliable checks before marking the task complete. - -## LLM Knowledge Base Policy - -Use compiled context for orientation, not as source of truth. - -Source of truth: - -- Code, tests, package manifests, docs, and runtime/live evidence when relevant. - -Compiled context: - -- `AGENTS.md`, directory-specific `AGENTS.md` files, `CLAUDE.md`, and repo-managed `.codex/`, `.cursor/`, and `.claude/` workflow files. -- `docs/**`, tracked task notes, and tracked `llms.txt` / `llms-full.txt` files when present. - -Agents may use compiled context to navigate quickly, but must verify against source files before making behavioral claims or edits. External code graph, RAG, MCP, or wiki tools are optional local accelerators unless the developer explicitly asks to make one part of the committed workflow. - -## Repository Shape (Critical) - -```text -mintpass/ -├── web/ # Next.js 15 app (pages router) + API routes -├── contracts/ # Hardhat + Solidity contracts and deployment scripts -├── challenge/ # TypeScript challenge package for pkc-js -├── dist/challenge/ # Published challenge artifact copied from challenge/dist -└── docs/ # Specs and challenge docs -``` - -Important: -- Root workspaces include `contracts` and `challenge` only. -- `web` has its own `package.json` and `yarn.lock`; install/run it separately. -- `challenge/dist` and root `dist/challenge` are generated artifacts. Do not hand-edit them. - -## Stack - -- Node.js `22.12.0` via `.nvmrc` -- Yarn 4 via Corepack (run `corepack enable` once per machine, then use plain `yarn`) -- TypeScript (strict mode in `web`, `contracts`, `challenge`) -- Web: Next.js 15, React 19, Tailwind, Radix/shadcn-style UI, Zod, Upstash/Vercel KV -- Contracts: Solidity `0.8.24`, Hardhat, OpenZeppelin, ethers v6 -- Challenge: TypeScript ESM + `viem` + `keyv`, integrated with pkc-js challenge interface - -## Commands - -### Root - -```bash -yarn install # install root + contracts + challenge deps -yarn build # build contracts + challenge, then publish challenge artifact to dist/challenge -yarn test # contracts test suite -yarn test:contracts -yarn test:challenge -yarn test:challenge:local -yarn clean -``` - -### Web (`web/`) - -```bash -cd web -yarn install -yarn dev # local dev server -yarn build # production build -yarn start # run built app -yarn lint # Next.js lint rules -yarn smoke:preview # preview smoke flow (requires env) -yarn smoke:prod # production smoke flow (requires env) -``` - -### Contracts (`contracts/`) - -```bash -cd contracts -yarn install -yarn compile -yarn test -yarn coverage -yarn deploy:testnet -yarn deploy:mainnet -``` - -### Challenge (`challenge/`) - -```bash -cd challenge -yarn install -yarn build -yarn test # automated local integration (hardhat + kubo) -yarn test:manual -yarn clean -``` - -## React Doctor (Advisory) - -React Doctor is advisory quality tooling for React architecture/perf/correctness checks. **Scope: `web/` only** (the Next.js app). - -**Standard commands** (run from `web/`): -- `cd web && yarn doctor`, `cd web && yarn doctor:score`, `cd web && yarn doctor:verbose` - -**Trigger rules:** -- Run after touching React UI logic (`components`, `hooks`, route/page/view files, state/store code used by UI). -- Run before opening PRs that include React behavior changes. - -**Interpretation:** -- Treat diagnostics as actionable recommendations. -- Prioritize `error` diagnostics first, then `warning`. -- Score is informative only; no merge blocking based on score yet. - -## Scope-Driven Validation (Required) - -Run checks based on what you changed: - -- If you change `web/**`: - - `cd web && yarn doctor:score` - - `cd web && yarn lint` - - `cd web && yarn build` - - If API flow changed and envs are available: run smoke test (`yarn smoke:preview` or `yarn smoke:prod`) - -- If you change `contracts/**`: - - `cd contracts && yarn test` - - `cd contracts && yarn compile` - -- If you change `challenge/**`: - - `cd challenge && yarn test` - - `cd challenge && yarn build` - - If challenge runtime/API changed, sync artifacts with root: - - `yarn build:challenge` - - `yarn publish:challenge` - -- If you change public docs or AI context (`README.md`, `AGENTS.md`, `docs/**`, `web/README.md`, `challenge/README.md`, `contracts/README.md`, or `scripts/generate-llms-files.mjs`): - - `yarn llms:generate` - - Inspect and commit any resulting changes to `llms*.txt` and `web/public/llms*.txt` - -- If you change multiple areas: - - Run each affected package checks - - Then run root `yarn build` and root `yarn test` - -## Code Style and Architecture - -- Keep TypeScript strict-safe; avoid `any` unless unavoidable and documented. -- Prefer small focused functions and modules over large route handlers. -- Preserve existing naming and folder conventions in each package. -- Add brief comments only where logic is non-obvious. - -### Web-Specific Rules - -- API handlers live in `web/src/pages/api/**`; shared backend logic belongs in `web/lib/**`. -- Validate request bodies with `zod` before business logic. -- `web/lib/env.ts` is server-only; never import it into client-rendered code. -- Do not leak secrets, OTPs, raw phone numbers, or private keys in logs/responses. -- Keep anti-abuse behavior intact unless explicitly requested: - - rate limits - - cooldowns - - IP/phone risk checks - - hashed identifier storage via `hashIdentifier` - -### Contracts-Specific Rules - -- Preserve role boundaries (`ADMIN_ROLE`, `MINTER_ROLE`) and access controls. -- Keep deterministic deployment and network config behavior stable unless requested. -- Treat contract interface changes as breaking unless migration/versioning is planned. -- Prefer explicit tests for any change affecting minting, roles, token types, or metadata. - -### Challenge-Specific Rules - -- Source of truth is `challenge/src/**`, primarily `challenge/src/mintpass.ts`. -- Maintain compatibility with pkc-js challenge contract (factory + option handling). -- Be careful with chain/wallet fallback behavior and transfer cooldown logic. -- Rebuild generated outputs when source/public types change. - -## Security and Privacy Boundaries (Critical) - -- Never commit `.env` files, secrets, API keys, private keys, bypass tokens, or OTPs. -- Never log raw PII (phone/IP) when hashed storage/logging is available. -- Keep Preview-only shortcuts gated to Preview (`VERCEL_ENV=preview`) only. -- Do not weaken cooldown/rate-limit defaults without explicit user approval. -- For web changes touching auth/mint flow, favor fail-closed behavior. - -## Generated Artifacts - -- Do not manually edit: - - `challenge/dist/**` - - `dist/challenge/**` -- When challenge source changes, regenerate artifacts and commit them when relevant to the change. - -## Recommended Skills - -Use these when applicable (they are available in this repo setup): - -- `context7`: fetch current library/framework docs before API-sensitive changes -- `vercel-react-best-practices`: performance and React/Next.js patterns for `web/` -- `you-might-not-need-an-effect`: audit/refactor unnecessary `useEffect` usage -- `playwright-cli`: browser automation and UI validation -- `commit-format`: standardize Conventional Commit message output -- `issue-format`: standardize GitHub issue title/description output -- `impeccable`: design, redesign, critique, audit, polish, layout, typography, color, motion, or visual hierarchy work for `web/` (one `/impeccable` entry point with 23 design subcommands) - -## AI Tooling Rules - -- Treat `.codex/`, `.cursor/`, and `.claude/` as repo-managed contributor tooling, not private scratch space. -- Keep equivalent workflow files aligned across all toolchains when their directories contain the same skill, hook, or agent. -- When changing shared agent behavior, update the relevant files in `.codex/skills/`, `.cursor/skills/`, `.claude/skills/`, `.codex/agents/`, `.cursor/agents/`, `.claude/agents/`, `.codex/hooks/`, `.cursor/hooks/`, `.claude/hooks/`, and their `hooks.json` or `config.toml` entry points as needed. -- If `AGENTS.md` references a skill, agent, or hook, prefer a tracked file under `.codex/`, `.cursor/`, or `.claude/` rather than an untracked local-only instruction. - -## AI Agent Hooks - -This repo already includes hooks: -- `.codex/hooks.json` -- `.cursor/hooks.json` - -Configured scripts: -- `afterFileEdit`: `.cursor/hooks/format.sh` -- `afterFileEdit`: `.cursor/hooks/yarn-install.sh` -- `stop`: `.cursor/hooks/verify.sh` - -Use these as defaults when your agent supports lifecycle hooks. - -## Git Worktrees - -- Always give a new worktree a descriptive name that reflects the task (e.g. `fix-mint-cooldown`, not `wt1`, `tmp`, `feature`, or a numbered slug), so it can be identified at a glance in a long list of worktrees. - -## GitHub Workflow - -### Commits - -When proposing or implementing code changes, suggest a commit message: -- Title in Conventional Commits format, wrapped in backticks -- Use `perf:` for performance optimizations -- Optional short description: 1-3 technical sentences about the solution - -Example: - -> **Commit title:** `fix: enforce mint cooldown check before writing mint state` -> -> Moved the cooldown guard earlier in `web/src/pages/api/mint.ts` so failed requests do not write mint markers. - -### Issues - -When proposing or implementing code changes, suggest a trackable issue: -- Short title wrapped in backticks -- Description focuses on the problem (as-if not fixed yet), 2-3 concise sentences - -## Bug Investigation (Mandatory First Step) - -If the user reports a bug in a specific file/line/area, check git history first before editing. - -1. Inspect recent commit titles scoped to the file: - ```bash - git log --oneline -10 -- path/to/file - ``` -2. If needed, inspect line ownership: - ```bash - git blame -L , path/to/file - ``` -3. Read only relevant commits in detail: - ```bash - git show -- path/to/file - ``` - -Then proceed with code changes. - -## Dependency Management - -- Use exact versions when adding/updating packages (`pkg@x.y.z`, no bare installs). -- Do not do broad dependency rewrites unless explicitly requested. -- Keep lockfiles in sync for the package you touched: - - root `yarn.lock` - - `web/yarn.lock` - -## Tooling Preferences - -- Use `gh` CLI for GitHub operations (issues, PRs, actions, project ops). -- Prefer CLI + scripts over heavy MCP servers when both are available. -- Use `rg` for fast code search. - -## MCP Servers (Avoid by Default) - -- Do not use GitHub MCP for routine GitHub tasks; use `gh` CLI. -- Do not use browser MCPs for UI testing; use `playwright-cli`. -- Keep active MCP set small. Large MCP tool surfaces waste context and reduce agent quality. - -## Troubleshooting - -- If a bug is unclear after local debugging and git-history review, search the web for recent framework/library issues and validated fixes. - -## Practical Boundaries - -- Keep diffs minimal and scoped to the request. -- Do not silently refactor unrelated areas. -- Preserve backwards compatibility unless the user asks for a breaking change. -- For UI changes, verify desktop and mobile behavior. -``` - ---- - -## web/README.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/web/README.md - -```markdown -## MintPass Web - -Serverless website and API that power the SMS verification flow and NFT minting at `mintpass.org`. - -### How it works (code map) -- UI: `src/pages/request/` — phone + OTP form, error handling, and success state -- API routes: - - `POST /api/sms/send` → rate-limit, optional IP/phone risk checks, then start Twilio Verify SMS (or non-prod smoke `kv-fallback`); returns `mode` (`verify` | `kv-fallback`) - - `POST /api/sms/verify` → verify OTP, mark phone as verified - - `POST /api/pre-check-eligibility` → quick check before sending code - - `POST /api/check-eligibility` → final eligibility check before mint - - `POST /api/mint` → on‑chain mint (when envs set) or record as minted -- Libraries and helpers: `lib/` — KV (Upstash), rate‑limits, cooldowns, hashing, SMS provider adapter, IP/phone intelligence, and admin auth/session utilities - -### Anti-Sybil and Security Requirements -- **Phone number database**: Track used numbers; prevent reuse for minting. -- **IP address tracking**: Rate limit per IP; detect abuse patterns. -- **SMS verification state**: Verify with Twilio Verify; keep short-lived fallback codes only for smoke flow. -- **Minter key security**: Private key only in Vercel env vars; never in code or logs. -- **Rate limiting**: Global and per-route limits to mitigate spam. -- **Geolocation filtering**: Optional country blocking via `middleware.ts`. -- **Audit trail (optional)**: Log key events to a separate store with redaction. - - **VPN/Proxy detection (optional)**: If `IPQS_API_KEY` is set, block VPNs/proxies/cloud provider IPs. - - **Disposable/VOIP phone detection (optional)**: If `ABSTRACTAPI_PHONE_KEY` is set, block disposable/VOIP/high-risk numbers. - - **Cooldowns**: Per-IP mint cooldown and per-IP/phone SMS send cooldowns configurable via env. - - **Keyed hashing (pepper)**: If `HASH_PEPPER` is set, phone numbers and IPs are stored as HMAC-SHA256 digests (domain-separated) in KV keys to reduce offline brute-force risk if a DB-only leak occurs. - -#### Preview-only testing behavior -- In Vercel Preview deployments (`VERCEL_ENV=preview`), the disposable/VOIP/high-risk phone check is bypassed in `POST /api/sms/send` to allow testing with temporary numbers. Production (`VERCEL_ENV=production`) remains strict and continues to block such numbers. - -### Vercel Setup (exact steps) -1. Create a new Vercel project and select this repo. Set root directory to `web`. -2. Add storage via Marketplace: Upstash → Redis. Create separate databases per environment (recommended): - - `mintpass-kv-prod` (Production) - - `mintpass-kv-preview` (Preview) - - `mintpass-kv-dev` (optional local) - Settings for each DB: Plan = Pay as You Go, Primary Region = `iad1` (US‑East), Read Regions = none, Eviction = off, Auto‑upgrade = on. -3. In Project Settings → Environment Variables, add: - - `MINTER_PRIVATE_KEY` (server only) - - `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_VERIFY_SERVICE_SID` (Verify mode; recommended for OTP) - - `BLOCKED_COUNTRIES` (comma-separated ISO codes if needed) - - `RATE_LIMIT_WINDOW_SECONDS`, `RATE_LIMIT_MAX_REQUESTS` (optional) - - `IPQS_API_KEY` (optional) to enable IP reputation checks - - `ABSTRACTAPI_PHONE_KEY` (optional) to enable disposable/VOIP phone checks - - `SMS_SEND_COOLDOWN_SECONDS` (optional) default 120 - - `MINT_IP_COOLDOWN_SECONDS` (optional) default 604800 (7 days) - - Map Upstash credentials to app envs per environment: - - Production: `KV_REST_API_URL` = Upstash prod REST URL; `KV_REST_API_TOKEN` = Upstash prod REST token - - Preview: `KV_REST_API_URL` = Upstash preview REST URL; `KV_REST_API_TOKEN` = Upstash preview REST token - - Local dev (optional): set the same in `.env.local` pointing to `mintpass-kv-dev` -4. Deploy. After first deploy, add the domain `mintpass.org` in Domains, set as primary. -5. Ensure the KV database is scoped to the production environment and not shared with preview. - -### Runtime regions -- Vercel Project → Settings → Functions → Region: set to `iad1` to co‑locate with Redis and reduce latency. - -### Storage notes -- Why Redis/KV: fast TTL keys for OTPs and cooldowns, atomic counters, and simple idempotency. -- Cost model (Pay as You Go): ~$0.20 per 100k commands. Typical flow is ~20 commands per successful mint. - -### Environments and KV mapping (prod/preview/local) -- **Databases to create**: - - `mintpass-kv-prod` → used by Vercel Production - - `mintpass-kv-preview` → used by Vercel Preview (and local dev by default) - - Optional later: `mintpass-kv-dev` → used only for local dev - -- **Vercel → Project → Settings → Environment Variables**: - - Production: set `KV_REST_API_URL` and `KV_REST_API_TOKEN` from `mintpass-kv-prod` - - Preview: set `KV_REST_API_URL` and `KV_REST_API_TOKEN` from `mintpass-kv-preview` - - Do not point local or preview to prod. - -- **Local development**: - - Copy `.env.example` to `.env.local` - - Set `KV_REST_API_URL` and `KV_REST_API_TOKEN` to the preview DB (or to `mintpass-kv-dev` if you created it) - - Run `yarn dev` - -### API Routes -- `POST /api/sms/send` → request SMS code (rate-limited; Verify-first with non-prod smoke fallback) -- `POST /api/sms/verify` → verify code and mark phone as verified -- `POST /api/check-eligibility` → confirm address + phone can mint -- `POST /api/mint` → on-chain mint on Base Sepolia when envs are set; otherwise records local minted state. Requires `authorAddress` string; country is derived from `x-vercel-ip-country` header. - -### Local Development - -Requires [Portless](https://github.com/vercel-labs/portless), installed with project dependencies via `corepack yarn install` - -```bash -corepack enable -corepack yarn install -corepack yarn dev # https://mintpass.localhost -``` - -The dev server runs at https://mintpass.localhost via [Portless](https://github.com/vercel-labs/portless), which gives each Bitsocial project a stable, named URL instead of a random port. To bypass Portless: `PORTLESS=0 yarn dev` - -To test API calls locally, use `curl` or your preferred REST client. - -### Smoke test (prod/preview) -Create local env files (not committed) with the target base URL and test identifiers. Include Upstash REST URL/Token when you need `kv-fallback` full E2E: - -- `.env.smoke.prod` (for Production) -``` -BASE_URL=https://mintpass.org -PHONE=+15555550123 -ADDR=0x1111111111111111111111111111111111111111 -``` - -- `.env.smoke.preview` (for Preview) -``` -KV_REST_API_URL= -KV_REST_API_TOKEN= -PREVIEW_BASE_URL=https://.vercel.app -PHONE=+15555550123 -ADDR=0x1111111111111111111111111111111111111111 -BYPASS_TOKEN=... -SMOKE_TEST_TOKEN=... -``` - -Run the script: -```bash -yarn smoke:prod -# or -yarn smoke:preview -``` - -Notes: -- The script inspects `POST /api/sms/send` response JSON for `mode` (`verify` | `kv-fallback`). -- **mode=kv-fallback**: runs full E2E (fetch code from KV/debug → verify → eligibility → mint). -- **mode=verify + prod**: send-health (send ok) + eligibility check only; OTP verify/mint skipped by design. -- **mode=verify + preview**: full E2E only when fallback is used; otherwise OTP verify/mint skipped with clear message. -- `KV_REST_API_URL` and `KV_REST_API_TOKEN` are required only when `mode=kv-fallback`. -- `BYPASS_TOKEN` and `SMOKE_TEST_TOKEN` supported. -- The script loads ENVFILE (if provided), then `.env.smoke.{prod|preview}`, then `.env.local`, then `.env`. -- No SMS provider needed for kv-fallback; OTP is read from KV via REST for testing. -- Cooldowns and rate limits apply; you may need to wait 120s for repeated runs. - - If your Preview custom domain is protected via Vercel Auth and proxied by Cloudflare, prefer the vercel.app URL for smoke tests. - -### Contributor quickstart: Preview smoke test -- Create/connect a Preview Upstash KV to this project and ensure the Preview env has `KV_REST_API_URL` and `KV_REST_API_TOKEN` (use the plain names; avoid double prefixes). Optionally set `SMOKE_TEST_TOKEN` to enable a debug echo of the OTP. -- If Deployment Protection is enabled, create a Protection Bypass token and use it as `BYPASS_TOKEN` in the `.env.smoke.preview` file. The script will set the bypass cookie and header automatically. -- Trigger a new Preview deployment and copy its per-deployment vercel.app URL from Vercel → Deployments. Use that URL as `PREVIEW_BASE_URL`. -- Create `web/.env.smoke.preview` with: - - `KV_REST_API_URL`, `KV_REST_API_TOKEN` - - `PREVIEW_BASE_URL`, `PHONE`, `ADDR` - - `BYPASS_TOKEN` (only if protection is enabled) - - `SMOKE_TEST_TOKEN` (optional; returns `debugCode` during send) -- Run `corepack yarn install` then `corepack yarn smoke:preview`. -- Expected: send → verify → eligibility=true → mint ok (stubbed unless on-chain envs are set). - -### Environment Variables -Copy `.env.example` to `.env.local` and fill in values. Do not commit `.env.local`. - -Required for runtime: -- `KV_REST_API_URL`, `KV_REST_API_TOKEN` -- `HASH_PEPPER` (optional; HMAC key for hashing identifiers used in KV keys) - -Optional for SMS provider (Twilio Verify preferred): -- `TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_VERIFY_SERVICE_SID` — required in production for Verify mode. Create a Verify Service in Twilio Console and use its SID. -- Legacy (kv-fallback only; deprecated for OTP): `TWILIO_MESSAGING_SERVICE_SID` or `SMS_SENDER_ID` - -Optional for on-chain mint (Base Sepolia): -- `MINTER_PRIVATE_KEY` -- `MINTPASSV1_ADDRESS_BASE_SEPOLIA` -- `BASE_SEPOLIA_RPC_URL` - -Optional for smoke testing (Preview only): -- `SMOKE_TEST_TOKEN` (debug-only echo of OTP when `x-smoke-test-token` header is present) -- `HASH_PEPPER` (optional; if set, `scripts/smoke-test.sh` derives the hashed OTP KV key via OpenSSL when available) - -### Next Steps -- Add additional authentication methods beyond SMS (e.g., pay‑to‑mint, others). -- Add abuse heuristics (velocity checks per phone/IP, lightweight device signals if needed). -- Continue UI polish and success animations; broaden admin tooling and observability. - -This project includes both backend APIs and frontend UI components built with shadcn/ui and mobile-first responsive design. - -### Operational recommendations -- Put Cloudflare in front of Vercel for additional DDoS protection and WAF/challenge. Set `CF-Connecting-IP` pass-through so backend uses real client IP. -- Monitor rate-limit headers (`X-RateLimit-*`) and adjust envs based on traffic. -``` - ---- - -## challenge/README.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/challenge/README.md - -```markdown -# @bitsocial/mintpass-challenge - -MintPass challenge for pkc-js that verifies users own a MintPass NFT before publishing. - -## Requirements - -- Node.js `>=22` -- ESM-only environment - -## Using mintpass in your community - -Community owners add the mintpass challenge to their community settings. When enabled, every publication (post, reply, vote) requires the author to own a MintPass NFT. The challenge is published as [`@bitsocial/mintpass-challenge`](https://www.npmjs.com/package/@bitsocial/mintpass-challenge) on npm. - -### With pkc-js over RPC - -If your RPC server is already running, first install the challenge on the server: - -```bash -bitsocial challenge install @bitsocial/mintpass-challenge -``` - -Then from your RPC client, connect and set the challenge on your community by name — no npm install or challenge registration needed on the client side: - -```ts -import PKC from "@pkcprotocol/pkc-js"; - -const pkc = await PKC({ - pkcRpcClientsOptions: ["ws://localhost:9138"] -}); - -const community = await pkc.createCommunity({ address: "your-community-address.bso" }); - -await community.edit({ - settings: { - challenges: [ - { - name: "@bitsocial/mintpass-challenge", - options: { - chainTicker: "base", - contractAddress: "0x13d41d6B8EA5C86096bb7a94C3557FCF184491b9", - requiredTokenType: "0", - transferCooldownSeconds: "604800" - } - } - ] - } -}); -``` - -### With pkc-js (TypeScript) - -Install the challenge package: - -```bash -npm install @bitsocial/mintpass-challenge -``` - -Register the challenge and configure your community: - -```typescript -import PKC from '@pkcprotocol/pkc-js' -import { mintpass } from '@bitsocial/mintpass-challenge' - -// Register the challenge so it can be referenced by name -PKC.challenges['@bitsocial/mintpass-challenge'] = mintpass - -const pkc = await PKC({ /* your pkc options */ }) -const community = await pkc.createCommunity({ address: 'your-community.bso' }) - -await community.edit({ - settings: { - challenges: [{ - name: '@bitsocial/mintpass-challenge', - options: { - chainTicker: 'base', - contractAddress: '0x13d41d6B8EA5C86096bb7a94C3557FCF184491b9', - requiredTokenType: '0', - transferCooldownSeconds: '604800', - } - }] - } -}) -``` - -#### Challenge options - -All option values must be strings (pkc-js challenge convention). - -| Option | Default | Description | -|--------|---------|-------------| -| `chainTicker` | `"base"` | Chain where MintPass contract is deployed | -| `contractAddress` | Known deployment per chain | If omitted and `chainTicker` is supported, defaults to the known MintPass deployment for that chain | -| `requiredTokenType` | `"0"` | Required token type (0=SMS, 1=Email, 2+=future methods) | -| `transferCooldownSeconds` | `"604800"` | Cooldown period after NFT transfer (1 week) | -| `error` | Default message | Custom error message for users without NFT. Use `{authorAddress}` as a placeholder | - -### With bitsocial-cli - -Install the challenge package: - -```bash -bitsocial challenge install @bitsocial/mintpass-challenge -``` - -Edit your community to use the challenge: - -```bash -bitsocial community edit your-community.bso \ - '--settings.challenges[0].name' @bitsocial/mintpass-challenge \ - '--settings.challenges[0].options.chainTicker' 'base' \ - '--settings.challenges[0].options.contractAddress' '0x13d41d6B8EA5C86096bb7a94C3557FCF184491b9' \ - '--settings.challenges[0].options.requiredTokenType' '0' \ - '--settings.challenges[0].options.transferCooldownSeconds' '604800' -``` - -See the [bitsocial-cli documentation](https://github.com/bitsocial/bitsocial-cli) for full CLI reference. - -## Scripts - -```bash -yarn build -yarn test -yarn clean -``` -``` - ---- - -## contracts/README.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/contracts/README.md - -```markdown -# MintPassV1 Smart Contract - -This directory contains the MintPassV1 NFT smart contract for the MintPass authentication system. - -## Features - -- **ERC721 + ERC721Enumerable**: Standard NFT functionality with enumeration support -- **Access Control**: Admin and Minter roles for secure operations -- **Token Types**: Each NFT has a type (e.g., 0 = SMS verification, 1 = Email verification) -- **Batch Operations**: Gas-efficient batch minting -- **Utility Functions**: Comprehensive ownership and type checking functions -- **Upgradeable Metadata**: Admin can update base URI for metadata - -## Contract Specification - -- **Name**: MintPassV1 -- **Symbol**: MPSS -- **Base URI**: `https://mintpass.org/mint1/` -- **Network**: Base (Layer 2) -- **Token Types**: uint16 (65,536 possible types) - - Type 0: SMS verification - - Type 1+: Future verification methods - -## Quick Start - -Contributor setup: -1. Run `nvm install && nvm use` -2. Run `corepack enable` once per machine -3. Use plain `yarn install`, `yarn compile`, and `yarn test` - -1. **Install dependencies**: - ```bash - yarn install - ``` - -2. **Compile contracts**: - ```bash - yarn compile - ``` - -3. **Run tests**: - ```bash - yarn test - ``` - -4. **Deploy to Base Sepolia (testnet)**: - ```bash - # Copy .env.example to .env and fill in your values - cp .env.example .env - - # Deploy - yarn deploy:base-sepolia - ``` - -5. **Deploy to Base Mainnet**: - ```bash - yarn deploy:base - ``` - -## Environment Setup - -Create a `.env` file with the following variables: - -```env -# Private key for deployment (without 0x prefix) -PRIVATE_KEY=your_private_key_here - -# Base network explorer API key for contract verification -BASESCAN_API_KEY=your_basescan_api_key_here - -# Gas reporting (optional) -REPORT_GAS=true -``` - -## Core Functions - -### Minting -- `mint(address to, uint16 tokenType)`: Mint single NFT -- `mintBatch(address[] recipients, uint16[] tokenTypes)`: Batch mint - -### Token Information -- `tokenType(uint256 tokenId)`: Get token type for a token ID -- `tokensOfOwner(address owner)`: Get all tokens and types owned by address -- `tokensOfOwners(address[] owners)`: Batch version of above - -### Ownership Checks -- `ownsTokenType(address owner, uint16 tokenType)`: Check if owns specific type -- `ownsTokenTypes(address owner, uint16[] tokenTypes)`: Check if owns all types -- `ownsOneOfTokenTypes(address owner, uint16[] tokenTypes)`: Check if owns any type - -### Admin Functions -- `setBaseURI(string newBaseURI)`: Update metadata base URI (admin only) -- Role management via AccessControl - -## Testing - -The test suite covers: -- ✅ Deployment and initialization -- ✅ Minting (single and batch) -- ✅ Token type tracking -- ✅ All utility functions -- ✅ Access control -- ✅ ERC721 compatibility -- ✅ Admin functions - -Run tests with: -```bash -yarn test -``` - -For coverage report: -```bash -yarn coverage -``` - -## Gas Optimization - -The contract includes several gas optimizations: -- Batch minting for multiple NFTs -- Efficient token type storage -- Optimized enumeration functions -- No unnecessary storage reads - -## Security Features - -- **Role-based access control**: Admin and Minter roles -- **No proxy pattern**: Immutable core logic (versioned approach) -- **Transfer detection**: External systems can implement cooldowns -- **Admin functions limited**: Only cosmetic changes allowed - -## Deployment Networks - -- **Base Sepolia** (Testnet): Chain ID 84532 -- **Base Mainnet**: Chain ID 8453 - -## Next Steps - -1. Deploy contract to Base Sepolia for testing -2. Verify contract on BaseScan -3. Test minting functionality -4. Integrate with the PKC challenge system -5. Iterate on web integration and tooling -``` - ---- - -## docs/pkc-info.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/docs/pkc-info.md - -```markdown -# Info about PKC - -PKC-js is a decentralized Reddit-like protocol built on top of IPFS and libp2p PubSub. It enables censorship-resistant communities called communities, each with its own moderation rules, where moderation is enforced through challenge-response games between peers rather than through centralized control. - -### 1. IPFS + PubSub Backbone -PKC-js uses libp2p's PubSub (gossipsub) to propagate posts and comments. Each community is essentially a pubsub topic. Peers subscribe to the topics they care about (communities) and exchange content via the decentralized mesh. -### 2. Community Moderation via P2P Challenge-Response -Instead of centralized mods, PKC lets community owners define arbitrary logic (expressed in WASM or interpreted JavaScript) for moderation challenges. Any peer can challenge a post or comment according to the rules defined by the community. -### 3. Challenges -A challenge is a message sent directly (peer-to-peer) to the post/comment author. The author must reply with a valid response (or the post is hidden locally). This creates an adversarial moderation environment that still honors local control and censorship-resistance. -### 4 No Global Consensus -The system is subjective. Every peer maintains their own view of the network, deciding whether to accept or reject content based on challenges they observe and responses received. -### 5. Example: -A community might define a rule like: -"You must prove that your account is older than 7 days to post." -This challenge would be enforced by sending a P2P challenge to posters and expecting a valid proof. - -Existing Challenge API on pkc-js library: - -```ts -import { EventEmitter } from "events"; -import { pkcJsChallenges } from "../../../dist/node/runtime/node/community/challenges/index.js"; - -// define mock Author instances -const highKarmaAuthor = { - address: "high-karma.eth", - wallets: { eth: { address: "0x...", signature: "0x..." } } -}; -const lowKarmaAuthor = { address: "low-karma.eth" }; -const authors = [highKarmaAuthor, lowKarmaAuthor]; - -// mock comment instance -function Comment(cid) { - const split = cid.replace("Qm...", "").split(","); - const communityAddress = split[0]; - const karma = split[1]; - const age = split[2]; - this.communityAddress = communityAddress; - this.updatedAt = undefined; - - // define author - this.author = { address: "Qm..." }; - if (karma === "high") { - this.author.address = highKarmaAuthor.address; - } else if (karma === "low") { - this.author.address = lowKarmaAuthor.address; - } - - // use this value to mock giving 'high' or 'low' karma to the author - this.karma = karma; - this.age = age; -} -Object.setPrototypeOf(Comment.prototype, EventEmitter.prototype); - -Comment.prototype.update = function () { - setTimeout(() => { - this.updatedAt = 123456; - if (this.karma === "high") { - this.author.community = { - postScore: 1000, - replyScore: 1000 - }; - } else if (this.karma === "low") { - this.author.community = { - postScore: 1, - replyScore: 1 - }; - } - if (this.age === "old") { - this.author.community.firstCommentTimestamp = Math.round(Date.now() / 1000) - 60 * 60 * 24 * 999; // 999 days ago - } else if (this.age === "new") { - this.author.community.firstCommentTimestamp = Math.round(Date.now() / 1000) - 60 * 60 * 24 * 1; // 1 day ago - } - this.emit("update", this); - }, 5).unref?.(); -}; - -Comment.prototype.stop = function () { - this.removeAllListeners(); -}; - -// mock pkc sync -const createPKC = () => { - return { - getComment: (cid) => new Comment(cid), - createComment: (cid) => new Comment(cid) - }; -}; -// mock PKC async -const PKC = () => createPKC(); - -// define mock challenges included with pkc-js -PKC.challenges = pkcJsChallenges; - -// define mock Community instances -const textMathChallengeCommunity = { - title: "text-math challenge community", - settings: { - challenges: [ - { - name: "text-math", - options: { difficulty: "3" }, - description: "Complete a math challenge." - } - ] - } -}; -// comment out because don't know how to make the captcha node code work in the browser -// const captchaAndMathChallengeCommunity = { -// title: 'captcha and math challenge community', -// settings: { -// challenges: [ -// { -// name: 'captcha-canvas-v3', -// options: { -// width: '600', -// height: '400', -// characters: '10', -// color: '#000000' -// }, -// description: 'Complete a captcha challenge.' -// }, -// { -// name: 'text-math', -// options: {difficulty: '2'}, -// description: 'Complete a math challenge.' -// } -// ] -// } -// } -const excludeHighKarmaChallengeCommunity = { - title: "exclude high karma challenge community", - settings: { - challenges: [ - { - name: "text-math", - options: { difficulty: "3" }, - // exclude if the author match any one item in the array - exclude: [ - { postScore: 100, replyScore: 100 }, // exclude author that has more than 100 post score AND 100 reply score - // exclude author with account age older than 100 days (Math.round(Date.now() / 1000)- 60*60*24*100) - { firstCommentTimestamp: 60 * 60 * 24 * 100 } - ] - } - ] - } -}; -const excludeAccountAgeChallengeCommunity = { - title: "exclude account age challenge community", - settings: { - challenges: [ - { - name: "fail", - // exclude if the author match any one item in the array - exclude: [ - // exclude author with account age older than 100 days (Math.round(Date.now() / 1000)- 60*60*24*100) - { firstCommentTimestamp: 60 * 60 * 24 * 100 } - ] - } - ] - } -}; -const whitelistChallengeCommunity = { - title: "whitelist challenge community", - settings: { - challenges: [ - { - // the fail challenge always fails - name: "fail", - options: { - error: `You're not whitelisted.` - }, - // challenge should never be triggered if the author address is excluded - exclude: [{ address: ["high-karma.eth"] }] - } - ] - } -}; -const blacklistChallengeCommunity = { - title: "blacklist challenge community", - settings: { - challenges: [ - { - name: "blacklist", - options: { - blacklist: "low-karma.eth,some-author.eth" - } - } - ] - } -}; -// comment out because don't know how to require external challenge in the browser tests -// const erc20PaymentChallengeCommunity = { -// title: 'erc20 payment challenge community', -// settings: { -// challenges: [ -// { -// path: path.join(__dirname, 'challenges', 'erc20-payment'), -// options: { -// chainTicker: 'eth', -// contractAddress: '0x...', -// recipientAddress: '0x...', -// symbol: 'PLEB', -// decimals: '18', -// postPrice: '1000', -// replyPrice: '100', -// votePrice: '10' -// }, -// }, -// ] -// } -// } -const evmContractCallChallengeCommunity = { - title: "evm contract call challenge community", - settings: { - challenges: [ - { - name: "evm-contract-call", - options: { - chainTicker: "eth", - // contract address - address: "0x...", - // abi of the contract method - abi: '{"constant":true,"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"}', - condition: ">1000", - // error to display to the user if condition fails - error: "PLEB token balance must be greater than 1000." - } - } - ] - } -}; -const passwordChallengeCommunity = { - title: "password challenge community", - settings: { - challenges: [ - { - name: "question", - options: { - question: "What is the password?", - answer: "password" - } - } - ] - } -}; -const excludeFriendlySubKarmaChallengeCommunity = { - title: "exclude friendly community karma challenge community", - settings: { - challenges: [ - { - name: "fail", - exclude: [ - // exclude author with karma in those subs using publication.challengeCommentCids - { - community: { - addresses: ["friendly-sub.eth", "friendly-sub2.eth"], - postScore: 100, - replyScore: 100, - maxCommentCids: 3 - } - } - ] - } - ] - } -}; -const twoOutOf4SuccessChallengeCommunity = { - title: "2 out of 4 success challenge community", - settings: { - // challenge 0, 1 fail, but excluded if 2, 3 succeed, which makes challengeVerification.challengeSuccess = true - challenges: [ - { - name: "fail", - exclude: [{ challenges: [2, 3] }] - }, - { - name: "fail", - exclude: [{ challenges: [2, 3] }] - }, - { - name: "blacklist", - options: { blacklist: "low-karma.eth,some-author.eth" } - }, - { - name: "blacklist", - options: { blacklist: "low-karma.eth,some-author.eth" } - } - ] - } -}; -const twoOutOf4SuccessInverseChallengeCommunity = { - title: "2 out of 4 success inverse challenge community", - settings: { - // challenge 0, 1 fail, but excluded if 2, 3 succeed, which makes challengeVerification.challengeSuccess = true - challenges: [ - { - name: "blacklist", - options: { blacklist: "low-karma.eth,some-author.eth" } - }, - { - name: "blacklist", - options: { blacklist: "low-karma.eth,some-author.eth" } - }, - { - name: "fail", - exclude: [{ challenges: [0, 1] }] - }, - { - name: "fail", - exclude: [{ challenges: [0, 1] }] - } - ] - } -}; -const rateLimitChallengeCommunity = { - title: "rate limit challenge community", - settings: { - challenges: [ - { - name: "fail", - options: { - error: `You're doing this too much, rate limit: 0 post/h, 10 replies/h, 100 votes/h.` - }, - exclude: [ - // different rate limit per publication type - { publicationType: { post: true }, rateLimit: 0 }, // 0 per hour - { publicationType: { reply: true }, rateLimit: 10 }, // 10 per hour - { publicationType: { vote: true }, rateLimit: 100 } // 100 per hour - ] - } - ] - } -}; -const rateLimitChallengeSuccessChallengeCommunity = { - title: "rate limit challenge success challenge community", - settings: { - challenges: [ - { - name: "fail", - options: { - error: `You're doing this too much.` - }, - exclude: [ - // only 1 successful publication per hour - { rateLimit: 1, rateLimitChallengeSuccess: true }, - // only 100 failed challenge request per hour - { rateLimit: 100, rateLimitChallengeSuccess: false } - ] - } - ] - } -}; -const excludeModsChallengeCommunity = { - title: "exclude mods challenge community", - roles: { - "high-karma.eth": { - role: "moderator" - } - }, - settings: { - challenges: [ - { - name: "fail", - options: { - error: `You're not a mod.` - }, - exclude: [{ role: ["moderator", "admin", "owner"] }] - } - ] - } -}; - -// define mock author karma scores and account age -const communityAuthors = {}; -communityAuthors[highKarmaAuthor.address] = {}; -communityAuthors[highKarmaAuthor.address][excludeHighKarmaChallengeCommunity.title] = { - postScore: 1000, - replyScore: 1000, - firstCommentTimestamp: 1 -}; -communityAuthors[highKarmaAuthor.address][excludeAccountAgeChallengeCommunity.title] = { - postScore: 1, - replyScore: 1, - firstCommentTimestamp: 1 -}; -communityAuthors[lowKarmaAuthor.address] = {}; -communityAuthors[lowKarmaAuthor.address][excludeHighKarmaChallengeCommunity.title] = { postScore: 1, replyScore: 1000 }; -communityAuthors[lowKarmaAuthor.address][excludeAccountAgeChallengeCommunity.title] = { postScore: 1000, replyScore: 1000 }; - -// define mock friendly community comment cids -const challengeCommentCids = {}; -challengeCommentCids[highKarmaAuthor.address] = ["Qm...friendly-sub.eth,high,old", "Qm...friendly-sub.eth,high,old"]; - -const challengeAnswers = {}; -challengeAnswers[highKarmaAuthor.address] = {}; -challengeAnswers[highKarmaAuthor.address][passwordChallengeCommunity.title] = ["password"]; -challengeAnswers[lowKarmaAuthor.address] = {}; -challengeAnswers[lowKarmaAuthor.address][passwordChallengeCommunity.title] = ["wrong"]; - -const communities = [ - textMathChallengeCommunity, - // captchaAndMathChallengeCommunity, - excludeHighKarmaChallengeCommunity, - excludeAccountAgeChallengeCommunity, - whitelistChallengeCommunity, - blacklistChallengeCommunity, - // erc20PaymentChallengeCommunity, - // evmContractCallChallengeCommunity, - passwordChallengeCommunity, - excludeFriendlySubKarmaChallengeCommunity, - twoOutOf4SuccessChallengeCommunity, - twoOutOf4SuccessInverseChallengeCommunity, - rateLimitChallengeCommunity, - rateLimitChallengeSuccessChallengeCommunity, - excludeModsChallengeCommunity -]; - -const results = {}; -results[textMathChallengeCommunity.title] = { - "high-karma.eth": { - pendingChallenges: [{ challenge: "660 - 256", type: "text/plain" }] - }, - "low-karma.eth": { - pendingChallenges: [{ challenge: "69 * 63", type: "text/plain" }] - } -}; -// comment out because don't know how to make the captcha node code work in the browser -// results[captchaAndMathChallengeCommunity.title] = { -// 'high-karma.eth': { -// pendingChallenges: [ -// { challenge: '...', type: 'image' }, -// { challenge: '94 + 25', type: 'text/plain' } -// ] -// }, -// 'low-karma.eth': { -// pendingChallenges: [ -// { challenge: '...', type: 'image' }, -// { challenge: '99 - 90', type: 'text/plain' } -// ] -// } -// } -results[excludeHighKarmaChallengeCommunity.title] = { - "high-karma.eth": { challengeSuccess: true }, - "low-karma.eth": { - pendingChallenges: [{ challenge: "82 * 45", type: "text/plain" }] - } -}; -results[excludeAccountAgeChallengeCommunity.title] = { - "high-karma.eth": { challengeSuccess: true }, - "low-karma.eth": { - challengeSuccess: false, - challengeErrors: { 0: "You're not allowed to publish." } - } -}; -results[whitelistChallengeCommunity.title] = { - "high-karma.eth": { challengeSuccess: true }, - "low-karma.eth": { - challengeSuccess: false, - challengeErrors: { 0: "You're not whitelisted." } - } -}; -results[blacklistChallengeCommunity.title] = { - "high-karma.eth": { challengeSuccess: true }, - "low-karma.eth": { - challengeSuccess: false, - challengeErrors: { 0: "You're blacklisted." } - } -}; -// comment out because don't know how to require external challenge in the browser tests -// results[erc20PaymentChallengeCommunity.title] = { -// 'high-karma.eth': { challengeSuccess: true }, -// 'low-karma.eth': { -// challengeSuccess: false, -// challengeErrors: {"0": "Author doesn't have wallet (eth) set." } -// } -// } -results[evmContractCallChallengeCommunity.title] = { - "high-karma.eth": { challengeSuccess: true }, - "low-karma.eth": { - challengeSuccess: false, - challengeErrors: { 0: "Author doesn't have a wallet set." } - } -}; -results[passwordChallengeCommunity.title] = { - "high-karma.eth": { challengeSuccess: true }, - "low-karma.eth": { challengeSuccess: false, challengeErrors: { 0: "Wrong answer." } } -}; -results[excludeFriendlySubKarmaChallengeCommunity.title] = { - "high-karma.eth": { challengeSuccess: true }, - "low-karma.eth": { - challengeSuccess: false, - challengeErrors: { 0: "You're not allowed to publish." } - } -}; -results[twoOutOf4SuccessChallengeCommunity.title] = { - "high-karma.eth": { challengeSuccess: true }, - "low-karma.eth": { - challengeSuccess: false, - challengeErrors: { - 0: "You're not allowed to publish.", - 1: "You're not allowed to publish.", - 2: "You're blacklisted.", - 3: "You're blacklisted." - } - } -}; -results[twoOutOf4SuccessInverseChallengeCommunity.title] = { - "high-karma.eth": { challengeSuccess: true }, - "low-karma.eth": { - challengeSuccess: false, - challengeErrors: { - 0: "You're blacklisted.", - 1: "You're blacklisted.", - 2: "You're not allowed to publish.", - 3: "You're not allowed to publish." - } - } -}; -results[rateLimitChallengeCommunity.title] = { - "high-karma.eth": { - challengeSuccess: false, - challengeErrors: { 0: "You're doing this too much, rate limit: 0 post/h, 10 replies/h, 100 votes/h." } - }, - "low-karma.eth": { - challengeSuccess: false, - challengeErrors: { 0: "You're doing this too much, rate limit: 0 post/h, 10 replies/h, 100 votes/h." } - } -}; -results[rateLimitChallengeSuccessChallengeCommunity.title] = { - "high-karma.eth": { - challengeSuccess: true - }, - "low-karma.eth": { - challengeSuccess: true - } -}; -results[excludeModsChallengeCommunity.title] = { - "high-karma.eth": { - challengeSuccess: true - }, - "low-karma.eth": { - challengeSuccess: false, - challengeErrors: { 0: "You're not a mod." } - } -}; - -// add mock pkc to add the mock community instances -for (const community of communities) { - community._pkc = createPKC(); -} - -export { PKC, communities, authors, communityAuthors, challengeCommentCids, challengeAnswers, results }; - -```ts -``` - ---- - -## docs/challenges/README.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/README.md - -```markdown -NOTE: Challenges included with pkc-js are located in ./pkc-js-challenges - -#### How to use: - -```js -const {getChallengeVerification} = require('./challenges') - -// NOTE: publishing challenge pubsub message and waiting for challenge answer message go inside the getChallengeAnswers callback -// because they are sometimes skipped -const getChallengeAnswers = async (challenges) => { - // ...get challenge answers from user. e.g.: - // step 1. community publishes challenge pubsub message with `challenges` provided in argument of `getChallengeAnswers` - // step 2. community waits for challenge answer pubsub message with `challengeAnswers` and then returns `challengeAnswers` - return challengeAnswers -} - -// NOTE: we try to get challenge verification immediately after receiving challenge request -// because some challenges are automatic and skip the challenge message -let challengeVerification -try { - challengeVerification = await getChallengeVerification(challengeRequest, community, getChallengeAnswers) -} -// getChallengeVerification will throw if one of the getChallenge function throws, which indicates a bug with the challenge script -catch (e) { - // notify the community owner that that one of his challenge is misconfigured via an error event - community.emit('error', e.message) - - // notify the author that his publication wasn't published because the community is misconfigured - challengeVerification = { - challengeSuccess: false, - reason: `One of the community challenges is misconfigured: ${e.message}` - } -} -``` - -#### Types: - -```javascript -// list of challenges included with pkc-js -PKC.challenges = {[challengeName: string]: ChallengeFile} - -// new props -ChallengeRequestMessage { - encrypted: Encrypted - /* ChallengeRequestMessage.encrypted.ciphertext decrypts to JSON { - publication: Publication - challengeAnswers?: string[] // some challenges might be included in community.challenges and can be pre-answered - challengeCommentCids?: string[] // some challenges could require including comment cids in other communities, like friendly community karma challenges - } */ -} -Community { - // challenges is public, part of the IPNS record - challenges: CommunityChallenge[] - // settings is private, not part of the IPNS record - settings: { - challenges: CommunityChallengeSettings[] - } -} - -// public challenges types -CommunityChallenge { // copy values from private community.settings and publish to community.challenges - exclude?: Exclude[] // copied from community.settings.challenges.exclude - description?: string // copied from community.settings.challenges.description - challenge?: string // copied from ChallengeFile.challenge - type?: // copied from ChallengeFile.type -} -CommunityChallengeSettings { // the private settings of the challenge (community.settings.challenges) - path?: string // (only if name is undefined) the path to the challenge js file, used to get the props ChallengeFile {optionInputs, type, getChallenge} - name?: string // (only if path is undefined) the challengeName from PKC.challenges to identify it - options?: [optionPropertyName: string]: string // the options to be used to the getChallenge function, all values must be strings for UI ease of use - exclude?: Exclude[] // singular because it only has to match 1 exclude, the client must know the exclude setting to configure what challengeCommentCids to send - description?: string // describe in the frontend what kind of challenge the user will receive when publishing -} -ChallengeFile { // the result of the function exported by the challenge file - optionInputs?: OptionInput[] // the options inputs fields to display to the user - type: 'image/png' | 'text/plain' | 'chain/' - challenge?: string // some challenges can be static and asked before the user publishes, like a password for example - description?: string // describe what the challenge does to display in the UI - getChallenge: GetChallengeFunction -} -GetChallengeFunction { - (challenge: CommunityChallengeSettings, challengeRequest: ChallengeRequestMessage, challengeIndex: number): Challenge | ChallengeResult -} -Challenge { // if the result of a challenge can't be optained by getChallenge(), return a challenge - challenge: string // e.g. '2 + 2' - verify: async (answer: string): ChallengeResult - type: 'image/png' | 'text/plain' | 'chain/' -} -ChallengeResult { // if the result of a challenge can be optained by getChallenge, return the result - success?: boolean - error?: string // the reason why the challenge failed, add it to ChallengeVerificationMessage.errors -} -Exclude { // all conditions in Exclude are AND, for OR, use another Exclude item in the Exclude array - community?: ExcludeCommunity // exclude if author karma (from challengeRequestMessage.challengeCommentCids) in another community is greater or equal - postScore?: number // exclude if author post score is greater or equal - postReply?: number // exclude if author reply score is greater or equal - firstCommentTimestamp?: number // exclude if author account age is greater or equal than now - firstCommentTimestamp - challenges?: number[] // exclude if all challenges with indexes passed, e.g. challenges: [0, 1] excludes if challenges at index 0 AND 1 passed, plural because has to match all - publicationType?: ExcludePublicationType // exclude post, reply, vote, etc. - role?: string[] // exclude challenge if author.role.role = one of the string, singular because it only has to match 1 role - address?: string[] // exclude challenge if author.address = one of the string, singular because it only has to match 1 address - rateLimit?: number // exclude if publication per hour is lower than ratelimit - rateLimitChallengeSuccess?: boolean // only rate limit if the challengeVerification.challengeSuccess === rateLimitChallengeSuccess -} -ExcludePublicationType { // singular because it only has to match 1 publication type - post?: boolean // exclude challenge if publication is a post - reply?: boolean // exclude challenge if publication is a reply - vote?: boolean // exclude challenge if publication is a vote - commentEdit?: boolean // exclude challenge if publication is a comment edit - commentModeration?: boolean // exclude challenge if publication is a comment moderation -} -ExcludeCommunity { // singular because it only has to match 1 community - addresses: string[] // list of community addresses that can be used to exclude, plural because not a condition field like 'role' - maxCommentCids: number // maximum amount of comment cids that will be fetched to check - postScore?: number - postReply?: number - firstCommentTimestamp?: number // exclude if author account age is greater or equal than now - firstCommentTimestamp -} -OptionInput { - option: string // option property name, e.g. characterCount - label: string // option title, e.g. Character Count - default: string // option default value, e.g. 10 - description?: string // e.g. Amount of characters of the captcha - placeholder?: string // the value to display if the input field is empty, e.g. 10 - required?: boolean // the option is required, the challenge will throw without it -} -``` - -#### Ideas: - -- interface so that the community owner can display on publication.author.community the amount paid by the user for payment challenges -- "standard" challenges like "fail" and "evm-contract-call" so that the frontend could calculate the exclude and result of the challenge to see if the author passes it before even publishing -``` - ---- - -## docs/challenges/question.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/question.md - -```markdown -# Question challenge - -API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges - -Code: - -```ts -import type { Challenge, ChallengeFile, ChallengeResult, CommunityChallengeSetting } from "../../../../../community/types.js"; -import type { DecryptedChallengeRequestMessageTypeWithCommunityAuthor } from "../../../../../pubsub-messages/types.js"; - -const optionInputs = >[ - { - option: "question", - label: "Question", - default: "", - description: "The question to answer.", - placeholder: "" - }, - { - option: "answer", - label: "Answer", - default: "", - description: "The answer to the question.", - placeholder: "", - required: true - } -]; - -const type: Challenge["type"] = "text/plain"; - -const description = `Ask a question, like 'What is the password?'`; - -const getChallenge = async ( - communityChallengeSettings: CommunityChallengeSetting, - challengeRequestMessage: DecryptedChallengeRequestMessageTypeWithCommunityAuthor, - challengeIndex: number -): Promise => { - if (!communityChallengeSettings?.options?.question) throw Error("No option question"); - let answer = communityChallengeSettings?.options?.answer; - if (!answer) { - throw Error("no option answer"); - } - - // use the answer preincluded in the challenge request when possible - const challengeAnswer = challengeRequestMessage?.challengeAnswers?.[challengeIndex]; - - // the author didn't preinclude his answer, so send him a pubsub challenge message - if (challengeAnswer === undefined) { - return { - challenge: communityChallengeSettings?.options?.question, - verify: async (_answer: string) => { - if (_answer === answer) - return { - success: true - }; - return { - success: false, - error: "Wrong answer." - }; - }, - type - }; - } - - // the author did preinclude his answer, but it's wrong, so send him a failed challenge verification - if (challengeAnswer !== answer) { - return { - success: false, - error: "Wrong answer." - }; - } - - // the author did preinclude his answer, and it's correct, so send him a success challenge verification - return { - success: true - }; -}; - -function ChallengeFileFactory(communityChallengeSettings: CommunityChallengeSetting): ChallengeFile { - // some challenges can prepublish the challenge so that it can be preanswered - // in the challengeRequestMessage - const question = communityChallengeSettings?.options?.question; - const challenge = question; - - return { getChallenge, optionInputs, type, challenge, description }; -} - -export default ChallengeFileFactory; -``` -``` - ---- - -## docs/challenges/evm-contract-call.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/evm-contract-call.md - -```markdown -# EVM contract call challenge - -API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges - -Code: - -```ts -import { LocalCommunity } from "../../../local-community.js"; -import { getPkcAddressFromPublicKey } from "../../../../../../signer/util.js"; -import type { ChainTicker } from "../../../../../../types.js"; -import type { - DecryptedChallengeRequestMessageTypeWithCommunityAuthor, - PublicationWithCommunityAuthorFromDecryptedChallengeRequest -} from "../../../../../../pubsub-messages/types.js"; -import type { Challenge, ChallengeFile, ChallengeResult, CommunityChallengeSetting } from "../../../../../../community/types.js"; -import { decodeFunctionResult, encodeFunctionData } from "viem"; -import Logger from "@pkcprotocol/pkc-logger"; -import type { PKC } from "../../../../../../pkc/pkc.js"; -import { derivePublicationFromChallengeRequest, isStringDomain } from "../../../../../../util.js"; -import { normalize } from "viem/ens"; - -const optionInputs = >[ - { - option: "chainTicker", - label: "chainTicker", - default: "eth", - description: "The chain ticker", - placeholder: "eth", - required: true - }, - { - option: "address", - label: "Address", - default: "", - description: "The contract address.", - placeholder: "0x...", - required: true - }, - { - option: "abi", - label: "ABI", - default: "", - description: "The ABI of the contract method.", - placeholder: '{"constant":true,"inputs":[{"internalType":"address","name":"account...', - required: true - }, - { - option: "condition", - label: "Condition", - default: "", - description: "The condition the contract call response must pass.", - placeholder: ">1000", - required: true - }, - { - option: "error", - label: "Error", - default: `Contract call response doesn't pass condition.`, - description: "The error to display to the author." - } -]; - -const description = "The response from an EVM contract call passes a condition, e.g. a token balance challenge."; - -// Unrelated to challenges API -//prettier-ignore -const nftAbi = [ - {"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}, - {"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"} - ]; - -const supportedConditionOperators = ["=", ">", "<"]; - -const _getChainProviderWithSafety = (pkc: PKC, chainTicker: ChainTicker) => { - const chainProvider = pkc.chainProviders[chainTicker]; - if (!chainProvider) throw Error("pkc.chainProviders[chainTicker] is not defined"); - return chainProvider; -}; - -const verifyAuthorWalletAddress = async (props: { - publication: PublicationWithCommunityAuthorFromDecryptedChallengeRequest; - chainTicker: string; - condition: string; - abi: any; - error: string; - contractAddress: string; - pkc: PKC; -}): Promise => { - const log = Logger("pkc-js:local-community:evm-contract-call-v1:verifyAuthorWalletAddress"); - const authorWallet = props.publication.author.wallets?.[props.chainTicker]; - if (typeof authorWallet?.address !== "string") return "The author wallet address is not defined"; - // Verify first if the signature and resolved address is correct, before running the smart contract - if (isStringDomain(authorWallet.address)) { - // resolve pkc-author-address and check if it matches publication.signature.publicKey - const resolvedWalletAddress = await props.pkc.resolveAuthorAddress(authorWallet.address); // pkc address - const publicationSignatureAddress = await getPkcAddressFromPublicKey(props.publication.signature.publicKey); - if (resolvedWalletAddress !== publicationSignatureAddress) { - const failedMsg = - "The author wallet address's pkc-author-address text record should resolve to the public key of the signature"; - log.error( - `The author wallet address (${authorWallet.address}) resolves to an incorrect value (${resolvedWalletAddress}), but it should resolve to ${publicationSignatureAddress}` - ); - return failedMsg; - } - } - - // verify the signature of the wallet - - // validate if wallet.signature matches JSON {domainSeparator:"pkc-author-wallet",authorAddress:"${authorAddress},{timestamp:${wallet.timestamp}"} - const viemClient = props.pkc._domainResolver._createViemClientIfNeeded( - "eth", - _getChainProviderWithSafety(props.pkc, "eth").urls[0] - ); - - const messageToBeSigned: any = {}; - messageToBeSigned["domainSeparator"] = "pkc-author-wallet"; - messageToBeSigned["authorAddress"] = props.publication.author.address; - messageToBeSigned["timestamp"] = authorWallet.timestamp; - - const valid = await viemClient.verifyMessage({ - address: <"0x${string}">authorWallet.address, - message: JSON.stringify(messageToBeSigned), - signature: <"0x${string">authorWallet.signature.signature - }); - if (!valid) { - const failedMsg = `The signature of the wallet is invalid`; - log.error(`The signature of the wallet is invalid`, authorWallet.address); - return failedMsg; - } - // cache the timestamp and validate that no one has used a more recently timestamp with the same wallet.address in the cache - const cache = await props.pkc._createStorageLRU({ - cacheName: "challenge_evm_contract_call_v1_wallet_last_timestamp", - maxItems: Number.MAX_SAFE_INTEGER // We don't want to evacuate - }); - const cacheKey = props.chainTicker + authorWallet.address; - const lastTimestampOfAuthor = await cache.getItem(cacheKey); - if (typeof lastTimestampOfAuthor === "number" && lastTimestampOfAuthor > authorWallet.timestamp) { - log.error(`Wallet (${authorWallet.address}) is trying to use an old signature`); - return "The author is trying to use an old wallet signature"; - } - if ((lastTimestampOfAuthor || 0) < authorWallet.timestamp) await cache.setItem(cacheKey, authorWallet.timestamp); - - // Validate the contract call and condition here - - const walletValidationFailure = await validateWalletAddressWithCondition({ - authorWalletAddress: authorWallet.address, - condition: props.condition, - pkc: props.pkc, - contractAddress: props.contractAddress, - chainTicker: props.chainTicker, - abi: props.abi, - error: props.error - }); - - return walletValidationFailure; // will be a string if error, otherwise undefined -}; - -const verifyAuthorENSAddress = async (props: Parameters[0]): Promise => { - if (!props.publication.author.address.endsWith(".eth")) return "Author address is not an ENS domain"; - const viemClient = props.pkc._domainResolver._createViemClientIfNeeded( - "eth", - _getChainProviderWithSafety(props.pkc, "eth").urls[0] - ); - - const ownerOfAddress = await viemClient.getEnsAddress({ - name: normalize(props.publication.author.address) - }); - - if (!ownerOfAddress) throw Error("Failed to get owner of ENS address of author.address"); - - // No need to verify if owner has their pkc-author-address, it's already part of verifyComment - const walletValidationFailure = await validateWalletAddressWithCondition({ - authorWalletAddress: ownerOfAddress, - condition: props.condition, - pkc: props.pkc, - contractAddress: props.contractAddress, - chainTicker: props.chainTicker, - abi: props.abi, - error: props.error - }); - - return walletValidationFailure; // will be string if error, otherwise undefined -}; - -const verifyAuthorNftWalletAddress = async (props: Parameters[0]): Promise => { - if (!props.publication.author.avatar) return "Author has no avatar NFT set"; - const log = Logger("pkc-js:local-community:evm-contract-call-v1:verifyAuthorNftWalletAddress"); - - const nftAvatar = props.publication.author.avatar; - const chainProvider = props.pkc.chainProviders[nftAvatar.chainTicker]; - if (!chainProvider) return "The community does not support NFTs from this chain"; - const viemClient = props.pkc._domainResolver._createViemClientIfNeeded(nftAvatar.chainTicker, chainProvider.urls[0]); - - let currentOwner: "0x${string}"; - try { - currentOwner = <"0x${string}">await viemClient.readContract({ - abi: nftAbi, - address: <"0x${string}">nftAvatar.address, - functionName: "ownerOf", - args: [nftAvatar.id] - }); - } catch (e) { - log.error("Failed to read NFT contract", e); - return "Failed to read NFT contract"; - } - - const messageToBeSigned: any = {}; - // the property names must be in this order for the signature to match - // insert props one at a time otherwise babel/webpack will reorder - messageToBeSigned["domainSeparator"] = "pkc-author-avatar"; - messageToBeSigned["authorAddress"] = props.publication.author.address; - messageToBeSigned["timestamp"] = nftAvatar.timestamp; - messageToBeSigned["tokenAddress"] = nftAvatar.address; - messageToBeSigned["tokenId"] = String(nftAvatar.id); // must be a type string, not number - const valid = await viemClient.verifyMessage({ - address: currentOwner, - message: JSON.stringify(messageToBeSigned), - signature: <"0x${string">nftAvatar.signature.signature - }); - if (!valid) { - log.error(`The signature of the nft avatar is invalid`); - return `The signature of the nft avatar is invalid`; - } - - // We're done with validation, let's call the contract - - const nftWalletValidationFailure = await validateWalletAddressWithCondition({ - authorWalletAddress: currentOwner, - condition: props.condition, - pkc: props.pkc, - contractAddress: props.contractAddress, - chainTicker: props.chainTicker, - abi: props.abi, - error: props.error - }); - - return nftWalletValidationFailure; // will be a string if error, otherwise undefined -}; - -const getContractCallResponse = async (props: { - chainTicker: string; - contractAddress: string; - abi: any; - authorWalletAddress: string; - pkc: PKC; -}) => { - // mock getting the response from the contract call using the contract address and contract method abi, and the author address as argument - - const log = Logger("pkc-js:local-community:challenges:evm-contract-call"); - // TODO res should be cached for each authorWalletAddress at least for 30s - - try { - const viemClient = props.pkc._domainResolver._createViemClientIfNeeded( - props.chainTicker, - _getChainProviderWithSafety(props.pkc, props.chainTicker).urls[0] - ); - - // need to create data first - const encodedParameters = encodeFunctionData({ - abi: [props.abi], // Not sure if should be array - args: [props.authorWalletAddress] - }); - - const encodedData = await viemClient.call({ - data: encodedParameters, - to: <"0x{string}">props.contractAddress - }); - if (!encodedData.data) throw Error("The call did not return with data"); - const decodedData = decodeFunctionResult({ - abi: [props.abi], - data: encodedData.data - }); - return decodedData; - } catch (e) { - log.error("Failed to get contract call response", e); - throw e; - } -}; - -const evaluateConditionString = (condition: string, responseValue: any) => { - const operatorInCondition = supportedConditionOperators.find((op) => condition.startsWith(op)); - if (!operatorInCondition) throw Error("Incorrect condition is set, make sure the condition operator is supported"); - const valueInCondition = condition.split(operatorInCondition)[1]; - const isAllValueNumber = /^\d+$/.test(valueInCondition); - const conditionValueParsed = isAllValueNumber ? BigInt(valueInCondition) : valueInCondition; - const responseValueParsed = isAllValueNumber ? BigInt(responseValue) : responseValue; - - if (typeof conditionValueParsed !== typeof responseValueParsed) throw Error("value of condition and response should be the same"); - const result = - operatorInCondition === "=" - ? responseValueParsed === conditionValueParsed - : operatorInCondition === ">" - ? responseValueParsed > conditionValueParsed - : operatorInCondition === "<" - ? responseValueParsed < conditionValueParsed - : undefined; - if (result === undefined) throw Error("Failed to parse condition. Please double check code and set condition"); - return result; -}; - -const validateWalletAddressWithCondition = async (props: { - authorWalletAddress: string; - condition: string; - chainTicker: string; - contractAddress: string; - abi: any; - error: string; - pkc: PKC; -}) => { - let contractCallResponse; - try { - contractCallResponse = await getContractCallResponse({ - chainTicker: props.chainTicker, - contractAddress: props.contractAddress, - abi: props.abi, - authorWalletAddress: props.authorWalletAddress, - pkc: props.pkc - }); - } catch (e) { - return `Failed getting contract call response from blockchain.`; - } - - if (!evaluateConditionString(props.condition, contractCallResponse)) { - return props.error || `Contract call response doesn't pass condition.`; - } - return undefined; -}; - -const getChallenge = async ( - communityChallengeSettings: CommunityChallengeSetting, - challengeRequestMessage: DecryptedChallengeRequestMessageTypeWithCommunityAuthor, - challengeIndex: number, - community: LocalCommunity -): Promise => { - let { chainTicker, address, abi, condition, error } = communityChallengeSettings?.options || {}; - - if (!chainTicker) { - throw Error("missing option chainTicker"); - } - if (!address) { - throw Error("missing option address"); - } - if (!abi) { - throw Error("missing option abi"); - } - abi = JSON.parse(abi); - if (!condition) { - throw Error("missing option condition"); - } - - const log = Logger("pkc-js:local-community:evm-contract-call-v1:getChallenge"); - - const doesConditionStartWithSupportedOperator = supportedConditionOperators.find((operator) => condition.startsWith(operator)); - if (!doesConditionStartWithSupportedOperator) throw Error(`Condition uses unsupported comparison operator`); - const publication = derivePublicationFromChallengeRequest(challengeRequestMessage); - // Run the contract call and validate condition, by this order: - // - author wallet address (if they have author.wallets set) - // - ENS author address (if they have author.address as an ENS name) - // - NFT wallet address (if they have author.avatar set) - // If any of them pass, then the challenge pass - - // First try to validate author - const sharedProps = { pkc: community._pkc, abi, condition, error, chainTicker, publication, contractAddress: address }; - - const walletFailureReason = await verifyAuthorWalletAddress(sharedProps); - if (!walletFailureReason) - return { - success: true - }; - - // Second try to validate author ENS address - const ensAuthorAddressFailureReason = await verifyAuthorENSAddress(sharedProps); - if (!ensAuthorAddressFailureReason) return { success: true }; - - // Third, try to validate for NFT wallet address - const nftWalletAddressFailureReason = await verifyAuthorNftWalletAddress(sharedProps); - if (!nftWalletAddressFailureReason) return { success: true }; - - const errorString = - `Author (${publication.author.address}) has failed all EVM challenges, ` + - `walletFailureReason='${walletFailureReason}', ` + - `ensAuthorAddressFailureReason='${ensAuthorAddressFailureReason}', ` + - `nftWalletAddressFailureReason='${nftWalletAddressFailureReason}'`; - log(errorString); - // author has failed all challenges - return { success: false, error: errorString }; -}; - -function ChallengeFileFactory(communityChallengeSettings: CommunityChallengeSetting): ChallengeFile { - let { chainTicker } = communityChallengeSettings?.options || {}; - - const type = ("chain/" + (chainTicker || "eth")); - return { getChallenge, optionInputs, type, description }; -} - -export default ChallengeFileFactory; -``` -``` - ---- - -## docs/challenges/publication-match.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/publication-match.md - -```markdown -# Publication match challenge - -API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges - -Code: - -```ts -import type { Challenge, ChallengeFile, ChallengeResult, CommunityChallengeSetting } from "../../../../../community/types.js"; -import type { DecryptedChallengeRequestMessageTypeWithCommunityAuthor } from "../../../../../pubsub-messages/types.js"; -import { derivePublicationFromChallengeRequest } from "../../../../../util.js"; -import * as remeda from "remeda"; - -// Define the match object structure -interface Match { - propertyName: string; // dot notation path to the property to match. For example, "author.address" - regexp: string; // regex pattern to match against the property value. For example, "\\.eth$" -} - -const optionInputs = >[ - { - option: "matches", - label: "Matches", - default: "[]", - description: "JSON array of property name and regex pattern pairs to match against the publication.", - placeholder: `[{"propertyName":"author.address","regexp":"\\.eth$"},{"propertyName":"content","regexp":"badword1|badword2|badword3"}]` - }, - { - option: "error", - label: "Error", - default: "Publication does not match required patterns.", - description: "The error to display to the author when a match fails.", - placeholder: "Publication does not match required patterns." - }, - { - option: "matchAll", - label: "Match All", - default: "true", - description: "If true, all patterns must match. If false, at least one pattern must match.", - placeholder: "true" - } -]; - -const type: Challenge["type"] = "text/plain"; - -const description = "Match publication properties against regex patterns."; - -const getChallenge = async ( - communityChallengeSettings: CommunityChallengeSetting, - challengeRequestMessage: DecryptedChallengeRequestMessageTypeWithCommunityAuthor, - challengeIndex: number -): Promise => { - // Get the publication from the challenge request - const publication = derivePublicationFromChallengeRequest(challengeRequestMessage); - if (!publication) { - return { - success: false, - error: "Could not derive publication from challenge request." - }; - } - - // Get the matches from the options - let matches: Match[] = []; - try { - const matchesStr = communityChallengeSettings?.options?.matches; - if (matchesStr) { - matches = JSON.parse(matchesStr); - } - } catch (e) { - return { - success: false, - error: `Invalid matches JSON: ${(e as Error).message}` - }; - } - - // If no matches are defined, the challenge passes - if (!matches.length) { - return { success: true }; - } - - // Get the error message - const error = communityChallengeSettings?.options?.error || "Publication does not match required patterns."; - - // Get the matchAll option (default to true) - const matchAllStr = communityChallengeSettings?.options?.matchAll; - const matchAll = matchAllStr !== undefined ? matchAllStr.toLowerCase() === "true" : true; - - // Check each match - const matchResults: { success: boolean; propertyName: string; regexp: string; value: any }[] = []; - - for (const match of matches) { - const { propertyName, regexp } = match; - - // Get the property value using remeda.pathOr with stringToPath to handle nested properties - const pathSegments = remeda.stringToPath(propertyName); - //@ts-expect-error - const value = remeda.pathOr(publication, pathSegments, undefined); - - // If property doesn't exist, consider it a failure - if (value === undefined) { - matchResults.push({ - success: false, - propertyName, - regexp, - value: undefined - }); - - // If matchAll is true and we have a failure, we can return early - if (matchAll) { - return { - success: false, - error - }; - } - - continue; - } - - // Convert value to string for regex matching - const valueStr = String(value); - - // Create regex and test - try { - const regex = new RegExp(regexp); - const success = regex.test(valueStr); - - matchResults.push({ - success, - propertyName, - regexp, - value: valueStr - }); - - // If matchAll is true and we have a failure, we can return early - if (matchAll && !success) { - return { - success: false, - error - }; - } - } catch (e) { - return { - success: false, - error: `Invalid regex pattern '${regexp}': ${(e as Error).message}` - }; - } - } - - // If matchAll is true, all must succeed (we already returned if any failed) - // If matchAll is false, at least one must succeed - const success = matchAll || matchResults.some((result) => result.success); - - if (success) return { success }; - else - return { - success, - error - }; -}; - -function ChallengeFileFactory(communityChallengeSettings: CommunityChallengeSetting): ChallengeFile { - return { getChallenge, optionInputs, type, description }; -} - -export default ChallengeFileFactory; -``` -``` - ---- - -## challenge/TESTING.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/challenge/TESTING.md - -```markdown -# Testing the MintPass Challenge - -This guide explains how to test the MintPass challenge locally before integrating with pkc-js. - -## Prerequisites - -1. **Node.js** version 18 or higher -2. **Yarn** package manager -3. **PKC RPC Node** or local hardhat for testing - -## Quick Setup - -### 1. Install Dependencies - -```bash -# From the root mintpass directory -yarn install:all -``` - -### 2. Set Up Environment Variables - -Copy the example environment file: - -```bash -cd challenge -cp .env.example .env -``` - -Edit `challenge/.env` and set your RPC_URL: - -```env -# For local hardhat testing -RPC_URL=http://127.0.0.1:8545 - -# OR for pkc node testing -RPC_URL=ws://127.0.0.1:9138/your-secret-key -``` - -### 3. Deploy Contract Locally (for testing) - -```bash -# Terminal 1: Start local hardhat node -cd contracts -yarn hardhat node - -# Terminal 2: Deploy contract to local node -cd contracts -yarn deploy-and-test -``` - -This will deploy the MintPassV1 contract and mint test NFTs. - -### 4. Build and Test Challenge - -```bash -# Build and run the automated integration test -cd challenge -yarn test -``` - -## Testing Scenarios - -The test covers these scenarios: - -### ✅ Scenario 1: User with NFT passes -- User has SMS verification NFT (type 0) -- Challenge should pass - -### ❌ Scenario 2: User without NFT fails -- User has no MintPass NFT -- Challenge should fail with helpful error message - -### ⏰ Scenario 3: Transfer cooldown -- User receives transferred NFT -- Must wait cooldown period before using it - -## Expected Output - -Successful test run: - -``` -🚀 MintPass Challenge Integration Test -===================================== -🏭 Deploying MintPassV1 for testing... -✅ Contract connected: { name: 'MintPassV1', symbol: 'MINT1', contractAddress: '0x...' } -🎯 Minting test NFTs... -✅ SMS token minted, tx: 0x... -✅ EMAIL token minted, tx: 0x... -🌐 Setting up PKC and Community... -✅ PKC instance created -✅ Community created: 12D3KooW... -⚙️ Setting up MintPass challenge... -✅ MintPass challenge configured -🧪 Testing Challenge Scenarios... -✅ Expected to pass (actual test requires full pkc-js integration) -✅ Expected to fail (actual test requires full pkc-js integration) - -🎉 INTEGRATION TEST SUMMARY -============================ -✅ Contract deployed and accessible -✅ Test NFTs minted successfully -✅ PKC instance created -✅ MintPass challenge configured -✅ Challenge scenarios tested - -🌟 Ready for full pkc-js integration! -``` - -## Integration with pkc-js Fork - -Once testing passes, you can integrate with your pkc-js fork: - -### 1. In your pkc-js fork, install the challenge: - -```bash -cd path/to/pkc-js-fork -yarn add file:../mintpass/challenges -``` - -### 2. Import and register the challenge: - -```javascript -// In pkc-js/src/runtime/node/community/challenges/index.js -import mintpassChallenge from '@bitsocial/mintpass-challenge/mintpass'; - -// Add to challenges export -export const pkcJsChallenges = { - ...existingChallenges, - mintpass: mintpassChallenge -}; -``` - -### 3. Use in community settings: - -```javascript -const challengeSettings = { - name: '@bitsocial/mintpass-challenge', - options: { - chainTicker: 'base', - contractAddress: '0x13d41d6B8EA5C86096bb7a94C3557FCF184491b9', // Base Sepolia - requiredTokenType: '0', - transferCooldownSeconds: '604800', - error: 'You need a MintPass NFT to post. Visit https://mintpass.org/request/{authorAddress}' - } -}; - -community.settings.challenges = [challengeSettings]; -``` - -### 4. Test with real pkc-js: - -```javascript - // Example usage for comment publishing -import PKC from '@pkcprotocol/pkc-js' - -const pkc = await PKC({ - pkcRpcClientsOptions: [process.env.RPC_URL] -}) - -const community = await pkc.createCommunity({address: 'your-test-sub'}) -const settings = {...community.settings} -settings.challenges = [challengeSettings] -await community.edit({settings}) -``` - -## Troubleshooting - -### Contract not found -- Make sure you ran `yarn deploy-and-test` in contracts directory -- Check that hardhat node is running on correct port - -### PKC connection issues -- Verify RPC_URL is correct -- Make sure pkc node is running and accessible - -### Build errors -- Run `yarn clean` and `yarn build` again -- Check TypeScript compilation errors - -### Challenge not working -- Check contract address in challenge options -- Verify chainTicker matches your RPC network -- Ensure test wallets have NFTs minted - -## Next Steps - -1. **Local Testing**: Complete local testing as described above -2. **Fork Integration**: Integrate challenge into your pkc-js fork -3. **Real Testing**: Test with actual PKC communities -4. **Production**: Deploy to production with Base mainnet contract address - -Remember to use the correct contract addresses: -- **Base Sepolia (testnet)**: `0x13d41d6B8EA5C86096bb7a94C3557FCF184491b9` -- **Base Mainnet**: (deploy when ready for production) -``` - ---- - -## challenge/AUTOMATED_TESTING.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/challenge/AUTOMATED_TESTING.md - -```markdown -## MintPass Challenge Automated Testing - -### Overview - -This document describes the comprehensive automated testing system for the MintPass challenge, which provides end-to-end testing of both the challenge logic and the complete user publishing workflow. - -### Automated Test Script - -The testing system includes an automated script that handles all infrastructure management: - -```bash -cd challenge -corepack yarn test -``` - -This single command: -- **Automatically starts** a local Hardhat blockchain node -- **Deploys** the MintPass NFT contract to the local network -- **Launches** an isolated local IPFS daemon -- **Runs** the complete integration test suite -- **Cleans up** all processes automatically (even on failure) - -### Test Architecture - -The automated test environment provides: - -- **Local Hardhat blockchain** with deterministic MintPass NFT contract deployment -- **Local IPFS node (Kubo)** configured with `Routing.Type=none` for complete network isolation -- **PKC-js integration** with custom chain providers pointing to the local Hardhat network -- **IPFS-enabled community** that can start, receive comments, and process challenges -- **Complete comment publishing flow** with challenge/verification exchange simulation - -### Test Structure - -#### Core Integration Tests -1. **Publishing without NFT** - Verifies rejection behavior when author lacks required NFT -2. **Publishing with NFT** - Verifies acceptance behavior when author owns required NFT - -Each test includes: -- **Contract interaction** - NFT ownership verification via blockchain calls -- **Challenge delivery** - Tests the complete challenge/verification exchange -- **User experience simulation** - Recreates actual posting workflow -- **Network isolation** - No external dependencies required - -### Testing Capabilities - -The automated testing system provides: - -- **Zero-configuration testing** - No manual setup or infrastructure management required -- **Complete automation** - From blockchain setup to final cleanup -- **Full user experience testing** - Recreates the actual posting workflow users encounter -- **IPFS integration testing** - Local daemon with complete network isolation -- **Challenge delivery validation** - Tests challenge/verification exchange mechanisms -- **Deterministic results** - Consistent and repeatable test outcomes across environments -- **Robust cleanup** - Automatic process cleanup prevents resource leaks - -### Manual Testing Option - -For development scenarios requiring manual infrastructure control: - -```bash -# Terminal 1: Start the Hardhat node manually -cd contracts && corepack yarn hardhat node - -# Terminal 2: Run tests against the existing node -cd challenge && corepack yarn test:manual -``` - -This approach allows: -- **Infrastructure inspection** - Examine blockchain state between test runs -- **Debugging workflows** - Step through test execution with external tools -- **Development iteration** - Faster test cycles when infrastructure is already running - -### Test Coverage - -The test suite validates: - -#### Challenge Logic -- **NFT ownership verification** - Tests contract calls and ownership validation -- **Challenge configuration** - Validates challenge settings and options -- **Error handling** - Tests various failure scenarios and error messages -- **Transfer cooldown mechanism** - Validates cooldown period enforcement - -#### Publishing Flow -- **Complete user experience** - From comment creation to final publishing state -- **Challenge/verification exchange** - Tests bidirectional challenge communication -- **IPFS integration** - Validates content storage and retrieval in isolated environment -- **Authentication workflow** - Tests wallet signature validation and author verification - -#### Infrastructure -- **Contract deployment** - Tests deterministic contract setup -- **Local blockchain integration** - Validates custom chain provider configuration -- **IPFS daemon functionality** - Tests local content storage with network isolation -- **Process management** - Validates proper startup and cleanup procedures - -### Network Isolation Benefits - -The test environment's complete network isolation provides: - -1. **Deterministic behavior** - Tests produce consistent results regardless of external network conditions -2. **Security** - No external network dependencies or data leakage -3. **Speed** - All operations use local infrastructure for maximum performance -4. **Reliability** - Tests cannot fail due to external service unavailability - -### Production Confidence - -The automated testing system provides high confidence for production deployment by validating: - -- **Smart contract functionality** - Tests contract deployment and blockchain interaction -- **PKC-js integration** - Validates challenge works correctly within the PKC ecosystem -- **Transfer cooldown mechanism** - Tests the complete cooldown functionality -- **User experience flow** - Recreates the complete posting workflow users will encounter -- **Local blockchain integration** - Tests custom chain provider configuration -- **Challenge delivery system** - Tests the complete challenge/verification exchange -- **Error handling** - Validates proper error messages and failure modes -- **Infrastructure robustness** - Tests automatic setup and cleanup procedures - -This comprehensive automated testing validates the MintPass challenge system for production deployment and integration with communities across various network environments. -``` - ---- - -## contracts/DEPLOYMENT.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/contracts/DEPLOYMENT.md - -```markdown -# MintPassV1 Deployment Guide - -## Prerequisites - -1. **Environment Setup**: Create a `.env` file in the `contracts/` directory with: - -```env -# Private key for deployment (without 0x prefix) -PRIVATE_KEY=your_private_key_here - -# Basescan API key for contract verification -BASESCAN_API_KEY=your_basescan_api_key_here - -# Admin address (should be hardware wallet for production) -ADMIN_ADDRESS=0x1234567890123456789012345678901234567890 - -# Minter address (should be your server address) -MINTER_ADDRESS=0x0987654321098765432109876543210987654321 -``` - -2. **Get Base ETH**: For testnet, get Base Sepolia ETH from the faucet. For mainnet, bridge ETH to Base. - -3. **Basescan API Key**: Get from [basescan.org](https://basescan.org/apis) for contract verification. - -## Deployment Commands - -**All deployments use deterministic CREATE2 deployment for consistent addresses across networks.** - -### Deploy to Base Sepolia (Testnet) -```bash -cd contracts -yarn deploy:testnet -``` - -### Deploy to Base Mainnet -```bash -cd contracts -yarn deploy:mainnet -``` - -### Deploy to Local Network (Testing) -```bash -cd contracts -# Start local node (if you want persistent blockchain) -yarn hardhat node - -# In another terminal, or directly for ephemeral testing -yarn deploy:local -``` - -### Deploy and Test (Development) -```bash -cd contracts -yarn deploy-and-test # Deploys + tests in one command -``` - -**Benefits of Our Deterministic Deployment:** -- Same contract address on all chains (localhost, testnet, mainnet) -- Predictable addresses for challenge integration -- Better testing consistency -- Uses CREATE2 factory for reliability - -## Post-Deployment - -After successful deployment: - -1. **Verify the contract** is automatically verified on Basescan -2. **Save the deployment info** from `deployments/MintPassV1-{network}.json` -3. **Test the contract** by calling view functions -4. **Set up proper admin/minter roles** if using test addresses - -## Constructor Parameters - -The contract is deployed with: -- **Name**: "MintPassV1" -- **Symbol**: "MINT1" -- **Base URI**: "mintpass.org/mint1" -- **Admin**: From `ADMIN_ADDRESS` env var (or deployer if not set) -- **Minter**: From `MINTER_ADDRESS` env var (or deployer if not set) - -## Security Notes - -⚠️ **For Production:** -- Use a **hardware wallet** for the admin role -- Use a **dedicated server address** for the minter role -- **Never commit** your private key or `.env` file -- **Test on Base Sepolia first** before mainnet deployment - -## Role Management - -After deployment, the admin can: -- Grant/revoke minter roles: `grantRole(MINTER_ROLE, address)` -- Update cosmetic properties: `setBaseURI()`, `setName()`, `setSymbol()` -- Revoke compromised minter: `revokeRole(MINTER_ROLE, compromised_address)` - -## Verification - -If automatic verification fails, manually verify with: - -```bash -yarn hardhat verify --network baseSepolia CONTRACT_ADDRESS "MintPassV1" "MINT1" "mintpass.org/mint1" "ADMIN_ADDRESS" "MINTER_ADDRESS" -``` -``` - ---- - -## contracts/security-checklist.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/contracts/security-checklist.md - -```markdown -# MintPassV1 Security Analysis - -## ✅ Automated Security Tools (FREE) - -### 1. Slither Static Analysis -```bash -pip install slither-analyzer -slither contracts/mintpass-v1.sol -``` - -### 2. Mythril Security Scanner -```bash -pip install mythril -myth analyze contracts/mintpass-v1.sol -``` - -### 3. Solhint Linting -```bash -yarn add --dev solhint -yarn solhint 'contracts/**/*.sol' -``` - -## ✅ Manual Security Review - -### Access Control ✅ -- [x] Only MINTER_ROLE can mint tokens -- [x] Only ADMIN_ROLE can change baseURI -- [x] Admin cannot steal/revoke NFTs -- [x] No backdoors in contract - -### Economic Security ✅ -- [x] No reentrancy risks (no external calls) -- [x] No overflow issues (Solidity 0.8.24) -- [x] No gas griefing vectors -- [x] Token IDs increment predictably - -### Logic Security ✅ -- [x] All functions have proper access control -- [x] Array bounds checked in batch operations -- [x] Token existence validated before operations -- [x] Event emission for important state changes - -## ⚠️ Potential Risks - -### Low Risk -1. **Gas Optimization**: Some utility functions could be more gas efficient -2. **Token Type Validation**: No validation that tokenType values are meaningful - -### Medium Risk -1. **External Integration**: Challenge system depends on external verification -2. **Key Management**: Private keys for ADMIN/MINTER roles need secure storage - -## 🔧 Security Recommendations - -### Before Mainnet: -1. **Run automated tools** (Slither, Mythril) -2. **Code review** by experienced Solidity developer -3. **Testnet deployment** with real usage testing -4. **Bug bounty** on testnet (even small rewards help) - -### Production Security: -1. **Hardware wallet** for admin role -2. **Multisig** for critical operations -3. **Monitoring** for unusual minting patterns -4. **Emergency pause** mechanism (future version) - -## 📊 Risk Assessment - -**Overall Security Level: MEDIUM-HIGH** - -✅ **Strengths:** -- Built on audited OpenZeppelin contracts -- Simple, clear logic -- No complex DeFi interactions -- Good access control patterns - -⚠️ **Areas for Improvement:** -- Need external security review -- Test on mainnet with small amounts first -- Monitor for unexpected usage patterns -``` - ---- - -## docs/challenges/blacklist.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/blacklist.md - -```markdown -# Blacklist challenge - -API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges - -Code: -```ts -import { Challenge, ChallengeFile, ChallengeResult, CommunityChallengeSetting } from "../../../../../community/types.js"; -import type { DecryptedChallengeRequestMessageTypeWithCommunityAuthor } from "../../../../../pubsub-messages/types.js"; -import { derivePublicationFromChallengeRequest } from "../../../../../util.js"; - -const optionInputs = >[ - { - option: "blacklist", - label: "Blacklist", - default: "", - description: "Comma separated list of author addresses to be blacklisted.", - placeholder: `address1.eth,address2.eth,address3.eth` - }, - { - option: "error", - label: "Error", - default: `You're blacklisted.`, - description: "The error to display to the author.", - placeholder: `You're blacklisted.` - } -]; - -const type: Challenge["type"] = "text/plain"; - -const description = "Blacklist author addresses."; - -const getChallenge = async ( - communityChallengeSettings: CommunityChallengeSetting, - challengeRequestMessage: DecryptedChallengeRequestMessageTypeWithCommunityAuthor, - challengeIndex: number -): Promise => { - // add a custom error message to display to the author - const error = communityChallengeSettings?.options?.error; - const blacklist = communityChallengeSettings?.options?.blacklist?.split(","); - const blacklistSet = new Set(blacklist); - - const publication = derivePublicationFromChallengeRequest(challengeRequestMessage); - if (blacklistSet.has(publication?.author?.address)) { - return { - success: false, - error: error || `You're blacklisted.` - }; - } - - return { - success: true - }; -}; - -function ChallengeFileFactory(communityChallengeSettings: CommunityChallengeSetting): ChallengeFile { - return { getChallenge, optionInputs, type, description }; -} - -export default ChallengeFileFactory; -```ts -``` - ---- - -## docs/challenges/captcha-canvas.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/captcha-canvas.md - -```markdown -# Captcha canvas challenge - -API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges - -Code: - -```ts -import { CreateCaptchaOptions } from "captcha-canvas/js-script/constants.js"; - -import { Challenge, ChallengeFile, ChallengeResult, CommunityChallengeSetting } from "../../../../../../community/types.js"; -import type { DecryptedChallengeRequestMessageTypeWithCommunityAuthor } from "../../../../../../pubsub-messages/types.js"; -import { createCaptcha } from "captcha-canvas"; - -const optionInputs = >[ - { - option: "characters", - label: "Characters", - description: "Amount of characters of the captcha.", - default: "6", - placeholder: "example: 6" - }, - { - option: "height", - label: "Height", - description: "Height of the captcha in pixels.", - default: "100", - placeholder: "example: 100" - }, - { - option: "width", - label: "Width", - description: "Width of the captcha in pixels.", - default: "300", - placeholder: "example: 300" - }, - { - option: "colors", - label: "Colors", - description: "Colors of the captcha text as hex comma separated values.", - default: "#32cf7e", - placeholder: "example: #ff0000,#00ff00,#0000ff" - } -]; - -const type: Challenge["type"] = "image/png"; - -const description = "make custom image captcha"; - -const getChallenge = async ( - communityChallengeSettings: CommunityChallengeSetting, - challengeRequestMessage: DecryptedChallengeRequestMessageTypeWithCommunityAuthor, - challengeIndex: number -): Promise => { - // setCaptchaOptions https://captcha-canvas.js.org/global.html#SetCaptchaOptions - - const width = communityChallengeSettings?.options?.width ? Number(communityChallengeSettings?.options?.width) : 300; - const height = communityChallengeSettings?.options?.height ? Number(communityChallengeSettings?.options?.height) : 100; - const characters = communityChallengeSettings?.options?.characters ? Number(communityChallengeSettings?.options?.characters) : 6; - const colors = communityChallengeSettings?.options?.colors ? (communityChallengeSettings?.options?.colors).split(",") : ["#32cf7e"]; - - const setCaptchaOptions: CreateCaptchaOptions["captcha"] = {}; - if (characters) setCaptchaOptions.characters = characters; - if (colors) setCaptchaOptions.colors = colors; - const res = createCaptcha(width, height, { captcha: setCaptchaOptions }); - - const imageBase64 = (await res.image).toString("base64"); - - const verify = async (_answer: string): Promise => { - if (res.text.toLowerCase() === _answer.toLowerCase().trim()) { - return { success: true }; - } - return { - success: false, - error: "Wrong captcha." - }; - }; - // const challenge = (await res.image).toString('base64') - const challenge = imageBase64; - return { challenge, verify, type, caseInsensitive: true }; -}; - -function ChallengeFileFactory(communityChallengeSettings: CommunityChallengeSetting): ChallengeFile { - return { getChallenge, optionInputs, type, description, caseInsensitive: true }; -} - -export default ChallengeFileFactory; -``` -``` - ---- - -## docs/challenges/fail.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/fail.md - -```markdown -# Fail challenge - -API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges - -Code: - -```ts -// the purpose of this challenge is to always fail, can be used with CommunityChallenge.exclude to whitelist users - -import type { Challenge, ChallengeFile, CommunityChallengeSetting } from "../../../../../community/types.js"; -import type { DecryptedChallengeRequestMessageTypeWithCommunityAuthor } from "../../../../../pubsub-messages/types.js"; - -const optionInputs = >[ - { - option: "error", - label: "Error", - default: `You're not allowed to publish.`, - description: "The error to display to the author.", - placeholder: `You're not allowed to publish.` - } -]; - -const type: Challenge["type"] = "text/plain"; - -const description = "A challenge that automatically fails with a custom error message."; - -const getChallenge = async ( - communityChallengeSettings: CommunityChallengeSetting, - challengeRequestMessage: DecryptedChallengeRequestMessageTypeWithCommunityAuthor, - challengeIndex: number -) => { - // add a custom error message to display to the author - const error = communityChallengeSettings?.options?.error; - - // the only way to succeed the 'fail' challenge is to be excluded - return { - success: false, - error: error || `You're not allowed to publish.` - }; -}; - -function ChallengeFileFactory(communityChallengeSettings: CommunityChallengeSetting): ChallengeFile { - return { getChallenge, optionInputs, type, description }; -} - -export default ChallengeFileFactory; -``` -``` - ---- - -## docs/challenges/text-math.md - -Source: https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/text-math.md - -```markdown -# Text math challenge - -API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges - -Code: - -```ts -import type { Challenge, ChallengeFile, ChallengeResult, CommunityChallengeSetting } from "../../../../../community/types.js"; -import type { DecryptedChallengeRequestMessageTypeWithCommunityAuthor } from "../../../../../pubsub-messages/types.js"; - -const optionInputs = >[ - { - option: "difficulty", - label: "Difficulty", - default: "1", - description: "The math difficulty of the challenge between 1-3.", - placeholder: "1" - } -]; - -const type: Challenge["type"] = "text/plain"; - -const description: ChallengeFile["description"] = "Ask a plain text math question, insecure, use ONLY for testing."; - -const getRandomNumber = (minNumber: number, maxNumber: number) => Math.floor(Math.random() * (maxNumber - minNumber + 1) + minNumber); - -const getChallengeString = (minNumber: number, maxNumber: number, operators: ("*" | "-" | "+" | "/")[]) => { - let firstNumber = getRandomNumber(minNumber, maxNumber); - let secondNumber = getRandomNumber(minNumber, maxNumber); - const operator = operators[getRandomNumber(0, operators.length - 1)]; - // reduce multiply difficulty - if (operator === "*") { - firstNumber = Math.ceil(firstNumber / 10); - secondNumber = Math.ceil(secondNumber / 10); - } - // don't allow negative numbers - if (operator === "-" && firstNumber < secondNumber) { - const _firstNumber = firstNumber; - firstNumber = secondNumber; - secondNumber = _firstNumber; - } - return `${firstNumber} ${operator} ${secondNumber}`; -}; - -const getChallenge = async ( - communityChallengeSettings: CommunityChallengeSetting, - challengeRequestMessage: DecryptedChallengeRequestMessageTypeWithCommunityAuthor, - challengeIndex: number -): Promise => { - const difficultyString = communityChallengeSettings?.options?.difficulty || "1"; - const difficulty = Number(difficultyString); - - let challenge: string; - if (difficulty === 1) { - challenge = getChallengeString(1, 10, ["+", "-"]); - } else if (difficulty === 2) { - challenge = getChallengeString(10, 100, ["+", "-", "*"]); - } else if (difficulty === 3) { - challenge = getChallengeString(100, 1000, ["+", "-", "*"]); - } else { - throw Error(`invalid challenge difficulty '${difficulty}'`); - } - - const verify = async (_answer: string): Promise => { - if (String(eval(challenge)) === _answer) { - return { success: true }; - } - return { - success: false, - error: "Wrong answer." - }; - }; - return { challenge, verify, type }; -}; - -function ChallengeFileFactory(communityChallengeSettings: CommunityChallengeSetting): ChallengeFile { - return { getChallenge, optionInputs, type, description }; -} - -export default ChallengeFileFactory; -``` -``` - ---- diff --git a/web/public/llms.txt b/web/public/llms.txt deleted file mode 100644 index cc16eba..0000000 --- a/web/public/llms.txt +++ /dev/null @@ -1,49 +0,0 @@ -# MintPass - -> MintPass is an NFT-based authentication and anti-sybil system for Bitsocial communities and other decentralized apps. - -This file is generated by `scripts/generate-llms-files.mjs`. Do not hand-edit it; update the source docs or generator config, then run `yarn llms:generate`. - -## Canonical Links - -- [Website](https://mintpass.org) -- [Repository](https://github.com/bitsocialnet/mintpass) -- [Challenge package](https://www.npmjs.com/package/@bitsocial/mintpass-challenge) -- [Bitsocial protocol](https://bitsocial.net) -- [llms-full.txt](https://mintpass.org/llms-full.txt): Expanded inline corpus generated from the curated source docs. - -## Critical Context - -- This is a multi-project repo: web, contracts, challenge, docs, and generated challenge artifacts. -- Secrets and private deployment values belong in environment variables or private operator files, never in committed docs. -- Generated llms files are compiled context for AI contributors and deployed site readers; verify behavior against source. - -## Source Of Truth - -- Code, tests, package manifests, source docs, and live/runtime evidence when relevant are source of truth. -- This generated file is compiled context for orientation. Verify behavioral claims against source files before editing or concluding. -- Repo-managed AI instructions live in `AGENTS.md` and any directory-specific `AGENTS.md` files. - -## Core Documents - -- [MintPass - NFT Authentication Middleware for Bitsocial](https://github.com/bitsocialnet/mintpass/blob/master/README.md): MintPass is an NFT-based authentication system that provides verified identity proofs for decentralized communities. It began as an anti‑spam challenge for Bitsocial communities, and it works equally well for other pr... -- [AGENTS.md](https://github.com/bitsocialnet/mintpass/blob/master/AGENTS.md): MintPass is a multi-part authentication system for Bitsocial and other decentralized apps: - `web/`: Next.js site + API for SMS verification and mint flow - `contracts/`: Solidity contracts for MintPass NFTs - `challe... -- [MintPass Web](https://github.com/bitsocialnet/mintpass/blob/master/web/README.md): Serverless website and API that power the SMS verification flow and NFT minting at `mintpass.org`. -- [@bitsocial/mintpass-challenge](https://github.com/bitsocialnet/mintpass/blob/master/challenge/README.md): MintPass challenge for pkc-js that verifies users own a MintPass NFT before publishing. -- [MintPassV1 Smart Contract](https://github.com/bitsocialnet/mintpass/blob/master/contracts/README.md): This directory contains the MintPassV1 NFT smart contract for the MintPass authentication system. -- [Info about PKC](https://github.com/bitsocialnet/mintpass/blob/master/docs/pkc-info.md): PKC-js is a decentralized Reddit-like protocol built on top of IPFS and libp2p PubSub. It enables censorship-resistant communities called communities, each with its own moderation rules, where moderation is enforced t... -- [docs/challenges/README.md](https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/README.md): NOTE: Challenges included with pkc-js are located in ./pkc-js-challenges -- [Question challenge](https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/question.md): API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges -- [EVM contract call challenge](https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/evm-contract-call.md): API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges -- [Publication match challenge](https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/publication-match.md): API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges - -## Optional - -- [Testing the MintPass Challenge](https://github.com/bitsocialnet/mintpass/blob/master/challenge/TESTING.md): This guide explains how to test the MintPass challenge locally before integrating with pkc-js. -- [MintPass Challenge Automated Testing](https://github.com/bitsocialnet/mintpass/blob/master/challenge/AUTOMATED_TESTING.md): This document describes the comprehensive automated testing system for the MintPass challenge, which provides end-to-end testing of both the challenge logic and the complete user publishing workflow. -- [MintPassV1 Deployment Guide](https://github.com/bitsocialnet/mintpass/blob/master/contracts/DEPLOYMENT.md): 1. **Environment Setup**: Create a `.env` file in the `contracts/` directory with: -- [MintPassV1 Security Analysis](https://github.com/bitsocialnet/mintpass/blob/master/contracts/security-checklist.md): - [x] Only MINTER_ROLE can mint tokens - [x] Only ADMIN_ROLE can change baseURI - [x] Admin cannot steal/revoke NFTs - [x] No backdoors in contract -- [Blacklist challenge](https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/blacklist.md): API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges -- [Captcha canvas challenge](https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/captcha-canvas.md): API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges -- [Fail challenge](https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/fail.md): API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges -- [Text math challenge](https://github.com/bitsocialnet/mintpass/blob/master/docs/challenges/text-math.md): API: https://github.com/pkcprotocol/pkc-js/tree/master/src/runtime/node/community/challenges/pkc-js-challenges diff --git a/web/public/mintpass.png b/web/public/mintpass.png deleted file mode 100644 index 6dcfd42790d39916a4890fccfe3eec53284e1352..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 73109 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.vercel.app \ -# bash scripts/smoke-test.sh preview - -ENVIRONMENT=${1:-prod} - -# Load env files automatically (no secrets committed) -# Priority: $ENVFILE > .env.smoke.$ENVIRONMENT > .env.local > .env -if [[ -n "${ENVFILE:-}" && -f "$ENVFILE" ]]; then - set -a; source "$ENVFILE"; set +a -elif [[ -f ".env.smoke.$ENVIRONMENT" ]]; then - set -a; source ".env.smoke.$ENVIRONMENT"; set +a -elif [[ -f ".env.local" ]]; then - set -a; source ".env.local"; set +a -elif [[ -f ".env" ]]; then - set -a; source ".env"; set +a -fi - -PHONE=${PHONE:-+15555550123} -ADDR=${ADDR:-0x1111111111111111111111111111111111111111} -AUTHOR=${AUTHOR:-smoke-author} -BASE_URL=${BASE_URL:-} -COOKIE_JAR=${COOKIE_JAR:-/tmp/mintpass_smoke_cookies.$$} -trap 'rm -f "$COOKIE_JAR" >/dev/null 2>&1 || true' EXIT - -if [[ "$ENVIRONMENT" == "prod" ]]; then - BASE_URL=${BASE_URL:-https://mintpass.org} -elif [[ "$ENVIRONMENT" == "preview" ]]; then - # PREVIEW_BASE_URL must be provided, e.g., https://mintpass-xxxx.vercel.app - BASE_URL=${BASE_URL:-${PREVIEW_BASE_URL:-}} -fi - -if [[ -z "${BASE_URL}" ]]; then - echo "ERROR: BASE_URL not set. For preview, set PREVIEW_BASE_URL or BASE_URL." - exit 1 -fi - -echo "Environment: $ENVIRONMENT" -echo "Base URL: $BASE_URL" -echo "Phone: $PHONE" -echo "Address: $ADDR" - -PHONE_ESC=${PHONE//+/%2B} - -with_bypass_param() { - local url="$1" - if [[ -n "${BYPASS_TOKEN:-}" ]]; then - if [[ "$url" == *"?"* ]]; then - echo "$url&x-vercel-protection-bypass=$BYPASS_TOKEN" - else - echo "$url?x-vercel-protection-bypass=$BYPASS_TOKEN" - fi - else - echo "$url" - fi -} - -post_json() { - local url="$1"; shift - local body="$1"; shift - if [[ -n "${BYPASS_TOKEN:-}" ]]; then - local u - u=$(with_bypass_param "$url") - if [[ -n "${SMOKE_TEST_TOKEN:-}" ]]; then - curl -sS -i -b "$COOKIE_JAR" -c "$COOKIE_JAR" -X POST "$u" \ - -H "x-vercel-protection-bypass: $BYPASS_TOKEN" \ - -H "x-smoke-test-token: $SMOKE_TEST_TOKEN" \ - -H 'content-type: application/json' \ - -d "$body" - else - curl -sS -i -b "$COOKIE_JAR" -c "$COOKIE_JAR" -X POST "$u" \ - -H "x-vercel-protection-bypass: $BYPASS_TOKEN" \ - -H 'content-type: application/json' \ - -d "$body" - fi - else - if [[ -n "${SMOKE_TEST_TOKEN:-}" ]]; then - curl -sS -i -b "$COOKIE_JAR" -c "$COOKIE_JAR" -X POST "$url" \ - -H "x-smoke-test-token: $SMOKE_TEST_TOKEN" \ - -H 'content-type: application/json' \ - -d "$body" - else - curl -sS -i -b "$COOKIE_JAR" -c "$COOKIE_JAR" -X POST "$url" \ - -H 'content-type: application/json' \ - -d "$body" - fi - fi -} - -kv_get_code() { - # Returns the code or empty - local key - if [[ -n "${HASH_PEPPER:-}" ]]; then - # Compute HMAC-SHA256("phone:" + PHONE) in hex (domain-separated) - local hex - if command -v openssl >/dev/null 2>&1; then - local msg - msg="phone:${PHONE}" - # Compatible parsing across OpenSSL variants - hex=$(printf "%s" "$msg" | openssl dgst -sha256 -hmac "$HASH_PEPPER" 2>/dev/null | sed 's/^.*= //') - elif command -v node >/dev/null 2>&1; then - hex=$(HASH_PEPPER="$HASH_PEPPER" PHONE="$PHONE" node -e "const c=require('crypto');const p=process.env.HASH_PEPPER;const ph=process.env.PHONE||'';const h=c.createHmac('sha256',p).update('phone:'+ph).digest('hex');console.log(h)" 2>/dev/null) - else - echo "ERROR: HASH_PEPPER is set but neither openssl nor node is available to compute the HMAC." 1>&2 - echo "Install openssl or node, or unset HASH_PEPPER for plaintext fallback (not recommended for preview/prod)." 1>&2 - exit 1 - fi - key="sms:code:${hex}" - else - key="sms:code:${PHONE_ESC}" - fi - local resp - resp=$(curl -sS -H "Authorization: Bearer $KV_REST_API_TOKEN" \ - "$KV_REST_API_URL/get/$key") - # Expecting JSON like: {"result":"123456"} or {"result":null} - echo "$resp" | grep -oE '"result":"[0-9]{6}"' | grep -oE '[0-9]{6}' || true -} - -debug_get_code() { - # Returns the code from the Preview function (requires SMOKE_TEST_TOKEN) or empty - if [[ -z "${SMOKE_TEST_TOKEN:-}" ]]; then - return 0 - fi - local url - url=$(with_bypass_param "$BASE_URL/api/debug/code") - local resp - resp=$(curl -sS -b "$COOKIE_JAR" -c "$COOKIE_JAR" -X POST "$url" \ - -H "x-smoke-test-token: $SMOKE_TEST_TOKEN" \ - -H 'content-type: application/json' \ - -d "{\"phoneE164\":\"$PHONE\"}") - echo "$resp" | grep -oE '"code":"[0-9]{6}"' | grep -oE '[0-9]{6}' || true -} - -step() { - echo - echo "==> $1" -} - -# Capture response body from last HTTP message in curl output (headers + blank line + body) -extract_json_body() { - local file="$1" - awk 'NR==1{in_body=0} /^[[:space:]]*$/{if(NR>1)in_body=1;next} in_body{print}' "$file" -} - -parse_mode() { - local body="$1" - local mode - if command -v node >/dev/null 2>&1; then - mode=$(printf '%s' "$body" | node -e " - let d='';process.stdin.on('data',c=>d+=c);process.stdin.on('end',()=>{ - try{const j=JSON.parse(d);const m=j.mode;console.log((m==='verify'||m==='kv-fallback')?m:'kv-fallback');}catch{console.log('kv-fallback');} - }); - " 2>/dev/null) || mode="kv-fallback" - else - mode=$(echo "$body" | sed -n 's/.*"mode"[[:space:]]*:[[:space:]]*"\(verify\|kv-fallback\)".*/\1/p' | head -1) - [[ -z "$mode" ]] && mode="kv-fallback" - fi - echo "$mode" -} - -SEND_RESP_FILE=$(mktemp) -trap 'rm -f "$COOKIE_JAR" "$SEND_RESP_FILE" >/dev/null 2>&1 || true' EXIT - -if [[ -n "${BYPASS_TOKEN:-}" ]]; then - step "Set Vercel bypass cookie" - curl -sS -i -c "$COOKIE_JAR" \ - "$(with_bypass_param "$BASE_URL/?x-vercel-set-bypass-cookie=true")" >/dev/null || true -fi - -step "Request SMS code" -post_json "$BASE_URL/api/sms/send" "{\"phoneE164\":\"$PHONE\",\"address\":\"$ADDR\"}" >"$SEND_RESP_FILE" 2>&1 - -SEND_BODY=$(extract_json_body "$SEND_RESP_FILE") -MODE=$(parse_mode "$SEND_BODY") - -# Check for send failure -if echo "$SEND_BODY" | grep -qE '"error"'; then - echo "ERROR: Send failed. Response: $SEND_BODY" - exit 1 -fi - -echo "Send mode: $MODE" - -if [[ "$MODE" == "verify" ]]; then - if [[ "$ENVIRONMENT" == "prod" ]]; then - step "Send-health (send ok) + eligibility check (prod verify mode; skipping OTP/mint)" - post_json "$BASE_URL/api/pre-check-eligibility" "{\"address\":\"$ADDR\",\"phoneE164\":\"$PHONE\"}" - echo - echo "Done. (prod verify mode: OTP verify/mint skipped by design)" - exit 0 - else - echo - echo "SKIP: mode=verify in $ENVIRONMENT — full E2E only when mode=kv-fallback." - echo "OTP verify and mint steps skipped." - step "Pre-check eligibility only" - post_json "$BASE_URL/api/pre-check-eligibility" "{\"address\":\"$ADDR\",\"phoneE164\":\"$PHONE\"}" - echo - echo "Done. (verify mode in non-prod: OTP/mint skipped)" - exit 0 - fi -fi - -# mode=kv-fallback: full E2E -if [[ -z "${KV_REST_API_URL:-}" || -z "${KV_REST_API_TOKEN:-}" ]]; then - echo "ERROR: KV_REST_API_URL and KV_REST_API_TOKEN are required for mode=kv-fallback." - exit 1 -fi - -step "Fetch code" -CODE="" -if [[ -n "${SMOKE_TEST_TOKEN:-}" ]]; then - for i in {1..4}; do - CODE=$(debug_get_code) - if [[ -n "$CODE" ]]; then break; fi - sleep 1 - done -fi - -if [[ -z "$CODE" ]]; then - for i in {1..8}; do - CODE=$(kv_get_code) - if [[ -n "$CODE" ]]; then break; fi - sleep 2 - done -fi -if [[ -z "$CODE" ]]; then - echo "ERROR: No code found in KV for $PHONE." - exit 1 -fi -echo "CODE=$CODE" - -step "Verify code" -post_json "$BASE_URL/api/sms/verify" "{\"phoneE164\":\"$PHONE\",\"code\":\"$CODE\"}" - -step "Check eligibility" -post_json "$BASE_URL/api/check-eligibility" "{\"address\":\"$ADDR\",\"phoneE164\":\"$PHONE\"}" - -step "Mint (stubbed)" -post_json "$BASE_URL/api/mint" "{\"address\":\"$ADDR\",\"phoneE164\":\"$PHONE\",\"authorAddress\":\"$AUTHOR\"}" - -echo -echo "Done." - - diff --git a/web/scripts/start-dev.mjs b/web/scripts/start-dev.mjs deleted file mode 100644 index 6451a08..0000000 --- a/web/scripts/start-dev.mjs +++ /dev/null @@ -1,152 +0,0 @@ -#!/usr/bin/env node - -import { existsSync } from "node:fs"; -import { spawn, spawnSync } from "node:child_process"; -import { get as httpGet } from "node:http"; -import { get as httpsGet } from "node:https"; -import path from "node:path"; -import process from "node:process"; -import { fileURLToPath } from "node:url"; - -const __dirname = path.dirname(fileURLToPath(import.meta.url)); -const webRoot = path.resolve(__dirname, ".."); -const isWindows = process.platform === "win32"; -const binDir = path.join(webRoot, "node_modules", ".bin"); -const executableSuffix = isWindows ? ".cmd" : ""; -const portlessBin = path.join(binDir, `portless${executableSuffix}`); -const appName = "mintpass"; -const canonicalBranches = new Set(["main", "master"]); -const usePortless = process.env.PORTLESS !== "0" && !isWindows && existsSync(portlessBin); -const portlessProxyPort = process.env.PORTLESS_PORT || "443"; -const portlessEnv = { - ...process.env, - PORTLESS_PORT: portlessProxyPort, - PORTLESS_HTTPS: process.env.PORTLESS_HTTPS ?? "1", - PORTLESS_LAN: process.env.PORTLESS_LAN ?? "0", -}; - -function sanitizeLabel(value) { - return value - .toLowerCase() - .replace(/[^a-z0-9]+/g, "-") - .replace(/^-+|-+$/g, "") - .replace(/-{2,}/g, "-"); -} - -function getCurrentBranch() { - const result = spawnSync("git", ["branch", "--show-current"], { - cwd: webRoot, - encoding: "utf8", - }); - - if (result.status !== 0) { - return null; - } - - return result.stdout.trim() || null; -} - -function getPortlessAppName() { - const branch = getCurrentBranch(); - - if (!branch || canonicalBranches.has(branch)) { - return appName; - } - - const lastSegment = branch.split("/").pop() ?? branch; - const label = sanitizeLabel(lastSegment); - - return `${label}.${appName}`; -} - -function ensurePortlessProxy() { - const result = spawnSync(portlessBin, ["proxy", "start", "--port", portlessProxyPort, "--https"], { - cwd: webRoot, - env: portlessEnv, - stdio: "inherit", - }); - - if (result.status !== 0) { - process.exit(result.status ?? 1); - } -} - -if (usePortless) { - ensurePortlessProxy(); -} - -const portlessAppName = getPortlessAppName(); -const publicUrl = usePortless ? `https://${portlessAppName}.localhost` : null; -const command = usePortless ? portlessBin : "next"; -const args = usePortless - ? [portlessAppName, "next", "dev", "--turbopack"] - : ["dev", "--turbopack"]; - -const child = spawn(command, args, { - cwd: webRoot, - stdio: "inherit", - env: usePortless ? portlessEnv : process.env, -}); - -if (publicUrl && process.env.BROWSER !== "none") { - waitForUrlReady(publicUrl, 30_000) - .then(() => { - console.log(`Opening ${publicUrl} in browser...`); - openInBrowser(publicUrl); - }) - .catch((error) => { - console.warn(`Could not auto-open ${publicUrl}: ${error.message}`); - }); -} - -child.on("exit", (code, signal) => { - if (signal) { - process.kill(process.pid, signal); - return; - } - - process.exit(code ?? 0); -}); - -async function waitForUrlReady(url, timeoutMs) { - const startedAt = Date.now(); - - while (Date.now() - startedAt < timeoutMs) { - const ready = await new Promise((resolve) => { - const parsedUrl = new URL(url); - const getUrl = parsedUrl.protocol === "https:" ? httpsGet : httpGet; - const onResponse = (response) => { - response.resume(); - const statusCode = response.statusCode ?? 500; - resolve(statusCode >= 200 && statusCode < 400); - }; - const request = - parsedUrl.protocol === "https:" - ? getUrl(parsedUrl, { rejectUnauthorized: false }, onResponse) - : getUrl(parsedUrl, onResponse); - - request.on("error", () => resolve(false)); - request.setTimeout(2_000, () => { - request.destroy(); - resolve(false); - }); - }); - - if (ready) { - return; - } - - await new Promise((resolve) => setTimeout(resolve, 200)); - } - - throw new Error(`Timed out waiting for ${url}`); -} - -function openInBrowser(url) { - const opener = - process.platform === "darwin" ? { cmd: "open", args: [url] } - : process.platform === "win32" ? { cmd: "cmd", args: ["/c", "start", '""', url] } - : { cmd: "xdg-open", args: [url] }; - - spawn(opener.cmd, opener.args, { stdio: "ignore", detached: true }).unref(); -} diff --git a/web/src/components/confetti-celebration.tsx b/web/src/components/confetti-celebration.tsx deleted file mode 100644 index 9228c88..0000000 --- a/web/src/components/confetti-celebration.tsx +++ /dev/null @@ -1,59 +0,0 @@ -"use client"; - -import confetti from "canvas-confetti"; -import { useEffect, useRef } from "react"; - -export function ConfettiCelebration() { - const animationIdRef = useRef(null); - - useEffect(() => { - const celebrateWithSideCannons = () => { - const end = Date.now() + 1 * 1000; // 1 second - const colors = ["#9ddcdd", "#077b91"]; // MintPass project colors - - const frame = () => { - if (Date.now() > end) return; - - confetti({ - particleCount: 2, - angle: 60, - spread: 55, - startVelocity: 60, - origin: { x: 0, y: 0.5 }, - colors: colors, - }); - confetti({ - particleCount: 2, - angle: 120, - spread: 55, - startVelocity: 60, - origin: { x: 1, y: 0.5 }, - colors: colors, - }); - - if (animationIdRef.current !== null) { - cancelAnimationFrame(animationIdRef.current); - } - animationIdRef.current = requestAnimationFrame(frame); - }; - - frame(); - - // Return cleanup function - return () => { - if (animationIdRef.current !== null) { - cancelAnimationFrame(animationIdRef.current); - animationIdRef.current = null; - } - }; - }; - - // Start celebration and get cleanup function - const cleanup = celebrateWithSideCannons(); - - // Return cleanup to useEffect - return cleanup; - }, []); - - return null; // This component just triggers effects -} diff --git a/web/src/components/footer.tsx b/web/src/components/footer.tsx deleted file mode 100644 index 83e8efc..0000000 --- a/web/src/components/footer.tsx +++ /dev/null @@ -1,45 +0,0 @@ -import Link from 'next/link'; - -export function Footer() { - return ( - - ); -} diff --git a/web/src/components/header.tsx b/web/src/components/header.tsx deleted file mode 100644 index 02707c2..0000000 --- a/web/src/components/header.tsx +++ /dev/null @@ -1,49 +0,0 @@ -import { useRouter } from 'next/router'; -import { useCallback } from 'react'; -import Image from 'next/image'; -import { AnimatedThemeToggler } from './magicui/animated-theme-toggler'; -import Link from 'next/link'; -import { Button } from '@/components/ui/button'; - -type HeaderProps = { - /** Additional content to show in the navigation area (like links) */ - children?: React.ReactNode; -}; - -export function Header({ children }: HeaderProps) { - const router = useRouter(); - - const handleTitleClick = useCallback(() => { - router.push('/'); - }, [router]); - - return ( -
-
- -
- - {children} - -
-
-
- ); -} diff --git a/web/src/components/magicui/animated-theme-toggler.tsx b/web/src/components/magicui/animated-theme-toggler.tsx deleted file mode 100644 index aba0e86..0000000 --- a/web/src/components/magicui/animated-theme-toggler.tsx +++ /dev/null @@ -1,109 +0,0 @@ -"use client"; - -import { Moon, SunDim } from "lucide-react"; -import { useRef } from "react"; -import { flushSync } from "react-dom"; -import { useTheme } from "next-themes"; -import { cn } from "@/lib/utils"; - -type props = { - className?: string; -}; - -export const AnimatedThemeToggler = ({ className }: props) => { - const { setTheme, resolvedTheme } = useTheme(); - const buttonRef = useRef(null); - const mounted = resolvedTheme !== undefined; - - const changeTheme = async () => { - if (!buttonRef.current) return; - - const newTheme = resolvedTheme === "dark" ? "light" : "dark"; - - // Check if user prefers reduced motion - const prefersReducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches; - - // Check if browser supports view transitions with proper feature detection - if (prefersReducedMotion || typeof document.startViewTransition !== 'function') { - setTheme(newTheme); - return; - } - - try { - await document.startViewTransition(() => { - flushSync(() => { - setTheme(newTheme); - }); - }).ready; - } catch { - // Fallback if View Transitions fails/rejects - console.warn('startViewTransition failed; falling back to direct theme set'); - flushSync(() => { - setTheme(newTheme); - }); - } - - // Guard against unmounts or ref becoming null after async boundary - const buttonEl = buttonRef.current; - if (!buttonEl || !buttonEl.isConnected || !document.documentElement) return; - - const { top, left, width, height } = buttonEl.getBoundingClientRect(); - - // Calculate center coordinates - const centerX = left + width / 2; - const centerY = top + height / 2; - - // Calculate maximum distances from center to viewport edges - const dx = Math.max(centerX, window.innerWidth - centerX); - const dy = Math.max(centerY, window.innerHeight - centerY); - const maxRad = Math.hypot(dx, dy); - - // As a final guard, wrap animate in try/catch to avoid runtime errors - try { - document.documentElement.animate( - { - clipPath: [ - `circle(0px at ${centerX}px ${centerY}px)`, - `circle(${maxRad}px at ${centerX}px ${centerY}px)`, - ], - }, - { - duration: 700, - easing: "ease-in-out", - pseudoElement: "::view-transition-new(root)", - }, - ); - } catch { - // no-op: animation is best-effort - } - }; - - // Show consistent loading state until hydration is complete - if (!mounted) { - return ( - - ); - } - - return ( - - ); -}; diff --git a/web/src/components/magicui/confetti.tsx b/web/src/components/magicui/confetti.tsx deleted file mode 100644 index e5a9774..0000000 --- a/web/src/components/magicui/confetti.tsx +++ /dev/null @@ -1,171 +0,0 @@ -"use client"; - -import type { - GlobalOptions as ConfettiGlobalOptions, - CreateTypes as ConfettiInstance, - Options as ConfettiOptions, -} from "canvas-confetti"; -import confetti from "canvas-confetti"; -import type { ReactNode } from "react"; -import React, { - createContext, - forwardRef, - useCallback, - useEffect, - useImperativeHandle, - useMemo, - useRef, -} from "react"; - -import { Button, ButtonProps } from "@/components/ui/button"; - -type Api = { - fire: (options?: ConfettiOptions) => void; -}; - -type Props = React.ComponentPropsWithRef<"canvas"> & { - options?: ConfettiOptions; - globalOptions?: ConfettiGlobalOptions; - manualstart?: boolean; - children?: ReactNode; -}; - -export type ConfettiRef = Api | null; - -const ConfettiContext = createContext({} as Api); - -// Define component first -const ConfettiComponent = forwardRef((props, ref) => { - const { - options, - globalOptions = { resize: true, useWorker: true }, - manualstart = false, - children, - ...rest - } = props; - const instanceRef = useRef(null); - - const canvasRef = useCallback( - (node: HTMLCanvasElement) => { - if (node !== null) { - if (instanceRef.current) { - try { - instanceRef.current.reset(); - } catch {} - instanceRef.current = null; - } - instanceRef.current = confetti.create(node, { - resize: true, // Default value - ...globalOptions, // Allow globalOptions to override defaults - }); - } else { - if (instanceRef.current) { - try { - instanceRef.current.reset(); - } catch {} - instanceRef.current = null; - } - } - }, - [globalOptions], - ); - - const fire = useCallback( - async (opts = {}) => { - try { - await instanceRef.current?.({ ...(options ?? {}), ...(opts ?? {}) }); - } catch (error) { - console.error("Confetti error:", error); - } - }, - [options], - ); - - const api = useMemo( - () => ({ - fire, - }), - [fire], - ); - - useImperativeHandle(ref, () => api, [api]); - - useEffect(() => { - if (!manualstart) { - (async () => { - try { - await fire(); - } catch (error) { - console.error("Confetti effect error:", error); - } - })(); - } - }, [manualstart, fire]); - - // Cleanup confetti instance on unmount - useEffect(() => { - return () => { - if (instanceRef.current) { - instanceRef.current.reset(); - instanceRef.current = null; - } - }; - }, []); - - return ( - - - {children} - - ); -}); - -// Set display name immediately -ConfettiComponent.displayName = "Confetti"; - -// Export as Confetti -export const Confetti = ConfettiComponent; - -interface ConfettiButtonProps extends Omit { - options?: ConfettiOptions & - ConfettiGlobalOptions & { canvas?: HTMLCanvasElement }; - children?: React.ReactNode; - onClick?: (event: React.MouseEvent) => void | Promise; -} - -const ConfettiButtonComponent = ({ - options, - children, - onClick, - ...props -}: ConfettiButtonProps) => { - const handleClick = async (event: React.MouseEvent) => { - try { - // Call original onClick handler if provided - if (typeof onClick === 'function') await onClick(event); - - const rect = event.currentTarget.getBoundingClientRect(); - const x = rect.left + rect.width / 2; - const y = rect.top + rect.height / 2; - await confetti({ - ...(options ?? {}), - origin: { - x: x / window.innerWidth, - y: y / window.innerHeight, - }, - }); - } catch (error) { - console.error("Confetti button error:", error); - } - }; - - return ( - - ); -}; - -ConfettiButtonComponent.displayName = "ConfettiButton"; - -export const ConfettiButton = ConfettiButtonComponent; diff --git a/web/src/components/magicui/rainbow-button.tsx b/web/src/components/magicui/rainbow-button.tsx deleted file mode 100644 index 3e1543c..0000000 --- a/web/src/components/magicui/rainbow-button.tsx +++ /dev/null @@ -1,59 +0,0 @@ -import { cn } from "@/lib/utils"; -import { Slot } from "@radix-ui/react-slot"; -import { cva, VariantProps } from "class-variance-authority"; -import React from "react"; - -const rainbowButtonVariants = cva( - cn( - "relative cursor-pointer group transition-all animate-rainbow", - "inline-flex items-center justify-center gap-2 shrink-0", - "rounded-sm outline-none focus-visible:ring-[3px] aria-invalid:border-destructive", - "text-sm font-medium whitespace-nowrap", - "disabled:pointer-events-none disabled:opacity-50", - "[&_svg]:pointer-events-none [&_svg:not([class*='size-'])]:size-4 [&_svg]:shrink-0", - ), - { - variants: { - variant: { - default: - "border-0 bg-[linear-gradient(#121213,#121213),linear-gradient(#121213_50%,rgba(18,18,19,0.6)_80%,rgba(18,18,19,0)),linear-gradient(90deg,var(--color-1),var(--color-5),var(--color-3),var(--color-4),var(--color-2))] bg-[length:200%] text-primary-foreground [background-clip:padding-box,border-box,border-box] [background-origin:border-box] [border:calc(0.125rem)_solid_transparent] before:absolute before:bottom-[-20%] before:left-1/2 before:z-0 before:h-1/5 before:w-3/5 before:-translate-x-1/2 before:animate-rainbow before:bg-[linear-gradient(90deg,var(--color-1),var(--color-5),var(--color-3),var(--color-4),var(--color-2))] before:[filter:blur(0.75rem)] dark:bg-[linear-gradient(#fff,#fff),linear-gradient(#fff_50%,rgba(255,255,255,0.6)_80%,rgba(0,0,0,0)),linear-gradient(90deg,var(--color-1),var(--color-5),var(--color-3),var(--color-4),var(--color-2))]", - outline: - "border border-input border-b-transparent bg-[linear-gradient(#ffffff,#ffffff),linear-gradient(#ffffff_50%,rgba(18,18,19,0.6)_80%,rgba(18,18,19,0)),linear-gradient(90deg,var(--color-1),var(--color-5),var(--color-3),var(--color-4),var(--color-2))] bg-[length:200%] text-accent-foreground [background-clip:padding-box,border-box,border-box] [background-origin:border-box] before:absolute before:bottom-[-20%] before:left-1/2 before:z-0 before:h-1/5 before:w-3/5 before:-translate-x-1/2 before:animate-rainbow before:bg-[linear-gradient(90deg,var(--color-1),var(--color-5),var(--color-3),var(--color-4),var(--color-2))] before:[filter:blur(0.75rem)] dark:bg-[linear-gradient(#0a0a0a,#0a0a0a),linear-gradient(#0a0a0a_50%,rgba(255,255,255,0.6)_80%,rgba(0,0,0,0)),linear-gradient(90deg,var(--color-1),var(--color-5),var(--color-3),var(--color-4),var(--color-2))]", - }, - size: { - default: "h-9 px-4 py-2", - sm: "h-8 rounded-xl px-3 text-xs", - lg: "h-11 rounded-xl px-8", - icon: "size-9", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - }, -); - -interface RainbowButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean; -} - -const RainbowButton = React.forwardRef( - ({ className, variant, size, asChild = false, ...props }, ref) => { - const Comp = asChild ? Slot : "button"; - return ( - - ); - }, -); - -RainbowButton.displayName = "RainbowButton"; - -export { RainbowButton, rainbowButtonVariants, type RainbowButtonProps }; diff --git a/web/src/components/page-card.tsx b/web/src/components/page-card.tsx deleted file mode 100644 index 1bfdd35..0000000 --- a/web/src/components/page-card.tsx +++ /dev/null @@ -1,63 +0,0 @@ -import * as React from 'react' - -import { cn } from '@/lib/utils' -import { Card, CardContent, CardHeader, CardFooter } from './ui/card' - -type PageCardProps = { - title: string - children: React.ReactNode - contentClassName?: string - titleClassName?: string - containerClassName?: string - titleAs?: React.ElementType - footer?: React.ReactNode - footerClassName?: string -} - -export function PageCard({ - title, - children, - contentClassName = '', - titleClassName = '', - containerClassName, - titleAs = 'h2', - footer, - footerClassName = '', -}: PageCardProps) { - const TitleTag = titleAs - - // Get appropriate font size class based on heading level - const getDefaultTitleClasses = (tagName: React.ElementType) => { - if (typeof tagName === 'string') { - switch (tagName) { - case 'h1': return 'text-xl md:text-2xl font-semibold leading-none tracking-tight' - case 'h2': return 'text-lg md:text-xl font-semibold leading-none tracking-tight' - case 'h3': return 'text-base md:text-lg font-semibold leading-none tracking-tight' - default: return 'font-semibold leading-none tracking-tight' - } - } - return 'font-semibold leading-none tracking-tight' - } - - return ( -
- - - - {title} - - - - {children} - - {footer && ( - - {footer} - - )} - -
- ) -} - - diff --git a/web/src/components/ui/button.tsx b/web/src/components/ui/button.tsx deleted file mode 100644 index 1926964..0000000 --- a/web/src/components/ui/button.tsx +++ /dev/null @@ -1,58 +0,0 @@ -import * as React from "react" -import { Slot } from "@radix-ui/react-slot" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const buttonVariants = cva( - "inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0", - { - variants: { - variant: { - default: - "bg-primary text-primary-foreground shadow hover:bg-primary/90", - destructive: - "bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90", - outline: - "border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground", - secondary: - "bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80", - ghost: "hover:bg-accent hover:text-accent-foreground", - link: "text-primary underline-offset-4 hover:underline", - }, - size: { - default: "h-9 px-4 py-2", - sm: "h-8 rounded-md px-3 text-xs", - lg: "h-10 rounded-md px-8", - icon: "h-9 w-9", - }, - }, - defaultVariants: { - variant: "default", - size: "default", - }, - } -) - -export interface ButtonProps - extends React.ButtonHTMLAttributes, - VariantProps { - asChild?: boolean -} - -const Button = React.forwardRef( - ({ className, variant, size, asChild = false, type, ...props }, ref) => { - const Comp = asChild ? Slot : "button" - return ( - - ) - } -) -Button.displayName = "Button" - -export { Button, buttonVariants } diff --git a/web/src/components/ui/card.tsx b/web/src/components/ui/card.tsx deleted file mode 100644 index 6b1adea..0000000 --- a/web/src/components/ui/card.tsx +++ /dev/null @@ -1,76 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -const Card = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -Card.displayName = "Card" - -const CardHeader = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardHeader.displayName = "CardHeader" - -const CardTitle = React.forwardRef< - HTMLHeadingElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardTitle.displayName = "CardTitle" - -const CardDescription = React.forwardRef< - HTMLParagraphElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardDescription.displayName = "CardDescription" - -const CardContent = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -

-)) -CardContent.displayName = "CardContent" - -const CardFooter = React.forwardRef< - HTMLDivElement, - React.HTMLAttributes ->(({ className, ...props }, ref) => ( -
-)) -CardFooter.displayName = "CardFooter" - -export { Card, CardHeader, CardFooter, CardTitle, CardDescription, CardContent } diff --git a/web/src/components/ui/command.tsx b/web/src/components/ui/command.tsx deleted file mode 100644 index 9036e39..0000000 --- a/web/src/components/ui/command.tsx +++ /dev/null @@ -1,153 +0,0 @@ -"use client" - -import * as React from "react" -import { type DialogProps } from "@radix-ui/react-dialog" -import { Command as CommandPrimitive } from "cmdk" -import { Search } from "lucide-react" - -import { cn } from "@/lib/utils" -import { Dialog, DialogContent } from "@/components/ui/dialog" - -const Command = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -Command.displayName = CommandPrimitive.displayName - -const CommandDialog = ({ children, ...props }: DialogProps) => { - return ( - - - - {children} - - - - ) -} - -const CommandInput = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( -
- - -
-)) - -CommandInput.displayName = CommandPrimitive.Input.displayName - -const CommandList = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) - -CommandList.displayName = CommandPrimitive.List.displayName - -const CommandEmpty = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->((props, ref) => ( - -)) - -CommandEmpty.displayName = CommandPrimitive.Empty.displayName - -const CommandGroup = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) - -CommandGroup.displayName = CommandPrimitive.Group.displayName - -const CommandSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -CommandSeparator.displayName = CommandPrimitive.Separator.displayName - -const CommandItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) - -CommandItem.displayName = CommandPrimitive.Item.displayName - -const CommandShortcut = ({ - className, - ...props -}: React.HTMLAttributes) => { - return ( - - ) -} -CommandShortcut.displayName = "CommandShortcut" - -export { - Command, - CommandDialog, - CommandInput, - CommandList, - CommandEmpty, - CommandGroup, - CommandItem, - CommandShortcut, - CommandSeparator, -} diff --git a/web/src/components/ui/dialog.tsx b/web/src/components/ui/dialog.tsx deleted file mode 100644 index 9dbeaa0..0000000 --- a/web/src/components/ui/dialog.tsx +++ /dev/null @@ -1,120 +0,0 @@ -import * as React from "react" -import * as DialogPrimitive from "@radix-ui/react-dialog" -import { X } from "lucide-react" - -import { cn } from "@/lib/utils" - -const Dialog = DialogPrimitive.Root - -const DialogTrigger = DialogPrimitive.Trigger - -const DialogPortal = DialogPrimitive.Portal - -const DialogClose = DialogPrimitive.Close - -const DialogOverlay = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DialogOverlay.displayName = DialogPrimitive.Overlay.displayName - -const DialogContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - {children} - - - Close - - - -)) -DialogContent.displayName = DialogPrimitive.Content.displayName - -const DialogHeader = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -DialogHeader.displayName = "DialogHeader" - -const DialogFooter = ({ - className, - ...props -}: React.HTMLAttributes) => ( -
-) -DialogFooter.displayName = "DialogFooter" - -const DialogTitle = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DialogTitle.displayName = DialogPrimitive.Title.displayName - -const DialogDescription = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DialogDescription.displayName = DialogPrimitive.Description.displayName - -export { - Dialog, - DialogPortal, - DialogOverlay, - DialogTrigger, - DialogClose, - DialogContent, - DialogHeader, - DialogFooter, - DialogTitle, - DialogDescription, -} diff --git a/web/src/components/ui/dropdown-menu.tsx b/web/src/components/ui/dropdown-menu.tsx deleted file mode 100644 index e804bca..0000000 --- a/web/src/components/ui/dropdown-menu.tsx +++ /dev/null @@ -1,199 +0,0 @@ -import * as React from "react" -import * as DropdownMenuPrimitive from "@radix-ui/react-dropdown-menu" -import { Check, ChevronRight, Circle } from "lucide-react" - -import { cn } from "@/lib/utils" - -const DropdownMenu = DropdownMenuPrimitive.Root - -const DropdownMenuTrigger = DropdownMenuPrimitive.Trigger - -const DropdownMenuGroup = DropdownMenuPrimitive.Group - -const DropdownMenuPortal = DropdownMenuPrimitive.Portal - -const DropdownMenuSub = DropdownMenuPrimitive.Sub - -const DropdownMenuRadioGroup = DropdownMenuPrimitive.RadioGroup - -const DropdownMenuSubTrigger = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } ->(({ className, inset, children, ...props }, ref) => ( - - {children} - - -)) -DropdownMenuSubTrigger.displayName = - DropdownMenuPrimitive.SubTrigger.displayName - -const DropdownMenuSubContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DropdownMenuSubContent.displayName = - DropdownMenuPrimitive.SubContent.displayName - -const DropdownMenuContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, sideOffset = 4, ...props }, ref) => ( - - - -)) -DropdownMenuContent.displayName = DropdownMenuPrimitive.Content.displayName - -const DropdownMenuItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } ->(({ className, inset, ...props }, ref) => ( - svg]:size-4 [&>svg]:shrink-0", - inset && "pl-8", - className - )} - {...props} - /> -)) -DropdownMenuItem.displayName = DropdownMenuPrimitive.Item.displayName - -const DropdownMenuCheckboxItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, checked, ...props }, ref) => ( - - - - - - - {children} - -)) -DropdownMenuCheckboxItem.displayName = - DropdownMenuPrimitive.CheckboxItem.displayName - -const DropdownMenuRadioItem = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - - - - - {children} - -)) -DropdownMenuRadioItem.displayName = DropdownMenuPrimitive.RadioItem.displayName - -const DropdownMenuLabel = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & { - inset?: boolean - } ->(({ className, inset, ...props }, ref) => ( - -)) -DropdownMenuLabel.displayName = DropdownMenuPrimitive.Label.displayName - -const DropdownMenuSeparator = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, ...props }, ref) => ( - -)) -DropdownMenuSeparator.displayName = DropdownMenuPrimitive.Separator.displayName - -const DropdownMenuShortcut = ({ - className, - ...props -}: React.HTMLAttributes) => { - return ( - - ) -} -DropdownMenuShortcut.displayName = "DropdownMenuShortcut" - -export { - DropdownMenu, - DropdownMenuTrigger, - DropdownMenuContent, - DropdownMenuItem, - DropdownMenuCheckboxItem, - DropdownMenuRadioItem, - DropdownMenuLabel, - DropdownMenuSeparator, - DropdownMenuShortcut, - DropdownMenuGroup, - DropdownMenuPortal, - DropdownMenuSub, - DropdownMenuSubContent, - DropdownMenuSubTrigger, - DropdownMenuRadioGroup, -} diff --git a/web/src/components/ui/input-otp.tsx b/web/src/components/ui/input-otp.tsx deleted file mode 100644 index 2c733bd..0000000 --- a/web/src/components/ui/input-otp.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import * as React from "react" -import { OTPInput, OTPInputContext } from "input-otp" -import { Minus } from "lucide-react" - -import { cn } from "@/lib/utils" - -const InputOTP = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, containerClassName, ...props }, ref) => ( - -)) -InputOTP.displayName = "InputOTP" - -const InputOTPGroup = React.forwardRef< - React.ElementRef<"div">, - React.ComponentPropsWithoutRef<"div"> ->(({ className, ...props }, ref) => ( -
-)) -InputOTPGroup.displayName = "InputOTPGroup" - -const InputOTPSlot = React.forwardRef< - React.ElementRef<"div">, - React.ComponentPropsWithoutRef<"div"> & { index: number } ->(({ index, className, ...props }, ref) => { - const inputOTPContext = React.useContext(OTPInputContext) - - // Compute safe defaults and then render once - const slots = inputOTPContext?.slots - const hasValidIndex = Array.isArray(slots) && index >= 0 && index < slots.length - const char = hasValidIndex ? slots[index].char : '' - const hasFakeCaret = hasValidIndex ? slots[index].hasFakeCaret : false - const isActive = hasValidIndex ? slots[index].isActive : false - - return ( -
- {char} - {hasFakeCaret && ( -
-
-
- )} -
- ) -}) -InputOTPSlot.displayName = "InputOTPSlot" - -const InputOTPSeparator = React.forwardRef< - React.ElementRef<"div">, - React.ComponentPropsWithoutRef<"div"> ->(({ ...props }, ref) => ( -
- -
-)) -InputOTPSeparator.displayName = "InputOTPSeparator" - -export { InputOTP, InputOTPGroup, InputOTPSlot, InputOTPSeparator } diff --git a/web/src/components/ui/input.tsx b/web/src/components/ui/input.tsx deleted file mode 100644 index 69b64fb..0000000 --- a/web/src/components/ui/input.tsx +++ /dev/null @@ -1,22 +0,0 @@ -import * as React from "react" - -import { cn } from "@/lib/utils" - -const Input = React.forwardRef>( - ({ className, type, ...props }, ref) => { - return ( - - ) - } -) -Input.displayName = "Input" - -export { Input } diff --git a/web/src/components/ui/label.tsx b/web/src/components/ui/label.tsx deleted file mode 100644 index 683faa7..0000000 --- a/web/src/components/ui/label.tsx +++ /dev/null @@ -1,24 +0,0 @@ -import * as React from "react" -import * as LabelPrimitive from "@radix-ui/react-label" -import { cva, type VariantProps } from "class-variance-authority" - -import { cn } from "@/lib/utils" - -const labelVariants = cva( - "text-sm font-medium leading-none peer-disabled:cursor-not-allowed peer-disabled:opacity-70" -) - -const Label = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef & - VariantProps ->(({ className, ...props }, ref) => ( - -)) -Label.displayName = LabelPrimitive.Root.displayName - -export { Label } diff --git a/web/src/components/ui/phone-input.tsx b/web/src/components/ui/phone-input.tsx deleted file mode 100644 index da55dec..0000000 --- a/web/src/components/ui/phone-input.tsx +++ /dev/null @@ -1,298 +0,0 @@ -import * as React from "react"; -import { CheckIcon, ChevronsUpDown } from "lucide-react"; -import * as RPNInput from "react-phone-number-input"; -import flags from "react-phone-number-input/flags"; -import { parsePhoneNumber } from "react-phone-number-input"; - -import { Button } from "@/components/ui/button"; -import { - Command, - CommandEmpty, - CommandGroup, - CommandInput, - CommandItem, - CommandList, -} from "@/components/ui/command"; -import { Input } from "@/components/ui/input"; -import { Popover, PopoverContent, PopoverTrigger } from "@/components/ui/popover"; -import { ScrollArea } from "@/components/ui/scroll-area"; -import { cn } from "@/lib/utils"; - -// Countries restricted for SMS verification due to policy and security reasons -const UNSUPPORTED_COUNTRIES: RPNInput.Country[] = [ - "AF", // Afghanistan - "BY", // Belarus - "CU", // Cuba - "IR", // Iran - "IL", // Israel - "KP", // North Korea - "MM", // Myanmar - "RU", // Russia - "SY", // Syria - "VE", // Venezuela - "AZ", // Azerbaijan - "BD", // Bangladesh - "ID", // Indonesia - "OM", // Oman - "LK", // Sri Lanka - "PS", // Palestinian Territory - "TJ", // Tajikistan - "VN", // Vietnam - "PK", // Pakistan - "DZ", // Algeria - "NG", // Nigeria - "TN", // Tunisia -]; - -type PhoneInputProps = Omit, "onChange" | "value" | "ref"> & - Omit, "onChange"> & { - onChange?: (value: RPNInput.Value) => void; - onCountryChange?: (country: RPNInput.Country | undefined) => void; - }; - -const PhoneInput: React.ForwardRefExoticComponent = React.forwardRef< - React.ElementRef, - PhoneInputProps ->(({ className, onChange, onCountryChange, value, ...props }, ref) => { - return ( - { - const phoneValue = value || ("" as RPNInput.Value); - onChange?.(phoneValue); - - // Extract country from phone number and call onCountryChange - if (onCountryChange) { - let country: RPNInput.Country | undefined; - try { - if (phoneValue) { - const parsed = parsePhoneNumber(phoneValue); - country = parsed?.country; - } - } catch { - // If parsing fails, country remains undefined - } - onCountryChange(country); - } - }} - {...props} - /> - ); -}); -PhoneInput.displayName = "PhoneInput"; - -const InputComponent = React.forwardRef>( - ({ className, ...props }, ref) => ( - - ), -); -InputComponent.displayName = "InputComponent"; - -type CountryEntry = { label: string; value: RPNInput.Country | undefined }; - -type CountrySelectProps = { - disabled?: boolean; - value: RPNInput.Country; - options: CountryEntry[]; - onChange: (country: RPNInput.Country) => void; -}; - -const CountrySelect = ({ - disabled, - value: selectedCountry, - options: countryList, - onChange, -}: CountrySelectProps) => { - const scrollAreaRef = React.useRef(null); - const inputRef = React.useRef(null); - const [searchValue, setSearchValue] = React.useState(""); - const [isOpen, setIsOpen] = React.useState(false); - - // Detect mobile device - calculated during rendering (not expensive, no need for useMemo) - const isMobileDevice = - typeof window !== "undefined" && - /android|iphone|ipad|ipod|blackberry|iemobile|opera mini/i.test(navigator.userAgent); - - // Track whether user has manually clicked the input (to allow manual search on mobile) - const [hasUserFocused, setHasUserFocused] = React.useState(false); - - // Helper function to blur input on mobile devices only - const blurInputAfterOpen = React.useCallback(() => { - requestAnimationFrame(() => { - if (inputRef.current) { - inputRef.current.blur(); - } - }); - }, []); - - const filteredCountryList = countryList.filter(({ value }) => value); - - return ( - { - setIsOpen(open); - if (open) { - setSearchValue(""); - setHasUserFocused(false); - // Only prevent auto-focus on mobile devices - if (isMobileDevice) { - blurInputAfterOpen(); - } - // On desktop, allow natural autofocus behavior - } - }} - > - - - - - - { - setSearchValue(value); - requestAnimationFrame(() => { - if (scrollAreaRef.current) { - const viewportElement = scrollAreaRef.current.querySelector( - "[data-radix-scroll-area-viewport]", - ); - if (viewportElement) { - viewportElement.scrollTop = 0; - } - } - }); - }} - onFocus={(e) => { - // On mobile, prevent automatic focus (but allow it after user clicks the input) - if (isMobileDevice && !hasUserFocused) { - e.preventDefault(); - e.target.blur(); - return false; - } - // On desktop, allow all focus events naturally - }} - onClick={() => { - // When user clicks the input, allow focus (works on both mobile and desktop) - setHasUserFocused(true); - }} - placeholder="Search country..." - autoFocus={!isMobileDevice} - /> - - - No country found. - - {filteredCountryList.map(({ value, label }) => - value ? ( - setIsOpen(false)} - isSupported={!UNSUPPORTED_COUNTRIES.includes(value)} - /> - ) : null, - )} - - - - - - - ); -}; - -interface CountrySelectOptionProps extends RPNInput.FlagProps { - selectedCountry: RPNInput.Country; - onChange: (country: RPNInput.Country) => void; - onSelectComplete: () => void; - isSupported: boolean; -} - -const CountrySelectOption = ({ - country, - countryName, - selectedCountry, - onChange, - onSelectComplete, - isSupported, -}: CountrySelectOptionProps) => { - const handleSelect = () => { - if (!isSupported) return; // Don't allow selection of unsupported countries - onChange(country); - onSelectComplete(); - }; - - // Calculate country code during rendering - const countryCode = React.useMemo(() => { - try { - const code = RPNInput.getCountryCallingCode(country); - return code ? `+${code}` : null; - } catch { - return null; - } - }, [country]); - - return ( - - - {countryName} - {!isSupported ? ( - not available - ) : countryCode ? ( - {countryCode} - ) : null} - - - ); -}; - -const FlagComponent = ({ country, countryName }: RPNInput.FlagProps) => { - type PhoneFlagComponent = React.ComponentType<{ title?: string }>; - const map = flags as Record; - const Flag = country ? map[country] : undefined; - - return ( - - {Flag ? : null} - - ); -}; - -export { PhoneInput, UNSUPPORTED_COUNTRIES }; diff --git a/web/src/components/ui/popover.tsx b/web/src/components/ui/popover.tsx deleted file mode 100644 index fdcb511..0000000 --- a/web/src/components/ui/popover.tsx +++ /dev/null @@ -1,31 +0,0 @@ -import * as React from "react" -import * as PopoverPrimitive from "@radix-ui/react-popover" - -import { cn } from "@/lib/utils" - -const Popover = PopoverPrimitive.Root - -const PopoverTrigger = PopoverPrimitive.Trigger - -const PopoverAnchor = PopoverPrimitive.Anchor - -const PopoverContent = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, align = "center", sideOffset = 4, ...props }, ref) => ( - - - -)) -PopoverContent.displayName = PopoverPrimitive.Content.displayName - -export { Popover, PopoverTrigger, PopoverContent, PopoverAnchor } diff --git a/web/src/components/ui/scroll-area.tsx b/web/src/components/ui/scroll-area.tsx deleted file mode 100644 index d59c53c..0000000 --- a/web/src/components/ui/scroll-area.tsx +++ /dev/null @@ -1,46 +0,0 @@ -import * as React from "react" -import * as ScrollAreaPrimitive from "@radix-ui/react-scroll-area" - -import { cn } from "@/lib/utils" - -const ScrollArea = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, children, ...props }, ref) => ( - - - {children} - - - - -)) -ScrollArea.displayName = ScrollAreaPrimitive.Root.displayName - -const ScrollBar = React.forwardRef< - React.ElementRef, - React.ComponentPropsWithoutRef ->(({ className, orientation = "vertical", ...props }, ref) => ( - - - -)) -ScrollBar.displayName = ScrollAreaPrimitive.Scrollbar.displayName - -export { ScrollArea, ScrollBar } diff --git a/web/src/components/ui/shadcn-io/hexagon-background/index.tsx b/web/src/components/ui/shadcn-io/hexagon-background/index.tsx deleted file mode 100644 index 3e7ea31..0000000 --- a/web/src/components/ui/shadcn-io/hexagon-background/index.tsx +++ /dev/null @@ -1,250 +0,0 @@ -'use client'; - -import * as React from 'react'; - -import { cn } from '@/lib/utils'; - -type HexagonBackgroundProps = React.ComponentProps<'div'> & { - children?: React.ReactNode; - hexagonProps?: React.ComponentProps<'div'>; - hexagonSize?: number; // value greater than 50 - hexagonMargin?: number; -}; - -function HexagonBackground({ - className, - children, - hexagonProps, - hexagonSize = 75, - hexagonMargin = 3, - ...props -}: HexagonBackgroundProps) { - // Validate/coerce size early (do not early-return before hooks) - const size = Number(hexagonSize); - const isValidSize = Number.isFinite(size) && size > 50; - - const hexagonWidth = size; - const hexagonHeight = size * 1.1; - const rowSpacing = size * 0.8; - const baseMarginTop = -36 - 0.275 * (size - 100); - const computedMarginTop = baseMarginTop + hexagonMargin; - const oddRowMarginLeft = -(size / 2); - const evenRowMarginLeft = hexagonMargin / 2; - - const [gridDimensions, setGridDimensions] = React.useState({ - rows: 0, - columns: 0, - }); - const containerRef = React.useRef(null); - const trailDurationMs = 700; - const activeTimersRef = React.useRef>(new Map()); - const activeKeysRef = React.useRef>(new Set()); - const debounceTimerRef = React.useRef(null); - const expiryMapRef = React.useRef>(new Map()); - const hexRefsRef = React.useRef>(new Map()); - - const updateGridDimensions = React.useCallback(() => { - if (typeof window === 'undefined' || !isValidSize) return; - // Use the full document height instead of just viewport height - const documentHeight = Math.max( - document.body.scrollHeight, - document.documentElement.scrollHeight, - window.innerHeight - ); - const rows = Math.ceil(documentHeight / rowSpacing); - const columns = Math.ceil(window.innerWidth / hexagonWidth) + 1; - setGridDimensions({ rows, columns }); - }, [rowSpacing, hexagonWidth, isValidSize]); - - React.useEffect(() => { - if (!isValidSize) return; - updateGridDimensions(); - window.addEventListener('resize', updateGridDimensions); - - // Prefer a scoped ResizeObserver on the component container - let ro: ResizeObserver | null = null; - if (typeof ResizeObserver !== 'undefined' && containerRef.current) { - ro = new ResizeObserver(() => { - if (debounceTimerRef.current !== null) { - clearTimeout(debounceTimerRef.current); - } - debounceTimerRef.current = window.setTimeout(updateGridDimensions, 100); - }); - ro.observe(containerRef.current); - } - - return () => { - window.removeEventListener('resize', updateGridDimensions); - if (ro) ro.disconnect(); - if (debounceTimerRef.current !== null) { - clearTimeout(debounceTimerRef.current); - debounceTimerRef.current = null; - } - }; - }, [updateGridDimensions, isValidSize]); - - const clearActiveKey = React.useCallback((key: string) => { - const timersMap = activeTimersRef.current; - const existingTimeout = timersMap.get(key); - if (existingTimeout !== undefined) { - window.clearTimeout(existingTimeout); - timersMap.delete(key); - } - expiryMapRef.current.delete(key); - activeKeysRef.current.delete(key); - const el = hexRefsRef.current.get(key); - if (el) { - el.removeAttribute('data-active'); - } - }, []); - - const clearAllActive = React.useCallback(() => { - for (const key of Array.from(activeKeysRef.current)) { - clearActiveKey(key); - } - }, [clearActiveKey]); - - const activateHex = React.useCallback((key: string) => { - if (activeKeysRef.current.has(key)) return; - activeKeysRef.current.add(key); - const el = hexRefsRef.current.get(key); - if (el) { - el.setAttribute('data-active', 'true'); - } - expiryMapRef.current.set(key, Date.now() + trailDurationMs + 50); - const timeoutId = window.setTimeout(() => { - clearActiveKey(key); - }, trailDurationMs); - activeTimersRef.current.set(key, timeoutId); - }, [trailDurationMs, clearActiveKey]); - - const updateActiveFromPoint = React.useCallback((clientX: number, clientY: number) => { - if (!containerRef.current) return; - const rect = containerRef.current.getBoundingClientRect(); - const x = clientX - rect.left; - const y = clientY - rect.top; - - const row = Math.floor(y / rowSpacing); - if (row < 0 || row >= gridDimensions.rows) return; - const shift = (((row + 1) % 2 === 0 ? evenRowMarginLeft : oddRowMarginLeft) - 10); - const col = Math.floor((x - shift) / hexagonWidth); - if (col < 0 || col >= gridDimensions.columns) return; - const key = `${row}-${col}`; - - // If this hex is not currently in the trail, add it and schedule removal - if (!activeTimersRef.current.has(key)) { - activateHex(key); - } - }, [gridDimensions.rows, gridDimensions.columns, rowSpacing, hexagonWidth, evenRowMarginLeft, oddRowMarginLeft, activateHex]); - - React.useEffect(() => { - if (!isValidSize) return; - const move = (e: MouseEvent) => updateActiveFromPoint(e.clientX, e.clientY); - const leave = () => clearAllActive(); - const onVisibility = () => clearAllActive(); - window.addEventListener('mousemove', move, { passive: true }); - window.addEventListener('mouseleave', leave, { passive: true }); - window.addEventListener('blur', leave); - document.addEventListener('visibilitychange', onVisibility); - return () => { - window.removeEventListener('mousemove', move); - window.removeEventListener('mouseleave', leave); - window.removeEventListener('blur', leave); - document.removeEventListener('visibilitychange', onVisibility); - clearAllActive(); - }; - }, [updateActiveFromPoint, isValidSize, clearAllActive]); - - // Failsafe GC: periodically clear any overdue actives in case a timeout was throttled/lost - React.useEffect(() => { - if (!isValidSize) return; - const intervalId = window.setInterval(() => { - const now = Date.now(); - const expired: string[] = []; - for (const [key, expiry] of expiryMapRef.current) { - if (expiry <= now) expired.push(key); - } - if (expired.length) { - for (const key of expired) clearActiveKey(key); - } - }, 500); - return () => window.clearInterval(intervalId); - }, [isValidSize, clearActiveKey]); - - // Trail is managed with per-hex timeouts; no idle loop needed - - if (!isValidSize) return null; - - return ( -
- -
- {Array.from({ length: gridDimensions.rows }).map((_, rowIndex) => ( -
- {Array.from({ length: gridDimensions.columns }).map( - (_, colIndex) => ( -
{ - const key = `${rowIndex}-${colIndex}`; - if (el) { - hexRefsRef.current.set(key, el); - } else { - hexRefsRef.current.delete(key); - } - }} - /> - ), - )} -
- ))} -
-
- {children} -
-
- ); -} - -export { HexagonBackground, type HexagonBackgroundProps }; \ No newline at end of file diff --git a/web/src/lib/utils.ts b/web/src/lib/utils.ts deleted file mode 100644 index bd0c391..0000000 --- a/web/src/lib/utils.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { clsx, type ClassValue } from "clsx" -import { twMerge } from "tailwind-merge" - -export function cn(...inputs: ClassValue[]) { - return twMerge(clsx(inputs)) -} diff --git a/web/src/pages/404.tsx b/web/src/pages/404.tsx deleted file mode 100644 index b52f11a..0000000 --- a/web/src/pages/404.tsx +++ /dev/null @@ -1,50 +0,0 @@ -import { useEffect, useState } from 'react'; -import { useRouter } from 'next/router'; -import Link from 'next/link'; -import { Header } from '../components/header'; -import { Footer } from '../components/footer'; -import { PageCard } from '../components/page-card'; - - -export default function NotFoundPage() { - const router = useRouter(); - const [secondsLeft, setSecondsLeft] = useState(5); - - useEffect(() => { - const interval = setInterval(() => { - setSecondsLeft((prev) => { - if (prev <= 1) { - clearInterval(interval); - void router.replace('/'); - return 0; - } - return prev - 1; - }); - }, 1000); - return () => clearInterval(interval); - }, [router]); - - return ( -
-
-
- -

- The page you are looking for doesn't exist or may have moved. -

-

- Redirecting to home in {secondsLeft} second{secondsLeft !== 1 ? 's' : ''}... -

-
-
-
-
- ); -} diff --git a/web/src/pages/_app.tsx b/web/src/pages/_app.tsx deleted file mode 100644 index 29a43d3..0000000 --- a/web/src/pages/_app.tsx +++ /dev/null @@ -1,21 +0,0 @@ -import type { AppProps } from 'next/app'; -import { ThemeProvider } from 'next-themes'; -import '../styles/globals.css'; -import { HexagonBackground } from '@/components/ui/shadcn-io/hexagon-background'; -import { Analytics } from '@vercel/analytics/next'; - -export default function App({ Component, pageProps }: AppProps) { - return ( - - - - - - - ); -} diff --git a/web/src/pages/_document.tsx b/web/src/pages/_document.tsx deleted file mode 100644 index d65126a..0000000 --- a/web/src/pages/_document.tsx +++ /dev/null @@ -1,40 +0,0 @@ -import { Html, Head, Main, NextScript } from 'next/document'; - -export default function Document() { - return ( - - - {/* Standard favicon */} - - - {/* PNG favicons for different sizes */} - - - - {/* Apple Touch Icon */} - - - {/* Android/Chrome icons */} - - - - {/* Web App Manifest */} - - - {/* Theme color for mobile browsers */} - - - {/* Additional meta tags */} - - - - - - - -
- - - - ); -} diff --git a/web/src/pages/admin.tsx b/web/src/pages/admin.tsx deleted file mode 100644 index eb39ccb..0000000 --- a/web/src/pages/admin.tsx +++ /dev/null @@ -1,327 +0,0 @@ -import { useRef, useState } from 'react'; -import type { GetServerSideProps, GetServerSidePropsContext } from 'next'; -import { verifyAdminToken } from '../../lib/admin-auth'; -import { Header } from '../components/header'; -import { Footer } from '../components/footer'; -import { Button } from '../components/ui/button'; -import { Input } from '../components/ui/input'; -import { PhoneInput } from '../components/ui/phone-input'; -import { Label } from '../components/ui/label'; -import { PageCard } from '../components/page-card'; - -async function postJson( - path: string, - body: unknown, - options: { timeout?: number; maxRetries?: number } = {} -): Promise { - const { timeout = 5000, maxRetries = 3 } = options; - let lastError: Error | null = null; - - function isHttpError(e: unknown): e is { status?: number; nonRetryable?: boolean } { - return typeof e === 'object' && e !== null && ('status' in e || 'nonRetryable' in e); - } - - for (let attempt = 1; attempt <= maxRetries; attempt++) { - const controller = new AbortController(); - const timeoutId = setTimeout(() => controller.abort(), timeout); - - try { - const res = await fetch(path, { - method: 'POST', - headers: { 'content-type': 'application/json' }, - body: JSON.stringify(body), - signal: controller.signal, - }); - - clearTimeout(timeoutId); - - const json = (await res.json().catch(() => ({}))) as unknown; - - // Don't retry on 4xx errors - if (res.status >= 400 && res.status < 500) { - const errMsg = (json as { error?: string })?.error || 'Request failed'; - const e = new Error(errMsg) as Error & { status?: number; nonRetryable?: boolean }; - e.status = res.status; - e.nonRetryable = true; - throw e; - } - - if (!res.ok) { - // Retry on 5xx errors - if (attempt < maxRetries) { - const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000); // Exponential backoff, max 5s - await new Promise(resolve => setTimeout(resolve, delay)); - continue; - } - const errMsg = (json as { error?: string })?.error || 'Request failed'; - throw new Error(errMsg); - } - - return json as T; - } catch (error: unknown) { - clearTimeout(timeoutId); - lastError = error instanceof Error ? error : new Error('Request failed'); - - // Don't retry on abort/timeout for non-network errors - if (error instanceof Error && error.name === 'AbortError') { - if (attempt < maxRetries) { - const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000); - await new Promise(resolve => setTimeout(resolve, delay)); - continue; - } - throw new Error('Request timed out'); - } - - // Retry only on network/fetch errors - const status = isHttpError(error) ? error.status : undefined; - const nonRetryable = isHttpError(error) ? Boolean(error.nonRetryable) : false; - if (!nonRetryable && (status === undefined || status < 400 || status >= 500) && attempt < maxRetries) { - const delay = Math.min(1000 * Math.pow(2, attempt - 1), 5000); - await new Promise(resolve => setTimeout(resolve, delay)); - continue; - } - - throw lastError; - } - } - - throw lastError || new Error('All retry attempts failed'); -} - -type Props = { authorized: boolean }; - -export default function AdminPage({ authorized: initialAuthorized }: Props) { - const [authorized, setAuthorized] = useState(initialAuthorized); - const [password, setPassword] = useState(''); - const [address, setAddress] = useState(''); - const [phone, setPhone] = useState(''); - const [clearIpCooldowns, setClearIpCooldowns] = useState(true); // Default to true since IP cooldowns often block testing - const [loading, setLoading] = useState(false); - const [message, setMessage] = useState(''); - const [error, setError] = useState(''); - const [targetIp, setTargetIp] = useState(''); - const [ipError, setIpError] = useState(''); - const clearInFlightRef = useRef(false); - - // Simple IPv4/IPv6 validators - const isValidIPv4 = (ip: string) => /^(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)(?:\.(?:25[0-5]|2[0-4]\d|1\d\d|[1-9]?\d)){3}$/.test(ip); - const isValidIPv6 = (ip: string) => { - try { - // Use the browser's URL parsing for a quick sanity check; fallback to simple test - // Note: Prefer server-side net.isIP for true validation on the API route. - return ip.includes(':') && /^[0-9a-fA-F:.%]+$/.test(ip); - } catch { - return false; - } - }; - const isValidIp = (ip: string) => isValidIPv4(ip) || isValidIPv6(ip); - - async function handleLogin() { - if (!password.trim()) { - setError('Admin password required'); - return; - } - - try { - setLoading(true); - setError(''); - await postJson<{ ok: boolean }>('/api/admin/login', { password }); - setPassword(''); - setAuthorized(true); - } catch (e: unknown) { - const msg = e instanceof Error ? e.message : 'Login failed'; - setError(msg); - } finally { - setLoading(false); - } - } - - async function handleLogout() { - try { - setLoading(true); - await postJson<{ ok: boolean }>('/api/admin/logout', {}); - setAuthorized(false); - setMessage('Logged out'); - } catch (e) { - console.error('Logout failed:', e); - setError('Logout failed'); - } finally { - setLoading(false); - } - } - - async function handleClearUser() { - // Prevent accidental double-submits by ignoring while in flight - if (clearInFlightRef.current) return; - try { - setError(''); - setMessage(''); - setIpError(''); - if (clearIpCooldowns) { - const trimmed = targetIp.trim(); - const hasIdentity = (address.trim().length > 0) || (phone.trim().length > 0); - if (!hasIdentity && !trimmed) { - setError('Provide a target IP or an address/phone to clear IP cooldowns'); - return; - } - if (trimmed && !isValidIp(trimmed)) { - setIpError('Enter a valid IPv4 or IPv6 address'); - return; - } - } - clearInFlightRef.current = true; - setLoading(true); - - const result = await postJson<{ - ok: boolean; - message: string; - deletedKeys: number; - attemptedKeys: number; - debug?: { - keysAttempted: string[]; - addressKeys: number; - phoneKeys: number; - ipCooldownKeys: number; - }; - }>('/api/admin/clear-user', { - address: address.trim() || undefined, - phoneE164: phone.trim() || undefined, - clearIpCooldowns: clearIpCooldowns, - targetIp: clearIpCooldowns ? targetIp.trim() : undefined, - }); - - setMessage(result.message); - // Log debug info in development for transparency - if (result.debug) { - console.log('Admin clear debug info:', result.debug); - } - setAddress(''); - setPhone(''); - setTargetIp(''); - } catch (e: unknown) { - const msg = e instanceof Error ? e.message : 'Failed to clear user'; - console.error('Admin clear user error:', e); - setError(msg); - } finally { - setLoading(false); - clearInFlightRef.current = false; - } - } - - return ( -
-
-
- {!authorized ? ( - -
- - setPassword(e.target.value)} - placeholder="Enter your password" - autoComplete="current-password" - /> -
- {error &&

{error}

} - -
- ) : ( - -
- - setAddress(e.target.value)} - placeholder="0x123..." - /> -
- -
- - setPhone(value || '')} - placeholder="Enter phone number" - defaultCountry="US" - /> -
- -
- setClearIpCooldowns(e.target.checked)} - className="h-4 w-4 rounded border-input text-primary" - /> - -
- - {clearIpCooldowns && ( -
- - { - const v = e.target.value; - setTargetIp(v); - const trimmed = v.trim(); - if (trimmed.length === 0) { - setIpError(''); - } else { - setIpError(isValidIp(trimmed) ? '' : 'Enter a valid IPv4 or IPv6 address'); - } - }} - placeholder="127.0.0.1 or ::1" - /> - {ipError &&

{ipError}

} -
- )} - - {message &&

{message}

} - {error &&

{error}

} - -
- - -
-
- )} -
-
-
- ); -} - -export const getServerSideProps: GetServerSideProps = async (context: GetServerSidePropsContext) => { - const req = context.req; - // Next.js may not parse cookies on Node 19/Edge; ensure we handle both - const cookieHeader = req.headers?.cookie as string | undefined; - let token: string | undefined = req.cookies?.['admin_session']; - if (!token && typeof cookieHeader === 'string') { - const parts = cookieHeader.split(';'); - for (const p of parts) { - const [k, ...v] = p.trim().split('='); - if (k === 'admin_session') { - token = v.join('='); - break; - } - } - } - const authorized = verifyAdminToken(token); - return { props: { authorized } }; -}; diff --git a/web/src/pages/api/admin/clear-user.ts b/web/src/pages/api/admin/clear-user.ts deleted file mode 100644 index 70844a2..0000000 --- a/web/src/pages/api/admin/clear-user.ts +++ /dev/null @@ -1,180 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import net from 'node:net'; -import { z } from 'zod'; -import { kv } from '@vercel/kv'; -import { hashIdentifier } from '../../../../lib/hash'; -import { getHashedIpsForAddress, getHashedIpsForPhone } from '../../../../lib/kv'; -import { requireAdmin } from '../../../../lib/admin-auth'; -import { createRatelimit } from '../../../../lib/rate-limit'; - -const Body = z - .object({ - address: z.string().min(1).optional(), - phoneE164: z.string().min(5).optional(), - clearIpCooldowns: z.boolean().optional(), - targetIp: z.string().trim().optional(), - }) - .refine( - (data) => { - const hasIdentity = Boolean(data.address) || Boolean(data.phoneE164); - const wantsIpClear = Boolean(data.clearIpCooldowns); - const hasTargetIp = typeof data.targetIp === 'string' && data.targetIp.trim().length > 0; - // Valid if: provided address/phone for general clear, OR if requesting IP cooldown clear with either a target IP or identity to resolve from - return hasIdentity || (wantsIpClear && (hasTargetIp || hasIdentity)); - }, - { - message: 'Provide address or phoneE164, or include targetIp when clearing IP cooldowns', - path: ['address', 'phoneE164', 'targetIp'], - } - ); - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' }); - - if (!requireAdmin(req, res)) return; - - const parse = Body.safeParse(req.body); - if (!parse.success) { - const firstIssue = parse.error.issues?.[0]; - const message = firstIssue?.message || 'Invalid body'; - return res.status(400).json({ error: message }); - } - - const { address, phoneE164, clearIpCooldowns, targetIp } = parse.data; - const adminIp = (req.headers['cf-connecting-ip'] as string) || (req.headers['x-real-ip'] as string) || req.socket.remoteAddress || 'unknown'; - // Lightweight rate limit for clear operations - const clearLimit = createRatelimit('rl:admin:clear', 10, 60); // 10 per minute per project - const { success: allowClear } = await clearLimit.limit('all'); - if (!allowClear) return res.status(429).json({ error: 'Too many clear requests' }); - - const keysToDelete: string[] = []; - - if (address) { - const lowerAddr = address.toLowerCase(); - const hashedAddr = hashIdentifier('addr', lowerAddr); - keysToDelete.push( - `mint:address:${hashedAddr}`, - `mint:address:${lowerAddr}` // Legacy plaintext fallback - ); - } - - if (phoneE164) { - const hashedPhone = hashIdentifier('phone', phoneE164); - keysToDelete.push( - `mint:phone:${hashedPhone}`, - `mint:phone:${phoneE164}`, // Legacy plaintext fallback - `sms:code:${hashedPhone}`, - `sms:code:${phoneE164}`, // Legacy plaintext fallback - `sms:verified:${hashedPhone}`, - `sms:verified:${phoneE164}`, // Legacy plaintext fallback - `cd:sms:phone:${hashedPhone}`, - `cd:sms:phone:${phoneE164}` // Legacy plaintext fallback - ); - } - - if (clearIpCooldowns) { - // If a specific target IP is provided, clear its cooldowns (hashed + legacy plaintext) - const targetIpRaw = typeof targetIp === 'string' ? targetIp.trim() : undefined; - if (targetIpRaw) { - const isValidIp = net.isIP(targetIpRaw) > 0; - if (!isValidIp) { - return res.status(400).json({ error: 'Invalid targetIp' }); - } - try { - const ts = new Date().toISOString(); - console.info('[AUDIT] admin_clear_ip_cooldowns_intent', { ts, actor: adminIp, targetIp: targetIpRaw }); - } catch {} - const hashedIp = hashIdentifier('ip', targetIpRaw); - keysToDelete.push( - `cd:mint:ip:${hashedIp}`, - `cd:mint:ip:${targetIpRaw}`, - `cd:sms:ip:${hashedIp}`, - `cd:sms:ip:${targetIpRaw}` - ); - } - - // Also support resolving hashed IPs associated to the provided address/phone - const hashedIps: Set = new Set(); - try { - if (phoneE164) { - for (const h of await getHashedIpsForPhone(phoneE164)) hashedIps.add(h); - } - if (address) { - for (const h of await getHashedIpsForAddress(address)) hashedIps.add(h); - } - } catch {} - if (hashedIps.size > 0) { - for (const ipHash of hashedIps) { - keysToDelete.push(`cd:mint:ip:${ipHash}`, `cd:sms:ip:${ipHash}`); - } - } else if (!targetIpRaw) { - // If no targetIp was supplied and no associations were found, return a helpful error - return res.status(404).json({ error: 'No associated IP cooldowns found for the provided address/phone' }); - } - } - - // Delete all keys and get actual deletion count - let actualDeletedCount = 0; - if (keysToDelete.length > 0) { - try { - const deleteResult = await kv.del(...keysToDelete); - actualDeletedCount = typeof deleteResult === 'number' ? deleteResult : 0; - } catch (err) { - // Audit failure (avoid PII; hash already applied in keys) - try { - const ts = new Date().toISOString(); - const actor = req.headers['cf-connecting-ip'] || req.headers['x-real-ip'] || req.socket.remoteAddress || 'unknown'; - console.error('[AUDIT] admin_clear_user_failed', { ts, actor, attemptedKeys: keysToDelete.length, error: 'kv_del_failed' }); - } catch {} - console.error('Failed to delete keys in clear-user', { address, phoneE164, keysToDelete, err }); - return res.status(500).json({ error: 'Failed to delete some keys' }); - } - } - - // Debug info for development (derive counts from keysToDelete) - const debugInfo = process.env.NODE_ENV === 'development' ? ((): { - keysAttempted: string[]; - addressKeys: number; - phoneKeys: number; - ipCooldownKeys: number; - } => { - let addressKeys = 0; - let phoneKeys = 0; - let ipCooldownKeys = 0; - if (address) { - // Two address keys are added when address is provided - addressKeys = keysToDelete.filter((k) => k.startsWith('mint:address:')).length; - } - if (phoneE164) { - // Eight phone-related keys are added when phoneE164 is provided - const phonePrefixes = ['mint:phone:', 'sms:code:', 'sms:verified:', 'cd:sms:phone:']; - phoneKeys = keysToDelete.filter((k) => phonePrefixes.some((p) => k.startsWith(p))).length; - } - if (clearIpCooldowns) { - // Four IP cooldown keys are added when clearIpCooldowns is set - const ipPrefixes = ['cd:mint:ip:', 'cd:sms:ip:']; - ipCooldownKeys = keysToDelete.filter((k) => ipPrefixes.some((p) => k.startsWith(p))).length; - } - return { - keysAttempted: keysToDelete, - addressKeys, - phoneKeys, - ipCooldownKeys, - }; - })() : undefined; - - // Audit success - try { - const ts = new Date().toISOString(); - const actor = req.headers['cf-connecting-ip'] || req.headers['x-real-ip'] || req.socket.remoteAddress || 'unknown'; - console.info('[AUDIT] admin_clear_user_success', { ts, actor, attemptedKeys: keysToDelete.length, deletedKeys: actualDeletedCount }); - } catch {} - - return res.status(200).json({ - ok: true, - deletedKeys: actualDeletedCount, - attemptedKeys: keysToDelete.length, - message: `Successfully cleared ${actualDeletedCount} existing entries (checked ${keysToDelete.length} possible keys)`, - debug: debugInfo - }); -} diff --git a/web/src/pages/api/admin/login.ts b/web/src/pages/api/admin/login.ts deleted file mode 100644 index a13e570..0000000 --- a/web/src/pages/api/admin/login.ts +++ /dev/null @@ -1,47 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { z } from 'zod'; -import { AdminAuth, setAdminSessionCookie, createAdminToken } from '../../../../lib/admin-auth'; -import { getAdminPassword } from '../../../../lib/env'; -import { getClientIp } from '../../../../lib/request-ip'; -import { createRatelimit, ratelimitKeyForIp } from '../../../../lib/rate-limit'; -import { timingSafeEqual, createHash } from 'crypto'; - -const Body = z.object({ password: z.string().min(1) }); - -const loginRatelimit = createRatelimit('rl:admin:login', 5, 60); // 5 per minute per IP - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' }); - - // Rate limit by IP - const ip = getClientIp(req); - const key = ratelimitKeyForIp(ip); - const { success } = await loginRatelimit.limit(key); - if (!success) return res.status(429).json({ error: 'Too many login attempts' }); - - const parse = Body.safeParse(req.body); - if (!parse.success) return res.status(400).json({ error: 'Invalid body' }); - - const envPassword = getAdminPassword(); - if (!envPassword) return res.status(500).json({ error: 'ADMIN_PASSWORD not configured' }); - - // timing-safe compare of hashed values to normalize length - const providedHash = createHash('sha256').update(parse.data.password).digest(); - const expectedHash = createHash('sha256').update(envPassword).digest(); - const ok = timingSafeEqual(providedHash, expectedHash); - if (!ok) { - // Audit failed login attempt (do not log secrets) - try { - const ts = new Date().toISOString(); - const ipForLog = ip; - console.warn('[AUDIT] admin_login_failed', { ts, ip: ipForLog, reason: 'Invalid password' }); - } catch {} - return res.status(401).json({ error: 'Invalid password' }); - } - - const token = createAdminToken(); - setAdminSessionCookie(res, token, AdminAuth.DEFAULT_SESSION_TTL_SECONDS); - return res.status(200).json({ ok: true }); -} - - diff --git a/web/src/pages/api/admin/logout.ts b/web/src/pages/api/admin/logout.ts deleted file mode 100644 index 1ee7ba4..0000000 --- a/web/src/pages/api/admin/logout.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { clearAdminSessionCookie } from '../../../../lib/admin-auth'; - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' }); - // Strict CSRF protection: require Origin and validate protocol+host - const origin = req.headers['origin'] as string | undefined; - const host = req.headers['host']; - const expectedHost = typeof host === 'string' ? host : undefined; - if (!origin || !expectedHost) return res.status(403).json({ error: 'Invalid origin' }); - try { - const u = new URL(origin); - const isProd = process.env.NODE_ENV === 'production'; - if ((isProd && u.protocol !== 'https:') || u.host !== expectedHost) { - return res.status(403).json({ error: 'Invalid origin' }); - } - } catch { - return res.status(403).json({ error: 'Invalid origin' }); - } - - clearAdminSessionCookie(res); - return res.status(200).json({ ok: true }); -} - - diff --git a/web/src/pages/api/check-eligibility.ts b/web/src/pages/api/check-eligibility.ts deleted file mode 100644 index 84fb2fe..0000000 --- a/web/src/pages/api/check-eligibility.ts +++ /dev/null @@ -1,40 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { z } from 'zod'; -import { hasMinted, hasPhoneMinted, isPhoneVerified } from '../../../lib/kv'; -import { globalIpRatelimit } from '../../../lib/rate-limit'; -import { getClientIp } from '../../../lib/request-ip'; -import { hashIdentifier } from '../../../lib/hash'; - -const Body = z.object({ - address: z.string().min(1), - phoneE164: z.string().min(5), - authorAddress: z.string().min(1).optional(), -}); - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' }); - - // Global IP rate limiting - const ip = getClientIp(req); - const hashedIp = hashIdentifier('ip', ip); - const { success, limit, reset, remaining } = await globalIpRatelimit.limit(hashedIp); - res.setHeader('X-RateLimit-Limit', String(limit)); - res.setHeader('X-RateLimit-Remaining', String(remaining)); - res.setHeader('X-RateLimit-Reset', String(reset)); - if (!success) return res.status(429).json({ error: 'Too many requests' }); - - const parse = Body.safeParse(req.body); - if (!parse.success) return res.status(400).json({ error: 'Invalid body' }); - const { address, phoneE164 } = parse.data; - - const [mintedAddr, mintedPhone, verified] = await Promise.all([ - hasMinted(address), - hasPhoneMinted(phoneE164), - isPhoneVerified(phoneE164), - ]); - - const eligible = !mintedAddr && !mintedPhone && verified; - return res.status(200).json({ eligible, mintedAddr, mintedPhone, verified }); -} - - diff --git a/web/src/pages/api/debug/code.ts b/web/src/pages/api/debug/code.ts deleted file mode 100644 index de2e775..0000000 --- a/web/src/pages/api/debug/code.ts +++ /dev/null @@ -1,25 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -import { z } from "zod"; -import { readSmsCode } from "../../../../lib/kv"; -import { isProductionRuntime, shouldUseKvFallback } from "../../../../lib/sms"; - -const Body = z.object({ - phoneE164: z.string().min(5), -}); - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== "POST") return res.status(405).json({ error: "Method not allowed" }); - if (isProductionRuntime()) return res.status(404).json({ error: "Not found" }); - - const hdr = (req.headers["x-smoke-test-token"] as string) || ""; - if (!shouldUseKvFallback(hdr)) { - return res.status(401).json({ ok: false, match: false }); - } - - const parse = Body.safeParse(req.body); - if (!parse.success) return res.status(400).json({ error: "Invalid body" }); - const { phoneE164 } = parse.data; - - const code = await readSmsCode(phoneE164); - return res.status(200).json({ ok: true, code }); -} diff --git a/web/src/pages/api/mint.ts b/web/src/pages/api/mint.ts deleted file mode 100644 index 3bc2721..0000000 --- a/web/src/pages/api/mint.ts +++ /dev/null @@ -1,131 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { z } from 'zod'; -import { hasMinted, hasPhoneMinted, isPhoneVerified, markMinted, addIpAssociationForPhone, addIpAssociationForAddress } from '../../../lib/kv'; -import { getClientIp } from '../../../lib/request-ip'; -import { isMintIpInCooldown, setMintIpCooldown } from '../../../lib/cooldowns'; -import { env, requireEnv } from '../../../lib/env'; -import { MintPassV1Abi } from '../../../lib/abi'; -import { Wallet, JsonRpcProvider, Contract } from 'ethers'; -import { hashIdentifier } from '../../../lib/hash'; -import { globalIpRatelimit } from '../../../lib/rate-limit'; - -const Body = z.object({ - address: z.string().min(1), - phoneE164: z.string().min(5), - tokenType: z.number().int().min(0).max(65535).optional(), - authorAddress: z.string().min(1), -}); - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' }); - - const parse = Body.safeParse(req.body); - if (!parse.success) return res.status(400).json({ error: 'Invalid body' }); - const { address, phoneE164, tokenType = 0 } = parse.data; - const ip = getClientIp(req); - - // Global IP rate limiting - const hashedIp = hashIdentifier('ip', ip); - const { success, limit, reset, remaining } = await globalIpRatelimit.limit(hashedIp); - res.setHeader('X-RateLimit-Limit', String(limit)); - res.setHeader('X-RateLimit-Remaining', String(remaining)); - res.setHeader('X-RateLimit-Reset', String(reset)); - if (!success) return res.status(429).json({ error: 'Too many requests' }); - - const [mintedAddr, mintedPhone, verified] = await Promise.all([ - hasMinted(address), - hasPhoneMinted(phoneE164), - isPhoneVerified(phoneE164), - ]); - - if (!verified) return res.status(400).json({ error: 'Phone not verified' }); - if (mintedAddr || mintedPhone) return res.status(400).json({ error: 'Already minted' }); - - // Optional IP-based mint cooldown - if (await isMintIpInCooldown(ip)) { - return res.status(429).json({ error: 'Mint cooldown active for this IP' }); - } - - // Derive ISO country code from edge headers if present (available for future geo-blocking) - // const hdrCountry = (req.headers['x-vercel-ip-country'] as string) || ''; - // const country2 = (hdrCountry || '').toUpperCase(); // Available for future use - - // If on-chain envs are configured, perform on-chain mint; otherwise, stub-mark as minted - let txHash: string | null = null; - if ( - env.MINTER_PRIVATE_KEY && - env.BASE_SEPOLIA_RPC_URL && - env.MINTPASSV1_ADDRESS_BASE_SEPOLIA - ) { - try { - const provider = new JsonRpcProvider(requireEnv('BASE_SEPOLIA_RPC_URL')); - const wallet = new Wallet(requireEnv('MINTER_PRIVATE_KEY'), provider); - const contract = new Contract(requireEnv('MINTPASSV1_ADDRESS_BASE_SEPOLIA'), MintPassV1Abi, wallet) as unknown as { - estimateGas: { mint: (to: string, tokenType: number) => Promise }; - mint: ( - to: string, - tokenType: number, - overrides?: { gasLimit?: bigint } - ) => Promise<{ hash: string; wait: () => Promise<{ hash?: string; status?: number; transactionHash?: string }>; }>; - }; - // Ethers v6 compatibility: estimateGas helpers may be stripped depending on build - // Use a narrow contract type and fall back to provider auto-estimation when unavailable - type MintContract = { - estimateGas?: { mint?: (to: string, tokenType: number) => Promise }; - mint: ( - to: string, - tokenType: number, - overrides?: { gasLimit?: bigint } - ) => Promise<{ hash: string; wait: () => Promise<{ hash?: string; status?: number; transactionHash?: string }>; }>; - }; - const mintContract = contract as unknown as MintContract; - let gasOverrides: { gasLimit?: bigint } | undefined; - try { - const estimated = await mintContract.estimateGas?.mint?.(address, tokenType); - if (typeof estimated === 'bigint') { - gasOverrides = { gasLimit: estimated + (estimated / BigInt(5)) }; - } - } catch (estErr) { - console.warn('[mint] estimateGas.mint failed; proceeding without overrides', { - address, - tokenType, - err: estErr instanceof Error ? estErr.message : String(estErr), - }); - gasOverrides = undefined; - } - const tx = gasOverrides - ? await mintContract.mint(address, tokenType, gasOverrides) - : await mintContract.mint(address, tokenType); - const receipt = await tx.wait(); - const status = receipt.status; - if (typeof status === 'number' && status !== 1) { - console.error('[mint] Receipt status not successful', { hash: tx.hash, address, tokenType, status }); - return res.status(500).json({ error: 'On-chain mint failed (status)' }); - } - txHash = receipt?.transactionHash ?? receipt?.hash ?? tx.hash; - } catch (err) { - console.error('[mint] On-chain mint error', { - address, - tokenType, - rpc: env.BASE_SEPOLIA_RPC_URL?.slice(0, 16), - contract: env.MINTPASSV1_ADDRESS_BASE_SEPOLIA, - err, - }); - return res.status(500).json({ error: err instanceof Error ? err.message : 'On-chain mint failed' }); - } - } - - await markMinted(address, phoneE164); - await setMintIpCooldown(ip); - // Index hashed IP associations for phone and address (mint attempt) - try { - await Promise.all([ - addIpAssociationForPhone(phoneE164, ip), - addIpAssociationForAddress(address, ip), - ]); - } catch {} - - return res.status(200).json({ ok: true, txHash, tokenType }); -} - - diff --git a/web/src/pages/api/pre-check-eligibility.ts b/web/src/pages/api/pre-check-eligibility.ts deleted file mode 100644 index 2c4f6af..0000000 --- a/web/src/pages/api/pre-check-eligibility.ts +++ /dev/null @@ -1,45 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from 'next'; -import { z } from 'zod'; -import { hasMinted, hasPhoneMinted } from '../../../lib/kv'; -import { globalIpRatelimit } from '../../../lib/rate-limit'; -import { getClientIp } from '../../../lib/request-ip'; -import { hashIdentifier } from '../../../lib/hash'; - -const Body = z.object({ - address: z.string().min(1), - phoneE164: z.string().min(5), -}); - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== 'POST') return res.status(405).json({ error: 'Method not allowed' }); - - // Global IP rate limiting - const ip = getClientIp(req); - const hashedIp = hashIdentifier('ip', ip); - const { success, limit, reset, remaining } = await globalIpRatelimit.limit(hashedIp); - res.setHeader('X-RateLimit-Limit', String(limit)); - res.setHeader('X-RateLimit-Remaining', String(remaining)); - res.setHeader('X-RateLimit-Reset', String(reset)); - if (!success) return res.status(429).json({ error: 'Too many requests' }); - - const parse = Body.safeParse(req.body); - if (!parse.success) return res.status(400).json({ error: 'Invalid body' }); - const { address, phoneE164 } = parse.data; - - const [mintedAddr, mintedPhone] = await Promise.all([ - hasMinted(address), - hasPhoneMinted(phoneE164), - ]); - - const eligible = !mintedAddr && !mintedPhone; - return res.status(200).json({ - eligible, - mintedAddr, - mintedPhone, - reason: !eligible - ? mintedAddr - ? 'Address has already minted a MintPass NFT' - : 'Phone number has already been used to mint a MintPass NFT' - : null - }); -} diff --git a/web/src/pages/api/sms/send.ts b/web/src/pages/api/sms/send.ts deleted file mode 100644 index 73b2f1c..0000000 --- a/web/src/pages/api/sms/send.ts +++ /dev/null @@ -1,174 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -import { z } from "zod"; -import { globalIpRatelimit } from "../../../../lib/rate-limit"; -import { - saveSmsCode, - addIpAssociationForPhone, - addIpAssociationForAddress, -} from "../../../../lib/kv"; -import { assessIpReputation } from "../../../../lib/ip-reputation"; -import { analyzePhone } from "../../../../lib/phone-intel"; -import { getClientIp } from "../../../../lib/request-ip"; -import { - isSmsSendInCooldown, - setSmsSendCooldown, - getSmsSendCooldownRemaining, -} from "../../../../lib/cooldowns"; -import { - isProductionRuntime, - isVerifyConfigured, - startSmsVerification, - shouldUseKvFallback, - type SmsProviderError, -} from "../../../../lib/sms"; -import { hashIdentifier } from "../../../../lib/hash"; - -const Body = z.object({ - phoneE164: z.string().min(5), - address: z.string().min(1), -}); - -function generateCode(): string { - return Math.floor(100000 + Math.random() * 900000).toString(); -} - -async function readCooldownRemaining(ip: string, phoneE164: string): Promise { - try { - return await getSmsSendCooldownRemaining(ip, phoneE164); - } catch { - return 0; - } -} - -function toClientProviderError(providerError: SmsProviderError | undefined) { - if (!providerError) return undefined; - return { - provider: providerError.provider, - status: providerError.status, - errorCode: providerError.errorCode, - errorMessage: providerError.errorMessage, - // Backwards-compatible aliases for existing client-side error rendering. - code: providerError.errorCode, - message: providerError.errorMessage, - }; -} - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== "POST") return res.status(405).json({ error: "Method not allowed" }); - - // Rate limit by IP - const ip = getClientIp(req); - const hashedIp = hashIdentifier("ip", ip); - const { success, limit, reset, remaining } = await globalIpRatelimit.limit(hashedIp); - res.setHeader("X-RateLimit-Limit", String(limit)); - res.setHeader("X-RateLimit-Remaining", String(remaining)); - res.setHeader("X-RateLimit-Reset", String(reset)); - if (!success) return res.status(429).json({ error: "Too many requests" }); - - const parse = Body.safeParse(req.body); - if (!parse.success) return res.status(400).json({ error: "Invalid body" }); - const { phoneE164, address } = parse.data; - - // Reject VPNs/proxies/cloud-provider IPs if IP intelligence is configured - const rep = await assessIpReputation(req); - if (rep.isVpnOrProxy || rep.isCloudProvider) { - return res.status(400).json({ error: "VPNs and proxies are not allowed" }); - } - - // Cooldown checks per IP and phone - if (await isSmsSendInCooldown(ip, phoneE164)) { - let remainingSeconds = 0; - try { - remainingSeconds = await getSmsSendCooldownRemaining(ip, phoneE164); - } catch { - remainingSeconds = 0; - } - const remainingTime = remainingSeconds > 0 ? `${remainingSeconds}s` : ""; - const errorMessage = remainingTime - ? `Please wait ${remainingTime} before requesting another code` - : "Please wait before requesting another code"; - if (remainingSeconds > 0) res.setHeader("Retry-After", String(remainingSeconds)); - return res.status(429).json({ error: errorMessage, cooldownSeconds: remainingSeconds }); - } - - // Reject disposable/VOIP/high-risk numbers if phone intelligence is configured - const pcheck = await analyzePhone(phoneE164); - // Allow high-risk numbers only in Preview environment to enable testing - const isPreviewEnv = (process.env.VERCEL_ENV || "").toLowerCase() === "preview"; - if (!isPreviewEnv && pcheck.isHighRisk) { - return res.status(400).json({ error: "Phone number not eligible" }); - } - - const smokeHeader = (req.headers["x-smoke-test-token"] as string) || ""; - const useKvFallback = shouldUseKvFallback(smokeHeader); - const mode: "verify" | "kv-fallback" = useKvFallback ? "kv-fallback" : "verify"; - if (mode === "verify" && !isVerifyConfigured()) { - const errorMessage = isProductionRuntime() - ? "SMS verification service unavailable." - : "SMS verification service unavailable. Use the smoke fallback token in non-production."; - return res.status(503).json({ error: errorMessage }); - } - - let fallbackCode: string | undefined; - if (mode === "kv-fallback") { - fallbackCode = generateCode(); - await saveSmsCode(phoneE164, fallbackCode); - } - - // Keep cooldown writes at send time for both verify and fallback modes. - await setSmsSendCooldown(ip, phoneE164); - - // Index hashed IP associations for phone and address for admin tooling - try { - await Promise.all([ - addIpAssociationForPhone(phoneE164, ip), - addIpAssociationForAddress(address, ip), - ]); - } catch {} - - if (mode === "kv-fallback") { - return res.status(200).json({ - ok: true, - mode, - ...(fallbackCode ? { debugCode: fallbackCode } : {}), - }); - } - - const result = await startSmsVerification(phoneE164, { - timeoutMs: 5000, - maxRetries: 1, - baseDelayMs: 300, - deviceIp: ip, - }); - - if (!result.ok) { - const remainingSeconds = await readCooldownRemaining(ip, phoneE164); - const providerError = toClientProviderError(result.providerError); - const isClientError = - typeof providerError?.status === "number" && - providerError.status >= 400 && - providerError.status < 500; - - const statusCode = isClientError ? 400 : 502; - const errorMessage = isClientError - ? "Unable to deliver SMS to this number. Service is not available for this destination yet." - : "SMS provider error. Please try again later."; - - // Log minimal diagnostic info with hashed phone (no PII or OTP values). - try { - console.warn("SMS send failed", { - phone: hashIdentifier("phone", phoneE164), - status: providerError?.status, - provider: providerError?.provider, - code: providerError?.errorCode, - message: providerError?.errorMessage, - }); - } catch {} - - return res - .status(statusCode) - .json({ error: errorMessage, cooldownSeconds: remainingSeconds, providerError }); - } - - return res.status(200).json({ ok: true, sid: result.sid, mode }); -} diff --git a/web/src/pages/api/sms/verify.ts b/web/src/pages/api/sms/verify.ts deleted file mode 100644 index d63caf8..0000000 --- a/web/src/pages/api/sms/verify.ts +++ /dev/null @@ -1,120 +0,0 @@ -import type { NextApiRequest, NextApiResponse } from "next"; -import { z } from "zod"; -import { - clearSmsCode, - markPhoneVerified, - readSmsCode, - addIpAssociationForPhone, -} from "../../../../lib/kv"; -import { globalIpRatelimit } from "../../../../lib/rate-limit"; -import { getClientIp } from "../../../../lib/request-ip"; -import { hashIdentifier } from "../../../../lib/hash"; -import { - checkSmsVerification, - isProductionRuntime, - isVerifyConfigured, - shouldUseKvFallback, - type SmsProviderError, -} from "../../../../lib/sms"; - -const Body = z.object({ - phoneE164: z.string().min(5), - code: z.string().length(6), -}); - -function toClientProviderError(providerError: SmsProviderError | undefined) { - if (!providerError) return undefined; - return { - provider: providerError.provider, - status: providerError.status, - errorCode: providerError.errorCode, - errorMessage: providerError.errorMessage, - // Backwards-compatible aliases for existing client-side error rendering. - code: providerError.errorCode, - message: providerError.errorMessage, - }; -} - -export default async function handler(req: NextApiRequest, res: NextApiResponse) { - if (req.method !== "POST") return res.status(405).json({ error: "Method not allowed" }); - - // Global IP rate limiting - const ip = getClientIp(req); - const hashedIp = hashIdentifier("ip", ip); - const { success, limit, reset, remaining } = await globalIpRatelimit.limit(hashedIp); - res.setHeader("X-RateLimit-Limit", String(limit)); - res.setHeader("X-RateLimit-Remaining", String(remaining)); - res.setHeader("X-RateLimit-Reset", String(reset)); - if (!success) return res.status(429).json({ error: "Too many requests" }); - - const parse = Body.safeParse(req.body); - if (!parse.success) return res.status(400).json({ error: "Invalid body" }); - const { phoneE164, code } = parse.data; - - const smokeHeader = (req.headers["x-smoke-test-token"] as string) || ""; - const useKvFallback = shouldUseKvFallback(smokeHeader); - - if (useKvFallback) { - const stored = await readSmsCode(phoneE164); - if (!stored) { - return res.status(400).json({ error: "Code expired or invalid. Request a new code." }); - } - - // Normalize both sides to string to tolerate provider/SDK returning numbers - const storedStr = typeof stored === "string" ? stored : String(stored); - const codeStr = String(code); - if (storedStr !== codeStr) { - return res - .status(400) - .json({ error: "Invalid code", debug: { posted: codeStr, stored: storedStr } }); - } - } else { - if (!isVerifyConfigured()) { - const errorMessage = isProductionRuntime() - ? "SMS verification service unavailable." - : "SMS verification service unavailable. Use the smoke fallback token in non-production."; - return res.status(503).json({ error: errorMessage }); - } - - const verifyResult = await checkSmsVerification(phoneE164, code, { - timeoutMs: 5000, - maxRetries: 1, - baseDelayMs: 300, - deviceIp: ip, - }); - if (!verifyResult.ok) { - if (verifyResult.reason === "invalid_code") { - return res.status(400).json({ error: "Invalid code" }); - } - if (verifyResult.reason === "expired_or_invalid") { - return res.status(400).json({ error: "Code expired or invalid. Request a new code." }); - } - - const providerError = toClientProviderError(verifyResult.providerError); - try { - console.warn("SMS verify failed", { - phone: hashIdentifier("phone", phoneE164), - status: providerError?.status, - provider: providerError?.provider, - code: providerError?.errorCode, - message: providerError?.errorMessage, - }); - } catch {} - - return res.status(502).json({ - error: "SMS provider error. Please try again later.", - providerError, - }); - } - } - - await markPhoneVerified(phoneE164); - // Always clear fallback KV code after successful verification. - await clearSmsCode(phoneE164); - // Index hashed IP association on verify as well (covers flows where send indexing failed) - try { - const ip = getClientIp(req); - await addIpAssociationForPhone(phoneE164, ip); - } catch {} - return res.status(200).json({ ok: true }); -} diff --git a/web/src/pages/index.tsx b/web/src/pages/index.tsx deleted file mode 100644 index 5d1e1a8..0000000 --- a/web/src/pages/index.tsx +++ /dev/null @@ -1,37 +0,0 @@ -import Link from 'next/link'; -import { useRouter } from 'next/router'; -import { Header } from '../components/header'; -import { Footer } from '../components/footer'; -import { PageCard } from '../components/page-card'; -import { RainbowButton } from '../components/magicui/rainbow-button'; - -export default function Home() { - const router = useRouter(); - const hideNft = router.query['hide-nft'] === 'true'; - - return ( -
-
-
- -

- {hideNft - ? "Verify your phone and get authenticated for secure access." - : "Verify your phone and receive your authentication NFT." - } -

- - Start Verification - -
-
-
-
- ); -} diff --git a/web/src/pages/privacy-policy.tsx b/web/src/pages/privacy-policy.tsx deleted file mode 100644 index 3b8704c..0000000 --- a/web/src/pages/privacy-policy.tsx +++ /dev/null @@ -1,114 +0,0 @@ -import Link from 'next/link'; -import { Header } from '../components/header'; -import { Footer } from '../components/footer'; -import { PageCard } from '../components/page-card'; - -export default function PrivacyPolicy() { - return ( -
-
-
- -

- This document describes how the MintPass website and backend handle data. MintPass is operated by{' '} - - Bitsocial - - {' '}This is provided for transparency and is not legal advice. -

- -
-

Summary

-
    -
  • No marketing analytics. No sale of personal data.
  • -
  • Minimal operational data only: verification codes, verification markers, rate-limit and cooldown keys, and mint association records.
  • -
  • Phone numbers and IPs are stored as HMAC-SHA256 digests when a hash pepper is configured.
  • -
  • SMS codes are short‑lived; verification markers expire shortly after use.
  • -
  • Mint association (wallet ↔ phone) persists to enforce anti-Sybil guarantees.
  • -
-
- -
-

Data We Process

-
    -
  • - Phone number (E.164): used to send and verify one‑time SMS codes. Stored as a hashed key when HASH_PEPPER is set. The code value itself is temporary. -
  • -
  • - IP address: used for global rate limits and cooldowns. Stored as a hashed key when HASH_PEPPER is set. -
  • -
  • - Ethereum address: used to check and record whether a wallet has minted an authentication NFT. -
  • -
  • - Optional IP/phone reputation signals if you enable providers (e.g., VPN/Proxy or VOIP checks). These are used to block abuse and are not retained beyond the result state. -
  • -
-
- -
-

Retention

-
    -
  • SMS codes: ~5 minutes TTL.
  • -
  • SMS verified markers: short TTL (minutes) after successful verification.
  • -
  • Rate‑limit and cooldown keys (IP/phone): short TTL as configured in the environment.
  • -
  • Mint association (wallet and phone): retained to prevent duplicate mints and preserve anti-Sybil guarantees.
  • -
-
- -
-

“No‑logs” Clarification

-

- MintPass uses a minimal‑data model rather than a strict "no‑logs" policy. We avoid server request logging for analytics and do not profile users. However, we must keep short‑lived operational keys (e.g., OTPs, verification markers, rate‑limits/cooldowns) and a persistent mint association record to protect against abuse. This means MintPass is not "strict no‑logs," but it is "no analytics, minimal operational data." -

-
- -
-

Infrastructure

-

- The site is hosted on Vercel. Operational state is stored in Upstash Redis (KV). Regions are configured to US‑East (iad1) in the reference setup. SMS delivery is via a provider such as Twilio if configured. The code is open source; deployments are configured to align with the repository, but users should consider the trust assumptions inherent in any hosted service. -

-
- -
-

Your Choices

-
    -
  • You can choose not to use MintPass, in which case no data is collected.
  • -
  • You can request deletion of verification cooldowns and related state via the admin tooling where appropriate; note that mint association records are retained by design.
  • -
-
- -
-

Contact

-

- For questions about this policy, open an issue on the project repository or contact{' '} - - Bitsocial - - . See the project README for details. -

-
- -
- - Terms and Conditions - -
-
-
-
-
- ); -} - - diff --git a/web/src/pages/request/[eth-address].tsx b/web/src/pages/request/[eth-address].tsx deleted file mode 100644 index b58bfe0..0000000 --- a/web/src/pages/request/[eth-address].tsx +++ /dev/null @@ -1,20 +0,0 @@ -import { useRouter } from 'next/router'; -import type { GetServerSideProps } from 'next'; -import RequestPage from '../request'; - -type RequestWithEthAddressProps = { - isNorthAmerica: boolean; -}; - -export default function RequestWithEthAddress({ isNorthAmerica }: RequestWithEthAddressProps) { - const router = useRouter(); - const { 'eth-address': ethAddress } = router.query as { 'eth-address'?: string }; - return ; -} - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const countryHeader = (ctx.req.headers['x-vercel-ip-country'] as string) || ''; - const country = countryHeader.toUpperCase(); - const isNorthAmerica = country === 'US' || country === 'CA'; - return { props: { isNorthAmerica } }; -}; diff --git a/web/src/pages/request/index.tsx b/web/src/pages/request/index.tsx deleted file mode 100644 index e27d7d1..0000000 --- a/web/src/pages/request/index.tsx +++ /dev/null @@ -1,501 +0,0 @@ -import { useEffect, useState } from "react"; -import type { GetServerSideProps } from "next"; -import Link from "next/link"; -import { useRouter } from "next/router"; -import { Button } from "../../components/ui/button"; -import { Input } from "../../components/ui/input"; -import { PhoneInput, UNSUPPORTED_COUNTRIES } from "../../components/ui/phone-input"; -import * as RPNInput from "react-phone-number-input"; -import { - InputOTP, - InputOTPGroup, - InputOTPSlot, - InputOTPSeparator, -} from "../../components/ui/input-otp"; -import { Label } from "../../components/ui/label"; -import { Header } from "../../components/header"; -import { Footer } from "../../components/footer"; -import { PageCard } from "../../components/page-card"; -import { ConfettiCelebration } from "../../components/confetti-celebration"; -import { ExternalLink } from "lucide-react"; - -async function postJson(path: string, body: unknown, opts?: { timeoutMs?: number }): Promise { - const timeoutMs = - typeof opts?.timeoutMs === "number" && opts.timeoutMs > 0 ? opts.timeoutMs : 10000; - const controller = new AbortController(); - const timer = setTimeout(() => controller.abort(), timeoutMs); - try { - const res = await fetch(path, { - method: "POST", - headers: { "content-type": "application/json" }, - body: JSON.stringify(body), - signal: controller.signal, - }); - const json = (await res.json().catch(() => ({}))) as unknown; - if (!res.ok) { - const data = json as { error?: string; cooldownSeconds?: unknown; providerError?: unknown }; - const errMsg = data?.error || "Request failed"; - const error = new Error(errMsg) as Error & { - cooldownSeconds?: number; - providerError?: unknown; - status?: number; - }; - error.status = res.status; - const cooldownSecondsValue = data?.cooldownSeconds; - if (typeof cooldownSecondsValue === "number") { - error.cooldownSeconds = cooldownSecondsValue; - } - const providerErrorValue = (data as { providerError?: unknown })?.providerError; - if (providerErrorValue && typeof providerErrorValue === "object") { - (error as { providerError?: unknown }).providerError = providerErrorValue; - } - throw error; - } - return json as T; - } catch (e: unknown) { - const name = (e as { name?: string } | null)?.name || ""; - if (name === "AbortError") { - throw new Error("Network timeout. Please try again."); - } - throw e as Error; - } finally { - clearTimeout(timer); - } -} - -export default function RequestPage({ - prefilledAddress = "", - isNorthAmerica = false, -}: { - prefilledAddress?: string; - isNorthAmerica?: boolean; -}) { - const router = useRouter(); - const [address, setAddress] = useState(""); - const [phone, setPhone] = useState(""); - const [code, setCode] = useState(""); - const [step, setStep] = useState<"enter" | "code" | "done">("enter"); - const [loading, setLoading] = useState(false); - const [error, setError] = useState(""); - const [txHash, setTxHash] = useState(null); - const [cooldownSeconds, setCooldownSeconds] = useState(0); - const [selectedCountry, setSelectedCountry] = useState(undefined); - - // Parse query parameters for demo customization - const hideNft = router.query["hide-nft"] === "true"; - const hideAddress = router.query["hide-address"] !== "false"; // defaults to true - - // Determine if address is prefilled from props or URL - const addressFromQuery = (router.query["eth-address"] as string) || ""; - const isAddressPrefilled = !!(prefilledAddress || addressFromQuery); - const prefilledAddressValue = prefilledAddress || addressFromQuery; - - // Determine if address input should be shown - const shouldShowAddressInput = !hideAddress || !isAddressPrefilled; - - useEffect(() => { - // Hydrate address from query if not passed as prop - const initial = prefilledAddressValue; - if (initial) setAddress(initial); - }, [prefilledAddressValue]); - - // Navigation protection during SMS verification - const isVerificationInProgress = step === "code" || (loading && step === "enter"); - - // Protect against tab closing during verification - useEffect(() => { - const handleBeforeUnload = (e: BeforeUnloadEvent) => { - if (isVerificationInProgress) { - e.preventDefault(); - e.returnValue = "You have an SMS verification in progress. Are you sure you want to leave?"; - return e.returnValue; - } - }; - - window.addEventListener("beforeunload", handleBeforeUnload); - return () => window.removeEventListener("beforeunload", handleBeforeUnload); - }, [isVerificationInProgress]); - - // Protect against navigation during verification - useEffect(() => { - const handleRouteChangeStart = (url: string) => { - if (isVerificationInProgress && !url.startsWith("/request")) { - const confirmed = window.confirm( - "You have an SMS verification in progress. Are you sure you want to leave?", - ); - if (!confirmed) { - router.events.emit("routeChangeError"); - throw "Route change aborted by user"; - } - } - }; - - router.events.on("routeChangeStart", handleRouteChangeStart); - return () => router.events.off("routeChangeStart", handleRouteChangeStart); - }, [router.events, isVerificationInProgress]); - - // Countdown timer effect - useEffect(() => { - if (cooldownSeconds > 0) { - const timer = setInterval(() => { - setCooldownSeconds((prev) => { - if (prev <= 1) { - setError(""); // Clear error when countdown reaches 0 - return 0; - } - return prev - 1; - }); - }, 1000); - - return () => clearInterval(timer); - } - }, [cooldownSeconds]); - - // Simple calculation during rendering (no need for useMemo) - // const canVerify = code.trim().length === 6; - - // Check if selected country is supported by SMS provider - const isCountrySupported = - !selectedCountry || !UNSUPPORTED_COUNTRIES.includes(selectedCountry as RPNInput.Country); - - function handleOtpComplete(value: string) { - if (loading) return; - const normalized = (value || "").trim(); - if (normalized.length === 6) { - setCode(normalized); - void handleVerifyAndMint(); - } - } - - async function handleSendCodeClick() { - // Determine current address based on whether input is shown and has value - const currentAddress = shouldShowAddressInput - ? address.trim() || prefilledAddressValue - : prefilledAddressValue; - - // Validate address - if (!currentAddress || currentAddress.trim().length === 0) { - setError("Please enter an Ethereum address"); - return; - } - - // Validate phone - if (!phone || phone.length < 5) { - setError("Please enter a valid phone number"); - return; - } - - // All validations passed, check eligibility and send code - await handleCheckEligibilityAndSendCode(currentAddress); - } - - async function handleCheckEligibilityAndSendCode(currentAddress: string) { - try { - setLoading(true); - setError(""); - - // First check eligibility - const result = await postJson<{ - eligible: boolean; - reason?: string; - }>("/api/pre-check-eligibility", { address: currentAddress.trim(), phoneE164: phone.trim() }); - - if (!result.eligible) { - if (result.reason) { - setError(result.reason); - } else { - setError("Not eligible to mint"); - } - return; - } - - // If eligible, send SMS code - await postJson<{ - ok: true; - sid?: string; - mode: "verify" | "kv-fallback"; - debugCode?: string; - }>("/api/sms/send", { phoneE164: phone, address: currentAddress }, { timeoutMs: 15000 }); - setStep("code"); - } catch (e: unknown) { - if (e instanceof Error) { - const errorWithCooldown = e as Error & { - status?: number; - cooldownSeconds?: number; - providerError?: { - provider?: string; - status?: number; - code?: number | string; - message?: string; - errorCode?: number | string; - errorMessage?: string; - }; - }; - const pe = errorWithCooldown.providerError; - const providerCode = pe?.errorCode ?? pe?.code; - const providerMessage = pe?.errorMessage ?? pe?.message; - // Prefer provider message/code if present - if (pe && (providerMessage || providerCode !== undefined)) { - const prov = pe.provider ? `${pe.provider} ` : ""; - const codePart = - providerCode !== undefined && providerCode !== null - ? ` (code ${String(providerCode)})` - : ""; - const detail = `${prov}${providerMessage || "delivery error"}${codePart}`; - setError(`${e.message} — ${detail}`); - } else if ( - errorWithCooldown.status === 429 && - typeof errorWithCooldown.cooldownSeconds === "number" && - errorWithCooldown.cooldownSeconds > 0 - ) { - // Only show cooldown countdown on explicit 429 - setCooldownSeconds(errorWithCooldown.cooldownSeconds); - setError(e.message); - } else { - // Generic error fallback - setError(e.message); - } - } else { - setError("Failed to send code"); - } - } finally { - setLoading(false); - } - } - - async function handleVerifyAndMint() { - try { - setError(""); - setLoading(true); - const currentAddress = shouldShowAddressInput - ? address.trim() || prefilledAddressValue - : prefilledAddressValue; - - await postJson("/api/sms/verify", { phoneE164: phone, code }); - const elig = await postJson<{ - eligible: boolean; - mintedAddr: boolean; - mintedPhone: boolean; - verified: boolean; - }>("/api/check-eligibility", { address: currentAddress, phoneE164: phone }); - - if (!elig.eligible) { - if (!elig.verified) { - setError("Phone number not verified"); - } else if (elig.mintedAddr) { - setError("Address has already minted the authentication NFT"); - } else if (elig.mintedPhone) { - setError("Phone number has already been used to mint the authentication NFT"); - } else { - setError("Not eligible to mint"); - } - return; - } - const mint = await postJson<{ ok: boolean; txHash?: string }>("/api/mint", { - address: currentAddress, - phoneE164: phone, - authorAddress: currentAddress, - }); - setTxHash(mint.txHash || null); - setStep("done"); - } catch (e: unknown) { - const msg = e instanceof Error ? e.message : "Failed to verify or mint"; - setError(msg); - } finally { - setLoading(false); - } - } - - return ( -
-
- {step === "done" && } -
- - {step === "enter" && ( - - )} - - ) : undefined - } - > - {step === "enter" && ( -
- {shouldShowAddressInput && ( -
- - { - setAddress(e.target.value); - // Clear error and cooldown on input change - setCooldownSeconds(0); - setError(""); - }} - placeholder="0x..." - disabled={loading} - /> -
- )} -
- - { - const next = value || ""; - setPhone(next); - // Clear error and cooldown on input change - setCooldownSeconds(0); - setError(""); - }} - onCountryChange={(country) => { - setSelectedCountry(country); - // Clear error when country changes - setError(""); - }} - placeholder="Enter phone number" - defaultCountry="US" - disabled={loading} - /> -
- {isNorthAmerica ? ( -

- By clicking “Send code”, you agree to the{" "} - - Terms and Conditions - {" "} - and{" "} - - Privacy Policy - {" "} - and consent to one-time phone verification via SMS. Message and data rates may - apply. -

- ) : ( -

- By clicking “Send code”, you agree to the{" "} - - Terms and Conditions - {" "} - and{" "} - - Privacy Policy - - . -

- )} - {(error || !isCountrySupported || cooldownSeconds > 0) && ( -

- {!isCountrySupported - ? "SMS verification is not available for the selected country due to security restrictions." - : cooldownSeconds > 0 - ? `Please wait ${cooldownSeconds}s before requesting another code` - : error} -

- )} -
- )} - - {step === "code" && ( -
-
- -
- - - - - - - - - - - - - -
-

- {loading - ? "Verifying... please don't close this page" - : "Please enter the 6-digit code to proceed with verification"} -

-
- {error &&

{error}

} -
- )} - - {step === "done" && ( -
-
-

- You are now authenticated by all communities that use MintPass as anti-spam - challenge. You can close this page and head back to the Bitsocial application of - your choice. -

-
- {!hideNft && ( - <> - {txHash ? ( - - ) : ( -

- On-chain mint not configured; recorded as minted. -

- )} - - )} -
- )} -
-
-
-
- ); -} - -export const getServerSideProps: GetServerSideProps = async (ctx) => { - const countryHeader = (ctx.req.headers["x-vercel-ip-country"] as string) || ""; - const country = countryHeader.toUpperCase(); - const isNorthAmerica = country === "US" || country === "CA"; - return { props: { isNorthAmerica } }; -}; diff --git a/web/src/pages/terms-and-conditions.tsx b/web/src/pages/terms-and-conditions.tsx deleted file mode 100644 index 321f6c7..0000000 --- a/web/src/pages/terms-and-conditions.tsx +++ /dev/null @@ -1,75 +0,0 @@ -import Link from 'next/link'; -import { Header } from '../components/header'; -import { Footer } from '../components/footer'; -import { PageCard } from '../components/page-card'; - -export default function TermsAndConditions() { - return ( -
-
-
- -

- Please read these terms carefully before using MintPass. MintPass is operated by{' '} - - Bitsocial - -

- -
-

Service

-

- MintPass provides an authentication NFT minting flow used by participating applications. The service verifies a phone number with an SMS code and, if eligible, mints an NFT to a provided Ethereum address (or records an equivalent mint state when on‑chain is disabled). -

-
- -
-

Eligibility

-
    -
  • You must submit a valid phone number you control for verification.
  • -
  • One authentication NFT per phone number and per wallet address.
  • -
  • We may block abusive activity, VPN/proxy usage, or high‑risk phone numbers.
  • -
-
- -
-

Assumptions and Risks

-
    -
  • Crypto transactions are irreversible and may incur gas fees. You are responsible for your wallet security.
  • -
  • The project code is open source; hosted deployments still require trust in the operator's configuration.
  • -
  • The service may change or be discontinued without notice.
  • -
-
- -
-

No Warranty

-

- The service is provided "as is," without warranties of any kind. To the maximum extent permitted by law, the operators and contributors disclaim all implied warranties and are not liable for damages arising from the use or inability to use the service. -

-
- -
-

Policy Changes

-

- We may update these terms and the privacy policy. Continued use of the service after changes constitutes acceptance of the updated terms. -

-
- -
- - Privacy Policy - -
-
-
-
-
- ); -} - - diff --git a/web/src/styles/globals.css b/web/src/styles/globals.css deleted file mode 100644 index 001dc4d..0000000 --- a/web/src/styles/globals.css +++ /dev/null @@ -1,86 +0,0 @@ - -@tailwind base; -@tailwind components; -@tailwind utilities; - -:root { - --background: 0 0% 100%; - --foreground: 0 0% 3.9%; - --card: 0 0% 100%; - --card-foreground: 0 0% 3.9%; - --popover: 0 0% 100%; - --popover-foreground: 0 0% 3.9%; - --primary: 186 94% 28%; - --primary-foreground: 0 0% 98%; - --secondary: 0 0% 96.1%; - --secondary-foreground: 0 0% 9%; - --muted: 0 0% 96.1%; - --muted-foreground: 0 0% 45.1%; - --accent: 0 0% 96.1%; - --accent-foreground: 0 0% 9%; - --destructive: 0 84.2% 60.2%; - --destructive-foreground: 0 0% 98%; - --border: 0 0% 89.8%; - --input: 0 0% 89.8%; - --ring: 186 94% 28%; - --radius: 0.5rem; -} - -.dark { - --background: 0 0% 3.9%; - --foreground: 0 0% 98%; - --card: 0 0% 3.9%; - --card-foreground: 0 0% 98%; - --popover: 0 0% 3.9%; - --popover-foreground: 0 0% 98%; - --primary: 174 56% 48%; - --primary-foreground: 0 0% 9%; - --secondary: 0 0% 14.9%; - --secondary-foreground: 0 0% 98%; - --muted: 0 0% 14.9%; - --muted-foreground: 0 0% 63.9%; - --accent: 0 0% 14.9%; - --accent-foreground: 0 0% 98%; - --destructive: 0 84.2% 65.2%; - --destructive-foreground: 0 0% 98%; - --border: 0 0% 14.9%; - --input: 0 0% 14.9%; - --ring: 174 56% 48%; -} - -@layer base { - * { - @apply border-border; - } - body { - @apply bg-background text-foreground; - } - :root { - --color-1: oklch(66.2% 0.225 25.9); - --color-2: oklch(60.4% 0.26 302); - --color-3: oklch(69.6% 0.165 251); - --color-4: oklch(80.2% 0.134 225); - --color-5: oklch(90.7% 0.231 133); - } - .dark { - /* Use lower lightness and adjusted chroma for contrast in dark mode */ - --color-1: oklch(62% 0.18 28); - --color-2: oklch(58% 0.22 305); - --color-3: oklch(60% 0.14 255); - --color-4: oklch(68% 0.11 230); - --color-5: oklch(74% 0.19 135); - } -} - -/* View transition styles - only disable default transitions, not all animations */ -::view-transition-old(root), ::view-transition-new(root) { - mix-blend-mode: normal; -} - -::view-transition-old(root) { - animation: none; -} - -::view-transition-new(root) { - animation: none; -} diff --git a/web/src/types/view-transitions.d.ts b/web/src/types/view-transitions.d.ts deleted file mode 100644 index 71d7e63..0000000 --- a/web/src/types/view-transitions.d.ts +++ /dev/null @@ -1,29 +0,0 @@ -// Type declarations for View Transitions API -// See: https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API - -interface ViewTransition { - /** Promise that fulfills when the transition is ready to start */ - ready: Promise; - /** Promise that fulfills when the transition animation finishes */ - finished: Promise; - /** Promise that fulfills when the update callback is done */ - updateCallbackDone: Promise; - /** Skips the animation part of the view transition */ - skipTransition(): void; -} - -interface Document { - /** - * Starts a view transition - * @param callback - Function that makes DOM changes - * @returns ViewTransition object - */ - startViewTransition?: (callback?: () => void | Promise) => ViewTransition; -} - -interface KeyframeAnimationOptions extends KeyframeEffectOptions { - /** Unique id for the animation (spec addition) */ - id?: string; - /** Associated timeline for the animation (spec addition) */ - timeline?: AnimationTimeline | null; -} diff --git a/web/tailwind.config.ts b/web/tailwind.config.ts deleted file mode 100644 index de139be..0000000 --- a/web/tailwind.config.ts +++ /dev/null @@ -1,75 +0,0 @@ -import type { Config } from 'tailwindcss'; - -const config: Config = { - darkMode: ['class'], - content: [ - './pages/**/*.{js,ts,jsx,tsx,mdx}', - './src/**/*.{js,ts,jsx,tsx,mdx}', - './components/**/*.{js,ts,jsx,tsx,mdx}', - ], - theme: { - extend: { - animation: { - rainbow: 'rainbow 2s linear infinite', - 'caret-blink': 'caret-blink 1.25s ease-out infinite', - }, - keyframes: { - rainbow: { - '0%': { - 'background-position': '0%', - }, - '100%': { - 'background-position': '200%', - }, - }, - 'caret-blink': { - '0%,70%,100%': { opacity: '1' }, - '20%,50%': { opacity: '0' }, - }, - }, - colors: { - border: 'hsl(var(--border))', - input: 'hsl(var(--input))', - ring: 'hsl(var(--ring))', - background: 'hsl(var(--background))', - foreground: 'hsl(var(--foreground))', - primary: { - DEFAULT: 'hsl(var(--primary))', - foreground: 'hsl(var(--primary-foreground))', - }, - secondary: { - DEFAULT: 'hsl(var(--secondary))', - foreground: 'hsl(var(--secondary-foreground))', - }, - destructive: { - DEFAULT: 'hsl(var(--destructive))', - foreground: 'hsl(var(--destructive-foreground))', - }, - muted: { - DEFAULT: 'hsl(var(--muted))', - foreground: 'hsl(var(--muted-foreground))', - }, - accent: { - DEFAULT: 'hsl(var(--accent))', - foreground: 'hsl(var(--accent-foreground))', - }, - popover: { - DEFAULT: 'hsl(var(--popover))', - foreground: 'hsl(var(--popover-foreground))', - }, - card: { - DEFAULT: 'hsl(var(--card))', - foreground: 'hsl(var(--card-foreground))', - }, - }, - borderRadius: { - lg: 'var(--radius)', - md: 'calc(var(--radius) - 2px)', - sm: 'calc(var(--radius) - 4px)', - }, - }, - }, - plugins: [], -}; - -export default config; diff --git a/web/tsconfig.json b/web/tsconfig.json deleted file mode 100644 index cda5f48..0000000 --- a/web/tsconfig.json +++ /dev/null @@ -1,37 +0,0 @@ -{ - "compilerOptions": { - "target": "ES2017", - "lib": [ - "dom", - "dom.iterable", - "esnext" - ], - "allowJs": true, - "skipLibCheck": true, - "strict": true, - "noEmit": true, - "esModuleInterop": true, - "module": "esnext", - "moduleResolution": "bundler", - "resolveJsonModule": true, - "isolatedModules": true, - "jsx": "react-jsx", - "incremental": true, - "types": [ - "node" - ], - "paths": { - "@/*": [ - "./src/*" - ] - } - }, - "include": [ - "next-env.d.ts", - "**/*.ts", - "**/*.tsx" - ], - "exclude": [ - "node_modules" - ] -} diff --git a/web/yarn.lock b/web/yarn.lock deleted file mode 100644 index 41be09b..0000000 --- a/web/yarn.lock +++ /dev/null @@ -1,7542 +0,0 @@ -# This file is generated by running "yarn install" inside your project. -# Manual changes might be lost - proceed with caution! - -__metadata: - version: 8 - cacheKey: 10c0 - -"@adraffy/ens-normalize@npm:1.10.1": - version: 1.10.1 - resolution: "@adraffy/ens-normalize@npm:1.10.1" - checksum: 10c0/fdd647604e8fac6204921888aaf5a6bc65eabf0d2921bc5f93b64d01f4bc33ead167c1445f7de05468d05cd92ac31b74c68d2be840c62b79d73693308f885c06 - languageName: node - linkType: hard - -"@alloc/quick-lru@npm:^5.2.0": - version: 5.2.0 - resolution: "@alloc/quick-lru@npm:5.2.0" - checksum: 10c0/7b878c48b9d25277d0e1a9b8b2f2312a314af806b4129dc902f2bc29ab09b58236e53964689feec187b28c80d2203aff03829754773a707a8a5987f1b7682d92 - languageName: node - linkType: hard - -"@babel/code-frame@npm:^7.28.6, @babel/code-frame@npm:^7.29.0": - version: 7.29.0 - resolution: "@babel/code-frame@npm:7.29.0" - dependencies: - "@babel/helper-validator-identifier": "npm:^7.28.5" - js-tokens: "npm:^4.0.0" - picocolors: "npm:^1.1.1" - checksum: 10c0/d34cc504e7765dfb576a663d97067afb614525806b5cad1a5cc1a7183b916fec8ff57fa233585e3926fd5a9e6b31aae6df91aa81ae9775fb7a28f658d3346f0d - languageName: node - linkType: hard - -"@babel/compat-data@npm:^7.28.6": - version: 7.29.0 - resolution: "@babel/compat-data@npm:7.29.0" - checksum: 10c0/08f348554989d23aa801bf1405aa34b15e841c0d52d79da7e524285c77a5f9d298e70e11d91cc578d8e2c9542efc586d50c5f5cf8e1915b254a9dcf786913a94 - languageName: node - linkType: hard - -"@babel/core@npm:^7.24.4": - version: 7.29.0 - resolution: "@babel/core@npm:7.29.0" - dependencies: - "@babel/code-frame": "npm:^7.29.0" - "@babel/generator": "npm:^7.29.0" - "@babel/helper-compilation-targets": "npm:^7.28.6" - "@babel/helper-module-transforms": "npm:^7.28.6" - "@babel/helpers": "npm:^7.28.6" - "@babel/parser": "npm:^7.29.0" - "@babel/template": "npm:^7.28.6" - "@babel/traverse": "npm:^7.29.0" - "@babel/types": "npm:^7.29.0" - "@jridgewell/remapping": "npm:^2.3.5" - convert-source-map: "npm:^2.0.0" - debug: "npm:^4.1.0" - gensync: "npm:^1.0.0-beta.2" - json5: "npm:^2.2.3" - semver: "npm:^6.3.1" - checksum: 10c0/5127d2e8e842ae409e11bcbb5c2dff9874abf5415e8026925af7308e903f4f43397341467a130490d1a39884f461bc2b67f3063bce0be44340db89687fd852aa - languageName: node - linkType: hard - -"@babel/generator@npm:^7.29.0": - version: 7.29.1 - resolution: "@babel/generator@npm:7.29.1" - dependencies: - "@babel/parser": "npm:^7.29.0" - "@babel/types": "npm:^7.29.0" - "@jridgewell/gen-mapping": "npm:^0.3.12" - "@jridgewell/trace-mapping": "npm:^0.3.28" - jsesc: "npm:^3.0.2" - checksum: 10c0/349086e6876258ef3fb2823030fee0f6c0eb9c3ebe35fc572e16997f8c030d765f636ddc6299edae63e760ea6658f8ee9a2edfa6d6b24c9a80c917916b973551 - languageName: node - linkType: hard - -"@babel/helper-compilation-targets@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/helper-compilation-targets@npm:7.28.6" - dependencies: - "@babel/compat-data": "npm:^7.28.6" - "@babel/helper-validator-option": "npm:^7.27.1" - browserslist: "npm:^4.24.0" - lru-cache: "npm:^5.1.1" - semver: "npm:^6.3.1" - checksum: 10c0/3fcdf3b1b857a1578e99d20508859dbd3f22f3c87b8a0f3dc540627b4be539bae7f6e61e49d931542fe5b557545347272bbdacd7f58a5c77025a18b745593a50 - languageName: node - linkType: hard - -"@babel/helper-globals@npm:^7.28.0": - version: 7.28.0 - resolution: "@babel/helper-globals@npm:7.28.0" - checksum: 10c0/5a0cd0c0e8c764b5f27f2095e4243e8af6fa145daea2b41b53c0c1414fe6ff139e3640f4e2207ae2b3d2153a1abd346f901c26c290ee7cb3881dd922d4ee9232 - languageName: node - linkType: hard - -"@babel/helper-module-imports@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/helper-module-imports@npm:7.28.6" - dependencies: - "@babel/traverse": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" - checksum: 10c0/b49d8d8f204d9dbfd5ac70c54e533e5269afb3cea966a9d976722b13e9922cc773a653405f53c89acb247d5aebdae4681d631a3ae3df77ec046b58da76eda2ac - languageName: node - linkType: hard - -"@babel/helper-module-transforms@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/helper-module-transforms@npm:7.28.6" - dependencies: - "@babel/helper-module-imports": "npm:^7.28.6" - "@babel/helper-validator-identifier": "npm:^7.28.5" - "@babel/traverse": "npm:^7.28.6" - peerDependencies: - "@babel/core": ^7.0.0 - checksum: 10c0/6f03e14fc30b287ce0b839474b5f271e72837d0cafe6b172d759184d998fbee3903a035e81e07c2c596449e504f453463d58baa65b6f40a37ded5bec74620b2b - languageName: node - linkType: hard - -"@babel/helper-string-parser@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-string-parser@npm:7.27.1" - checksum: 10c0/8bda3448e07b5583727c103560bcf9c4c24b3c1051a4c516d4050ef69df37bb9a4734a585fe12725b8c2763de0a265aa1e909b485a4e3270b7cfd3e4dbe4b602 - languageName: node - linkType: hard - -"@babel/helper-validator-identifier@npm:^7.28.5": - version: 7.28.5 - resolution: "@babel/helper-validator-identifier@npm:7.28.5" - checksum: 10c0/42aaebed91f739a41f3d80b72752d1f95fd7c72394e8e4bd7cdd88817e0774d80a432451bcba17c2c642c257c483bf1d409dd4548883429ea9493a3bc4ab0847 - languageName: node - linkType: hard - -"@babel/helper-validator-option@npm:^7.27.1": - version: 7.27.1 - resolution: "@babel/helper-validator-option@npm:7.27.1" - checksum: 10c0/6fec5f006eba40001a20f26b1ef5dbbda377b7b68c8ad518c05baa9af3f396e780bdfded24c4eef95d14bb7b8fd56192a6ed38d5d439b97d10efc5f1a191d148 - languageName: node - linkType: hard - -"@babel/helpers@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/helpers@npm:7.28.6" - dependencies: - "@babel/template": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" - checksum: 10c0/c4a779c66396bb0cf619402d92f1610601ff3832db2d3b86b9c9dd10983bf79502270e97ac6d5280cea1b1a37de2f06ecbac561bd2271545270407fbe64027cb - languageName: node - linkType: hard - -"@babel/parser@npm:^7.24.4, @babel/parser@npm:^7.28.6, @babel/parser@npm:^7.29.0": - version: 7.29.0 - resolution: "@babel/parser@npm:7.29.0" - dependencies: - "@babel/types": "npm:^7.29.0" - bin: - parser: ./bin/babel-parser.js - checksum: 10c0/333b2aa761264b91577a74bee86141ef733f9f9f6d4fc52548e4847dc35dfbf821f58c46832c637bfa761a6d9909d6a68f7d1ed59e17e4ffbb958dc510c17b62 - languageName: node - linkType: hard - -"@babel/template@npm:^7.28.6": - version: 7.28.6 - resolution: "@babel/template@npm:7.28.6" - dependencies: - "@babel/code-frame": "npm:^7.28.6" - "@babel/parser": "npm:^7.28.6" - "@babel/types": "npm:^7.28.6" - checksum: 10c0/66d87225ed0bc77f888181ae2d97845021838c619944877f7c4398c6748bcf611f216dfd6be74d39016af502bca876e6ce6873db3c49e4ac354c56d34d57e9f5 - languageName: node - linkType: hard - -"@babel/traverse@npm:^7.28.6, @babel/traverse@npm:^7.29.0": - version: 7.29.0 - resolution: "@babel/traverse@npm:7.29.0" - dependencies: - "@babel/code-frame": "npm:^7.29.0" - "@babel/generator": "npm:^7.29.0" - "@babel/helper-globals": "npm:^7.28.0" - "@babel/parser": "npm:^7.29.0" - "@babel/template": "npm:^7.28.6" - "@babel/types": "npm:^7.29.0" - debug: "npm:^4.3.1" - checksum: 10c0/f63ef6e58d02a9fbf3c0e2e5f1c877da3e0bc57f91a19d2223d53e356a76859cbaf51171c9211c71816d94a0e69efa2732fd27ffc0e1bbc84b636e60932333eb - languageName: node - linkType: hard - -"@babel/types@npm:^7.28.6, @babel/types@npm:^7.29.0": - version: 7.29.0 - resolution: "@babel/types@npm:7.29.0" - dependencies: - "@babel/helper-string-parser": "npm:^7.27.1" - "@babel/helper-validator-identifier": "npm:^7.28.5" - checksum: 10c0/23cc3466e83bcbfab8b9bd0edaafdb5d4efdb88b82b3be6728bbade5ba2f0996f84f63b1c5f7a8c0d67efded28300898a5f930b171bb40b311bca2029c4e9b4f - languageName: node - linkType: hard - -"@effect/platform-node-shared@npm:4.0.0-beta.70": - version: 4.0.0-beta.70 - resolution: "@effect/platform-node-shared@npm:4.0.0-beta.70" - dependencies: - "@types/ws": "npm:^8.18.1" - ws: "npm:^8.20.0" - peerDependencies: - effect: ^4.0.0-beta.70 - checksum: 10c0/91f1543a56806647405499677b45cf596be89e614c74cf016de5d105b2cc3413c326339851617e38ded4f1cbd61e9082fee00d9e2098856a0a4334aa1d7b49d1 - languageName: node - linkType: hard - -"@emnapi/core@npm:1.10.0": - version: 1.10.0 - resolution: "@emnapi/core@npm:1.10.0" - dependencies: - "@emnapi/wasi-threads": "npm:1.2.1" - tslib: "npm:^2.4.0" - checksum: 10c0/f51d08227857b60632de7714d708124f0e100a1462dde6df8221760939aa3204a73193830371830fac0716f3ccd2129f2cac1b17cd7d7958bc4da9018a296edb - languageName: node - linkType: hard - -"@emnapi/core@npm:^1.4.3": - version: 1.4.5 - resolution: "@emnapi/core@npm:1.4.5" - dependencies: - "@emnapi/wasi-threads": "npm:1.0.4" - tslib: "npm:^2.4.0" - checksum: 10c0/da4a57f65f325d720d0e0d1a9c6618b90c4c43a5027834a110476984e1d47c95ebaed4d316b5dddb9c0ed9a493ffeb97d1934f9677035f336d8a36c1f3b2818f - languageName: node - linkType: hard - -"@emnapi/core@npm:^1.7.1": - version: 1.8.1 - resolution: "@emnapi/core@npm:1.8.1" - dependencies: - "@emnapi/wasi-threads": "npm:1.1.0" - tslib: "npm:^2.4.0" - checksum: 10c0/2c242f4b49779bac403e1cbcc98edacdb1c8ad36562408ba9a20663824669e930bc8493be46a2522d9dc946b8d96cd7073970bae914928c7671b5221c85b432e - languageName: node - linkType: hard - -"@emnapi/runtime@npm:1.10.0": - version: 1.10.0 - resolution: "@emnapi/runtime@npm:1.10.0" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/953f14991d1aefb92ee6f8eb27dea725e484791a53a0cb5f47d9e0087b9a2c929ff2e92adf95af15d6ad456db6300c6b761ebf72b50a875b874a83520b3ba093 - languageName: node - linkType: hard - -"@emnapi/runtime@npm:^1.4.3": - version: 1.4.5 - resolution: "@emnapi/runtime@npm:1.4.5" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/37a0278be5ac81e918efe36f1449875cbafba947039c53c65a1f8fc238001b866446fc66041513b286baaff5d6f9bec667f5164b3ca481373a8d9cb65bfc984b - languageName: node - linkType: hard - -"@emnapi/runtime@npm:^1.7.0": - version: 1.9.0 - resolution: "@emnapi/runtime@npm:1.9.0" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/f825e53b2d3f9d31fd880e669197d006bb5158c3a52ab25f0546f3d52ac58eb539a4bd1dcc378af6c10d202956fa064b28ab7b572a76de58972c0b8656a692ef - languageName: node - linkType: hard - -"@emnapi/runtime@npm:^1.7.1": - version: 1.8.1 - resolution: "@emnapi/runtime@npm:1.8.1" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/f4929d75e37aafb24da77d2f58816761fe3f826aad2e37fa6d4421dac9060cbd5098eea1ac3c9ecc4526b89deb58153852fa432f87021dc57863f2ff726d713f - languageName: node - linkType: hard - -"@emnapi/wasi-threads@npm:1.0.4": - version: 1.0.4 - resolution: "@emnapi/wasi-threads@npm:1.0.4" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/2c91a53e62f875800baf035c4d42c9c0d18e5afd9a31ca2aac8b435aeaeaeaac386b5b3d0d0e70aa7a5a9852bbe05106b1f680cd82cce03145c703b423d41313 - languageName: node - linkType: hard - -"@emnapi/wasi-threads@npm:1.1.0": - version: 1.1.0 - resolution: "@emnapi/wasi-threads@npm:1.1.0" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/e6d54bf2b1e64cdd83d2916411e44e579b6ae35d5def0dea61a3c452d9921373044dff32a8b8473ae60c80692bdc39323e98b96a3f3d87ba6886b24dd0ef7ca1 - languageName: node - linkType: hard - -"@emnapi/wasi-threads@npm:1.2.1": - version: 1.2.1 - resolution: "@emnapi/wasi-threads@npm:1.2.1" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/32fcfa81ab396533b2ec1f4082b1ff779a05d9c836bbbd3f4398405b0e6814c0d9503b7993130e37bc6941dbc1ded49f55e9700ae9ca4e803bab2b5bc5deb331 - languageName: node - linkType: hard - -"@eslint-community/eslint-utils@npm:^4.8.0": - version: 4.9.0 - resolution: "@eslint-community/eslint-utils@npm:4.9.0" - dependencies: - eslint-visitor-keys: "npm:^3.4.3" - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 10c0/8881e22d519326e7dba85ea915ac7a143367c805e6ba1374c987aa2fbdd09195cc51183d2da72c0e2ff388f84363e1b220fd0d19bef10c272c63455162176817 - languageName: node - linkType: hard - -"@eslint-community/eslint-utils@npm:^4.9.1": - version: 4.9.1 - resolution: "@eslint-community/eslint-utils@npm:4.9.1" - dependencies: - eslint-visitor-keys: "npm:^3.4.3" - peerDependencies: - eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - checksum: 10c0/dc4ab5e3e364ef27e33666b11f4b86e1a6c1d7cbf16f0c6ff87b1619b3562335e9201a3d6ce806221887ff780ec9d828962a290bb910759fd40a674686503f02 - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.12.1": - version: 4.12.1 - resolution: "@eslint-community/regexpp@npm:4.12.1" - checksum: 10c0/a03d98c246bcb9109aec2c08e4d10c8d010256538dcb3f56610191607214523d4fb1b00aa81df830b6dffb74c5fa0be03642513a289c567949d3e550ca11cdf6 - languageName: node - linkType: hard - -"@eslint-community/regexpp@npm:^4.12.2": - version: 4.12.2 - resolution: "@eslint-community/regexpp@npm:4.12.2" - checksum: 10c0/fddcbc66851b308478d04e302a4d771d6917a0b3740dc351513c0da9ca2eab8a1adf99f5e0aa7ab8b13fa0df005c81adeee7e63a92f3effd7d367a163b721c2d - languageName: node - linkType: hard - -"@eslint/config-array@npm:^0.21.1": - version: 0.21.1 - resolution: "@eslint/config-array@npm:0.21.1" - dependencies: - "@eslint/object-schema": "npm:^2.1.7" - debug: "npm:^4.3.1" - minimatch: "npm:^3.1.2" - checksum: 10c0/2f657d4edd6ddcb920579b72e7a5b127865d4c3fb4dda24f11d5c4f445a93ca481aebdbd6bf3291c536f5d034458dbcbb298ee3b698bc6c9dd02900fe87eec3c - languageName: node - linkType: hard - -"@eslint/config-helpers@npm:^0.4.2": - version: 0.4.2 - resolution: "@eslint/config-helpers@npm:0.4.2" - dependencies: - "@eslint/core": "npm:^0.17.0" - checksum: 10c0/92efd7a527b2d17eb1a148409d71d80f9ac160b565ac73ee092252e8bf08ecd08670699f46b306b94f13d22e88ac88a612120e7847570dd7cdc72f234d50dcb4 - languageName: node - linkType: hard - -"@eslint/core@npm:^0.17.0": - version: 0.17.0 - resolution: "@eslint/core@npm:0.17.0" - dependencies: - "@types/json-schema": "npm:^7.0.15" - checksum: 10c0/9a580f2246633bc752298e7440dd942ec421860d1946d0801f0423830e67887e4aeba10ab9a23d281727a978eb93d053d1922a587d502942a713607f40ed704e - languageName: node - linkType: hard - -"@eslint/eslintrc@npm:^3, @eslint/eslintrc@npm:^3.3.1": - version: 3.3.1 - resolution: "@eslint/eslintrc@npm:3.3.1" - dependencies: - ajv: "npm:^6.12.4" - debug: "npm:^4.3.2" - espree: "npm:^10.0.1" - globals: "npm:^14.0.0" - ignore: "npm:^5.2.0" - import-fresh: "npm:^3.2.1" - js-yaml: "npm:^4.1.0" - minimatch: "npm:^3.1.2" - strip-json-comments: "npm:^3.1.1" - checksum: 10c0/b0e63f3bc5cce4555f791a4e487bf999173fcf27c65e1ab6e7d63634d8a43b33c3693e79f192cbff486d7df1be8ebb2bd2edc6e70ddd486cbfa84a359a3e3b41 - languageName: node - linkType: hard - -"@eslint/js@npm:9.39.2": - version: 9.39.2 - resolution: "@eslint/js@npm:9.39.2" - checksum: 10c0/00f51c52b04ac79faebfaa65a9652b2093b9c924e945479f1f3945473f78aee83cbc76c8d70bbffbf06f7024626575b16d97b66eab16182e1d0d39daff2f26f5 - languageName: node - linkType: hard - -"@eslint/object-schema@npm:^2.1.7": - version: 2.1.7 - resolution: "@eslint/object-schema@npm:2.1.7" - checksum: 10c0/936b6e499853d1335803f556d526c86f5fe2259ed241bc665000e1d6353828edd913feed43120d150adb75570cae162cf000b5b0dfc9596726761c36b82f4e87 - languageName: node - linkType: hard - -"@eslint/plugin-kit@npm:^0.4.1": - version: 0.4.1 - resolution: "@eslint/plugin-kit@npm:0.4.1" - dependencies: - "@eslint/core": "npm:^0.17.0" - levn: "npm:^0.4.1" - checksum: 10c0/51600f78b798f172a9915dffb295e2ffb44840d583427bc732baf12ecb963eb841b253300e657da91d890f4b323d10a1bd12934bf293e3018d8bb66fdce5217b - languageName: node - linkType: hard - -"@floating-ui/core@npm:^1.7.3": - version: 1.7.3 - resolution: "@floating-ui/core@npm:1.7.3" - dependencies: - "@floating-ui/utils": "npm:^0.2.10" - checksum: 10c0/edfc23800122d81df0df0fb780b7328ae6c5f00efbb55bd48ea340f4af8c5b3b121ceb4bb81220966ab0f87b443204d37105abdd93d94846468be3243984144c - languageName: node - linkType: hard - -"@floating-ui/dom@npm:^1.7.4": - version: 1.7.4 - resolution: "@floating-ui/dom@npm:1.7.4" - dependencies: - "@floating-ui/core": "npm:^1.7.3" - "@floating-ui/utils": "npm:^0.2.10" - checksum: 10c0/da6166c25f9b0729caa9f498685a73a0e28251613b35d27db8de8014bc9d045158a23c092b405321a3d67c2064909b6e2a7e6c1c9cc0f62967dca5779f5aef30 - languageName: node - linkType: hard - -"@floating-ui/react-dom@npm:^2.0.0": - version: 2.1.6 - resolution: "@floating-ui/react-dom@npm:2.1.6" - dependencies: - "@floating-ui/dom": "npm:^1.7.4" - peerDependencies: - react: ">=16.8.0" - react-dom: ">=16.8.0" - checksum: 10c0/6654834a8e73ecbdbc6cad2ad8f7abc698ac7c1800ded4d61113525c591c03d2e3b59d3cf9205859221465ea38c87af4f9e6e204703c5b7a7e85332d1eef2e18 - languageName: node - linkType: hard - -"@floating-ui/utils@npm:^0.2.10": - version: 0.2.10 - resolution: "@floating-ui/utils@npm:0.2.10" - checksum: 10c0/e9bc2a1730ede1ee25843937e911ab6e846a733a4488623cd353f94721b05ec2c9ec6437613a2ac9379a94c2fd40c797a2ba6fa1df2716f5ce4aa6ddb1cf9ea4 - languageName: node - linkType: hard - -"@gar/promise-retry@npm:^1.0.0": - version: 1.0.3 - resolution: "@gar/promise-retry@npm:1.0.3" - checksum: 10c0/885b02c8b0d75b2d215da25f3b639158c4fbe8fefe0d79163304534b9a6d0710db4b7699f7cd3cc1a730792bff04cbe19f4850a62d3e105a663eaeec88f38332 - languageName: node - linkType: hard - -"@humanfs/core@npm:^0.19.1": - version: 0.19.1 - resolution: "@humanfs/core@npm:0.19.1" - checksum: 10c0/aa4e0152171c07879b458d0e8a704b8c3a89a8c0541726c6b65b81e84fd8b7564b5d6c633feadc6598307d34564bd53294b533491424e8e313d7ab6c7bc5dc67 - languageName: node - linkType: hard - -"@humanfs/node@npm:^0.16.6": - version: 0.16.6 - resolution: "@humanfs/node@npm:0.16.6" - dependencies: - "@humanfs/core": "npm:^0.19.1" - "@humanwhocodes/retry": "npm:^0.3.0" - checksum: 10c0/8356359c9f60108ec204cbd249ecd0356667359b2524886b357617c4a7c3b6aace0fd5a369f63747b926a762a88f8a25bc066fa1778508d110195ce7686243e1 - languageName: node - linkType: hard - -"@humanwhocodes/module-importer@npm:^1.0.1": - version: 1.0.1 - resolution: "@humanwhocodes/module-importer@npm:1.0.1" - checksum: 10c0/909b69c3b86d482c26b3359db16e46a32e0fb30bd306a3c176b8313b9e7313dba0f37f519de6aa8b0a1921349e505f259d19475e123182416a506d7f87e7f529 - languageName: node - linkType: hard - -"@humanwhocodes/retry@npm:^0.3.0": - version: 0.3.1 - resolution: "@humanwhocodes/retry@npm:0.3.1" - checksum: 10c0/f0da1282dfb45e8120480b9e2e275e2ac9bbe1cf016d046fdad8e27cc1285c45bb9e711681237944445157b430093412b4446c1ab3fc4bb037861b5904101d3b - languageName: node - linkType: hard - -"@humanwhocodes/retry@npm:^0.4.2": - version: 0.4.3 - resolution: "@humanwhocodes/retry@npm:0.4.3" - checksum: 10c0/3775bb30087d4440b3f7406d5a057777d90e4b9f435af488a4923ef249e93615fb78565a85f173a186a076c7706a81d0d57d563a2624e4de2c5c9c66c486ce42 - languageName: node - linkType: hard - -"@iarna/toml@npm:^2.2.5": - version: 2.2.5 - resolution: "@iarna/toml@npm:2.2.5" - checksum: 10c0/d095381ad4554aca233b7cf5a91f243ef619e5e15efd3157bc640feac320545450d14b394aebbf6f02a2047437ced778ae598d5879a995441ab7b6c0b2c2f201 - languageName: node - linkType: hard - -"@img/colour@npm:^1.0.0": - version: 1.1.0 - resolution: "@img/colour@npm:1.1.0" - checksum: 10c0/2ebea2c0bbaee73b99badcefa04e1e71d83f36e5369337d3121dca841f4569533c4e2faddda6d62dd247f0d5cca143711f9446c59bcce81e427ba433a7a94a17 - languageName: node - linkType: hard - -"@img/sharp-darwin-arm64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-darwin-arm64@npm:0.34.5" - dependencies: - "@img/sharp-libvips-darwin-arm64": "npm:1.2.4" - dependenciesMeta: - "@img/sharp-libvips-darwin-arm64": - optional: true - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@img/sharp-darwin-x64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-darwin-x64@npm:0.34.5" - dependencies: - "@img/sharp-libvips-darwin-x64": "npm:1.2.4" - dependenciesMeta: - "@img/sharp-libvips-darwin-x64": - optional: true - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@img/sharp-libvips-darwin-arm64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-darwin-arm64@npm:1.2.4" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@img/sharp-libvips-darwin-x64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-darwin-x64@npm:1.2.4" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@img/sharp-libvips-linux-arm64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-arm64@npm:1.2.4" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-libvips-linux-arm@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-arm@npm:1.2.4" - conditions: os=linux & cpu=arm & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-libvips-linux-ppc64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-ppc64@npm:1.2.4" - conditions: os=linux & cpu=ppc64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-libvips-linux-riscv64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-riscv64@npm:1.2.4" - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-libvips-linux-s390x@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-s390x@npm:1.2.4" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-libvips-linux-x64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linux-x64@npm:1.2.4" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-libvips-linuxmusl-arm64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linuxmusl-arm64@npm:1.2.4" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@img/sharp-libvips-linuxmusl-x64@npm:1.2.4": - version: 1.2.4 - resolution: "@img/sharp-libvips-linuxmusl-x64@npm:1.2.4" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@img/sharp-linux-arm64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-arm64@npm:0.34.5" - dependencies: - "@img/sharp-libvips-linux-arm64": "npm:1.2.4" - dependenciesMeta: - "@img/sharp-libvips-linux-arm64": - optional: true - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-linux-arm@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-arm@npm:0.34.5" - dependencies: - "@img/sharp-libvips-linux-arm": "npm:1.2.4" - dependenciesMeta: - "@img/sharp-libvips-linux-arm": - optional: true - conditions: os=linux & cpu=arm & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-linux-ppc64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-ppc64@npm:0.34.5" - dependencies: - "@img/sharp-libvips-linux-ppc64": "npm:1.2.4" - dependenciesMeta: - "@img/sharp-libvips-linux-ppc64": - optional: true - conditions: os=linux & cpu=ppc64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-linux-riscv64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-riscv64@npm:0.34.5" - dependencies: - "@img/sharp-libvips-linux-riscv64": "npm:1.2.4" - dependenciesMeta: - "@img/sharp-libvips-linux-riscv64": - optional: true - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-linux-s390x@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-s390x@npm:0.34.5" - dependencies: - "@img/sharp-libvips-linux-s390x": "npm:1.2.4" - dependenciesMeta: - "@img/sharp-libvips-linux-s390x": - optional: true - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-linux-x64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linux-x64@npm:0.34.5" - dependencies: - "@img/sharp-libvips-linux-x64": "npm:1.2.4" - dependenciesMeta: - "@img/sharp-libvips-linux-x64": - optional: true - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@img/sharp-linuxmusl-arm64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linuxmusl-arm64@npm:0.34.5" - dependencies: - "@img/sharp-libvips-linuxmusl-arm64": "npm:1.2.4" - dependenciesMeta: - "@img/sharp-libvips-linuxmusl-arm64": - optional: true - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@img/sharp-linuxmusl-x64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-linuxmusl-x64@npm:0.34.5" - dependencies: - "@img/sharp-libvips-linuxmusl-x64": "npm:1.2.4" - dependenciesMeta: - "@img/sharp-libvips-linuxmusl-x64": - optional: true - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@img/sharp-wasm32@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-wasm32@npm:0.34.5" - dependencies: - "@emnapi/runtime": "npm:^1.7.0" - conditions: cpu=wasm32 - languageName: node - linkType: hard - -"@img/sharp-win32-arm64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-win32-arm64@npm:0.34.5" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@img/sharp-win32-ia32@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-win32-ia32@npm:0.34.5" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@img/sharp-win32-x64@npm:0.34.5": - version: 0.34.5 - resolution: "@img/sharp-win32-x64@npm:0.34.5" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@isaacs/fs-minipass@npm:^4.0.0": - version: 4.0.1 - resolution: "@isaacs/fs-minipass@npm:4.0.1" - dependencies: - minipass: "npm:^7.0.4" - checksum: 10c0/c25b6dc1598790d5b55c0947a9b7d111cfa92594db5296c3b907e2f533c033666f692a3939eadac17b1c7c40d362d0b0635dc874cbfe3e70db7c2b07cc97a5d2 - languageName: node - linkType: hard - -"@jridgewell/gen-mapping@npm:^0.3.12, @jridgewell/gen-mapping@npm:^0.3.2, @jridgewell/gen-mapping@npm:^0.3.5": - version: 0.3.13 - resolution: "@jridgewell/gen-mapping@npm:0.3.13" - dependencies: - "@jridgewell/sourcemap-codec": "npm:^1.5.0" - "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10c0/9a7d65fb13bd9aec1fbab74cda08496839b7e2ceb31f5ab922b323e94d7c481ce0fc4fd7e12e2610915ed8af51178bdc61e168e92a8c8b8303b030b03489b13b - languageName: node - linkType: hard - -"@jridgewell/remapping@npm:^2.3.5": - version: 2.3.5 - resolution: "@jridgewell/remapping@npm:2.3.5" - dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.5" - "@jridgewell/trace-mapping": "npm:^0.3.24" - checksum: 10c0/3de494219ffeb2c5c38711d0d7bb128097edf91893090a2dbc8ee0b55d092bb7347b1fd0f478486c5eab010e855c73927b1666f2107516d472d24a73017d1194 - languageName: node - linkType: hard - -"@jridgewell/resolve-uri@npm:^3.1.0": - version: 3.1.2 - resolution: "@jridgewell/resolve-uri@npm:3.1.2" - checksum: 10c0/d502e6fb516b35032331406d4e962c21fe77cdf1cbdb49c6142bcbd9e30507094b18972778a6e27cbad756209cfe34b1a27729e6fa08a2eb92b33943f680cf1e - languageName: node - linkType: hard - -"@jridgewell/sourcemap-codec@npm:^1.4.14, @jridgewell/sourcemap-codec@npm:^1.5.0": - version: 1.5.5 - resolution: "@jridgewell/sourcemap-codec@npm:1.5.5" - checksum: 10c0/f9e538f302b63c0ebc06eecb1dd9918dd4289ed36147a0ddce35d6ea4d7ebbda243cda7b2213b6a5e1d8087a298d5cf630fb2bd39329cdecb82017023f6081a0 - languageName: node - linkType: hard - -"@jridgewell/trace-mapping@npm:^0.3.24, @jridgewell/trace-mapping@npm:^0.3.28": - version: 0.3.31 - resolution: "@jridgewell/trace-mapping@npm:0.3.31" - dependencies: - "@jridgewell/resolve-uri": "npm:^3.1.0" - "@jridgewell/sourcemap-codec": "npm:^1.4.14" - checksum: 10c0/4b30ec8cd56c5fd9a661f088230af01e0c1a3888d11ffb6b47639700f71225be21d1f7e168048d6d4f9449207b978a235c07c8f15c07705685d16dc06280e9d9 - languageName: node - linkType: hard - -"@msgpackr-extract/msgpackr-extract-darwin-arm64@npm:3.0.4": - version: 3.0.4 - resolution: "@msgpackr-extract/msgpackr-extract-darwin-arm64@npm:3.0.4" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@msgpackr-extract/msgpackr-extract-darwin-x64@npm:3.0.4": - version: 3.0.4 - resolution: "@msgpackr-extract/msgpackr-extract-darwin-x64@npm:3.0.4" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@msgpackr-extract/msgpackr-extract-linux-arm64@npm:3.0.4": - version: 3.0.4 - resolution: "@msgpackr-extract/msgpackr-extract-linux-arm64@npm:3.0.4" - conditions: os=linux & cpu=arm64 - languageName: node - linkType: hard - -"@msgpackr-extract/msgpackr-extract-linux-arm@npm:3.0.4": - version: 3.0.4 - resolution: "@msgpackr-extract/msgpackr-extract-linux-arm@npm:3.0.4" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@msgpackr-extract/msgpackr-extract-linux-x64@npm:3.0.4": - version: 3.0.4 - resolution: "@msgpackr-extract/msgpackr-extract-linux-x64@npm:3.0.4" - conditions: os=linux & cpu=x64 - languageName: node - linkType: hard - -"@msgpackr-extract/msgpackr-extract-win32-x64@npm:3.0.4": - version: 3.0.4 - resolution: "@msgpackr-extract/msgpackr-extract-win32-x64@npm:3.0.4" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@napi-rs/wasm-runtime@npm:^0.2.11": - version: 0.2.12 - resolution: "@napi-rs/wasm-runtime@npm:0.2.12" - dependencies: - "@emnapi/core": "npm:^1.4.3" - "@emnapi/runtime": "npm:^1.4.3" - "@tybys/wasm-util": "npm:^0.10.0" - checksum: 10c0/6d07922c0613aab30c6a497f4df297ca7c54e5b480e00035e0209b872d5c6aab7162fc49477267556109c2c7ed1eb9c65a174e27e9b87568106a87b0a6e3ca7d - languageName: node - linkType: hard - -"@napi-rs/wasm-runtime@npm:^1.1.1": - version: 1.1.1 - resolution: "@napi-rs/wasm-runtime@npm:1.1.1" - dependencies: - "@emnapi/core": "npm:^1.7.1" - "@emnapi/runtime": "npm:^1.7.1" - "@tybys/wasm-util": "npm:^0.10.1" - checksum: 10c0/04d57b67e80736e41fe44674a011878db0a8ad893f4d44abb9d3608debb7c174224cba2796ed5b0c1d367368159f3ca6be45f1c59222f70e32ddc880f803d447 - languageName: node - linkType: hard - -"@napi-rs/wasm-runtime@npm:^1.1.4": - version: 1.1.4 - resolution: "@napi-rs/wasm-runtime@npm:1.1.4" - dependencies: - "@tybys/wasm-util": "npm:^0.10.1" - peerDependencies: - "@emnapi/core": ^1.7.1 - "@emnapi/runtime": ^1.7.1 - checksum: 10c0/2e88e1955258949ccf2d18c79975821ad38071b465ef126a5e14110977b97868867b016c1ad046e963cccc42c0bd9db6c8ff5fd1ebb61b87bb3487f339041658 - languageName: node - linkType: hard - -"@next/env@npm:16.2.3": - version: 16.2.3 - resolution: "@next/env@npm:16.2.3" - checksum: 10c0/56c3fee8ea226efe59ef065e054380f872c00c45c9fe4475eaa45f80773c3c1adc3ead3ccdd77447d3c1aeb4b3004aaaa033dd4a100d3e572fd01b83f992dde8 - languageName: node - linkType: hard - -"@next/eslint-plugin-next@npm:16.2.3": - version: 16.2.3 - resolution: "@next/eslint-plugin-next@npm:16.2.3" - dependencies: - fast-glob: "npm:3.3.1" - checksum: 10c0/be881aa89e0840ab60455b07a2bb9ec0d686c664a0d91e8ca815797a65ca71d7bd79d186b0df5b6892c2bf57bd07fa05421cd93e2812dfeaedfad5ed9fd1023e - languageName: node - linkType: hard - -"@next/swc-darwin-arm64@npm:16.2.3": - version: 16.2.3 - resolution: "@next/swc-darwin-arm64@npm:16.2.3" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@next/swc-darwin-x64@npm:16.2.3": - version: 16.2.3 - resolution: "@next/swc-darwin-x64@npm:16.2.3" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@next/swc-linux-arm64-gnu@npm:16.2.3": - version: 16.2.3 - resolution: "@next/swc-linux-arm64-gnu@npm:16.2.3" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@next/swc-linux-arm64-musl@npm:16.2.3": - version: 16.2.3 - resolution: "@next/swc-linux-arm64-musl@npm:16.2.3" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@next/swc-linux-x64-gnu@npm:16.2.3": - version: 16.2.3 - resolution: "@next/swc-linux-x64-gnu@npm:16.2.3" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@next/swc-linux-x64-musl@npm:16.2.3": - version: 16.2.3 - resolution: "@next/swc-linux-x64-musl@npm:16.2.3" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@next/swc-win32-arm64-msvc@npm:16.2.3": - version: 16.2.3 - resolution: "@next/swc-win32-arm64-msvc@npm:16.2.3" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@next/swc-win32-x64-msvc@npm:16.2.3": - version: 16.2.3 - resolution: "@next/swc-win32-x64-msvc@npm:16.2.3" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@noble/curves@npm:1.2.0": - version: 1.2.0 - resolution: "@noble/curves@npm:1.2.0" - dependencies: - "@noble/hashes": "npm:1.3.2" - checksum: 10c0/0bac7d1bbfb3c2286910b02598addd33243cb97c3f36f987ecc927a4be8d7d88e0fcb12b0f0ef8a044e7307d1844dd5c49bb724bfa0a79c8ec50ba60768c97f6 - languageName: node - linkType: hard - -"@noble/hashes@npm:1.3.2": - version: 1.3.2 - resolution: "@noble/hashes@npm:1.3.2" - checksum: 10c0/2482cce3bce6a596626f94ca296e21378e7a5d4c09597cbc46e65ffacc3d64c8df73111f2265444e36a3168208628258bbbaccba2ef24f65f58b2417638a20e7 - languageName: node - linkType: hard - -"@nodelib/fs.scandir@npm:2.1.5": - version: 2.1.5 - resolution: "@nodelib/fs.scandir@npm:2.1.5" - dependencies: - "@nodelib/fs.stat": "npm:2.0.5" - run-parallel: "npm:^1.1.9" - checksum: 10c0/732c3b6d1b1e967440e65f284bd06e5821fedf10a1bea9ed2bb75956ea1f30e08c44d3def9d6a230666574edbaf136f8cfd319c14fd1f87c66e6a44449afb2eb - languageName: node - linkType: hard - -"@nodelib/fs.stat@npm:2.0.5, @nodelib/fs.stat@npm:^2.0.2": - version: 2.0.5 - resolution: "@nodelib/fs.stat@npm:2.0.5" - checksum: 10c0/88dafe5e3e29a388b07264680dc996c17f4bda48d163a9d4f5c1112979f0ce8ec72aa7116122c350b4e7976bc5566dc3ddb579be1ceaacc727872eb4ed93926d - languageName: node - linkType: hard - -"@nodelib/fs.walk@npm:^1.2.3": - version: 1.2.8 - resolution: "@nodelib/fs.walk@npm:1.2.8" - dependencies: - "@nodelib/fs.scandir": "npm:2.1.5" - fastq: "npm:^1.6.0" - checksum: 10c0/db9de047c3bb9b51f9335a7bb46f4fcfb6829fb628318c12115fbaf7d369bfce71c15b103d1fc3b464812d936220ee9bc1c8f762d032c9f6be9acc99249095b1 - languageName: node - linkType: hard - -"@nolyfill/is-core-module@npm:1.0.39": - version: 1.0.39 - resolution: "@nolyfill/is-core-module@npm:1.0.39" - checksum: 10c0/34ab85fdc2e0250879518841f74a30c276bca4f6c3e13526d2d1fe515e1adf6d46c25fcd5989d22ea056d76f7c39210945180b4859fc83b050e2da411aa86289 - languageName: node - linkType: hard - -"@npmcli/agent@npm:^4.0.0": - version: 4.0.0 - resolution: "@npmcli/agent@npm:4.0.0" - dependencies: - agent-base: "npm:^7.1.0" - http-proxy-agent: "npm:^7.0.0" - https-proxy-agent: "npm:^7.0.1" - lru-cache: "npm:^11.2.1" - socks-proxy-agent: "npm:^8.0.3" - checksum: 10c0/f7b5ce0f3dd42c3f8c6546e8433573d8049f67ef11ec22aa4704bc41483122f68bf97752e06302c455ead667af5cb753e6a09bff06632bc465c1cfd4c4b75a53 - languageName: node - linkType: hard - -"@npmcli/fs@npm:^5.0.0": - version: 5.0.0 - resolution: "@npmcli/fs@npm:5.0.0" - dependencies: - semver: "npm:^7.3.5" - checksum: 10c0/26e376d780f60ff16e874a0ac9bc3399186846baae0b6e1352286385ac134d900cc5dafaded77f38d77f86898fc923ae1cee9d7399f0275b1aa24878915d722b - languageName: node - linkType: hard - -"@npmcli/redact@npm:^4.0.0": - version: 4.0.0 - resolution: "@npmcli/redact@npm:4.0.0" - checksum: 10c0/a1e9ba9c70a6b40e175bda2c3dd8cfdaf096e6b7f7a132c855c083c8dfe545c3237cd56702e2e6627a580b1d63373599d49a1192c4078a85bf47bbde824df31c - languageName: node - linkType: hard - -"@oxc-parser/binding-android-arm-eabi@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-android-arm-eabi@npm:0.132.0" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@oxc-parser/binding-android-arm64@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-android-arm64@npm:0.132.0" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"@oxc-parser/binding-darwin-arm64@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-darwin-arm64@npm:0.132.0" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@oxc-parser/binding-darwin-x64@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-darwin-x64@npm:0.132.0" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@oxc-parser/binding-freebsd-x64@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-freebsd-x64@npm:0.132.0" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@oxc-parser/binding-linux-arm-gnueabihf@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-linux-arm-gnueabihf@npm:0.132.0" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@oxc-parser/binding-linux-arm-musleabihf@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-linux-arm-musleabihf@npm:0.132.0" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@oxc-parser/binding-linux-arm64-gnu@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-linux-arm64-gnu@npm:0.132.0" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@oxc-parser/binding-linux-arm64-musl@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-linux-arm64-musl@npm:0.132.0" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@oxc-parser/binding-linux-ppc64-gnu@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-linux-ppc64-gnu@npm:0.132.0" - conditions: os=linux & cpu=ppc64 & libc=glibc - languageName: node - linkType: hard - -"@oxc-parser/binding-linux-riscv64-gnu@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-linux-riscv64-gnu@npm:0.132.0" - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@oxc-parser/binding-linux-riscv64-musl@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-linux-riscv64-musl@npm:0.132.0" - conditions: os=linux & cpu=riscv64 & libc=musl - languageName: node - linkType: hard - -"@oxc-parser/binding-linux-s390x-gnu@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-linux-s390x-gnu@npm:0.132.0" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@oxc-parser/binding-linux-x64-gnu@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-linux-x64-gnu@npm:0.132.0" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@oxc-parser/binding-linux-x64-musl@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-linux-x64-musl@npm:0.132.0" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@oxc-parser/binding-openharmony-arm64@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-openharmony-arm64@npm:0.132.0" - conditions: os=openharmony & cpu=arm64 - languageName: node - linkType: hard - -"@oxc-parser/binding-wasm32-wasi@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-wasm32-wasi@npm:0.132.0" - dependencies: - "@emnapi/core": "npm:1.10.0" - "@emnapi/runtime": "npm:1.10.0" - "@napi-rs/wasm-runtime": "npm:^1.1.4" - conditions: cpu=wasm32 - languageName: node - linkType: hard - -"@oxc-parser/binding-win32-arm64-msvc@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-win32-arm64-msvc@npm:0.132.0" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@oxc-parser/binding-win32-ia32-msvc@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-win32-ia32-msvc@npm:0.132.0" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@oxc-parser/binding-win32-x64-msvc@npm:0.132.0": - version: 0.132.0 - resolution: "@oxc-parser/binding-win32-x64-msvc@npm:0.132.0" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@oxc-project/types@npm:^0.132.0": - version: 0.132.0 - resolution: "@oxc-project/types@npm:0.132.0" - checksum: 10c0/d0ca5e98be0b873d69e4f0f743eb35026833603dac11db9d55f2b5438251b381b886dc556fe3175a17b673f8e2073c49bde88d7e6e702aa09298c22b8b5504e1 - languageName: node - linkType: hard - -"@oxc-resolver/binding-android-arm-eabi@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-android-arm-eabi@npm:11.19.1" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@oxc-resolver/binding-android-arm64@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-android-arm64@npm:11.19.1" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"@oxc-resolver/binding-darwin-arm64@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-darwin-arm64@npm:11.19.1" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@oxc-resolver/binding-darwin-x64@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-darwin-x64@npm:11.19.1" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@oxc-resolver/binding-freebsd-x64@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-freebsd-x64@npm:11.19.1" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@oxc-resolver/binding-linux-arm-gnueabihf@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-linux-arm-gnueabihf@npm:11.19.1" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@oxc-resolver/binding-linux-arm-musleabihf@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-linux-arm-musleabihf@npm:11.19.1" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@oxc-resolver/binding-linux-arm64-gnu@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-linux-arm64-gnu@npm:11.19.1" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@oxc-resolver/binding-linux-arm64-musl@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-linux-arm64-musl@npm:11.19.1" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@oxc-resolver/binding-linux-ppc64-gnu@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-linux-ppc64-gnu@npm:11.19.1" - conditions: os=linux & cpu=ppc64 & libc=glibc - languageName: node - linkType: hard - -"@oxc-resolver/binding-linux-riscv64-gnu@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-linux-riscv64-gnu@npm:11.19.1" - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@oxc-resolver/binding-linux-riscv64-musl@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-linux-riscv64-musl@npm:11.19.1" - conditions: os=linux & cpu=riscv64 & libc=musl - languageName: node - linkType: hard - -"@oxc-resolver/binding-linux-s390x-gnu@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-linux-s390x-gnu@npm:11.19.1" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@oxc-resolver/binding-linux-x64-gnu@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-linux-x64-gnu@npm:11.19.1" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@oxc-resolver/binding-linux-x64-musl@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-linux-x64-musl@npm:11.19.1" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@oxc-resolver/binding-openharmony-arm64@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-openharmony-arm64@npm:11.19.1" - conditions: os=openharmony & cpu=arm64 - languageName: node - linkType: hard - -"@oxc-resolver/binding-wasm32-wasi@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-wasm32-wasi@npm:11.19.1" - dependencies: - "@napi-rs/wasm-runtime": "npm:^1.1.1" - conditions: cpu=wasm32 - languageName: node - linkType: hard - -"@oxc-resolver/binding-win32-arm64-msvc@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-win32-arm64-msvc@npm:11.19.1" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@oxc-resolver/binding-win32-ia32-msvc@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-win32-ia32-msvc@npm:11.19.1" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@oxc-resolver/binding-win32-x64-msvc@npm:11.19.1": - version: 11.19.1 - resolution: "@oxc-resolver/binding-win32-x64-msvc@npm:11.19.1" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@oxlint/binding-android-arm-eabi@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-android-arm-eabi@npm:1.67.0" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@oxlint/binding-android-arm64@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-android-arm64@npm:1.67.0" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"@oxlint/binding-darwin-arm64@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-darwin-arm64@npm:1.67.0" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@oxlint/binding-darwin-x64@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-darwin-x64@npm:1.67.0" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@oxlint/binding-freebsd-x64@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-freebsd-x64@npm:1.67.0" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@oxlint/binding-linux-arm-gnueabihf@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-linux-arm-gnueabihf@npm:1.67.0" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@oxlint/binding-linux-arm-musleabihf@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-linux-arm-musleabihf@npm:1.67.0" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@oxlint/binding-linux-arm64-gnu@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-linux-arm64-gnu@npm:1.67.0" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@oxlint/binding-linux-arm64-musl@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-linux-arm64-musl@npm:1.67.0" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@oxlint/binding-linux-ppc64-gnu@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-linux-ppc64-gnu@npm:1.67.0" - conditions: os=linux & cpu=ppc64 & libc=glibc - languageName: node - linkType: hard - -"@oxlint/binding-linux-riscv64-gnu@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-linux-riscv64-gnu@npm:1.67.0" - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@oxlint/binding-linux-riscv64-musl@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-linux-riscv64-musl@npm:1.67.0" - conditions: os=linux & cpu=riscv64 & libc=musl - languageName: node - linkType: hard - -"@oxlint/binding-linux-s390x-gnu@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-linux-s390x-gnu@npm:1.67.0" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@oxlint/binding-linux-x64-gnu@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-linux-x64-gnu@npm:1.67.0" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@oxlint/binding-linux-x64-musl@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-linux-x64-musl@npm:1.67.0" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@oxlint/binding-openharmony-arm64@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-openharmony-arm64@npm:1.67.0" - conditions: os=openharmony & cpu=arm64 - languageName: node - linkType: hard - -"@oxlint/binding-win32-arm64-msvc@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-win32-arm64-msvc@npm:1.67.0" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@oxlint/binding-win32-ia32-msvc@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-win32-ia32-msvc@npm:1.67.0" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@oxlint/binding-win32-x64-msvc@npm:1.67.0": - version: 1.67.0 - resolution: "@oxlint/binding-win32-x64-msvc@npm:1.67.0" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@radix-ui/number@npm:1.1.1": - version: 1.1.1 - resolution: "@radix-ui/number@npm:1.1.1" - checksum: 10c0/0570ad92287398e8a7910786d7cee0a998174cdd6637ba61571992897c13204adf70b9ed02d0da2af554119411128e701d9c6b893420612897b438dc91db712b - languageName: node - linkType: hard - -"@radix-ui/primitive@npm:1.1.3": - version: 1.1.3 - resolution: "@radix-ui/primitive@npm:1.1.3" - checksum: 10c0/88860165ee7066fa2c179f32ffcd3ee6d527d9dcdc0e8be85e9cb0e2c84834be8e3c1a976c74ba44b193f709544e12f54455d892b28e32f0708d89deda6b9f1d - languageName: node - linkType: hard - -"@radix-ui/react-arrow@npm:1.1.7": - version: 1.1.7 - resolution: "@radix-ui/react-arrow@npm:1.1.7" - dependencies: - "@radix-ui/react-primitive": "npm:2.1.3" - 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 - checksum: 10c0/c3b46766238b3ee2a394d8806a5141432361bf1425110c9f0dcf480bda4ebd304453a53f294b5399c6ee3ccfcae6fd544921fd01ddc379cf5942acdd7168664b - languageName: node - linkType: hard - -"@radix-ui/react-collection@npm:1.1.7": - version: 1.1.7 - resolution: "@radix-ui/react-collection@npm:1.1.7" - dependencies: - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-context": "npm:1.1.2" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-slot": "npm:1.2.3" - 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 - checksum: 10c0/fa321a7300095508491f75414f02b243f0c3f179dc0728cfd115e2ea9f6f48f1516532b59f526d9ac81bbab63cd98a052074b4703ec0b9428fac945ebabec5fd - languageName: node - linkType: hard - -"@radix-ui/react-compose-refs@npm:1.1.2, @radix-ui/react-compose-refs@npm:^1.1.1": - version: 1.1.2 - resolution: "@radix-ui/react-compose-refs@npm:1.1.2" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/d36a9c589eb75d634b9b139c80f916aadaf8a68a7c1c4b8c6c6b88755af1a92f2e343457042089f04cc3f23073619d08bb65419ced1402e9d4e299576d970771 - languageName: node - linkType: hard - -"@radix-ui/react-context@npm:1.1.2": - version: 1.1.2 - resolution: "@radix-ui/react-context@npm:1.1.2" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/cece731f8cc25d494c6589cc681e5c01a93867d895c75889973afa1a255f163c286e390baa7bc028858eaabe9f6b57270d0ca6377356f652c5557c1c7a41ccce - languageName: node - linkType: hard - -"@radix-ui/react-dialog@npm:^1.1.15, @radix-ui/react-dialog@npm:^1.1.6": - version: 1.1.15 - resolution: "@radix-ui/react-dialog@npm:1.1.15" - dependencies: - "@radix-ui/primitive": "npm:1.1.3" - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-context": "npm:1.1.2" - "@radix-ui/react-dismissable-layer": "npm:1.1.11" - "@radix-ui/react-focus-guards": "npm:1.1.3" - "@radix-ui/react-focus-scope": "npm:1.1.7" - "@radix-ui/react-id": "npm:1.1.1" - "@radix-ui/react-portal": "npm:1.1.9" - "@radix-ui/react-presence": "npm:1.1.5" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-slot": "npm:1.2.3" - "@radix-ui/react-use-controllable-state": "npm:1.2.2" - aria-hidden: "npm:^1.2.4" - react-remove-scroll: "npm:^2.6.3" - 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 - checksum: 10c0/2f2c88e3c281acaea2fd9b96fa82132d59177d3aa5da2e7c045596fd4028e84e44ac52ac28f4f236910605dd7d9338c2858ba44a9ced2af2e3e523abbfd33014 - languageName: node - linkType: hard - -"@radix-ui/react-direction@npm:1.1.1": - version: 1.1.1 - resolution: "@radix-ui/react-direction@npm:1.1.1" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/7a89d9291f846a3105e45f4df98d6b7a08f8d7b30acdcd253005dc9db107ee83cbbebc9e47a9af1e400bcd47697f1511ceab23a399b0da854488fc7220482ac9 - languageName: node - linkType: hard - -"@radix-ui/react-dismissable-layer@npm:1.1.11": - version: 1.1.11 - resolution: "@radix-ui/react-dismissable-layer@npm:1.1.11" - dependencies: - "@radix-ui/primitive": "npm:1.1.3" - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-use-callback-ref": "npm:1.1.1" - "@radix-ui/react-use-escape-keydown": "npm:1.1.1" - 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 - checksum: 10c0/c825572a64073c4d3853702029979f6658770ffd6a98eabc4984e1dee1b226b4078a2a4dc7003f96475b438985e9b21a58e75f51db74dd06848dcae1f2d395dc - languageName: node - linkType: hard - -"@radix-ui/react-dropdown-menu@npm:^2.1.16": - version: 2.1.16 - resolution: "@radix-ui/react-dropdown-menu@npm:2.1.16" - dependencies: - "@radix-ui/primitive": "npm:1.1.3" - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-context": "npm:1.1.2" - "@radix-ui/react-id": "npm:1.1.1" - "@radix-ui/react-menu": "npm:2.1.16" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-use-controllable-state": "npm:1.2.2" - 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 - checksum: 10c0/8caaa8dd791ccb284568720adafa59855e13860aa29eb20e10a04ba671cbbfa519a4c5d3a339a4d9fb08009eeb1065f4a8b5c3c8ef45e9753161cc560106b935 - languageName: node - linkType: hard - -"@radix-ui/react-focus-guards@npm:1.1.3": - version: 1.1.3 - resolution: "@radix-ui/react-focus-guards@npm:1.1.3" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/0bab65eb8d7e4f72f685d63de7fbba2450e3cb15ad6a20a16b42195e9d335c576356f5a47cb58d1ffc115393e46d7b14b12c5d4b10029b0ec090861255866985 - languageName: node - linkType: hard - -"@radix-ui/react-focus-scope@npm:1.1.7": - version: 1.1.7 - resolution: "@radix-ui/react-focus-scope@npm:1.1.7" - dependencies: - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-use-callback-ref": "npm:1.1.1" - 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 - checksum: 10c0/8a6071331bdeeb79b223463de75caf759b8ad19339cab838e537b8dbb2db236891a1f4df252445c854d375d43d9d315dfcce0a6b01553a2984ec372bb8f1300e - languageName: node - linkType: hard - -"@radix-ui/react-id@npm:1.1.1, @radix-ui/react-id@npm:^1.1.0": - version: 1.1.1 - resolution: "@radix-ui/react-id@npm:1.1.1" - dependencies: - "@radix-ui/react-use-layout-effect": "npm:1.1.1" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/7d12e76818763d592c331277ef62b197e2e64945307e650bd058f0090e5ae48bbd07691b23b7e9e977901ef4eadcb3e2d5eaeb17a13859083384be83fc1292c7 - languageName: node - linkType: hard - -"@radix-ui/react-label@npm:^2.1.7": - version: 2.1.7 - resolution: "@radix-ui/react-label@npm:2.1.7" - dependencies: - "@radix-ui/react-primitive": "npm:2.1.3" - 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 - checksum: 10c0/d8c81411d5327b6db5cbf4b900bfcc52030315539911701cf8d82b4970aed80cbd66df5b62d2242859572c666cf4b0e147a8b39dc3c04bd024a4b4405e1183fe - languageName: node - linkType: hard - -"@radix-ui/react-menu@npm:2.1.16": - version: 2.1.16 - resolution: "@radix-ui/react-menu@npm:2.1.16" - dependencies: - "@radix-ui/primitive": "npm:1.1.3" - "@radix-ui/react-collection": "npm:1.1.7" - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-context": "npm:1.1.2" - "@radix-ui/react-direction": "npm:1.1.1" - "@radix-ui/react-dismissable-layer": "npm:1.1.11" - "@radix-ui/react-focus-guards": "npm:1.1.3" - "@radix-ui/react-focus-scope": "npm:1.1.7" - "@radix-ui/react-id": "npm:1.1.1" - "@radix-ui/react-popper": "npm:1.2.8" - "@radix-ui/react-portal": "npm:1.1.9" - "@radix-ui/react-presence": "npm:1.1.5" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-roving-focus": "npm:1.1.11" - "@radix-ui/react-slot": "npm:1.2.3" - "@radix-ui/react-use-callback-ref": "npm:1.1.1" - aria-hidden: "npm:^1.2.4" - react-remove-scroll: "npm:^2.6.3" - 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 - checksum: 10c0/27516b2b987fa9181c4da8645000af8f60691866a349d7a46b9505fa7d2e9d92b9e364db4f7305d08e9e57d0e1afc8df8354f8ee3c12aa05c0100c16b0e76c27 - languageName: node - linkType: hard - -"@radix-ui/react-popover@npm:^1.1.15": - version: 1.1.15 - resolution: "@radix-ui/react-popover@npm:1.1.15" - dependencies: - "@radix-ui/primitive": "npm:1.1.3" - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-context": "npm:1.1.2" - "@radix-ui/react-dismissable-layer": "npm:1.1.11" - "@radix-ui/react-focus-guards": "npm:1.1.3" - "@radix-ui/react-focus-scope": "npm:1.1.7" - "@radix-ui/react-id": "npm:1.1.1" - "@radix-ui/react-popper": "npm:1.2.8" - "@radix-ui/react-portal": "npm:1.1.9" - "@radix-ui/react-presence": "npm:1.1.5" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-slot": "npm:1.2.3" - "@radix-ui/react-use-controllable-state": "npm:1.2.2" - aria-hidden: "npm:^1.2.4" - react-remove-scroll: "npm:^2.6.3" - 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 - checksum: 10c0/c1c76b5e5985b128d03b621424fb453f769931d497759a1977734d303007da9f970570cf3ea1f6968ab609ab4a97f384168bff056197bd2d3d422abea0e3614b - languageName: node - linkType: hard - -"@radix-ui/react-popper@npm:1.2.8": - version: 1.2.8 - resolution: "@radix-ui/react-popper@npm:1.2.8" - dependencies: - "@floating-ui/react-dom": "npm:^2.0.0" - "@radix-ui/react-arrow": "npm:1.1.7" - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-context": "npm:1.1.2" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-use-callback-ref": "npm:1.1.1" - "@radix-ui/react-use-layout-effect": "npm:1.1.1" - "@radix-ui/react-use-rect": "npm:1.1.1" - "@radix-ui/react-use-size": "npm:1.1.1" - "@radix-ui/rect": "npm:1.1.1" - 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 - checksum: 10c0/48e3f13eac3b8c13aca8ded37d74db17e1bb294da8d69f142ab6b8719a06c3f90051668bed64520bf9f3abdd77b382ce7ce209d056bb56137cecc949b69b421c - languageName: node - linkType: hard - -"@radix-ui/react-portal@npm:1.1.9": - version: 1.1.9 - resolution: "@radix-ui/react-portal@npm:1.1.9" - dependencies: - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-use-layout-effect": "npm:1.1.1" - 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 - checksum: 10c0/45b432497c722720c72c493a29ef6085bc84b50eafe79d48b45c553121b63e94f9cdb77a3a74b9c49126f8feb3feee009fe400d48b7759d3552396356b192cd7 - languageName: node - linkType: hard - -"@radix-ui/react-presence@npm:1.1.5": - version: 1.1.5 - resolution: "@radix-ui/react-presence@npm:1.1.5" - dependencies: - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-use-layout-effect": "npm:1.1.1" - 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 - checksum: 10c0/d0e61d314250eeaef5369983cb790701d667f51734bafd98cf759072755562018052c594e6cdc5389789f4543cb0a4d98f03ff4e8f37338d6b5bf51a1700c1d1 - languageName: node - linkType: hard - -"@radix-ui/react-primitive@npm:2.1.3, @radix-ui/react-primitive@npm:^2.0.2": - version: 2.1.3 - resolution: "@radix-ui/react-primitive@npm:2.1.3" - dependencies: - "@radix-ui/react-slot": "npm:1.2.3" - 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 - checksum: 10c0/fdff9b84913bb4172ef6d3af7442fca5f9bba5f2709cba08950071f819d7057aec3a4a2d9ef44cf9cbfb8014d02573c6884a04cff175895823aaef809ebdb034 - languageName: node - linkType: hard - -"@radix-ui/react-roving-focus@npm:1.1.11": - version: 1.1.11 - resolution: "@radix-ui/react-roving-focus@npm:1.1.11" - dependencies: - "@radix-ui/primitive": "npm:1.1.3" - "@radix-ui/react-collection": "npm:1.1.7" - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-context": "npm:1.1.2" - "@radix-ui/react-direction": "npm:1.1.1" - "@radix-ui/react-id": "npm:1.1.1" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-use-callback-ref": "npm:1.1.1" - "@radix-ui/react-use-controllable-state": "npm:1.2.2" - 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 - checksum: 10c0/2cd43339c36e89a3bf1db8aab34b939113dfbde56bf3a33df2d74757c78c9489b847b1962f1e2441c67e41817d120cb6177943e0f655f47bc1ff8e44fd55b1a2 - languageName: node - linkType: hard - -"@radix-ui/react-scroll-area@npm:^1.2.10": - version: 1.2.10 - resolution: "@radix-ui/react-scroll-area@npm:1.2.10" - dependencies: - "@radix-ui/number": "npm:1.1.1" - "@radix-ui/primitive": "npm:1.1.3" - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-context": "npm:1.1.2" - "@radix-ui/react-direction": "npm:1.1.1" - "@radix-ui/react-presence": "npm:1.1.5" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-use-callback-ref": "npm:1.1.1" - "@radix-ui/react-use-layout-effect": "npm:1.1.1" - 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 - checksum: 10c0/8acdacd255fdfcefe4f72028a13dc554df73327db94c250f54a85b9608aa0313284dbb6c417f28a48e7b7b7bcaa76ddf3297e91ba07d833604d428f869259622 - languageName: node - linkType: hard - -"@radix-ui/react-slot@npm:1.2.3, @radix-ui/react-slot@npm:^1.2.3": - version: 1.2.3 - resolution: "@radix-ui/react-slot@npm:1.2.3" - dependencies: - "@radix-ui/react-compose-refs": "npm:1.1.2" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/5913aa0d760f505905779515e4b1f0f71a422350f077cc8d26d1aafe53c97f177fec0e6d7fbbb50d8b5e498aa9df9f707ca75ae3801540c283b26b0136138eef - languageName: node - linkType: hard - -"@radix-ui/react-toast@npm:^1.2.15": - version: 1.2.15 - resolution: "@radix-ui/react-toast@npm:1.2.15" - dependencies: - "@radix-ui/primitive": "npm:1.1.3" - "@radix-ui/react-collection": "npm:1.1.7" - "@radix-ui/react-compose-refs": "npm:1.1.2" - "@radix-ui/react-context": "npm:1.1.2" - "@radix-ui/react-dismissable-layer": "npm:1.1.11" - "@radix-ui/react-portal": "npm:1.1.9" - "@radix-ui/react-presence": "npm:1.1.5" - "@radix-ui/react-primitive": "npm:2.1.3" - "@radix-ui/react-use-callback-ref": "npm:1.1.1" - "@radix-ui/react-use-controllable-state": "npm:1.2.2" - "@radix-ui/react-use-layout-effect": "npm:1.1.1" - "@radix-ui/react-visually-hidden": "npm:1.2.3" - 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 - checksum: 10c0/e7050d356719f438e087e8033e47a8854fba001cf71eb4e0c0203d53a4fbbd35aca9f17f73abe4dadc406d2d85badf4e37065865d07835763d0e3cb9d95a518d - languageName: node - linkType: hard - -"@radix-ui/react-use-callback-ref@npm:1.1.1": - version: 1.1.1 - resolution: "@radix-ui/react-use-callback-ref@npm:1.1.1" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/5f6aff8592dea6a7e46589808912aba3fb3b626cf6edd2b14f01638b61dbbe49eeb9f67cd5601f4c15b2fb547b9a7e825f7c4961acd4dd70176c969ae405f8d8 - languageName: node - linkType: hard - -"@radix-ui/react-use-controllable-state@npm:1.2.2": - version: 1.2.2 - resolution: "@radix-ui/react-use-controllable-state@npm:1.2.2" - dependencies: - "@radix-ui/react-use-effect-event": "npm:0.0.2" - "@radix-ui/react-use-layout-effect": "npm:1.1.1" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/f55c4b06e895293aed4b44c9ef26fb24432539f5346fcd6519c7745800535b571058685314e83486a45bf61dc83887e24826490d3068acc317fb0a9010516e63 - languageName: node - linkType: hard - -"@radix-ui/react-use-effect-event@npm:0.0.2": - version: 0.0.2 - resolution: "@radix-ui/react-use-effect-event@npm:0.0.2" - dependencies: - "@radix-ui/react-use-layout-effect": "npm:1.1.1" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/e84ff72a3e76c5ae9c94941028bb4b6472f17d4104481b9eab773deab3da640ecea035e54da9d6f4df8d84c18ef6913baf92b7511bee06930dc58bd0c0add417 - languageName: node - linkType: hard - -"@radix-ui/react-use-escape-keydown@npm:1.1.1": - version: 1.1.1 - resolution: "@radix-ui/react-use-escape-keydown@npm:1.1.1" - dependencies: - "@radix-ui/react-use-callback-ref": "npm:1.1.1" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/bff53be99e940fef1d3c4df7d560e1d9133182e5a98336255d3063327d1d3dd4ec54a95dc5afe15cca4fb6c184f0a956c70de2815578c318cf995a7f9beabaa1 - languageName: node - linkType: hard - -"@radix-ui/react-use-layout-effect@npm:1.1.1": - version: 1.1.1 - resolution: "@radix-ui/react-use-layout-effect@npm:1.1.1" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/9f98fdaba008dfc58050de60a77670b885792df473cf82c1cef8daee919a5dd5a77d270209f5f0b0abfaac78cb1627396e3ff56c81b735be550409426fe8b040 - languageName: node - linkType: hard - -"@radix-ui/react-use-rect@npm:1.1.1": - version: 1.1.1 - resolution: "@radix-ui/react-use-rect@npm:1.1.1" - dependencies: - "@radix-ui/rect": "npm:1.1.1" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/271711404c05c589c8dbdaa748749e7daf44bcc6bffc9ecd910821c3ebca0ee245616cf5b39653ce690f53f875c3836fd3f36f51ab1c628273b6db599eee4864 - languageName: node - linkType: hard - -"@radix-ui/react-use-size@npm:1.1.1": - version: 1.1.1 - resolution: "@radix-ui/react-use-size@npm:1.1.1" - dependencies: - "@radix-ui/react-use-layout-effect": "npm:1.1.1" - peerDependencies: - "@types/react": "*" - react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/851d09a816f44282e0e9e2147b1b571410174cc048703a50c4fa54d672de994fd1dfff1da9d480ecfd12c77ae8f48d74f01adaf668f074156b8cd0043c6c21d8 - languageName: node - linkType: hard - -"@radix-ui/react-visually-hidden@npm:1.2.3": - version: 1.2.3 - resolution: "@radix-ui/react-visually-hidden@npm:1.2.3" - dependencies: - "@radix-ui/react-primitive": "npm:2.1.3" - 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 - checksum: 10c0/cf86a37f1cbee50a964056f3dc4f6bb1ee79c76daa321f913aa20ff3e1ccdfafbf2b114d7bb616aeefc7c4b895e6ca898523fdb67710d89bd5d8edb739a0d9b6 - languageName: node - linkType: hard - -"@radix-ui/rect@npm:1.1.1": - version: 1.1.1 - resolution: "@radix-ui/rect@npm:1.1.1" - checksum: 10c0/0dac4f0f15691199abe6a0e067821ddd9d0349c0c05f39834e4eafc8403caf724106884035ae91bbc826e10367e6a5672e7bec4d4243860fa7649de246b1f60b - languageName: node - linkType: hard - -"@rtsao/scc@npm:^1.1.0": - version: 1.1.0 - resolution: "@rtsao/scc@npm:1.1.0" - checksum: 10c0/b5bcfb0d87f7d1c1c7c0f7693f53b07866ed9fec4c34a97a8c948fb9a7c0082e416ce4d3b60beb4f5e167cbe04cdeefbf6771320f3ede059b9ce91188c409a5b - languageName: node - linkType: hard - -"@standard-schema/spec@npm:^1.1.0": - version: 1.1.0 - resolution: "@standard-schema/spec@npm:1.1.0" - checksum: 10c0/d90f55acde4b2deb983529c87e8025fa693de1a5e8b49ecc6eb84d1fd96328add0e03d7d551442156c7432fd78165b2c26ff561b970a9a881f046abb78d6a526 - languageName: node - linkType: hard - -"@swc/helpers@npm:0.5.15": - version: 0.5.15 - resolution: "@swc/helpers@npm:0.5.15" - dependencies: - tslib: "npm:^2.8.0" - checksum: 10c0/33002f74f6f885f04c132960835fdfc474186983ea567606db62e86acd0680ca82f34647e8e610f4e1e422d1c16fce729dde22cd3b797ab1fd9061a825dabca4 - languageName: node - linkType: hard - -"@tybys/wasm-util@npm:^0.10.0": - version: 0.10.0 - resolution: "@tybys/wasm-util@npm:0.10.0" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/044feba55c1e2af703aa4946139969badb183ce1a659a75ed60bc195a90e73a3f3fc53bcd643497c9954597763ddb051fec62f80962b2ca6fc716ba897dc696e - languageName: node - linkType: hard - -"@tybys/wasm-util@npm:^0.10.1": - version: 0.10.1 - resolution: "@tybys/wasm-util@npm:0.10.1" - dependencies: - tslib: "npm:^2.4.0" - checksum: 10c0/b255094f293794c6d2289300c5fbcafbb5532a3aed3a5ffd2f8dc1828e639b88d75f6a376dd8f94347a44813fd7a7149d8463477a9a49525c8b2dcaa38c2d1e8 - languageName: node - linkType: hard - -"@types/canvas-confetti@npm:^1.9.0": - version: 1.9.0 - resolution: "@types/canvas-confetti@npm:1.9.0" - checksum: 10c0/ffe2c674d466b8e13472c81ab2a97056f3433fd40a3513dbc1bb76764e4e7c3ff0a2a58d37b16ea6a245c831077c553db321b069dda6572eab59f2be61137b2e - languageName: node - linkType: hard - -"@types/esrecurse@npm:^4.3.1": - version: 4.3.1 - resolution: "@types/esrecurse@npm:4.3.1" - checksum: 10c0/90dad74d5da3ad27606d8e8e757322f33171cfeaa15ad558b615cf71bb2a516492d18f55f4816384685a3eb2412142e732bbae9a4a7cd2cf3deb7572aa4ebe03 - languageName: node - linkType: hard - -"@types/estree@npm:^1.0.6": - version: 1.0.8 - resolution: "@types/estree@npm:1.0.8" - checksum: 10c0/39d34d1afaa338ab9763f37ad6066e3f349444f9052b9676a7cc0252ef9485a41c6d81c9c4e0d26e9077993354edf25efc853f3224dd4b447175ef62bdcc86a5 - languageName: node - linkType: hard - -"@types/estree@npm:^1.0.8": - version: 1.0.9 - resolution: "@types/estree@npm:1.0.9" - checksum: 10c0/3ad3286ca2988cd550dafb8f2ad599c8474868e954fa601a36655bdfefd8039f7c714b8c1c7f2ae219ffbd58bd4660e66fa7479a0120fc02d4777057d4865387 - languageName: node - linkType: hard - -"@types/json-schema@npm:^7.0.15": - version: 7.0.15 - resolution: "@types/json-schema@npm:7.0.15" - checksum: 10c0/a996a745e6c5d60292f36731dd41341339d4eeed8180bb09226e5c8d23759067692b1d88e5d91d72ee83dfc00d3aca8e7bd43ea120516c17922cbcb7c3e252db - languageName: node - linkType: hard - -"@types/json5@npm:^0.0.29": - version: 0.0.29 - resolution: "@types/json5@npm:0.0.29" - checksum: 10c0/6bf5337bc447b706bb5b4431d37686aa2ea6d07cfd6f79cc31de80170d6ff9b1c7384a9c0ccbc45b3f512bae9e9f75c2e12109806a15331dc94e8a8db6dbb4ac - languageName: node - linkType: hard - -"@types/minimatch@npm:^6.0.0": - version: 6.0.0 - resolution: "@types/minimatch@npm:6.0.0" - dependencies: - minimatch: "npm:*" - checksum: 10c0/901fc4208cf6f5ab0e86bf86504055fb387f76092e06e604a3f2403db1c20e613c42104b235fde05552e0632d8f82e4ceacb83351d8700c7ffc5c31010a80804 - languageName: node - linkType: hard - -"@types/node@npm:*": - version: 25.9.1 - resolution: "@types/node@npm:25.9.1" - dependencies: - undici-types: "npm:>=7.24.0 <7.24.7" - checksum: 10c0/9a04682842bebbcf21a1779dfeab9aa733d7bd7bbc0a0edb641ab3a9a3d43eac543225acf669c334f458f1956443ebc072bc3c72840c543b8b356cab5c82d456 - languageName: node - linkType: hard - -"@types/node@npm:22.7.5": - version: 22.7.5 - resolution: "@types/node@npm:22.7.5" - dependencies: - undici-types: "npm:~6.19.2" - checksum: 10c0/cf11f74f1a26053ec58066616e3a8685b6bcd7259bc569738b8f752009f9f0f7f85a1b2d24908e5b0f752482d1e8b6babdf1fbb25758711ec7bb9500bfcd6e60 - languageName: node - linkType: hard - -"@types/node@npm:^20": - version: 20.19.9 - resolution: "@types/node@npm:20.19.9" - dependencies: - undici-types: "npm:~6.21.0" - checksum: 10c0/c6738131f1698258a5ac1e0185e4fc56977f7f566cd0ee11167f93f2339478470257bd82c5e1908a936a204e0ad7996d741356a1a07c04997a236161ea23a874 - languageName: node - linkType: hard - -"@types/react-dom@npm:^19.2.3": - version: 19.2.3 - resolution: "@types/react-dom@npm:19.2.3" - peerDependencies: - "@types/react": ^19.2.0 - checksum: 10c0/b486ebe0f4e2fb35e2e108df1d8fc0927ca5d6002d5771e8a739de11239fe62d0e207c50886185253c99eb9dedfeeb956ea7429e5ba17f6693c7acb4c02f8cd1 - languageName: node - linkType: hard - -"@types/react@npm:^19.2.7": - version: 19.2.7 - resolution: "@types/react@npm:19.2.7" - dependencies: - csstype: "npm:^3.2.2" - checksum: 10c0/a7b75f1f9fcb34badd6f84098be5e35a0aeca614bc91f93d2698664c0b2ba5ad128422bd470ada598238cebe4f9e604a752aead7dc6f5a92261d0c7f9b27cfd1 - languageName: node - linkType: hard - -"@types/ws@npm:^8.18.1": - version: 8.18.1 - resolution: "@types/ws@npm:8.18.1" - dependencies: - "@types/node": "npm:*" - checksum: 10c0/61aff1129143fcc4312f083bc9e9e168aa3026b7dd6e70796276dcfb2c8211c4292603f9c4864fae702f2ed86e4abd4d38aa421831c2fd7f856c931a481afbab - languageName: node - linkType: hard - -"@typescript-eslint/eslint-plugin@npm:8.57.1": - version: 8.57.1 - resolution: "@typescript-eslint/eslint-plugin@npm:8.57.1" - dependencies: - "@eslint-community/regexpp": "npm:^4.12.2" - "@typescript-eslint/scope-manager": "npm:8.57.1" - "@typescript-eslint/type-utils": "npm:8.57.1" - "@typescript-eslint/utils": "npm:8.57.1" - "@typescript-eslint/visitor-keys": "npm:8.57.1" - ignore: "npm:^7.0.5" - natural-compare: "npm:^1.4.0" - ts-api-utils: "npm:^2.4.0" - peerDependencies: - "@typescript-eslint/parser": ^8.57.1 - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/5bf9227f5d608d4313c9f898da3a2f6737eca985aa925df9e90b73499b9d552221781d3d09245543c6d09995ab262ea0d6773d2dae4b8bdf319765d46b22d0e1 - languageName: node - linkType: hard - -"@typescript-eslint/parser@npm:8.57.1": - version: 8.57.1 - resolution: "@typescript-eslint/parser@npm:8.57.1" - dependencies: - "@typescript-eslint/scope-manager": "npm:8.57.1" - "@typescript-eslint/types": "npm:8.57.1" - "@typescript-eslint/typescript-estree": "npm:8.57.1" - "@typescript-eslint/visitor-keys": "npm:8.57.1" - debug: "npm:^4.4.3" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/ab624f5ad6f3585ee690d11be36597135779a373e7f07810ed921163de2e879000f6d3213db67413ee630bcf25d5cfaa24b089ee49596cd11b0456372bc17163 - languageName: node - linkType: hard - -"@typescript-eslint/project-service@npm:8.57.1": - version: 8.57.1 - resolution: "@typescript-eslint/project-service@npm:8.57.1" - dependencies: - "@typescript-eslint/tsconfig-utils": "npm:^8.57.1" - "@typescript-eslint/types": "npm:^8.57.1" - debug: "npm:^4.4.3" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/7830f61e35364ba77799f4badeaca8bd8914bbcda6afe37b788821f94f4b88b9c49817c50f4bdba497e8e542a705e9d921d36f5e67960ebf33f4f3d3111cdfee - languageName: node - linkType: hard - -"@typescript-eslint/scope-manager@npm:8.57.1": - version: 8.57.1 - resolution: "@typescript-eslint/scope-manager@npm:8.57.1" - dependencies: - "@typescript-eslint/types": "npm:8.57.1" - "@typescript-eslint/visitor-keys": "npm:8.57.1" - checksum: 10c0/42b0b54981318bf21be6b107df82910718497b7b7b2b60df635aa06d78e313759e4b675830c0e542b6d87104d35b49df41b9fb7739b8ae326eaba2d6f7116166 - languageName: node - linkType: hard - -"@typescript-eslint/tsconfig-utils@npm:8.57.1, @typescript-eslint/tsconfig-utils@npm:^8.57.1": - version: 8.57.1 - resolution: "@typescript-eslint/tsconfig-utils@npm:8.57.1" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/3d3c8d80621507d31e4656c693534f28a1c04dfb047538cb79b0b6da874ef41875f5df5e814fa3a38812451cff6d5a7ae38d0bf77eb7fec7867f9c80af361b00 - languageName: node - linkType: hard - -"@typescript-eslint/type-utils@npm:8.57.1": - version: 8.57.1 - resolution: "@typescript-eslint/type-utils@npm:8.57.1" - dependencies: - "@typescript-eslint/types": "npm:8.57.1" - "@typescript-eslint/typescript-estree": "npm:8.57.1" - "@typescript-eslint/utils": "npm:8.57.1" - debug: "npm:^4.4.3" - ts-api-utils: "npm:^2.4.0" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/e8eae4e3b9ca71ad065c307fd3cdefdcc6abc31bda2ef74f0e54b5c9ac0ee6bc0e2d69ec9097899f4d7a99d4a8a72391503b47f4317b3b6b9ba41cea24e6b9e9 - languageName: node - linkType: hard - -"@typescript-eslint/types@npm:8.57.1, @typescript-eslint/types@npm:^8.57.1": - version: 8.57.1 - resolution: "@typescript-eslint/types@npm:8.57.1" - checksum: 10c0/f447015276a31871440b07e328c2bbcee8337d72dca90ae00ac91e87d09e28a8a9c2fe44726a5226fcaa7db9d5347aafa650d59f7577a074dc65ea1414d24da1 - languageName: node - linkType: hard - -"@typescript-eslint/types@npm:^8.59.3": - version: 8.60.0 - resolution: "@typescript-eslint/types@npm:8.60.0" - checksum: 10c0/d2b6d46081a6521f204fda30e8f03712480b788d80b62b311e0f33764752d3db3bd415dd4e1f8d28495931316da1dfb5ee259e40c5de970367fbaa1efe97223f - languageName: node - linkType: hard - -"@typescript-eslint/typescript-estree@npm:8.57.1": - version: 8.57.1 - resolution: "@typescript-eslint/typescript-estree@npm:8.57.1" - dependencies: - "@typescript-eslint/project-service": "npm:8.57.1" - "@typescript-eslint/tsconfig-utils": "npm:8.57.1" - "@typescript-eslint/types": "npm:8.57.1" - "@typescript-eslint/visitor-keys": "npm:8.57.1" - debug: "npm:^4.4.3" - minimatch: "npm:^10.2.2" - semver: "npm:^7.7.3" - tinyglobby: "npm:^0.2.15" - ts-api-utils: "npm:^2.4.0" - peerDependencies: - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/a87e1d920a8fd2231b6a98b279dc7680d10ceac072001e85a72cd43adce288ed471afcaf8f171378f5a3221c500b3cf0ffc10a75fd521fb69fbd8b26d4626677 - languageName: node - linkType: hard - -"@typescript-eslint/utils@npm:8.57.1": - version: 8.57.1 - resolution: "@typescript-eslint/utils@npm:8.57.1" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.9.1" - "@typescript-eslint/scope-manager": "npm:8.57.1" - "@typescript-eslint/types": "npm:8.57.1" - "@typescript-eslint/typescript-estree": "npm:8.57.1" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/c85d6e7c618dbf902fda98cc795883388bc512bc2c34c7ac0481ea43acb6dd3cd38d60bdb571b586f392419a17998c89330fd7b0b9a344161f4a595637dd3f55 - languageName: node - linkType: hard - -"@typescript-eslint/visitor-keys@npm:8.57.1": - version: 8.57.1 - resolution: "@typescript-eslint/visitor-keys@npm:8.57.1" - dependencies: - "@typescript-eslint/types": "npm:8.57.1" - eslint-visitor-keys: "npm:^5.0.0" - checksum: 10c0/088a545c4aec6d9cabb266e1e40634f5fafa06cb05ef172526555957b0d99ac08822733fb788a09227071fdd6bd8b63f054393a0ecf9d4599c54b57918aa0e57 - languageName: node - linkType: hard - -"@unrs/resolver-binding-android-arm-eabi@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-android-arm-eabi@npm:1.11.1" - conditions: os=android & cpu=arm - languageName: node - linkType: hard - -"@unrs/resolver-binding-android-arm64@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-android-arm64@npm:1.11.1" - conditions: os=android & cpu=arm64 - languageName: node - linkType: hard - -"@unrs/resolver-binding-darwin-arm64@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-darwin-arm64@npm:1.11.1" - conditions: os=darwin & cpu=arm64 - languageName: node - linkType: hard - -"@unrs/resolver-binding-darwin-x64@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-darwin-x64@npm:1.11.1" - conditions: os=darwin & cpu=x64 - languageName: node - linkType: hard - -"@unrs/resolver-binding-freebsd-x64@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-freebsd-x64@npm:1.11.1" - conditions: os=freebsd & cpu=x64 - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-linux-arm-gnueabihf@npm:1.11.1" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-arm-musleabihf@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-linux-arm-musleabihf@npm:1.11.1" - conditions: os=linux & cpu=arm - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-arm64-gnu@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-linux-arm64-gnu@npm:1.11.1" - conditions: os=linux & cpu=arm64 & libc=glibc - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-arm64-musl@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-linux-arm64-musl@npm:1.11.1" - conditions: os=linux & cpu=arm64 & libc=musl - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-ppc64-gnu@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-linux-ppc64-gnu@npm:1.11.1" - conditions: os=linux & cpu=ppc64 & libc=glibc - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-riscv64-gnu@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-linux-riscv64-gnu@npm:1.11.1" - conditions: os=linux & cpu=riscv64 & libc=glibc - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-riscv64-musl@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-linux-riscv64-musl@npm:1.11.1" - conditions: os=linux & cpu=riscv64 & libc=musl - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-s390x-gnu@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-linux-s390x-gnu@npm:1.11.1" - conditions: os=linux & cpu=s390x & libc=glibc - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-x64-gnu@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-linux-x64-gnu@npm:1.11.1" - conditions: os=linux & cpu=x64 & libc=glibc - languageName: node - linkType: hard - -"@unrs/resolver-binding-linux-x64-musl@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-linux-x64-musl@npm:1.11.1" - conditions: os=linux & cpu=x64 & libc=musl - languageName: node - linkType: hard - -"@unrs/resolver-binding-wasm32-wasi@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-wasm32-wasi@npm:1.11.1" - dependencies: - "@napi-rs/wasm-runtime": "npm:^0.2.11" - conditions: cpu=wasm32 - languageName: node - linkType: hard - -"@unrs/resolver-binding-win32-arm64-msvc@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-win32-arm64-msvc@npm:1.11.1" - conditions: os=win32 & cpu=arm64 - languageName: node - linkType: hard - -"@unrs/resolver-binding-win32-ia32-msvc@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-win32-ia32-msvc@npm:1.11.1" - conditions: os=win32 & cpu=ia32 - languageName: node - linkType: hard - -"@unrs/resolver-binding-win32-x64-msvc@npm:1.11.1": - version: 1.11.1 - resolution: "@unrs/resolver-binding-win32-x64-msvc@npm:1.11.1" - conditions: os=win32 & cpu=x64 - languageName: node - linkType: hard - -"@upstash/core-analytics@npm:^0.0.10": - version: 0.0.10 - resolution: "@upstash/core-analytics@npm:0.0.10" - dependencies: - "@upstash/redis": "npm:^1.28.3" - checksum: 10c0/c90b1bfaf1f54eed8a48f2aa679f8e082083f49931cf08bd90a0a0035b010f65b6e7420268677f15df1d04687f7e5a9093320c591ef4dbd45d804ea83d890f3f - languageName: node - linkType: hard - -"@upstash/ratelimit@npm:2.0.6": - version: 2.0.6 - resolution: "@upstash/ratelimit@npm:2.0.6" - dependencies: - "@upstash/core-analytics": "npm:^0.0.10" - peerDependencies: - "@upstash/redis": ^1.34.3 - checksum: 10c0/cc563f3bf23f6682eca937df7d317c35af945758cbcef5e6c82b4d9ac757725fb7e7885b111a3c3bcdeddb4f1a007ceb12549edbbdb7fb166535947b35bf57ef - languageName: node - linkType: hard - -"@upstash/redis@npm:1.35.3, @upstash/redis@npm:^1.28.3, @upstash/redis@npm:^1.34.0": - version: 1.35.3 - resolution: "@upstash/redis@npm:1.35.3" - dependencies: - uncrypto: "npm:^0.1.3" - checksum: 10c0/e81ae1341ac73dcc497234490524f9bf435b23d321ce460dae26c664440b9257344d1a994de91889bcf64e7ab48fa0f02ac58f8206958b4399ec7f1fff617fe1 - languageName: node - linkType: hard - -"@vercel/analytics@npm:^1.5.0": - version: 1.5.0 - resolution: "@vercel/analytics@npm:1.5.0" - peerDependencies: - "@remix-run/react": ^2 - "@sveltejs/kit": ^1 || ^2 - next: ">= 13" - react: ^18 || ^19 || ^19.0.0-rc - svelte: ">= 4" - vue: ^3 - vue-router: ^4 - peerDependenciesMeta: - "@remix-run/react": - optional: true - "@sveltejs/kit": - optional: true - next: - optional: true - react: - optional: true - svelte: - optional: true - vue: - optional: true - vue-router: - optional: true - checksum: 10c0/43d33ea83b32f5203fec21b7f43c399e398f0c37d2dd341d522969e0e6ee23fd652a2766a4203a3ce573f711beee5ee1ab7d36316f767a4901160e3e96ee31e5 - languageName: node - linkType: hard - -"@vercel/kv@npm:3.0.0": - version: 3.0.0 - resolution: "@vercel/kv@npm:3.0.0" - dependencies: - "@upstash/redis": "npm:^1.34.0" - checksum: 10c0/55c0e197967c21161ba7bbee02be821975d8e900f2ca3946c9bfaefa1cb5ce94f9ce04aef07aca027c8c39a5ab2e9a2b54edc5c6b617c994d2a8fddfd9d55dc8 - languageName: node - linkType: hard - -"abbrev@npm:^4.0.0": - version: 4.0.0 - resolution: "abbrev@npm:4.0.0" - checksum: 10c0/b4cc16935235e80702fc90192e349e32f8ef0ed151ef506aa78c81a7c455ec18375c4125414b99f84b2e055199d66383e787675f0bcd87da7a4dbd59f9eac1d5 - languageName: node - linkType: hard - -"acorn-jsx@npm:^5.3.2": - version: 5.3.2 - resolution: "acorn-jsx@npm:5.3.2" - peerDependencies: - acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 10c0/4c54868fbef3b8d58927d5e33f0a4de35f59012fe7b12cf9dfbb345fb8f46607709e1c4431be869a23fb63c151033d84c4198fa9f79385cec34fcb1dd53974c1 - languageName: node - linkType: hard - -"acorn@npm:^8.15.0": - version: 8.15.0 - resolution: "acorn@npm:8.15.0" - bin: - acorn: bin/acorn - checksum: 10c0/dec73ff59b7d6628a01eebaece7f2bdb8bb62b9b5926dcad0f8931f2b8b79c2be21f6c68ac095592adb5adb15831a3635d9343e6a91d028bbe85d564875ec3ec - languageName: node - linkType: hard - -"aes-js@npm:4.0.0-beta.5": - version: 4.0.0-beta.5 - resolution: "aes-js@npm:4.0.0-beta.5" - checksum: 10c0/444f4eefa1e602cbc4f2a3c644bc990f93fd982b148425fee17634da510586fc09da940dcf8ace1b2d001453c07ff042e55f7a0482b3cc9372bf1ef75479090c - languageName: node - linkType: hard - -"agent-base@npm:^7.1.0, agent-base@npm:^7.1.2": - version: 7.1.4 - resolution: "agent-base@npm:7.1.4" - checksum: 10c0/c2c9ab7599692d594b6a161559ada307b7a624fa4c7b03e3afdb5a5e31cd0e53269115b620fcab024c5ac6a6f37fa5eb2e004f076ad30f5f7e6b8b671f7b35fe - languageName: node - linkType: hard - -"agent-install@npm:0.0.5": - version: 0.0.5 - resolution: "agent-install@npm:0.0.5" - dependencies: - "@iarna/toml": "npm:^2.2.5" - commander: "npm:^14.0.0" - jsonc-parser: "npm:^3.3.1" - picocolors: "npm:^1.1.1" - prompts: "npm:^2.4.2" - yaml: "npm:^2.8.3" - bin: - agent-install: bin/agent-install.mjs - checksum: 10c0/57b740ff36d08716c5985ee6d0fc973fb59a55100283d62ac8ed58e889bf99c2eff040c971f9e72ed8ec426c70ef2f2c37db7534f02b516d46a3a11a293a9b8a - languageName: node - linkType: hard - -"ajv-formats@npm:^3.0.1": - version: 3.0.1 - resolution: "ajv-formats@npm:3.0.1" - dependencies: - ajv: "npm:^8.0.0" - peerDependencies: - ajv: ^8.0.0 - peerDependenciesMeta: - ajv: - optional: true - checksum: 10c0/168d6bca1ea9f163b41c8147bae537e67bd963357a5488a1eaf3abe8baa8eec806d4e45f15b10767e6020679315c7e1e5e6803088dfb84efa2b4e9353b83dd0a - languageName: node - linkType: hard - -"ajv@npm:^6.12.4": - version: 6.12.6 - resolution: "ajv@npm:6.12.6" - dependencies: - fast-deep-equal: "npm:^3.1.1" - fast-json-stable-stringify: "npm:^2.0.0" - json-schema-traverse: "npm:^0.4.1" - uri-js: "npm:^4.2.2" - checksum: 10c0/41e23642cbe545889245b9d2a45854ebba51cda6c778ebced9649420d9205f2efb39cb43dbc41e358409223b1ea43303ae4839db682c848b891e4811da1a5a71 - languageName: node - linkType: hard - -"ajv@npm:^8.0.0, ajv@npm:^8.17.1": - version: 8.20.0 - resolution: "ajv@npm:8.20.0" - dependencies: - fast-deep-equal: "npm:^3.1.3" - fast-uri: "npm:^3.0.1" - json-schema-traverse: "npm:^1.0.0" - require-from-string: "npm:^2.0.2" - checksum: 10c0/5df9a1c8f83863cde1bd3a9ddb426f599718f88e3dc9153616c79fb28e0be455335830d7f21d745576519f057b371352daa31047b6a33d7036fe08777d60cf2a - languageName: node - linkType: hard - -"ansi-styles@npm:^4.1.0": - version: 4.3.0 - resolution: "ansi-styles@npm:4.3.0" - dependencies: - color-convert: "npm:^2.0.1" - checksum: 10c0/895a23929da416f2bd3de7e9cb4eabd340949328ab85ddd6e484a637d8f6820d485f53933446f5291c3b760cbc488beb8e88573dd0f9c7daf83dccc8fe81b041 - languageName: node - linkType: hard - -"any-promise@npm:^1.0.0": - version: 1.3.0 - resolution: "any-promise@npm:1.3.0" - checksum: 10c0/60f0298ed34c74fef50daab88e8dab786036ed5a7fad02e012ab57e376e0a0b4b29e83b95ea9b5e7d89df762f5f25119b83e00706ecaccb22cfbacee98d74889 - languageName: node - linkType: hard - -"anymatch@npm:~3.1.2": - version: 3.1.3 - resolution: "anymatch@npm:3.1.3" - dependencies: - normalize-path: "npm:^3.0.0" - picomatch: "npm:^2.0.4" - checksum: 10c0/57b06ae984bc32a0d22592c87384cd88fe4511b1dd7581497831c56d41939c8a001b28e7b853e1450f2bf61992dfcaa8ae2d0d161a0a90c4fb631ef07098fbac - languageName: node - linkType: hard - -"arg@npm:^5.0.2": - version: 5.0.2 - resolution: "arg@npm:5.0.2" - checksum: 10c0/ccaf86f4e05d342af6666c569f844bec426595c567d32a8289715087825c2ca7edd8a3d204e4d2fb2aa4602e09a57d0c13ea8c9eea75aac3dbb4af5514e6800e - languageName: node - linkType: hard - -"argparse@npm:^2.0.1": - version: 2.0.1 - resolution: "argparse@npm:2.0.1" - checksum: 10c0/c5640c2d89045371c7cedd6a70212a04e360fd34d6edeae32f6952c63949e3525ea77dbec0289d8213a99bbaeab5abfa860b5c12cf88a2e6cf8106e90dd27a7e - languageName: node - linkType: hard - -"aria-hidden@npm:^1.2.4": - version: 1.2.6 - resolution: "aria-hidden@npm:1.2.6" - dependencies: - tslib: "npm:^2.0.0" - checksum: 10c0/7720cb539497a9f760f68f98a4b30f22c6767aa0e72fa7d58279f7c164e258fc38b2699828f8de881aab0fc8e9c56d1313a3f1a965046fc0381a554dbc72b54a - languageName: node - linkType: hard - -"aria-query@npm:^5.3.2": - version: 5.3.2 - resolution: "aria-query@npm:5.3.2" - checksum: 10c0/003c7e3e2cff5540bf7a7893775fc614de82b0c5dde8ae823d47b7a28a9d4da1f7ed85f340bdb93d5649caa927755f0e31ecc7ab63edfdfc00c8ef07e505e03e - languageName: node - linkType: hard - -"array-buffer-byte-length@npm:^1.0.1, array-buffer-byte-length@npm:^1.0.2": - version: 1.0.2 - resolution: "array-buffer-byte-length@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - is-array-buffer: "npm:^3.0.5" - checksum: 10c0/74e1d2d996941c7a1badda9cabb7caab8c449db9086407cad8a1b71d2604cc8abf105db8ca4e02c04579ec58b7be40279ddb09aea4784832984485499f48432d - languageName: node - linkType: hard - -"array-includes@npm:^3.1.6, array-includes@npm:^3.1.8, array-includes@npm:^3.1.9": - version: 3.1.9 - resolution: "array-includes@npm:3.1.9" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.24.0" - es-object-atoms: "npm:^1.1.1" - get-intrinsic: "npm:^1.3.0" - is-string: "npm:^1.1.1" - math-intrinsics: "npm:^1.1.0" - checksum: 10c0/0235fa69078abeac05ac4250699c44996bc6f774a9cbe45db48674ce6bd142f09b327d31482ff75cf03344db4ea03eae23edb862d59378b484b47ed842574856 - languageName: node - linkType: hard - -"array.prototype.findlast@npm:^1.2.5": - version: 1.2.5 - resolution: "array.prototype.findlast@npm:1.2.5" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/ddc952b829145ab45411b9d6adcb51a8c17c76bf89c9dd64b52d5dffa65d033da8c076ed2e17091779e83bc892b9848188d7b4b33453c5565e65a92863cb2775 - languageName: node - linkType: hard - -"array.prototype.findlastindex@npm:^1.2.6": - version: 1.2.6 - resolution: "array.prototype.findlastindex@npm:1.2.6" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.9" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - es-shim-unscopables: "npm:^1.1.0" - checksum: 10c0/82559310d2e57ec5f8fc53d7df420e3abf0ba497935de0a5570586035478ba7d07618cb18e2d4ada2da514c8fb98a034aaf5c06caa0a57e2f7f4c4adedef5956 - languageName: node - linkType: hard - -"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.3": - version: 1.3.3 - resolution: "array.prototype.flat@npm:1.3.3" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/d90e04dfbc43bb96b3d2248576753d1fb2298d2d972e29ca7ad5ec621f0d9e16ff8074dae647eac4f31f4fb7d3f561a7ac005fb01a71f51705a13b5af06a7d8a - languageName: node - linkType: hard - -"array.prototype.flatmap@npm:^1.3.2, array.prototype.flatmap@npm:^1.3.3": - version: 1.3.3 - resolution: "array.prototype.flatmap@npm:1.3.3" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/ba899ea22b9dc9bf276e773e98ac84638ed5e0236de06f13d63a90b18ca9e0ec7c97d622d899796e3773930b946cd2413d098656c0c5d8cc58c6f25c21e6bd54 - languageName: node - linkType: hard - -"array.prototype.tosorted@npm:^1.1.4": - version: 1.1.4 - resolution: "array.prototype.tosorted@npm:1.1.4" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.3" - es-errors: "npm:^1.3.0" - es-shim-unscopables: "npm:^1.0.2" - checksum: 10c0/eb3c4c4fc0381b0bf6dba2ea4d48d367c2827a0d4236a5718d97caaccc6b78f11f4cadf090736e86301d295a6aa4967ed45568f92ced51be8cbbacd9ca410943 - languageName: node - linkType: hard - -"arraybuffer.prototype.slice@npm:^1.0.4": - version: 1.0.4 - resolution: "arraybuffer.prototype.slice@npm:1.0.4" - dependencies: - array-buffer-byte-length: "npm:^1.0.1" - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - is-array-buffer: "npm:^3.0.4" - checksum: 10c0/2f2459caa06ae0f7f615003f9104b01f6435cc803e11bd2a655107d52a1781dc040532dc44d93026b694cc18793993246237423e13a5337e86b43ed604932c06 - languageName: node - linkType: hard - -"ast-types-flow@npm:^0.0.8": - version: 0.0.8 - resolution: "ast-types-flow@npm:0.0.8" - checksum: 10c0/f2a0ba8055353b743c41431974521e5e852a9824870cd6fce2db0e538ac7bf4da406bbd018d109af29ff3f8f0993f6a730c9eddbd0abd031fbcb29ca75c1014e - languageName: node - linkType: hard - -"async-function@npm:^1.0.0": - version: 1.0.0 - resolution: "async-function@npm:1.0.0" - checksum: 10c0/669a32c2cb7e45091330c680e92eaeb791bc1d4132d827591e499cd1f776ff5a873e77e5f92d0ce795a8d60f10761dec9ddfe7225a5de680f5d357f67b1aac73 - languageName: node - linkType: hard - -"atomically@npm:^2.0.3": - version: 2.1.1 - resolution: "atomically@npm:2.1.1" - dependencies: - stubborn-fs: "npm:^2.0.0" - when-exit: "npm:^2.1.4" - checksum: 10c0/8813decdea834eab9b95c63ae3762355e9182e718b49be50153539bb52f727851f5096ef180f84901572dac31c51cb113a3bf3dda12fa633a16bc58f49ba003d - languageName: node - linkType: hard - -"autoprefixer@npm:^10.4.21": - version: 10.4.21 - resolution: "autoprefixer@npm:10.4.21" - dependencies: - browserslist: "npm:^4.24.4" - caniuse-lite: "npm:^1.0.30001702" - fraction.js: "npm:^4.3.7" - normalize-range: "npm:^0.1.2" - picocolors: "npm:^1.1.1" - postcss-value-parser: "npm:^4.2.0" - peerDependencies: - postcss: ^8.1.0 - bin: - autoprefixer: bin/autoprefixer - checksum: 10c0/de5b71d26d0baff4bbfb3d59f7cf7114a6030c9eeb66167acf49a32c5b61c68e308f1e0f869d92334436a221035d08b51cd1b2f2c4689b8d955149423c16d4d4 - languageName: node - linkType: hard - -"available-typed-arrays@npm:^1.0.7": - version: 1.0.7 - resolution: "available-typed-arrays@npm:1.0.7" - dependencies: - possible-typed-array-names: "npm:^1.0.0" - checksum: 10c0/d07226ef4f87daa01bd0fe80f8f310982e345f372926da2e5296aecc25c41cab440916bbaa4c5e1034b453af3392f67df5961124e4b586df1e99793a1374bdb2 - languageName: node - linkType: hard - -"axe-core@npm:^4.10.0": - version: 4.10.3 - resolution: "axe-core@npm:4.10.3" - checksum: 10c0/1b1c24f435b2ffe89d76eca0001cbfff42dbf012ad9bd37398b70b11f0d614281a38a28bc3069e8972e3c90ec929a8937994bd24b0ebcbaab87b8d1e241ab0c7 - languageName: node - linkType: hard - -"axobject-query@npm:^4.1.0": - version: 4.1.0 - resolution: "axobject-query@npm:4.1.0" - checksum: 10c0/c470e4f95008f232eadd755b018cb55f16c03ccf39c027b941cd8820ac6b68707ce5d7368a46756db4256fbc91bb4ead368f84f7fb034b2b7932f082f6dc0775 - languageName: node - linkType: hard - -"balanced-match@npm:^1.0.0": - version: 1.0.2 - resolution: "balanced-match@npm:1.0.2" - checksum: 10c0/9308baf0a7e4838a82bbfd11e01b1cb0f0cf2893bc1676c27c2a8c0e70cbae1c59120c3268517a8ae7fb6376b4639ef81ca22582611dbee4ed28df945134aaee - languageName: node - linkType: hard - -"balanced-match@npm:^4.0.2": - version: 4.0.4 - resolution: "balanced-match@npm:4.0.4" - checksum: 10c0/07e86102a3eb2ee2a6a1a89164f29d0dbaebd28f2ca3f5ca786f36b8b23d9e417eb3be45a4acf754f837be5ac0a2317de90d3fcb7f4f4dc95720a1f36b26a17b - languageName: node - linkType: hard - -"baseline-browser-mapping@npm:^2.9.0": - version: 2.9.19 - resolution: "baseline-browser-mapping@npm:2.9.19" - bin: - baseline-browser-mapping: dist/cli.js - checksum: 10c0/569928db78bcd081953d7db79e4243a59a579a34b4ae1806b9b42d3b7f84e5bc40e6e82ae4fa06e7bef8291bf747b33b3f9ef5d3c6e1e420cb129d9295536129 - languageName: node - linkType: hard - -"baseline-browser-mapping@npm:^2.9.19": - version: 2.10.8 - resolution: "baseline-browser-mapping@npm:2.10.8" - bin: - baseline-browser-mapping: dist/cli.cjs - checksum: 10c0/a77882e8ac37a900a9a0757b9bf4e50f407829ed17ee7630273ab5da0ae10d9c64ed4c5a1e03afb3490e39713440092417ded4bb856eeb9bd44856eacbd97497 - languageName: node - linkType: hard - -"binary-extensions@npm:^2.0.0": - version: 2.3.0 - resolution: "binary-extensions@npm:2.3.0" - checksum: 10c0/75a59cafc10fb12a11d510e77110c6c7ae3f4ca22463d52487709ca7f18f69d886aa387557cc9864fbdb10153d0bdb4caacabf11541f55e89ed6e18d12ece2b5 - languageName: node - linkType: hard - -"brace-expansion@npm:1.1.13": - version: 1.1.13 - resolution: "brace-expansion@npm:1.1.13" - dependencies: - balanced-match: "npm:^1.0.0" - concat-map: "npm:0.0.1" - checksum: 10c0/384c61bb329b6adfdcc0cbbdd108dc19fb5f3e84ae15a02a74f94c6c791b5a9b035aae73b2a51929a8a478e2f0f212a771eb6a8b5b514cccfb8d0c9f2ce8cbd8 - languageName: node - linkType: hard - -"brace-expansion@npm:^5.0.2": - version: 5.0.4 - resolution: "brace-expansion@npm:5.0.4" - dependencies: - balanced-match: "npm:^4.0.2" - checksum: 10c0/359cbcfa80b2eb914ca1f3440e92313fbfe7919ee6b274c35db55bec555aded69dac5ee78f102cec90c35f98c20fa43d10936d0cd9978158823c249257e1643a - languageName: node - linkType: hard - -"brace-expansion@npm:^5.0.5": - version: 5.0.6 - resolution: "brace-expansion@npm:5.0.6" - dependencies: - balanced-match: "npm:^4.0.2" - checksum: 10c0/8c919869b90f61d533b341d3340be5ee4413232ea89b8246cbc2f38eb014f1d8182785c98a006eaf6111d02dc9eeffefdc240d5ac158625b2ed084dccd4bbf9b - languageName: node - linkType: hard - -"braces@npm:^3.0.3, braces@npm:~3.0.2": - version: 3.0.3 - resolution: "braces@npm:3.0.3" - dependencies: - fill-range: "npm:^7.1.1" - checksum: 10c0/7c6dfd30c338d2997ba77500539227b9d1f85e388a5f43220865201e407e076783d0881f2d297b9f80951b4c957fcf0b51c1d2d24227631643c3f7c284b0aa04 - languageName: node - linkType: hard - -"browserslist@npm:^4.24.0": - version: 4.28.1 - resolution: "browserslist@npm:4.28.1" - dependencies: - baseline-browser-mapping: "npm:^2.9.0" - caniuse-lite: "npm:^1.0.30001759" - electron-to-chromium: "npm:^1.5.263" - node-releases: "npm:^2.0.27" - update-browserslist-db: "npm:^1.2.0" - bin: - browserslist: cli.js - checksum: 10c0/545a5fa9d7234e3777a7177ec1e9134bb2ba60a69e6b95683f6982b1473aad347c77c1264ccf2ac5dea609a9731fbfbda6b85782bdca70f80f86e28a402504bd - languageName: node - linkType: hard - -"browserslist@npm:^4.24.4": - version: 4.25.4 - resolution: "browserslist@npm:4.25.4" - dependencies: - caniuse-lite: "npm:^1.0.30001737" - electron-to-chromium: "npm:^1.5.211" - node-releases: "npm:^2.0.19" - update-browserslist-db: "npm:^1.1.3" - bin: - browserslist: cli.js - checksum: 10c0/2b105948990dc2fc0bc2536b4889aadfa15d637e1d857a121611a704cdf539a68f575a391f6bf8b7ff19db36cee1b7834565571f35a7ea691051d2e7fb4f2eb1 - languageName: node - linkType: hard - -"cacache@npm:^20.0.1": - version: 20.0.4 - resolution: "cacache@npm:20.0.4" - dependencies: - "@npmcli/fs": "npm:^5.0.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^13.0.0" - lru-cache: "npm:^11.1.0" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^2.0.1" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^7.0.2" - ssri: "npm:^13.0.0" - checksum: 10c0/539bf4020e44ba9ca5afc2ec435623ed7e0dd80c020097677e6b4a0545df5cc9d20b473212d01209c8b4aea43c0d095af0bb6da97bcb991642ea6fac0d7c462b - languageName: node - linkType: hard - -"call-bind-apply-helpers@npm:^1.0.0, call-bind-apply-helpers@npm:^1.0.1, call-bind-apply-helpers@npm:^1.0.2": - version: 1.0.2 - resolution: "call-bind-apply-helpers@npm:1.0.2" - dependencies: - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - checksum: 10c0/47bd9901d57b857590431243fea704ff18078b16890a6b3e021e12d279bbf211d039155e27d7566b374d49ee1f8189344bac9833dec7a20cdec370506361c938 - languageName: node - linkType: hard - -"call-bind@npm:^1.0.7, call-bind@npm:^1.0.8": - version: 1.0.8 - resolution: "call-bind@npm:1.0.8" - dependencies: - call-bind-apply-helpers: "npm:^1.0.0" - es-define-property: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.4" - set-function-length: "npm:^1.2.2" - checksum: 10c0/a13819be0681d915144467741b69875ae5f4eba8961eb0bf322aab63ec87f8250eb6d6b0dcbb2e1349876412a56129ca338592b3829ef4343527f5f18a0752d4 - languageName: node - linkType: hard - -"call-bound@npm:^1.0.2, call-bound@npm:^1.0.3, call-bound@npm:^1.0.4": - version: 1.0.4 - resolution: "call-bound@npm:1.0.4" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - get-intrinsic: "npm:^1.3.0" - checksum: 10c0/f4796a6a0941e71c766aea672f63b72bc61234c4f4964dc6d7606e3664c307e7d77845328a8f3359ce39ddb377fed67318f9ee203dea1d47e46165dcf2917644 - languageName: node - linkType: hard - -"callsites@npm:^3.0.0": - version: 3.1.0 - resolution: "callsites@npm:3.1.0" - checksum: 10c0/fff92277400eb06c3079f9e74f3af120db9f8ea03bad0e84d9aede54bbe2d44a56cccb5f6cf12211f93f52306df87077ecec5b712794c5a9b5dac6d615a3f301 - languageName: node - linkType: hard - -"camelcase-css@npm:^2.0.1": - version: 2.0.1 - resolution: "camelcase-css@npm:2.0.1" - checksum: 10c0/1a1a3137e8a781e6cbeaeab75634c60ffd8e27850de410c162cce222ea331cd1ba5364e8fb21c95e5ca76f52ac34b81a090925ca00a87221355746d049c6e273 - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001579": - version: 1.0.30001731 - resolution: "caniuse-lite@npm:1.0.30001731" - checksum: 10c0/d8cddf817d5bec8e7c2106affdbf1bfc3923463ca16697c992b2efeb043e6a5d9dcb70cda913bc6acf9112fd66f9e80279316c08e7800359116925066a63fdfa - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001702, caniuse-lite@npm:^1.0.30001737": - version: 1.0.30001741 - resolution: "caniuse-lite@npm:1.0.30001741" - checksum: 10c0/45746f896205a61a8eeb85a32aeca243ebce640cd6eb80d04949d9389a13f4659c737860300d7b988057599f0958c55eeab74ec02ce9ef137feb7d006e75fec1 - languageName: node - linkType: hard - -"caniuse-lite@npm:^1.0.30001759": - version: 1.0.30001770 - resolution: "caniuse-lite@npm:1.0.30001770" - checksum: 10c0/02d15a8b723af65318cb4d888a52bb090076898da7b0de99e8676d537f8d1d2ae4797e81518e1e30cbfe84c33b048c322e8bfafc5b23cfee8defb0d2bf271149 - languageName: node - linkType: hard - -"canvas-confetti@npm:^1.9.3": - version: 1.9.3 - resolution: "canvas-confetti@npm:1.9.3" - checksum: 10c0/94c6f16591660d5ed4a48afb8da65902826ce6b38edc7644d62521aa9bf9ef5b950aa4396e980e7fe0a38e5f41a991a6d984721412a54c9fba4de3682c1eead0 - languageName: node - linkType: hard - -"chalk@npm:^4.0.0": - version: 4.1.2 - resolution: "chalk@npm:4.1.2" - dependencies: - ansi-styles: "npm:^4.1.0" - supports-color: "npm:^7.1.0" - checksum: 10c0/4a3fef5cc34975c898ffe77141450f679721df9dde00f6c304353fa9c8b571929123b26a0e4617bde5018977eb655b31970c297b91b63ee83bb82aeb04666880 - languageName: node - linkType: hard - -"chokidar@npm:^3.6.0": - version: 3.6.0 - resolution: "chokidar@npm:3.6.0" - dependencies: - anymatch: "npm:~3.1.2" - braces: "npm:~3.0.2" - fsevents: "npm:~2.3.2" - glob-parent: "npm:~5.1.2" - is-binary-path: "npm:~2.1.0" - is-glob: "npm:~4.0.1" - normalize-path: "npm:~3.0.0" - readdirp: "npm:~3.6.0" - dependenciesMeta: - fsevents: - optional: true - checksum: 10c0/8361dcd013f2ddbe260eacb1f3cb2f2c6f2b0ad118708a343a5ed8158941a39cb8fb1d272e0f389712e74ee90ce8ba864eece9e0e62b9705cb468a2f6d917462 - languageName: node - linkType: hard - -"chownr@npm:^3.0.0": - version: 3.0.0 - resolution: "chownr@npm:3.0.0" - checksum: 10c0/43925b87700f7e3893296c8e9c56cc58f926411cce3a6e5898136daaf08f08b9a8eb76d37d3267e707d0dcc17aed2e2ebdf5848c0c3ce95cf910a919935c1b10 - languageName: node - linkType: hard - -"class-variance-authority@npm:^0.7.1": - version: 0.7.1 - resolution: "class-variance-authority@npm:0.7.1" - dependencies: - clsx: "npm:^2.1.1" - checksum: 10c0/0f438cea22131808b99272de0fa933c2532d5659773bfec0c583de7b3f038378996d3350683426b8e9c74a6286699382106d71fbec52f0dd5fbb191792cccb5b - languageName: node - linkType: hard - -"classnames@npm:^2.5.1": - version: 2.5.1 - resolution: "classnames@npm:2.5.1" - checksum: 10c0/afff4f77e62cea2d79c39962980bf316bacb0d7c49e13a21adaadb9221e1c6b9d3cdb829d8bb1b23c406f4e740507f37e1dcf506f7e3b7113d17c5bab787aa69 - languageName: node - linkType: hard - -"client-only@npm:0.0.1": - version: 0.0.1 - resolution: "client-only@npm:0.0.1" - checksum: 10c0/9d6cfd0c19e1c96a434605added99dff48482152af791ec4172fb912a71cff9027ff174efd8cdb2160cc7f377543e0537ffc462d4f279bc4701de3f2a3c4b358 - languageName: node - linkType: hard - -"clsx@npm:^2.1.1": - version: 2.1.1 - resolution: "clsx@npm:2.1.1" - checksum: 10c0/c4c8eb865f8c82baab07e71bfa8897c73454881c4f99d6bc81585aecd7c441746c1399d08363dc096c550cceaf97bd4ce1e8854e1771e9998d9f94c4fe075839 - languageName: node - linkType: hard - -"cmdk@npm:^1.1.1": - version: 1.1.1 - resolution: "cmdk@npm:1.1.1" - dependencies: - "@radix-ui/react-compose-refs": "npm:^1.1.1" - "@radix-ui/react-dialog": "npm:^1.1.6" - "@radix-ui/react-id": "npm:^1.1.0" - "@radix-ui/react-primitive": "npm:^2.0.2" - peerDependencies: - react: ^18 || ^19 || ^19.0.0-rc - react-dom: ^18 || ^19 || ^19.0.0-rc - checksum: 10c0/5605ac4396ec9bc65c82f954da19dd89a0636a54026df72780e2470da1381f9d57434a80a53f2d57eaa4e759660a3ebba9232b74258dc09970576591eae03116 - languageName: node - linkType: hard - -"color-convert@npm:^2.0.1": - version: 2.0.1 - resolution: "color-convert@npm:2.0.1" - dependencies: - color-name: "npm:~1.1.4" - checksum: 10c0/37e1150172f2e311fe1b2df62c6293a342ee7380da7b9cfdba67ea539909afbd74da27033208d01d6d5cfc65ee7868a22e18d7e7648e004425441c0f8a15a7d7 - languageName: node - linkType: hard - -"color-name@npm:~1.1.4": - version: 1.1.4 - resolution: "color-name@npm:1.1.4" - checksum: 10c0/a1a3f914156960902f46f7f56bc62effc6c94e84b2cae157a526b1c1f74b677a47ec602bf68a61abfa2b42d15b7c5651c6dbe72a43af720bc588dff885b10f95 - languageName: node - linkType: hard - -"commander@npm:^14.0.0": - version: 14.0.3 - resolution: "commander@npm:14.0.3" - checksum: 10c0/755652564bbf56ff2ff083313912b326450d3f8d8c85f4b71416539c9a05c3c67dbd206821ca72635bf6b160e2afdefcb458e86b317827d5cb333b69ce7f1a24 - languageName: node - linkType: hard - -"commander@npm:^4.0.0": - version: 4.1.1 - resolution: "commander@npm:4.1.1" - checksum: 10c0/84a76c08fe6cc08c9c93f62ac573d2907d8e79138999312c92d4155bc2325d487d64d13f669b2000c9f8caf70493c1be2dac74fec3c51d5a04f8bc3ae1830bab - languageName: node - linkType: hard - -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 10c0/c996b1cfdf95b6c90fee4dae37e332c8b6eb7d106430c17d538034c0ad9a1630cb194d2ab37293b1bdd4d779494beee7786d586a50bd9376fd6f7bcc2bd4c98f - languageName: node - linkType: hard - -"conf@npm:^15.1.0": - version: 15.1.0 - resolution: "conf@npm:15.1.0" - dependencies: - ajv: "npm:^8.17.1" - ajv-formats: "npm:^3.0.1" - atomically: "npm:^2.0.3" - debounce-fn: "npm:^6.0.0" - dot-prop: "npm:^10.0.0" - env-paths: "npm:^3.0.0" - json-schema-typed: "npm:^8.0.1" - semver: "npm:^7.7.2" - uint8array-extras: "npm:^1.5.0" - checksum: 10c0/ba3c74891f48232a7d32e473508c147a431a7bfdd266ebdeaf4e737227568345ea632a42d02e35f13740cb9a54076d79572d31591d6debae3b6bee089fa91c8a - languageName: node - linkType: hard - -"convert-source-map@npm:^2.0.0": - version: 2.0.0 - resolution: "convert-source-map@npm:2.0.0" - checksum: 10c0/8f2f7a27a1a011cc6cc88cc4da2d7d0cfa5ee0369508baae3d98c260bb3ac520691464e5bbe4ae7cdf09860c1d69ecc6f70c63c6e7c7f7e3f18ec08484dc7d9b - languageName: node - linkType: hard - -"country-flag-icons@npm:^1.5.17": - version: 1.5.19 - resolution: "country-flag-icons@npm:1.5.19" - checksum: 10c0/f6adeadd7a406c593c8cfe4b3f0630d937188f79854755677448bd89024d404307b7a38b03612d5310c77c45ea535e0c409f24dc80d787673f1e3b35ddae43de - languageName: node - linkType: hard - -"cross-spawn@npm:^7.0.6": - version: 7.0.6 - resolution: "cross-spawn@npm:7.0.6" - dependencies: - path-key: "npm:^3.1.0" - shebang-command: "npm:^2.0.0" - which: "npm:^2.0.1" - checksum: 10c0/053ea8b2135caff68a9e81470e845613e374e7309a47731e81639de3eaeb90c3d01af0e0b44d2ab9d50b43467223b88567dfeb3262db942dc063b9976718ffc1 - languageName: node - linkType: hard - -"cssesc@npm:^3.0.0": - version: 3.0.0 - resolution: "cssesc@npm:3.0.0" - bin: - cssesc: bin/cssesc - checksum: 10c0/6bcfd898662671be15ae7827120472c5667afb3d7429f1f917737f3bf84c4176003228131b643ae74543f17a394446247df090c597bb9a728cce298606ed0aa7 - languageName: node - linkType: hard - -"csstype@npm:^3.2.2": - version: 3.2.3 - resolution: "csstype@npm:3.2.3" - checksum: 10c0/cd29c51e70fa822f1cecd8641a1445bed7063697469d35633b516e60fe8c1bde04b08f6c5b6022136bb669b64c63d4173af54864510fbb4ee23281801841a3ce - languageName: node - linkType: hard - -"damerau-levenshtein@npm:^1.0.8": - version: 1.0.8 - resolution: "damerau-levenshtein@npm:1.0.8" - checksum: 10c0/4c2647e0f42acaee7d068756c1d396e296c3556f9c8314bac1ac63ffb236217ef0e7e58602b18bb2173deec7ec8e0cac8e27cccf8f5526666b4ff11a13ad54a3 - languageName: node - linkType: hard - -"data-view-buffer@npm:^1.0.2": - version: 1.0.2 - resolution: "data-view-buffer@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.2" - checksum: 10c0/7986d40fc7979e9e6241f85db8d17060dd9a71bd53c894fa29d126061715e322a4cd47a00b0b8c710394854183d4120462b980b8554012acc1c0fa49df7ad38c - languageName: node - linkType: hard - -"data-view-byte-length@npm:^1.0.2": - version: 1.0.2 - resolution: "data-view-byte-length@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.2" - checksum: 10c0/f8a4534b5c69384d95ac18137d381f18a5cfae1f0fc1df0ef6feef51ef0d568606d970b69e02ea186c6c0f0eac77fe4e6ad96fec2569cc86c3afcc7475068c55 - languageName: node - linkType: hard - -"data-view-byte-offset@npm:^1.0.1": - version: 1.0.1 - resolution: "data-view-byte-offset@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - is-data-view: "npm:^1.0.1" - checksum: 10c0/fa7aa40078025b7810dcffc16df02c480573b7b53ef1205aa6a61533011005c1890e5ba17018c692ce7c900212b547262d33279fde801ad9843edc0863bf78c4 - languageName: node - linkType: hard - -"debounce-fn@npm:^6.0.0": - version: 6.0.0 - resolution: "debounce-fn@npm:6.0.0" - dependencies: - mimic-function: "npm:^5.0.0" - checksum: 10c0/ff5c48a7d644e292a653fd602db340b701bddba3973da7f64c6f25bbd9ab0fde9058567fdbe7efc72553561f3393f285413818d58f08614e73e0e85319f1da6e - languageName: node - linkType: hard - -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.4.3": - version: 4.4.3 - resolution: "debug@npm:4.4.3" - dependencies: - ms: "npm:^2.1.3" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10c0/d79136ec6c83ecbefd0f6a5593da6a9c91ec4d7ddc4b54c883d6e71ec9accb5f67a1a5e96d00a328196b5b5c86d365e98d8a3a70856aaf16b4e7b1985e67f5a6 - languageName: node - linkType: hard - -"debug@npm:^3.2.7": - version: 3.2.7 - resolution: "debug@npm:3.2.7" - dependencies: - ms: "npm:^2.1.1" - checksum: 10c0/37d96ae42cbc71c14844d2ae3ba55adf462ec89fd3a999459dec3833944cd999af6007ff29c780f1c61153bcaaf2c842d1e4ce1ec621e4fc4923244942e4a02a - languageName: node - linkType: hard - -"debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4, debug@npm:^4.4.0": - version: 4.4.1 - resolution: "debug@npm:4.4.1" - dependencies: - ms: "npm:^2.1.3" - peerDependenciesMeta: - supports-color: - optional: true - checksum: 10c0/d2b44bc1afd912b49bb7ebb0d50a860dc93a4dd7d946e8de94abc957bb63726b7dd5aa48c18c2386c379ec024c46692e15ed3ed97d481729f929201e671fcd55 - languageName: node - linkType: hard - -"deep-is@npm:^0.1.3": - version: 0.1.4 - resolution: "deep-is@npm:0.1.4" - checksum: 10c0/7f0ee496e0dff14a573dc6127f14c95061b448b87b995fc96c017ce0a1e66af1675e73f1d6064407975bc4ea6ab679497a29fff7b5b9c4e99cb10797c1ad0b4c - languageName: node - linkType: hard - -"define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": - version: 1.1.4 - resolution: "define-data-property@npm:1.1.4" - dependencies: - es-define-property: "npm:^1.0.0" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.0.1" - checksum: 10c0/dea0606d1483eb9db8d930d4eac62ca0fa16738b0b3e07046cddfacf7d8c868bbe13fa0cb263eb91c7d0d527960dc3f2f2471a69ed7816210307f6744fe62e37 - languageName: node - linkType: hard - -"define-properties@npm:^1.1.3, define-properties@npm:^1.2.1": - version: 1.2.1 - resolution: "define-properties@npm:1.2.1" - dependencies: - define-data-property: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.0" - object-keys: "npm:^1.1.1" - checksum: 10c0/88a152319ffe1396ccc6ded510a3896e77efac7a1bfbaa174a7b00414a1747377e0bb525d303794a47cf30e805c2ec84e575758512c6e44a993076d29fd4e6c3 - languageName: node - linkType: hard - -"deslop-js@npm:^0.0.12": - version: 0.0.12 - resolution: "deslop-js@npm:0.0.12" - dependencies: - "@oxc-project/types": "npm:^0.132.0" - fast-glob: "npm:^3.3.3" - minimatch: "npm:^10.2.5" - oxc-parser: "npm:^0.132.0" - oxc-resolver: "npm:^11.19.1" - typescript: "npm:^6.0.3" - checksum: 10c0/2012226bd8ab32678ba6af55f34b5d775b724f674b79d3704626ad636f5016f9a810e2dfe1886212b8f40021c59d79f4b42ae71616805e89d5335b6c0bf1611c - languageName: node - linkType: hard - -"detect-libc@npm:^2.0.1, detect-libc@npm:^2.1.2": - version: 2.1.2 - resolution: "detect-libc@npm:2.1.2" - checksum: 10c0/acc675c29a5649fa1fb6e255f993b8ee829e510b6b56b0910666949c80c364738833417d0edb5f90e4e46be17228b0f2b66a010513984e18b15deeeac49369c4 - languageName: node - linkType: hard - -"detect-node-es@npm:^1.1.0": - version: 1.1.0 - resolution: "detect-node-es@npm:1.1.0" - checksum: 10c0/e562f00de23f10c27d7119e1af0e7388407eb4b06596a25f6d79a360094a109ff285de317f02b090faae093d314cf6e73ac3214f8a5bb3a0def5bece94557fbe - languageName: node - linkType: hard - -"didyoumean@npm:^1.2.2": - version: 1.2.2 - resolution: "didyoumean@npm:1.2.2" - checksum: 10c0/95d0b53d23b851aacff56dfadb7ecfedce49da4232233baecfeecb7710248c4aa03f0aa8995062f0acafaf925adf8536bd7044a2e68316fd7d411477599bc27b - languageName: node - linkType: hard - -"dlv@npm:^1.1.3": - version: 1.1.3 - resolution: "dlv@npm:1.1.3" - checksum: 10c0/03eb4e769f19a027fd5b43b59e8a05e3fd2100ac239ebb0bf9a745de35d449e2f25cfaf3aa3934664551d72856f4ae8b7822016ce5c42c2d27c18ae79429ec42 - languageName: node - linkType: hard - -"doctrine@npm:^2.1.0": - version: 2.1.0 - resolution: "doctrine@npm:2.1.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10c0/b6416aaff1f380bf56c3b552f31fdf7a69b45689368deca72d28636f41c16bb28ec3ebc40ace97db4c1afc0ceeb8120e8492fe0046841c94c2933b2e30a7d5ac - languageName: node - linkType: hard - -"dot-prop@npm:^10.0.0": - version: 10.1.0 - resolution: "dot-prop@npm:10.1.0" - dependencies: - type-fest: "npm:^5.0.0" - checksum: 10c0/b034a06f017909ed55c6c164ddea962ccdce3d88b9b092f7106a9b738116a4cd003db5d47a0c6e140e93adbf1922b5e3a147e3d4a124c8556862940446ba5f75 - languageName: node - linkType: hard - -"dunder-proto@npm:^1.0.0, dunder-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "dunder-proto@npm:1.0.1" - dependencies: - call-bind-apply-helpers: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - gopd: "npm:^1.2.0" - checksum: 10c0/199f2a0c1c16593ca0a145dbf76a962f8033ce3129f01284d48c45ed4e14fea9bbacd7b3610b6cdc33486cef20385ac054948fefc6272fcce645c09468f93031 - languageName: node - linkType: hard - -"effect@npm:4.0.0-beta.70": - version: 4.0.0-beta.70 - resolution: "effect@npm:4.0.0-beta.70" - dependencies: - "@standard-schema/spec": "npm:^1.1.0" - fast-check: "npm:^4.8.0" - find-my-way-ts: "npm:^0.1.6" - ini: "npm:^7.0.0" - kubernetes-types: "npm:^1.30.0" - msgpackr: "npm:^2.0.1" - multipasta: "npm:^0.2.7" - toml: "npm:^4.1.1" - uuid: "npm:^14.0.0" - yaml: "npm:^2.9.0" - checksum: 10c0/6ba1d7fe3b83ef991a7d1f2e2b98d311dd0e135c5f17c45b69f2a721e1ead5923a55b293a3619bdbc541dc29b91b486f52ea34aef5110f60e38e4d2c0daa0a02 - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.5.211": - version: 1.5.215 - resolution: "electron-to-chromium@npm:1.5.215" - checksum: 10c0/3a45976d1193e57284533096b3bbec218a5d4d85af4f7c133522aae35b14bbf22734f48ccc3f0e43a451441ebc375fa2f4350390fd729dcedb97543692133e39 - languageName: node - linkType: hard - -"electron-to-chromium@npm:^1.5.263": - version: 1.5.286 - resolution: "electron-to-chromium@npm:1.5.286" - checksum: 10c0/5384510f9682d7e46f98fa48b874c3901d9639de96e9e387afce1fe010fbac31376df0534524edc15f66e9902bfacee54037a5e598004e9c6a617884e379926d - languageName: node - linkType: hard - -"emoji-regex@npm:^9.2.2": - version: 9.2.2 - resolution: "emoji-regex@npm:9.2.2" - checksum: 10c0/af014e759a72064cf66e6e694a7fc6b0ed3d8db680427b021a89727689671cefe9d04151b2cad51dbaf85d5ba790d061cd167f1cf32eb7b281f6368b3c181639 - languageName: node - linkType: hard - -"env-paths@npm:^2.2.0": - version: 2.2.1 - resolution: "env-paths@npm:2.2.1" - checksum: 10c0/285325677bf00e30845e330eec32894f5105529db97496ee3f598478e50f008c5352a41a30e5e72ec9de8a542b5a570b85699cd63bd2bc646dbcb9f311d83bc4 - languageName: node - linkType: hard - -"env-paths@npm:^3.0.0": - version: 3.0.0 - resolution: "env-paths@npm:3.0.0" - checksum: 10c0/76dec878cee47f841103bacd7fae03283af16f0702dad65102ef0a556f310b98a377885e0f32943831eb08b5ab37842a323d02529f3dfd5d0a40ca71b01b435f - languageName: node - linkType: hard - -"es-abstract@npm:^1.17.5, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3, es-abstract@npm:^1.23.5, es-abstract@npm:^1.23.6, es-abstract@npm:^1.23.9, es-abstract@npm:^1.24.0": - version: 1.24.0 - resolution: "es-abstract@npm:1.24.0" - dependencies: - array-buffer-byte-length: "npm:^1.0.2" - arraybuffer.prototype.slice: "npm:^1.0.4" - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - data-view-buffer: "npm:^1.0.2" - data-view-byte-length: "npm:^1.0.2" - data-view-byte-offset: "npm:^1.0.1" - es-define-property: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - es-set-tostringtag: "npm:^2.1.0" - es-to-primitive: "npm:^1.3.0" - function.prototype.name: "npm:^1.1.8" - get-intrinsic: "npm:^1.3.0" - get-proto: "npm:^1.0.1" - get-symbol-description: "npm:^1.1.0" - globalthis: "npm:^1.0.4" - gopd: "npm:^1.2.0" - has-property-descriptors: "npm:^1.0.2" - has-proto: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - internal-slot: "npm:^1.1.0" - is-array-buffer: "npm:^3.0.5" - is-callable: "npm:^1.2.7" - is-data-view: "npm:^1.0.2" - is-negative-zero: "npm:^2.0.3" - is-regex: "npm:^1.2.1" - is-set: "npm:^2.0.3" - is-shared-array-buffer: "npm:^1.0.4" - is-string: "npm:^1.1.1" - is-typed-array: "npm:^1.1.15" - is-weakref: "npm:^1.1.1" - math-intrinsics: "npm:^1.1.0" - object-inspect: "npm:^1.13.4" - object-keys: "npm:^1.1.1" - object.assign: "npm:^4.1.7" - own-keys: "npm:^1.0.1" - regexp.prototype.flags: "npm:^1.5.4" - safe-array-concat: "npm:^1.1.3" - safe-push-apply: "npm:^1.0.0" - safe-regex-test: "npm:^1.1.0" - set-proto: "npm:^1.0.0" - stop-iteration-iterator: "npm:^1.1.0" - string.prototype.trim: "npm:^1.2.10" - string.prototype.trimend: "npm:^1.0.9" - string.prototype.trimstart: "npm:^1.0.8" - typed-array-buffer: "npm:^1.0.3" - typed-array-byte-length: "npm:^1.0.3" - typed-array-byte-offset: "npm:^1.0.4" - typed-array-length: "npm:^1.0.7" - unbox-primitive: "npm:^1.1.0" - which-typed-array: "npm:^1.1.19" - checksum: 10c0/b256e897be32df5d382786ce8cce29a1dd8c97efbab77a26609bd70f2ed29fbcfc7a31758cb07488d532e7ccccdfca76c1118f2afe5a424cdc05ca007867c318 - languageName: node - linkType: hard - -"es-define-property@npm:^1.0.0, es-define-property@npm:^1.0.1": - version: 1.0.1 - resolution: "es-define-property@npm:1.0.1" - checksum: 10c0/3f54eb49c16c18707949ff25a1456728c883e81259f045003499efba399c08bad00deebf65cccde8c0e07908c1a225c9d472b7107e558f2a48e28d530e34527c - languageName: node - linkType: hard - -"es-errors@npm:^1.3.0": - version: 1.3.0 - resolution: "es-errors@npm:1.3.0" - checksum: 10c0/0a61325670072f98d8ae3b914edab3559b6caa980f08054a3b872052640d91da01d38df55df797fcc916389d77fc92b8d5906cf028f4db46d7e3003abecbca85 - languageName: node - linkType: hard - -"es-iterator-helpers@npm:^1.2.1": - version: 1.2.1 - resolution: "es-iterator-helpers@npm:1.2.1" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.6" - es-errors: "npm:^1.3.0" - es-set-tostringtag: "npm:^2.0.3" - function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.6" - globalthis: "npm:^1.0.4" - gopd: "npm:^1.2.0" - has-property-descriptors: "npm:^1.0.2" - has-proto: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - internal-slot: "npm:^1.1.0" - iterator.prototype: "npm:^1.1.4" - safe-array-concat: "npm:^1.1.3" - checksum: 10c0/97e3125ca472d82d8aceea11b790397648b52c26d8768ea1c1ee6309ef45a8755bb63225a43f3150c7591cffc17caf5752459f1e70d583b4184370a8f04ebd2f - languageName: node - linkType: hard - -"es-object-atoms@npm:^1.0.0, es-object-atoms@npm:^1.1.1": - version: 1.1.1 - resolution: "es-object-atoms@npm:1.1.1" - dependencies: - es-errors: "npm:^1.3.0" - checksum: 10c0/65364812ca4daf48eb76e2a3b7a89b3f6a2e62a1c420766ce9f692665a29d94fe41fe88b65f24106f449859549711e4b40d9fb8002d862dfd7eb1c512d10be0c - languageName: node - linkType: hard - -"es-set-tostringtag@npm:^2.0.3, es-set-tostringtag@npm:^2.1.0": - version: 2.1.0 - resolution: "es-set-tostringtag@npm:2.1.0" - dependencies: - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - has-tostringtag: "npm:^1.0.2" - hasown: "npm:^2.0.2" - checksum: 10c0/ef2ca9ce49afe3931cb32e35da4dcb6d86ab02592cfc2ce3e49ced199d9d0bb5085fc7e73e06312213765f5efa47cc1df553a6a5154584b21448e9fb8355b1af - languageName: node - linkType: hard - -"es-shim-unscopables@npm:^1.0.2, es-shim-unscopables@npm:^1.1.0": - version: 1.1.0 - resolution: "es-shim-unscopables@npm:1.1.0" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10c0/1b9702c8a1823fc3ef39035a4e958802cf294dd21e917397c561d0b3e195f383b978359816b1732d02b255ccf63e1e4815da0065b95db8d7c992037be3bbbcdb - languageName: node - linkType: hard - -"es-to-primitive@npm:^1.3.0": - version: 1.3.0 - resolution: "es-to-primitive@npm:1.3.0" - dependencies: - is-callable: "npm:^1.2.7" - is-date-object: "npm:^1.0.5" - is-symbol: "npm:^1.0.4" - checksum: 10c0/c7e87467abb0b438639baa8139f701a06537d2b9bc758f23e8622c3b42fd0fdb5bde0f535686119e446dd9d5e4c0f238af4e14960f4771877cf818d023f6730b - languageName: node - linkType: hard - -"escalade@npm:^3.2.0": - version: 3.2.0 - resolution: "escalade@npm:3.2.0" - checksum: 10c0/ced4dd3a78e15897ed3be74e635110bbf3b08877b0a41be50dcb325ee0e0b5f65fc2d50e9845194d7c4633f327e2e1c6cce00a71b617c5673df0374201d67f65 - languageName: node - linkType: hard - -"escape-string-regexp@npm:^4.0.0": - version: 4.0.0 - resolution: "escape-string-regexp@npm:4.0.0" - checksum: 10c0/9497d4dd307d845bd7f75180d8188bb17ea8c151c1edbf6b6717c100e104d629dc2dfb687686181b0f4b7d732c7dfdc4d5e7a8ff72de1b0ca283a75bbb3a9cd9 - languageName: node - linkType: hard - -"eslint-config-next@npm:16.2.3": - version: 16.2.3 - resolution: "eslint-config-next@npm:16.2.3" - dependencies: - "@next/eslint-plugin-next": "npm:16.2.3" - eslint-import-resolver-node: "npm:^0.3.6" - eslint-import-resolver-typescript: "npm:^3.5.2" - eslint-plugin-import: "npm:^2.32.0" - eslint-plugin-jsx-a11y: "npm:^6.10.0" - eslint-plugin-react: "npm:^7.37.0" - eslint-plugin-react-hooks: "npm:^7.0.0" - globals: "npm:16.4.0" - typescript-eslint: "npm:^8.46.0" - peerDependencies: - eslint: ">=9.0.0" - typescript: ">=3.3.1" - peerDependenciesMeta: - typescript: - optional: true - checksum: 10c0/c6fd3accadb53c636f034baf4363d22847bf824c8ca1ecfa8047a4eee7882d156e75f60f37098357c7ae07e646dfaa23a176336abd3c74aa9a2df61aee984653 - languageName: node - linkType: hard - -"eslint-import-resolver-node@npm:^0.3.6, eslint-import-resolver-node@npm:^0.3.9": - version: 0.3.9 - resolution: "eslint-import-resolver-node@npm:0.3.9" - dependencies: - debug: "npm:^3.2.7" - is-core-module: "npm:^2.13.0" - resolve: "npm:^1.22.4" - checksum: 10c0/0ea8a24a72328a51fd95aa8f660dcca74c1429806737cf10261ab90cfcaaf62fd1eff664b76a44270868e0a932711a81b250053942595bcd00a93b1c1575dd61 - languageName: node - linkType: hard - -"eslint-import-resolver-typescript@npm:^3.5.2": - version: 3.10.1 - resolution: "eslint-import-resolver-typescript@npm:3.10.1" - dependencies: - "@nolyfill/is-core-module": "npm:1.0.39" - debug: "npm:^4.4.0" - get-tsconfig: "npm:^4.10.0" - is-bun-module: "npm:^2.0.0" - stable-hash: "npm:^0.0.5" - tinyglobby: "npm:^0.2.13" - unrs-resolver: "npm:^1.6.2" - peerDependencies: - eslint: "*" - eslint-plugin-import: "*" - eslint-plugin-import-x: "*" - peerDependenciesMeta: - eslint-plugin-import: - optional: true - eslint-plugin-import-x: - optional: true - checksum: 10c0/02ba72cf757753ab9250806c066d09082e00807b7b6525d7687e1c0710bc3f6947e39120227fe1f93dabea3510776d86fb3fd769466ba3c46ce67e9f874cb702 - languageName: node - linkType: hard - -"eslint-module-utils@npm:^2.12.1": - version: 2.12.1 - resolution: "eslint-module-utils@npm:2.12.1" - dependencies: - debug: "npm:^3.2.7" - peerDependenciesMeta: - eslint: - optional: true - checksum: 10c0/6f4efbe7a91ae49bf67b4ab3644cb60bc5bd7db4cb5521de1b65be0847ffd3fb6bce0dd68f0995e1b312d137f768e2a1f842ee26fe73621afa05f850628fdc40 - languageName: node - linkType: hard - -"eslint-plugin-import@npm:^2.32.0": - version: 2.32.0 - resolution: "eslint-plugin-import@npm:2.32.0" - dependencies: - "@rtsao/scc": "npm:^1.1.0" - array-includes: "npm:^3.1.9" - array.prototype.findlastindex: "npm:^1.2.6" - array.prototype.flat: "npm:^1.3.3" - array.prototype.flatmap: "npm:^1.3.3" - debug: "npm:^3.2.7" - doctrine: "npm:^2.1.0" - eslint-import-resolver-node: "npm:^0.3.9" - eslint-module-utils: "npm:^2.12.1" - hasown: "npm:^2.0.2" - is-core-module: "npm:^2.16.1" - is-glob: "npm:^4.0.3" - minimatch: "npm:^3.1.2" - object.fromentries: "npm:^2.0.8" - object.groupby: "npm:^1.0.3" - object.values: "npm:^1.2.1" - semver: "npm:^6.3.1" - string.prototype.trimend: "npm:^1.0.9" - tsconfig-paths: "npm:^3.15.0" - peerDependencies: - eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 || ^9 - checksum: 10c0/bfb1b8fc8800398e62ddfefbf3638d185286edfed26dfe00875cc2846d954491b4f5112457831588b757fa789384e1ae585f812614c4797f0499fa234fd4a48b - languageName: node - linkType: hard - -"eslint-plugin-jsx-a11y@npm:^6.10.0": - version: 6.10.2 - resolution: "eslint-plugin-jsx-a11y@npm:6.10.2" - dependencies: - aria-query: "npm:^5.3.2" - array-includes: "npm:^3.1.8" - array.prototype.flatmap: "npm:^1.3.2" - ast-types-flow: "npm:^0.0.8" - axe-core: "npm:^4.10.0" - axobject-query: "npm:^4.1.0" - damerau-levenshtein: "npm:^1.0.8" - emoji-regex: "npm:^9.2.2" - hasown: "npm:^2.0.2" - jsx-ast-utils: "npm:^3.3.5" - language-tags: "npm:^1.0.9" - minimatch: "npm:^3.1.2" - object.fromentries: "npm:^2.0.8" - safe-regex-test: "npm:^1.0.3" - string.prototype.includes: "npm:^2.0.1" - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 - checksum: 10c0/d93354e03b0cf66f018d5c50964e074dffe4ddf1f9b535fa020d19c4ae45f89c1a16e9391ca61ac3b19f7042c751ac0d361a056a65cbd1de24718a53ff8daa6e - languageName: node - linkType: hard - -"eslint-plugin-react-hooks@npm:^7.0.0": - version: 7.0.1 - resolution: "eslint-plugin-react-hooks@npm:7.0.1" - dependencies: - "@babel/core": "npm:^7.24.4" - "@babel/parser": "npm:^7.24.4" - hermes-parser: "npm:^0.25.1" - zod: "npm:^3.25.0 || ^4.0.0" - zod-validation-error: "npm:^3.5.0 || ^4.0.0" - peerDependencies: - eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - checksum: 10c0/1e711d1a9d1fa9cfc51fa1572500656577201199c70c795c6a27adfc1df39e5c598f69aab6aa91117753d23cc1f11388579a2bed14921cf9a4efe60ae8618496 - languageName: node - linkType: hard - -"eslint-plugin-react@npm:^7.37.0": - version: 7.37.5 - resolution: "eslint-plugin-react@npm:7.37.5" - dependencies: - array-includes: "npm:^3.1.8" - array.prototype.findlast: "npm:^1.2.5" - array.prototype.flatmap: "npm:^1.3.3" - array.prototype.tosorted: "npm:^1.1.4" - doctrine: "npm:^2.1.0" - es-iterator-helpers: "npm:^1.2.1" - estraverse: "npm:^5.3.0" - hasown: "npm:^2.0.2" - jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" - minimatch: "npm:^3.1.2" - object.entries: "npm:^1.1.9" - object.fromentries: "npm:^2.0.8" - object.values: "npm:^1.2.1" - prop-types: "npm:^15.8.1" - resolve: "npm:^2.0.0-next.5" - semver: "npm:^6.3.1" - string.prototype.matchall: "npm:^4.0.12" - string.prototype.repeat: "npm:^1.0.0" - peerDependencies: - eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 - checksum: 10c0/c850bfd556291d4d9234f5ca38db1436924a1013627c8ab1853f77cac73ec19b020e861e6c7b783436a48b6ffcdfba4547598235a37ad4611b6739f65fd8ad57 - languageName: node - linkType: hard - -"eslint-scope@npm:^8.4.0": - version: 8.4.0 - resolution: "eslint-scope@npm:8.4.0" - dependencies: - esrecurse: "npm:^4.3.0" - estraverse: "npm:^5.2.0" - checksum: 10c0/407f6c600204d0f3705bd557f81bd0189e69cd7996f408f8971ab5779c0af733d1af2f1412066b40ee1588b085874fc37a2333986c6521669cdbdd36ca5058e0 - languageName: node - linkType: hard - -"eslint-scope@npm:^9.1.2": - version: 9.1.2 - resolution: "eslint-scope@npm:9.1.2" - dependencies: - "@types/esrecurse": "npm:^4.3.1" - "@types/estree": "npm:^1.0.8" - esrecurse: "npm:^4.3.0" - estraverse: "npm:^5.2.0" - checksum: 10c0/9fb8bca5a73e5741efb6cec84467027b6cb6f4203ff9b43a938e272c5cd30800bde46a5c20dfd1609f840225f0b62b7673be391b20acadf8658ca9fa4729b3dd - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^3.4.3": - version: 3.4.3 - resolution: "eslint-visitor-keys@npm:3.4.3" - checksum: 10c0/92708e882c0a5ffd88c23c0b404ac1628cf20104a108c745f240a13c332a11aac54f49a22d5762efbffc18ecbc9a580d1b7ad034bf5f3cc3307e5cbff2ec9820 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^4.2.1": - version: 4.2.1 - resolution: "eslint-visitor-keys@npm:4.2.1" - checksum: 10c0/fcd43999199d6740db26c58dbe0c2594623e31ca307e616ac05153c9272f12f1364f5a0b1917a8e962268fdecc6f3622c1c2908b4fcc2e047a106fe6de69dc43 - languageName: node - linkType: hard - -"eslint-visitor-keys@npm:^5.0.0, eslint-visitor-keys@npm:^5.0.1": - version: 5.0.1 - resolution: "eslint-visitor-keys@npm:5.0.1" - checksum: 10c0/16190bdf2cbae40a1109384c94450c526a79b0b9c3cb21e544256ed85ac48a4b84db66b74a6561d20fe6ab77447f150d711c2ad5ad74df4fcc133736bce99678 - languageName: node - linkType: hard - -"eslint@npm:^9.39.2": - version: 9.39.2 - resolution: "eslint@npm:9.39.2" - dependencies: - "@eslint-community/eslint-utils": "npm:^4.8.0" - "@eslint-community/regexpp": "npm:^4.12.1" - "@eslint/config-array": "npm:^0.21.1" - "@eslint/config-helpers": "npm:^0.4.2" - "@eslint/core": "npm:^0.17.0" - "@eslint/eslintrc": "npm:^3.3.1" - "@eslint/js": "npm:9.39.2" - "@eslint/plugin-kit": "npm:^0.4.1" - "@humanfs/node": "npm:^0.16.6" - "@humanwhocodes/module-importer": "npm:^1.0.1" - "@humanwhocodes/retry": "npm:^0.4.2" - "@types/estree": "npm:^1.0.6" - ajv: "npm:^6.12.4" - chalk: "npm:^4.0.0" - cross-spawn: "npm:^7.0.6" - debug: "npm:^4.3.2" - escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^8.4.0" - eslint-visitor-keys: "npm:^4.2.1" - espree: "npm:^10.4.0" - esquery: "npm:^1.5.0" - esutils: "npm:^2.0.2" - fast-deep-equal: "npm:^3.1.3" - file-entry-cache: "npm:^8.0.0" - find-up: "npm:^5.0.0" - glob-parent: "npm:^6.0.2" - ignore: "npm:^5.2.0" - imurmurhash: "npm:^0.1.4" - is-glob: "npm:^4.0.0" - json-stable-stringify-without-jsonify: "npm:^1.0.1" - lodash.merge: "npm:^4.6.2" - minimatch: "npm:^3.1.2" - natural-compare: "npm:^1.4.0" - optionator: "npm:^0.9.3" - peerDependencies: - jiti: "*" - peerDependenciesMeta: - jiti: - optional: true - bin: - eslint: bin/eslint.js - checksum: 10c0/bb88ca8fd16bb7e1ac3e13804c54d41c583214460c0faa7b3e7c574e69c5600c7122295500fb4b0c06067831111db740931e98da1340329527658e1cf80073d3 - languageName: node - linkType: hard - -"espree@npm:^10.0.1, espree@npm:^10.4.0": - version: 10.4.0 - resolution: "espree@npm:10.4.0" - dependencies: - acorn: "npm:^8.15.0" - acorn-jsx: "npm:^5.3.2" - eslint-visitor-keys: "npm:^4.2.1" - checksum: 10c0/c63fe06131c26c8157b4083313cb02a9a54720a08e21543300e55288c40e06c3fc284bdecf108d3a1372c5934a0a88644c98714f38b6ae8ed272b40d9ea08d6b - languageName: node - linkType: hard - -"esquery@npm:^1.5.0": - version: 1.6.0 - resolution: "esquery@npm:1.6.0" - dependencies: - estraverse: "npm:^5.1.0" - checksum: 10c0/cb9065ec605f9da7a76ca6dadb0619dfb611e37a81e318732977d90fab50a256b95fee2d925fba7c2f3f0523aa16f91587246693bc09bc34d5a59575fe6e93d2 - languageName: node - linkType: hard - -"esrecurse@npm:^4.3.0": - version: 4.3.0 - resolution: "esrecurse@npm:4.3.0" - dependencies: - estraverse: "npm:^5.2.0" - checksum: 10c0/81a37116d1408ded88ada45b9fb16dbd26fba3aadc369ce50fcaf82a0bac12772ebd7b24cd7b91fc66786bf2c1ac7b5f196bc990a473efff972f5cb338877cf5 - languageName: node - linkType: hard - -"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": - version: 5.3.0 - resolution: "estraverse@npm:5.3.0" - checksum: 10c0/1ff9447b96263dec95d6d67431c5e0771eb9776427421260a3e2f0fdd5d6bd4f8e37a7338f5ad2880c9f143450c9b1e4fc2069060724570a49cf9cf0312bd107 - languageName: node - linkType: hard - -"esutils@npm:^2.0.2": - version: 2.0.3 - resolution: "esutils@npm:2.0.3" - checksum: 10c0/9a2fe69a41bfdade834ba7c42de4723c97ec776e40656919c62cbd13607c45e127a003f05f724a1ea55e5029a4cf2de444b13009f2af71271e42d93a637137c7 - languageName: node - linkType: hard - -"ethers@npm:6.13.4": - version: 6.13.4 - resolution: "ethers@npm:6.13.4" - dependencies: - "@adraffy/ens-normalize": "npm:1.10.1" - "@noble/curves": "npm:1.2.0" - "@noble/hashes": "npm:1.3.2" - "@types/node": "npm:22.7.5" - aes-js: "npm:4.0.0-beta.5" - tslib: "npm:2.7.0" - ws: "npm:8.17.1" - checksum: 10c0/efcf9f39f841e38af68ec23cdbd745432c239c256aac4929842d1af04e55d7be0ff65e462f1cf3e93586f43f7bdcc0098fd56f2f7234f36d73e466521a5766ce - languageName: node - linkType: hard - -"exponential-backoff@npm:^3.1.1": - version: 3.1.3 - resolution: "exponential-backoff@npm:3.1.3" - checksum: 10c0/77e3ae682b7b1f4972f563c6dbcd2b0d54ac679e62d5d32f3e5085feba20483cf28bd505543f520e287a56d4d55a28d7874299941faf637e779a1aa5994d1267 - languageName: node - linkType: hard - -"fast-check@npm:^4.8.0": - version: 4.8.0 - resolution: "fast-check@npm:4.8.0" - dependencies: - pure-rand: "npm:^8.0.0" - checksum: 10c0/f72556a29db4ff386a8b6e50d420b06c7e5eaafff7db5560a99136c57d8d4777998155eb02d1bbeff396f575cc0b1442c8a1c4ddb798c4a919b542de1a1904ff - languageName: node - linkType: hard - -"fast-deep-equal@npm:^3.1.1, fast-deep-equal@npm:^3.1.3": - version: 3.1.3 - resolution: "fast-deep-equal@npm:3.1.3" - checksum: 10c0/40dedc862eb8992c54579c66d914635afbec43350afbbe991235fdcb4e3a8d5af1b23ae7e79bef7d4882d0ecee06c3197488026998fb19f72dc95acff1d1b1d0 - languageName: node - linkType: hard - -"fast-glob@npm:3.3.1": - version: 3.3.1 - resolution: "fast-glob@npm:3.3.1" - dependencies: - "@nodelib/fs.stat": "npm:^2.0.2" - "@nodelib/fs.walk": "npm:^1.2.3" - glob-parent: "npm:^5.1.2" - merge2: "npm:^1.3.0" - micromatch: "npm:^4.0.4" - checksum: 10c0/b68431128fb6ce4b804c5f9622628426d990b66c75b21c0d16e3d80e2d1398bf33f7e1724e66a2e3f299285dcf5b8d745b122d0304e7dd66f5231081f33ec67c - languageName: node - linkType: hard - -"fast-glob@npm:^3.3.2, fast-glob@npm:^3.3.3": - version: 3.3.3 - resolution: "fast-glob@npm:3.3.3" - dependencies: - "@nodelib/fs.stat": "npm:^2.0.2" - "@nodelib/fs.walk": "npm:^1.2.3" - glob-parent: "npm:^5.1.2" - merge2: "npm:^1.3.0" - micromatch: "npm:^4.0.8" - checksum: 10c0/f6aaa141d0d3384cf73cbcdfc52f475ed293f6d5b65bfc5def368b09163a9f7e5ec2b3014d80f733c405f58e470ee0cc451c2937685045cddcdeaa24199c43fe - languageName: node - linkType: hard - -"fast-json-stable-stringify@npm:^2.0.0": - version: 2.1.0 - resolution: "fast-json-stable-stringify@npm:2.1.0" - checksum: 10c0/7f081eb0b8a64e0057b3bb03f974b3ef00135fbf36c1c710895cd9300f13c94ba809bb3a81cf4e1b03f6e5285610a61abbd7602d0652de423144dfee5a389c9b - languageName: node - linkType: hard - -"fast-levenshtein@npm:^2.0.6": - version: 2.0.6 - resolution: "fast-levenshtein@npm:2.0.6" - checksum: 10c0/111972b37338bcb88f7d9e2c5907862c280ebf4234433b95bc611e518d192ccb2d38119c4ac86e26b668d75f7f3894f4ff5c4982899afced7ca78633b08287c4 - languageName: node - linkType: hard - -"fast-uri@npm:^3.0.1": - version: 3.1.2 - resolution: "fast-uri@npm:3.1.2" - checksum: 10c0/5b35641895959f3f7ab7a7b1b5542bded159346f25ec9f256817b206d50b64eda5828e90d605a2e2fc645c90519a7259c2bab2c942ee728c88b88e5be21b090d - languageName: node - linkType: hard - -"fastq@npm:^1.6.0": - version: 1.19.1 - resolution: "fastq@npm:1.19.1" - dependencies: - reusify: "npm:^1.0.4" - checksum: 10c0/ebc6e50ac7048daaeb8e64522a1ea7a26e92b3cee5cd1c7f2316cdca81ba543aa40a136b53891446ea5c3a67ec215fbaca87ad405f102dd97012f62916905630 - languageName: node - linkType: hard - -"fdir@npm:^6.4.4": - version: 6.4.6 - resolution: "fdir@npm:6.4.6" - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - checksum: 10c0/45b559cff889934ebb8bc498351e5acba40750ada7e7d6bde197768d2fa67c149be8ae7f8ff34d03f4e1eb20f2764116e56440aaa2f6689e9a4aa7ef06acafe9 - languageName: node - linkType: hard - -"fdir@npm:^6.5.0": - version: 6.5.0 - resolution: "fdir@npm:6.5.0" - peerDependencies: - picomatch: ^3 || ^4 - peerDependenciesMeta: - picomatch: - optional: true - checksum: 10c0/e345083c4306b3aed6cb8ec551e26c36bab5c511e99ea4576a16750ddc8d3240e63826cc624f5ae17ad4dc82e68a253213b60d556c11bfad064b7607847ed07f - languageName: node - linkType: hard - -"file-entry-cache@npm:^8.0.0": - version: 8.0.0 - resolution: "file-entry-cache@npm:8.0.0" - dependencies: - flat-cache: "npm:^4.0.0" - checksum: 10c0/9e2b5938b1cd9b6d7e3612bdc533afd4ac17b2fc646569e9a8abbf2eb48e5eb8e316bc38815a3ef6a1b456f4107f0d0f055a614ca613e75db6bf9ff4d72c1638 - languageName: node - linkType: hard - -"fill-range@npm:^7.1.1": - version: 7.1.1 - resolution: "fill-range@npm:7.1.1" - dependencies: - to-regex-range: "npm:^5.0.1" - checksum: 10c0/b75b691bbe065472f38824f694c2f7449d7f5004aa950426a2c28f0306c60db9b880c0b0e4ed819997ffb882d1da02cfcfc819bddc94d71627f5269682edf018 - languageName: node - linkType: hard - -"find-my-way-ts@npm:^0.1.6": - version: 0.1.6 - resolution: "find-my-way-ts@npm:0.1.6" - checksum: 10c0/16ad4b15275b56ee0ec361d0c61afbdff4c75bd0ac04112f6910f188cb1058096ba63529c2363914da6bb60266aa4def1025af04af26368ff87eb0df52f2862f - languageName: node - linkType: hard - -"find-up@npm:^5.0.0": - version: 5.0.0 - resolution: "find-up@npm:5.0.0" - dependencies: - locate-path: "npm:^6.0.0" - path-exists: "npm:^4.0.0" - checksum: 10c0/062c5a83a9c02f53cdd6d175a37ecf8f87ea5bbff1fdfb828f04bfa021441bc7583e8ebc0872a4c1baab96221fb8a8a275a19809fb93fbc40bd69ec35634069a - languageName: node - linkType: hard - -"flat-cache@npm:^4.0.0": - version: 4.0.1 - resolution: "flat-cache@npm:4.0.1" - dependencies: - flatted: "npm:^3.2.9" - keyv: "npm:^4.5.4" - checksum: 10c0/2c59d93e9faa2523e4fda6b4ada749bed432cfa28c8e251f33b25795e426a1c6dbada777afb1f74fcfff33934fdbdea921ee738fcc33e71adc9d6eca984a1cfc - languageName: node - linkType: hard - -"flatted@npm:3.4.2": - version: 3.4.2 - resolution: "flatted@npm:3.4.2" - checksum: 10c0/a65b67aae7172d6cdf63691be7de6c5cd5adbdfdfe2e9da1a09b617c9512ed794037741ee53d93114276bff3f93cd3b0d97d54f9b316e1e4885dde6e9ffdf7ed - languageName: node - linkType: hard - -"for-each@npm:^0.3.3, for-each@npm:^0.3.5": - version: 0.3.5 - resolution: "for-each@npm:0.3.5" - dependencies: - is-callable: "npm:^1.2.7" - checksum: 10c0/0e0b50f6a843a282637d43674d1fb278dda1dd85f4f99b640024cfb10b85058aac0cc781bf689d5fe50b4b7f638e91e548560723a4e76e04fe96ae35ef039cee - languageName: node - linkType: hard - -"fraction.js@npm:^4.3.7": - version: 4.3.7 - resolution: "fraction.js@npm:4.3.7" - checksum: 10c0/df291391beea9ab4c263487ffd9d17fed162dbb736982dee1379b2a8cc94e4e24e46ed508c6d278aded9080ba51872f1bc5f3a5fd8d7c74e5f105b508ac28711 - languageName: node - linkType: hard - -"fs-minipass@npm:^3.0.0": - version: 3.0.3 - resolution: "fs-minipass@npm:3.0.3" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/63e80da2ff9b621e2cb1596abcb9207f1cf82b968b116ccd7b959e3323144cce7fb141462200971c38bbf2ecca51695069db45265705bed09a7cd93ae5b89f94 - languageName: node - linkType: hard - -"fsevents@npm:~2.3.2": - version: 2.3.3 - resolution: "fsevents@npm:2.3.3" - dependencies: - node-gyp: "npm:latest" - checksum: 10c0/a1f0c44595123ed717febbc478aa952e47adfc28e2092be66b8ab1635147254ca6cfe1df792a8997f22716d4cbafc73309899ff7bfac2ac3ad8cf2e4ecc3ec60 - conditions: os=darwin - languageName: node - linkType: hard - -"fsevents@patch:fsevents@npm%3A~2.3.2#optional!builtin": - version: 2.3.3 - resolution: "fsevents@patch:fsevents@npm%3A2.3.3#optional!builtin::version=2.3.3&hash=df0bf1" - dependencies: - node-gyp: "npm:latest" - conditions: os=darwin - languageName: node - linkType: hard - -"function-bind@npm:^1.1.2": - version: 1.1.2 - resolution: "function-bind@npm:1.1.2" - checksum: 10c0/d8680ee1e5fcd4c197e4ac33b2b4dce03c71f4d91717292785703db200f5c21f977c568d28061226f9b5900cbcd2c84463646134fd5337e7925e0942bc3f46d5 - languageName: node - linkType: hard - -"function.prototype.name@npm:^1.1.6, function.prototype.name@npm:^1.1.8": - version: 1.1.8 - resolution: "function.prototype.name@npm:1.1.8" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - functions-have-names: "npm:^1.2.3" - hasown: "npm:^2.0.2" - is-callable: "npm:^1.2.7" - checksum: 10c0/e920a2ab52663005f3cbe7ee3373e3c71c1fb5558b0b0548648cdf3e51961085032458e26c71ff1a8c8c20e7ee7caeb03d43a5d1fa8610c459333323a2e71253 - languageName: node - linkType: hard - -"functions-have-names@npm:^1.2.3": - version: 1.2.3 - resolution: "functions-have-names@npm:1.2.3" - checksum: 10c0/33e77fd29bddc2d9bb78ab3eb854c165909201f88c75faa8272e35899e2d35a8a642a15e7420ef945e1f64a9670d6aa3ec744106b2aa42be68ca5114025954ca - languageName: node - linkType: hard - -"gensync@npm:^1.0.0-beta.2": - version: 1.0.0-beta.2 - resolution: "gensync@npm:1.0.0-beta.2" - checksum: 10c0/782aba6cba65b1bb5af3b095d96249d20edbe8df32dbf4696fd49be2583faf676173bf4809386588828e4dd76a3354fcbeb577bab1c833ccd9fc4577f26103f8 - languageName: node - linkType: hard - -"get-intrinsic@npm:^1.2.4, get-intrinsic@npm:^1.2.5, get-intrinsic@npm:^1.2.6, get-intrinsic@npm:^1.2.7, get-intrinsic@npm:^1.3.0": - version: 1.3.0 - resolution: "get-intrinsic@npm:1.3.0" - dependencies: - call-bind-apply-helpers: "npm:^1.0.2" - es-define-property: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.1.1" - function-bind: "npm:^1.1.2" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - hasown: "npm:^2.0.2" - math-intrinsics: "npm:^1.1.0" - checksum: 10c0/52c81808af9a8130f581e6a6a83e1ba4a9f703359e7a438d1369a5267a25412322f03dcbd7c549edaef0b6214a0630a28511d7df0130c93cfd380f4fa0b5b66a - languageName: node - linkType: hard - -"get-nonce@npm:^1.0.0": - version: 1.0.1 - resolution: "get-nonce@npm:1.0.1" - checksum: 10c0/2d7df55279060bf0568549e1ffc9b84bc32a32b7541675ca092dce56317cdd1a59a98dcc4072c9f6a980779440139a3221d7486f52c488e69dc0fd27b1efb162 - languageName: node - linkType: hard - -"get-proto@npm:^1.0.0, get-proto@npm:^1.0.1": - version: 1.0.1 - resolution: "get-proto@npm:1.0.1" - dependencies: - dunder-proto: "npm:^1.0.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/9224acb44603c5526955e83510b9da41baf6ae73f7398875fba50edc5e944223a89c4a72b070fcd78beb5f7bdda58ecb6294adc28f7acfc0da05f76a2399643c - languageName: node - linkType: hard - -"get-symbol-description@npm:^1.1.0": - version: 1.1.0 - resolution: "get-symbol-description@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.6" - checksum: 10c0/d6a7d6afca375779a4b307738c9e80dbf7afc0bdbe5948768d54ab9653c865523d8920e670991a925936eb524b7cb6a6361d199a760b21d0ca7620194455aa4b - languageName: node - linkType: hard - -"get-tsconfig@npm:^4.10.0": - version: 4.10.1 - resolution: "get-tsconfig@npm:4.10.1" - dependencies: - resolve-pkg-maps: "npm:^1.0.0" - checksum: 10c0/7f8e3dabc6a49b747920a800fb88e1952fef871cdf51b79e98db48275a5de6cdaf499c55ee67df5fa6fe7ce65f0063e26de0f2e53049b408c585aa74d39ffa21 - languageName: node - linkType: hard - -"glob-parent@npm:^5.1.2, glob-parent@npm:~5.1.2": - version: 5.1.2 - resolution: "glob-parent@npm:5.1.2" - dependencies: - is-glob: "npm:^4.0.1" - checksum: 10c0/cab87638e2112bee3f839ef5f6e0765057163d39c66be8ec1602f3823da4692297ad4e972de876ea17c44d652978638d2fd583c6713d0eb6591706825020c9ee - languageName: node - linkType: hard - -"glob-parent@npm:^6.0.2": - version: 6.0.2 - resolution: "glob-parent@npm:6.0.2" - dependencies: - is-glob: "npm:^4.0.3" - checksum: 10c0/317034d88654730230b3f43bb7ad4f7c90257a426e872ea0bf157473ac61c99bf5d205fad8f0185f989be8d2fa6d3c7dce1645d99d545b6ea9089c39f838e7f8 - languageName: node - linkType: hard - -"glob@npm:^13.0.0": - version: 13.0.6 - resolution: "glob@npm:13.0.6" - dependencies: - minimatch: "npm:^10.2.2" - minipass: "npm:^7.1.3" - path-scurry: "npm:^2.0.2" - checksum: 10c0/269c236f11a9b50357fe7a8c6aadac667e01deb5242b19c84975628f05f4438d8ee1354bb62c5d6c10f37fd59911b54d7799730633a2786660d8c69f1d18120a - languageName: node - linkType: hard - -"globals@npm:16.4.0": - version: 16.4.0 - resolution: "globals@npm:16.4.0" - checksum: 10c0/a14b447a78b664b42f6d324e8675fcae6fe5e57924fecc1f6328dce08af9b2ca3a3138501e1b1f244a49814a732dc60cfc1aa24e714e0b64ac8bd18910bfac90 - languageName: node - linkType: hard - -"globals@npm:^14.0.0": - version: 14.0.0 - resolution: "globals@npm:14.0.0" - checksum: 10c0/b96ff42620c9231ad468d4c58ff42afee7777ee1c963013ff8aabe095a451d0ceeb8dcd8ef4cbd64d2538cef45f787a78ba3a9574f4a634438963e334471302d - languageName: node - linkType: hard - -"globalthis@npm:^1.0.4": - version: 1.0.4 - resolution: "globalthis@npm:1.0.4" - dependencies: - define-properties: "npm:^1.2.1" - gopd: "npm:^1.0.1" - checksum: 10c0/9d156f313af79d80b1566b93e19285f481c591ad6d0d319b4be5e03750d004dde40a39a0f26f7e635f9007a3600802f53ecd85a759b86f109e80a5f705e01846 - languageName: node - linkType: hard - -"gopd@npm:^1.0.1, gopd@npm:^1.2.0": - version: 1.2.0 - resolution: "gopd@npm:1.2.0" - checksum: 10c0/50fff1e04ba2b7737c097358534eacadad1e68d24cccee3272e04e007bed008e68d2614f3987788428fd192a5ae3889d08fb2331417e4fc4a9ab366b2043cead - languageName: node - linkType: hard - -"graceful-fs@npm:^4.2.6": - version: 4.2.11 - resolution: "graceful-fs@npm:4.2.11" - checksum: 10c0/386d011a553e02bc594ac2ca0bd6d9e4c22d7fa8cfbfc448a6d148c59ea881b092db9dbe3547ae4b88e55f1b01f7c4a2ecc53b310c042793e63aa44cf6c257f2 - languageName: node - linkType: hard - -"has-bigints@npm:^1.0.2": - version: 1.1.0 - resolution: "has-bigints@npm:1.1.0" - checksum: 10c0/2de0cdc4a1ccf7a1e75ffede1876994525ac03cc6f5ae7392d3415dd475cd9eee5bceec63669ab61aa997ff6cceebb50ef75561c7002bed8988de2b9d1b40788 - languageName: node - linkType: hard - -"has-flag@npm:^4.0.0": - version: 4.0.0 - resolution: "has-flag@npm:4.0.0" - checksum: 10c0/2e789c61b7888d66993e14e8331449e525ef42aac53c627cc53d1c3334e768bcb6abdc4f5f0de1478a25beec6f0bd62c7549058b7ac53e924040d4f301f02fd1 - languageName: node - linkType: hard - -"has-property-descriptors@npm:^1.0.0, has-property-descriptors@npm:^1.0.2": - version: 1.0.2 - resolution: "has-property-descriptors@npm:1.0.2" - dependencies: - es-define-property: "npm:^1.0.0" - checksum: 10c0/253c1f59e80bb476cf0dde8ff5284505d90c3bdb762983c3514d36414290475fe3fd6f574929d84de2a8eec00d35cf07cb6776205ff32efd7c50719125f00236 - languageName: node - linkType: hard - -"has-proto@npm:^1.2.0": - version: 1.2.0 - resolution: "has-proto@npm:1.2.0" - dependencies: - dunder-proto: "npm:^1.0.0" - checksum: 10c0/46538dddab297ec2f43923c3d35237df45d8c55a6fc1067031e04c13ed8a9a8f94954460632fd4da84c31a1721eefee16d901cbb1ae9602bab93bb6e08f93b95 - languageName: node - linkType: hard - -"has-symbols@npm:^1.0.3, has-symbols@npm:^1.1.0": - version: 1.1.0 - resolution: "has-symbols@npm:1.1.0" - checksum: 10c0/dde0a734b17ae51e84b10986e651c664379018d10b91b6b0e9b293eddb32f0f069688c841fb40f19e9611546130153e0a2a48fd7f512891fb000ddfa36f5a20e - languageName: node - linkType: hard - -"has-tostringtag@npm:^1.0.2": - version: 1.0.2 - resolution: "has-tostringtag@npm:1.0.2" - dependencies: - has-symbols: "npm:^1.0.3" - checksum: 10c0/a8b166462192bafe3d9b6e420a1d581d93dd867adb61be223a17a8d6dad147aa77a8be32c961bb2f27b3ef893cae8d36f564ab651f5e9b7938ae86f74027c48c - languageName: node - linkType: hard - -"hasown@npm:^2.0.2": - version: 2.0.2 - resolution: "hasown@npm:2.0.2" - dependencies: - function-bind: "npm:^1.1.2" - checksum: 10c0/3769d434703b8ac66b209a4cca0737519925bbdb61dd887f93a16372b14694c63ff4e797686d87c90f08168e81082248b9b028bad60d4da9e0d1148766f56eb9 - languageName: node - linkType: hard - -"hermes-estree@npm:0.25.1": - version: 0.25.1 - resolution: "hermes-estree@npm:0.25.1" - checksum: 10c0/48be3b2fa37a0cbc77a112a89096fa212f25d06de92781b163d67853d210a8a5c3784fac23d7d48335058f7ed283115c87b4332c2a2abaaccc76d0ead1a282ac - languageName: node - linkType: hard - -"hermes-parser@npm:^0.25.1": - version: 0.25.1 - resolution: "hermes-parser@npm:0.25.1" - dependencies: - hermes-estree: "npm:0.25.1" - checksum: 10c0/3abaa4c6f1bcc25273f267297a89a4904963ea29af19b8e4f6eabe04f1c2c7e9abd7bfc4730ddb1d58f2ea04b6fee74053d8bddb5656ec6ebf6c79cc8d14202c - languageName: node - linkType: hard - -"http-cache-semantics@npm:^4.1.1": - version: 4.2.0 - resolution: "http-cache-semantics@npm:4.2.0" - checksum: 10c0/45b66a945cf13ec2d1f29432277201313babf4a01d9e52f44b31ca923434083afeca03f18417f599c9ab3d0e7b618ceb21257542338b57c54b710463b4a53e37 - languageName: node - linkType: hard - -"http-proxy-agent@npm:^7.0.0": - version: 7.0.2 - resolution: "http-proxy-agent@npm:7.0.2" - dependencies: - agent-base: "npm:^7.1.0" - debug: "npm:^4.3.4" - checksum: 10c0/4207b06a4580fb85dd6dff521f0abf6db517489e70863dca1a0291daa7f2d3d2d6015a57bd702af068ea5cf9f1f6ff72314f5f5b4228d299c0904135d2aef921 - languageName: node - linkType: hard - -"https-proxy-agent@npm:^7.0.1": - version: 7.0.6 - resolution: "https-proxy-agent@npm:7.0.6" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:4" - checksum: 10c0/f729219bc735edb621fa30e6e84e60ee5d00802b8247aac0d7b79b0bd6d4b3294737a337b93b86a0bd9e68099d031858a39260c976dc14cdbba238ba1f8779ac - languageName: node - linkType: hard - -"iconv-lite@npm:^0.7.2": - version: 0.7.2 - resolution: "iconv-lite@npm:0.7.2" - dependencies: - safer-buffer: "npm:>= 2.1.2 < 3.0.0" - checksum: 10c0/3c228920f3bd307f56bf8363706a776f4a060eb042f131cd23855ceca962951b264d0997ab38a1ad340e1c5df8499ed26e1f4f0db6b2a2ad9befaff22f14b722 - languageName: node - linkType: hard - -"ignore@npm:^5.2.0": - version: 5.3.2 - resolution: "ignore@npm:5.3.2" - checksum: 10c0/f9f652c957983634ded1e7f02da3b559a0d4cc210fca3792cb67f1b153623c9c42efdc1c4121af171e295444459fc4a9201101fb041b1104a3c000bccb188337 - languageName: node - linkType: hard - -"ignore@npm:^7.0.5": - version: 7.0.5 - resolution: "ignore@npm:7.0.5" - checksum: 10c0/ae00db89fe873064a093b8999fe4cc284b13ef2a178636211842cceb650b9c3e390d3339191acb145d81ed5379d2074840cf0c33a20bdbd6f32821f79eb4ad5d - languageName: node - linkType: hard - -"import-fresh@npm:^3.2.1": - version: 3.3.1 - resolution: "import-fresh@npm:3.3.1" - dependencies: - parent-module: "npm:^1.0.0" - resolve-from: "npm:^4.0.0" - checksum: 10c0/bf8cc494872fef783249709385ae883b447e3eb09db0ebd15dcead7d9afe7224dad7bd7591c6b73b0b19b3c0f9640eb8ee884f01cfaf2887ab995b0b36a0cbec - languageName: node - linkType: hard - -"imurmurhash@npm:^0.1.4": - version: 0.1.4 - resolution: "imurmurhash@npm:0.1.4" - checksum: 10c0/8b51313850dd33605c6c9d3fd9638b714f4c4c40250cff658209f30d40da60f78992fb2df5dabee4acf589a6a82bbc79ad5486550754bd9ec4e3fc0d4a57d6a6 - languageName: node - linkType: hard - -"ini@npm:^7.0.0": - version: 7.0.0 - resolution: "ini@npm:7.0.0" - checksum: 10c0/7520cae38bd5587e1cbca4637bb5fc0e157f38e0816522756456010ef703772d0018f9f4987cb9977bf3b10c1feccaad7800744dd1f5d85fb435e58a1baa9754 - languageName: node - linkType: hard - -"input-format@npm:^0.3.10": - version: 0.3.14 - resolution: "input-format@npm:0.3.14" - dependencies: - prop-types: "npm:^15.8.1" - peerDependencies: - react: ">=18.1.0" - react-dom: ">=18.1.0" - peerDependenciesMeta: - react: - optional: true - react-dom: - optional: true - checksum: 10c0/37bb23e0dd15223b2ac8a25b09bc26e4d613cbd93c040dcdb490a1661dd0782c2742ad819b9dbd4b154a9e09ce1a69046a78e4ee943171b7ec86b07b50324ad6 - languageName: node - linkType: hard - -"input-otp@npm:^1.4.2": - version: 1.4.2 - resolution: "input-otp@npm:1.4.2" - peerDependencies: - react: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^16.8 || ^17.0 || ^18.0 || ^19.0.0 || ^19.0.0-rc - checksum: 10c0/d3a3216a75ed832993f3f2852edd7a85c5bae30ea6d251182119120488bbf9fed7cfdd91819bcee6daff57b3cfcbca94fd16d6a7c92cee4d806c0d4fa6ff1128 - languageName: node - linkType: hard - -"internal-slot@npm:^1.1.0": - version: 1.1.0 - resolution: "internal-slot@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - hasown: "npm:^2.0.2" - side-channel: "npm:^1.1.0" - checksum: 10c0/03966f5e259b009a9bf1a78d60da920df198af4318ec004f57b8aef1dd3fe377fbc8cce63a96e8c810010302654de89f9e19de1cd8ad0061d15be28a695465c7 - languageName: node - linkType: hard - -"ip-address@npm:^10.0.1": - version: 10.1.0 - resolution: "ip-address@npm:10.1.0" - checksum: 10c0/0103516cfa93f6433b3bd7333fa876eb21263912329bfa47010af5e16934eeeff86f3d2ae700a3744a137839ddfad62b900c7a445607884a49b5d1e32a3d7566 - languageName: node - linkType: hard - -"is-array-buffer@npm:^3.0.4, is-array-buffer@npm:^3.0.5": - version: 3.0.5 - resolution: "is-array-buffer@npm:3.0.5" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - get-intrinsic: "npm:^1.2.6" - checksum: 10c0/c5c9f25606e86dbb12e756694afbbff64bc8b348d1bc989324c037e1068695131930199d6ad381952715dad3a9569333817f0b1a72ce5af7f883ce802e49c83d - languageName: node - linkType: hard - -"is-async-function@npm:^2.0.0": - version: 2.1.1 - resolution: "is-async-function@npm:2.1.1" - dependencies: - async-function: "npm:^1.0.0" - call-bound: "npm:^1.0.3" - get-proto: "npm:^1.0.1" - has-tostringtag: "npm:^1.0.2" - safe-regex-test: "npm:^1.1.0" - checksum: 10c0/d70c236a5e82de6fc4d44368ffd0c2fee2b088b893511ce21e679da275a5ecc6015ff59a7d7e1bdd7ca39f71a8dbdd253cf8cce5c6b3c91cdd5b42b5ce677298 - languageName: node - linkType: hard - -"is-bigint@npm:^1.1.0": - version: 1.1.0 - resolution: "is-bigint@npm:1.1.0" - dependencies: - has-bigints: "npm:^1.0.2" - checksum: 10c0/f4f4b905ceb195be90a6ea7f34323bf1c18e3793f18922e3e9a73c684c29eeeeff5175605c3a3a74cc38185fe27758f07efba3dbae812e5c5afbc0d2316b40e4 - languageName: node - linkType: hard - -"is-binary-path@npm:~2.1.0": - version: 2.1.0 - resolution: "is-binary-path@npm:2.1.0" - dependencies: - binary-extensions: "npm:^2.0.0" - checksum: 10c0/a16eaee59ae2b315ba36fad5c5dcaf8e49c3e27318f8ab8fa3cdb8772bf559c8d1ba750a589c2ccb096113bb64497084361a25960899cb6172a6925ab6123d38 - languageName: node - linkType: hard - -"is-boolean-object@npm:^1.2.1": - version: 1.2.2 - resolution: "is-boolean-object@npm:1.2.2" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/36ff6baf6bd18b3130186990026f5a95c709345c39cd368468e6c1b6ab52201e9fd26d8e1f4c066357b4938b0f0401e1a5000e08257787c1a02f3a719457001e - languageName: node - linkType: hard - -"is-bun-module@npm:^2.0.0": - version: 2.0.0 - resolution: "is-bun-module@npm:2.0.0" - dependencies: - semver: "npm:^7.7.1" - checksum: 10c0/7d27a0679cfa5be1f5052650391f9b11040cd70c48d45112e312c56bc6b6ca9c9aea70dcce6cc40b1e8947bfff8567a5c5715d3b066fb478522dab46ea379240 - languageName: node - linkType: hard - -"is-callable@npm:^1.2.7": - version: 1.2.7 - resolution: "is-callable@npm:1.2.7" - checksum: 10c0/ceebaeb9d92e8adee604076971dd6000d38d6afc40bb843ea8e45c5579b57671c3f3b50d7f04869618242c6cee08d1b67806a8cb8edaaaf7c0748b3720d6066f - languageName: node - linkType: hard - -"is-core-module@npm:^2.13.0, is-core-module@npm:^2.16.0, is-core-module@npm:^2.16.1": - version: 2.16.1 - resolution: "is-core-module@npm:2.16.1" - dependencies: - hasown: "npm:^2.0.2" - checksum: 10c0/898443c14780a577e807618aaae2b6f745c8538eca5c7bc11388a3f2dc6de82b9902bcc7eb74f07be672b11bbe82dd6a6edded44a00cb3d8f933d0459905eedd - languageName: node - linkType: hard - -"is-data-view@npm:^1.0.1, is-data-view@npm:^1.0.2": - version: 1.0.2 - resolution: "is-data-view@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - get-intrinsic: "npm:^1.2.6" - is-typed-array: "npm:^1.1.13" - checksum: 10c0/ef3548a99d7e7f1370ce21006baca6d40c73e9f15c941f89f0049c79714c873d03b02dae1c64b3f861f55163ecc16da06506c5b8a1d4f16650b3d9351c380153 - languageName: node - linkType: hard - -"is-date-object@npm:^1.0.5, is-date-object@npm:^1.1.0": - version: 1.1.0 - resolution: "is-date-object@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.2" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/1a4d199c8e9e9cac5128d32e6626fa7805175af9df015620ac0d5d45854ccf348ba494679d872d37301032e35a54fc7978fba1687e8721b2139aea7870cafa2f - languageName: node - linkType: hard - -"is-extglob@npm:^2.1.1": - version: 2.1.1 - resolution: "is-extglob@npm:2.1.1" - checksum: 10c0/5487da35691fbc339700bbb2730430b07777a3c21b9ebaecb3072512dfd7b4ba78ac2381a87e8d78d20ea08affb3f1971b4af629173a6bf435ff8a4c47747912 - languageName: node - linkType: hard - -"is-finalizationregistry@npm:^1.1.0": - version: 1.1.1 - resolution: "is-finalizationregistry@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10c0/818dff679b64f19e228a8205a1e2d09989a98e98def3a817f889208cfcbf918d321b251aadf2c05918194803ebd2eb01b14fc9d0b2bea53d984f4137bfca5e97 - languageName: node - linkType: hard - -"is-generator-function@npm:^1.0.10": - version: 1.1.0 - resolution: "is-generator-function@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.3" - get-proto: "npm:^1.0.0" - has-tostringtag: "npm:^1.0.2" - safe-regex-test: "npm:^1.1.0" - checksum: 10c0/fdfa96c8087bf36fc4cd514b474ba2ff404219a4dd4cfa6cf5426404a1eed259bdcdb98f082a71029a48d01f27733e3436ecc6690129a7ec09cb0434bee03a2a - languageName: node - linkType: hard - -"is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3, is-glob@npm:~4.0.1": - version: 4.0.3 - resolution: "is-glob@npm:4.0.3" - dependencies: - is-extglob: "npm:^2.1.1" - checksum: 10c0/17fb4014e22be3bbecea9b2e3a76e9e34ff645466be702f1693e8f1ee1adac84710d0be0bd9f967d6354036fd51ab7c2741d954d6e91dae6bb69714de92c197a - languageName: node - linkType: hard - -"is-map@npm:^2.0.3": - version: 2.0.3 - resolution: "is-map@npm:2.0.3" - checksum: 10c0/2c4d431b74e00fdda7162cd8e4b763d6f6f217edf97d4f8538b94b8702b150610e2c64961340015fe8df5b1fcee33ccd2e9b62619c4a8a3a155f8de6d6d355fc - languageName: node - linkType: hard - -"is-negative-zero@npm:^2.0.3": - version: 2.0.3 - resolution: "is-negative-zero@npm:2.0.3" - checksum: 10c0/bcdcf6b8b9714063ffcfa9929c575ac69bfdabb8f4574ff557dfc086df2836cf07e3906f5bbc4f2a5c12f8f3ba56af640c843cdfc74da8caed86c7c7d66fd08e - languageName: node - linkType: hard - -"is-number-object@npm:^1.1.1": - version: 1.1.1 - resolution: "is-number-object@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/97b451b41f25135ff021d85c436ff0100d84a039bb87ffd799cbcdbea81ef30c464ced38258cdd34f080be08fc3b076ca1f472086286d2aa43521d6ec6a79f53 - languageName: node - linkType: hard - -"is-number@npm:^7.0.0": - version: 7.0.0 - resolution: "is-number@npm:7.0.0" - checksum: 10c0/b4686d0d3053146095ccd45346461bc8e53b80aeb7671cc52a4de02dbbf7dc0d1d2a986e2fe4ae206984b4d34ef37e8b795ebc4f4295c978373e6575e295d811 - languageName: node - linkType: hard - -"is-regex@npm:^1.2.1": - version: 1.2.1 - resolution: "is-regex@npm:1.2.1" - dependencies: - call-bound: "npm:^1.0.2" - gopd: "npm:^1.2.0" - has-tostringtag: "npm:^1.0.2" - hasown: "npm:^2.0.2" - checksum: 10c0/1d3715d2b7889932349241680032e85d0b492cfcb045acb75ffc2c3085e8d561184f1f7e84b6f8321935b4aea39bc9c6ba74ed595b57ce4881a51dfdbc214e04 - languageName: node - linkType: hard - -"is-set@npm:^2.0.3": - version: 2.0.3 - resolution: "is-set@npm:2.0.3" - checksum: 10c0/f73732e13f099b2dc879c2a12341cfc22ccaca8dd504e6edae26484bd5707a35d503fba5b4daad530a9b088ced1ae6c9d8200fd92e09b428fe14ea79ce8080b7 - languageName: node - linkType: hard - -"is-shared-array-buffer@npm:^1.0.4": - version: 1.0.4 - resolution: "is-shared-array-buffer@npm:1.0.4" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10c0/65158c2feb41ff1edd6bbd6fd8403a69861cf273ff36077982b5d4d68e1d59278c71691216a4a64632bd76d4792d4d1d2553901b6666d84ade13bba5ea7bc7db - languageName: node - linkType: hard - -"is-string@npm:^1.1.1": - version: 1.1.1 - resolution: "is-string@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/2f518b4e47886bb81567faba6ffd0d8a8333cf84336e2e78bf160693972e32ad00fe84b0926491cc598dee576fdc55642c92e62d0cbe96bf36f643b6f956f94d - languageName: node - linkType: hard - -"is-symbol@npm:^1.0.4, is-symbol@npm:^1.1.1": - version: 1.1.1 - resolution: "is-symbol@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.2" - has-symbols: "npm:^1.1.0" - safe-regex-test: "npm:^1.1.0" - checksum: 10c0/f08f3e255c12442e833f75a9e2b84b2d4882fdfd920513cf2a4a2324f0a5b076c8fd913778e3ea5d258d5183e9d92c0cd20e04b03ab3df05316b049b2670af1e - languageName: node - linkType: hard - -"is-typed-array@npm:^1.1.13, is-typed-array@npm:^1.1.14, is-typed-array@npm:^1.1.15": - version: 1.1.15 - resolution: "is-typed-array@npm:1.1.15" - dependencies: - which-typed-array: "npm:^1.1.16" - checksum: 10c0/415511da3669e36e002820584e264997ffe277ff136643a3126cc949197e6ca3334d0f12d084e83b1994af2e9c8141275c741cf2b7da5a2ff62dd0cac26f76c4 - languageName: node - linkType: hard - -"is-weakmap@npm:^2.0.2": - version: 2.0.2 - resolution: "is-weakmap@npm:2.0.2" - checksum: 10c0/443c35bb86d5e6cc5929cd9c75a4024bb0fff9586ed50b092f94e700b89c43a33b186b76dbc6d54f3d3d09ece689ab38dcdc1af6a482cbe79c0f2da0a17f1299 - languageName: node - linkType: hard - -"is-weakref@npm:^1.0.2, is-weakref@npm:^1.1.1": - version: 1.1.1 - resolution: "is-weakref@npm:1.1.1" - dependencies: - call-bound: "npm:^1.0.3" - checksum: 10c0/8e0a9c07b0c780949a100e2cab2b5560a48ecd4c61726923c1a9b77b6ab0aa0046c9e7fb2206042296817045376dee2c8ab1dabe08c7c3dfbf195b01275a085b - languageName: node - linkType: hard - -"is-weakset@npm:^2.0.3": - version: 2.0.4 - resolution: "is-weakset@npm:2.0.4" - dependencies: - call-bound: "npm:^1.0.3" - get-intrinsic: "npm:^1.2.6" - checksum: 10c0/6491eba08acb8dc9532da23cb226b7d0192ede0b88f16199e592e4769db0a077119c1f5d2283d1e0d16d739115f70046e887e477eb0e66cd90e1bb29f28ba647 - languageName: node - linkType: hard - -"isarray@npm:^2.0.5": - version: 2.0.5 - resolution: "isarray@npm:2.0.5" - checksum: 10c0/4199f14a7a13da2177c66c31080008b7124331956f47bca57dd0b6ea9f11687aa25e565a2c7a2b519bc86988d10398e3049a1f5df13c9f6b7664154690ae79fd - languageName: node - linkType: hard - -"isexe@npm:^2.0.0": - version: 2.0.0 - resolution: "isexe@npm:2.0.0" - checksum: 10c0/228cfa503fadc2c31596ab06ed6aa82c9976eec2bfd83397e7eaf06d0ccf42cd1dfd6743bf9aeb01aebd4156d009994c5f76ea898d2832c1fe342da923ca457d - languageName: node - linkType: hard - -"isexe@npm:^4.0.0": - version: 4.0.0 - resolution: "isexe@npm:4.0.0" - checksum: 10c0/5884815115bceac452877659a9c7726382531592f43dc29e5d48b7c4100661aed54018cb90bd36cb2eaeba521092570769167acbb95c18d39afdccbcca06c5ce - languageName: node - linkType: hard - -"iterator.prototype@npm:^1.1.4": - version: 1.1.5 - resolution: "iterator.prototype@npm:1.1.5" - dependencies: - define-data-property: "npm:^1.1.4" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.6" - get-proto: "npm:^1.0.0" - has-symbols: "npm:^1.1.0" - set-function-name: "npm:^2.0.2" - checksum: 10c0/f7a262808e1b41049ab55f1e9c29af7ec1025a000d243b83edf34ce2416eedd56079b117fa59376bb4a724110690f13aa8427f2ee29a09eec63a7e72367626d0 - languageName: node - linkType: hard - -"jiti@npm:^1.21.7": - version: 1.21.7 - resolution: "jiti@npm:1.21.7" - bin: - jiti: bin/jiti.js - checksum: 10c0/77b61989c758ff32407cdae8ddc77f85e18e1a13fc4977110dbd2e05fc761842f5f71bce684d9a01316e1c4263971315a111385759951080bbfe17cbb5de8f7a - languageName: node - linkType: hard - -"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": - version: 4.0.0 - resolution: "js-tokens@npm:4.0.0" - checksum: 10c0/e248708d377aa058eacf2037b07ded847790e6de892bbad3dac0abba2e759cb9f121b00099a65195616badcb6eca8d14d975cb3e89eb1cfda644756402c8aeed - languageName: node - linkType: hard - -"js-yaml@npm:>=4.1.1": - version: 4.1.1 - resolution: "js-yaml@npm:4.1.1" - dependencies: - argparse: "npm:^2.0.1" - bin: - js-yaml: bin/js-yaml.js - checksum: 10c0/561c7d7088c40a9bb53cc75becbfb1df6ae49b34b5e6e5a81744b14ae8667ec564ad2527709d1a6e7d5e5fa6d483aa0f373a50ad98d42fde368ec4a190d4fae7 - languageName: node - linkType: hard - -"jsesc@npm:^3.0.2": - version: 3.1.0 - resolution: "jsesc@npm:3.1.0" - bin: - jsesc: bin/jsesc - checksum: 10c0/531779df5ec94f47e462da26b4cbf05eb88a83d9f08aac2ba04206508fc598527a153d08bd462bae82fc78b3eaa1a908e1a4a79f886e9238641c4cdefaf118b1 - languageName: node - linkType: hard - -"json-buffer@npm:3.0.1": - version: 3.0.1 - resolution: "json-buffer@npm:3.0.1" - checksum: 10c0/0d1c91569d9588e7eef2b49b59851f297f3ab93c7b35c7c221e288099322be6b562767d11e4821da500f3219542b9afd2e54c5dc573107c1126ed1080f8e96d7 - languageName: node - linkType: hard - -"json-schema-traverse@npm:^0.4.1": - version: 0.4.1 - resolution: "json-schema-traverse@npm:0.4.1" - checksum: 10c0/108fa90d4cc6f08243aedc6da16c408daf81793bf903e9fd5ab21983cda433d5d2da49e40711da016289465ec2e62e0324dcdfbc06275a607fe3233fde4942ce - languageName: node - linkType: hard - -"json-schema-traverse@npm:^1.0.0": - version: 1.0.0 - resolution: "json-schema-traverse@npm:1.0.0" - checksum: 10c0/71e30015d7f3d6dc1c316d6298047c8ef98a06d31ad064919976583eb61e1018a60a0067338f0f79cabc00d84af3fcc489bd48ce8a46ea165d9541ba17fb30c6 - languageName: node - linkType: hard - -"json-schema-typed@npm:^8.0.1": - version: 8.0.2 - resolution: "json-schema-typed@npm:8.0.2" - checksum: 10c0/89f5e2fb1495483b705c027203c07277ee6bf2665165ad25a9cb55de5af7f72570326d13d32565180781e4083ad5c9688102f222baed7b353c2f39c1e02b0428 - languageName: node - linkType: hard - -"json-stable-stringify-without-jsonify@npm:^1.0.1": - version: 1.0.1 - resolution: "json-stable-stringify-without-jsonify@npm:1.0.1" - checksum: 10c0/cb168b61fd4de83e58d09aaa6425ef71001bae30d260e2c57e7d09a5fd82223e2f22a042dedaab8db23b7d9ae46854b08bb1f91675a8be11c5cffebef5fb66a5 - languageName: node - linkType: hard - -"json5@npm:^1.0.2": - version: 1.0.2 - resolution: "json5@npm:1.0.2" - dependencies: - minimist: "npm:^1.2.0" - bin: - json5: lib/cli.js - checksum: 10c0/9ee316bf21f000b00752e6c2a3b79ecf5324515a5c60ee88983a1910a45426b643a4f3461657586e8aeca87aaf96f0a519b0516d2ae527a6c3e7eed80f68717f - languageName: node - linkType: hard - -"json5@npm:^2.2.3": - version: 2.2.3 - resolution: "json5@npm:2.2.3" - bin: - json5: lib/cli.js - checksum: 10c0/5a04eed94810fa55c5ea138b2f7a5c12b97c3750bc63d11e511dcecbfef758003861522a070c2272764ee0f4e3e323862f386945aeb5b85b87ee43f084ba586c - languageName: node - linkType: hard - -"jsonc-parser@npm:^3.3.1": - version: 3.3.1 - resolution: "jsonc-parser@npm:3.3.1" - checksum: 10c0/269c3ae0a0e4f907a914bf334306c384aabb9929bd8c99f909275ebd5c2d3bc70b9bcd119ad794f339dec9f24b6a4ee9cd5a8ab2e6435e730ad4075388fc2ab6 - languageName: node - linkType: hard - -"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.5": - version: 3.3.5 - resolution: "jsx-ast-utils@npm:3.3.5" - dependencies: - array-includes: "npm:^3.1.6" - array.prototype.flat: "npm:^1.3.1" - object.assign: "npm:^4.1.4" - object.values: "npm:^1.1.6" - checksum: 10c0/a32679e9cb55469cb6d8bbc863f7d631b2c98b7fc7bf172629261751a6e7bc8da6ae374ddb74d5fbd8b06cf0eb4572287b259813d92b36e384024ed35e4c13e1 - languageName: node - linkType: hard - -"keyv@npm:^4.5.4": - version: 4.5.4 - resolution: "keyv@npm:4.5.4" - dependencies: - json-buffer: "npm:3.0.1" - checksum: 10c0/aa52f3c5e18e16bb6324876bb8b59dd02acf782a4b789c7b2ae21107fab95fab3890ed448d4f8dba80ce05391eeac4bfabb4f02a20221342982f806fa2cf271e - languageName: node - linkType: hard - -"kleur@npm:^3.0.3": - version: 3.0.3 - resolution: "kleur@npm:3.0.3" - checksum: 10c0/cd3a0b8878e7d6d3799e54340efe3591ca787d9f95f109f28129bdd2915e37807bf8918bb295ab86afb8c82196beec5a1adcaf29042ce3f2bd932b038fe3aa4b - languageName: node - linkType: hard - -"kubernetes-types@npm:^1.30.0": - version: 1.30.0 - resolution: "kubernetes-types@npm:1.30.0" - checksum: 10c0/de3641e4f50cfc123c4102a73c12932e1db8e51783c7cae4ea8ad3561bd56fab0f1c2346801f84a4c36aae8cea0b25d21e9514cc0fcecd4d64b1314043263076 - languageName: node - linkType: hard - -"language-subtag-registry@npm:^0.3.20": - version: 0.3.23 - resolution: "language-subtag-registry@npm:0.3.23" - checksum: 10c0/e9b05190421d2cd36dd6c95c28673019c927947cb6d94f40ba7e77a838629ee9675c94accf897fbebb07923187deb843b8fbb8935762df6edafe6c28dcb0b86c - languageName: node - linkType: hard - -"language-tags@npm:^1.0.9": - version: 1.0.9 - resolution: "language-tags@npm:1.0.9" - dependencies: - language-subtag-registry: "npm:^0.3.20" - checksum: 10c0/9ab911213c4bd8bd583c850201c17794e52cb0660d1ab6e32558aadc8324abebf6844e46f92b80a5d600d0fbba7eface2c207bfaf270a1c7fd539e4c3a880bff - languageName: node - linkType: hard - -"levn@npm:^0.4.1": - version: 0.4.1 - resolution: "levn@npm:0.4.1" - dependencies: - prelude-ls: "npm:^1.2.1" - type-check: "npm:~0.4.0" - checksum: 10c0/effb03cad7c89dfa5bd4f6989364bfc79994c2042ec5966cb9b95990e2edee5cd8969ddf42616a0373ac49fac1403437deaf6e9050fbbaa3546093a59b9ac94e - languageName: node - linkType: hard - -"libphonenumber-js@npm:^1.11.20": - version: 1.12.15 - resolution: "libphonenumber-js@npm:1.12.15" - checksum: 10c0/d715c938f3e9a331b35f0dd93f5c194f7b19321b9e190b05ca76fab88df5c851936752f4354bea812df5d1d4f432a9133dc2c7199e444c7dbf89bb5b9cc75c3a - languageName: node - linkType: hard - -"lilconfig@npm:^3.1.1, lilconfig@npm:^3.1.3": - version: 3.1.3 - resolution: "lilconfig@npm:3.1.3" - checksum: 10c0/f5604e7240c5c275743561442fbc5abf2a84ad94da0f5adc71d25e31fa8483048de3dcedcb7a44112a942fed305fd75841cdf6c9681c7f640c63f1049e9a5dcc - languageName: node - linkType: hard - -"lines-and-columns@npm:^1.1.6": - version: 1.2.4 - resolution: "lines-and-columns@npm:1.2.4" - checksum: 10c0/3da6ee62d4cd9f03f5dc90b4df2540fb85b352081bee77fe4bbcd12c9000ead7f35e0a38b8d09a9bb99b13223446dd8689ff3c4959807620726d788701a83d2d - languageName: node - linkType: hard - -"locate-path@npm:^6.0.0": - version: 6.0.0 - resolution: "locate-path@npm:6.0.0" - dependencies: - p-locate: "npm:^5.0.0" - checksum: 10c0/d3972ab70dfe58ce620e64265f90162d247e87159b6126b01314dd67be43d50e96a50b517bce2d9452a79409c7614054c277b5232377de50416564a77ac7aad3 - languageName: node - linkType: hard - -"lodash.merge@npm:^4.6.2": - version: 4.6.2 - resolution: "lodash.merge@npm:4.6.2" - checksum: 10c0/402fa16a1edd7538de5b5903a90228aa48eb5533986ba7fa26606a49db2572bf414ff73a2c9f5d5fd36b31c46a5d5c7e1527749c07cbcf965ccff5fbdf32c506 - languageName: node - linkType: hard - -"loose-envify@npm:^1.4.0": - version: 1.4.0 - resolution: "loose-envify@npm:1.4.0" - dependencies: - js-tokens: "npm:^3.0.0 || ^4.0.0" - bin: - loose-envify: cli.js - checksum: 10c0/655d110220983c1a4b9c0c679a2e8016d4b67f6e9c7b5435ff5979ecdb20d0813f4dec0a08674fcbdd4846a3f07edbb50a36811fd37930b94aaa0d9daceb017e - languageName: node - linkType: hard - -"lru-cache@npm:^11.0.0, lru-cache@npm:^11.1.0, lru-cache@npm:^11.2.1": - version: 11.2.7 - resolution: "lru-cache@npm:11.2.7" - checksum: 10c0/549cdb59488baa617135fc12159cafb1a97f91079f35093bb3bcad72e849fc64ace636d244212c181dfdf1a99bbfa90757ff303f98561958ee4d0f885d9bd5f7 - languageName: node - linkType: hard - -"lru-cache@npm:^5.1.1": - version: 5.1.1 - resolution: "lru-cache@npm:5.1.1" - dependencies: - yallist: "npm:^3.0.2" - checksum: 10c0/89b2ef2ef45f543011e38737b8a8622a2f8998cddf0e5437174ef8f1f70a8b9d14a918ab3e232cb3ba343b7abddffa667f0b59075b2b80e6b4d63c3de6127482 - languageName: node - linkType: hard - -"lucide-react@npm:^0.543.0": - version: 0.543.0 - resolution: "lucide-react@npm:0.543.0" - peerDependencies: - react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - checksum: 10c0/76bb54f9c602ff5d44ec66f2786c035d92aaabca1e1abb380b0c8101dfb3290e52c82fa4d630e286ef07c05b63696e187f0ca3ae186535d9c5b4de7aa8825bd3 - languageName: node - linkType: hard - -"make-fetch-happen@npm:^15.0.0": - version: 15.0.5 - resolution: "make-fetch-happen@npm:15.0.5" - dependencies: - "@gar/promise-retry": "npm:^1.0.0" - "@npmcli/agent": "npm:^4.0.0" - "@npmcli/redact": "npm:^4.0.0" - cacache: "npm:^20.0.1" - http-cache-semantics: "npm:^4.1.1" - minipass: "npm:^7.0.2" - minipass-fetch: "npm:^5.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^1.0.0" - proc-log: "npm:^6.0.0" - ssri: "npm:^13.0.0" - checksum: 10c0/527580eb5e5476e6ad07a4e3bd017d13e935f4be815674b442081ae5a721c13d3af5715006619e6be79a85723067e047f83a0c9e699f41d8cec43609a8de4f7b - languageName: node - linkType: hard - -"math-intrinsics@npm:^1.1.0": - version: 1.1.0 - resolution: "math-intrinsics@npm:1.1.0" - checksum: 10c0/7579ff94e899e2f76ab64491d76cf606274c874d8f2af4a442c016bd85688927fcfca157ba6bf74b08e9439dc010b248ce05b96cc7c126a354c3bae7fcb48b7f - languageName: node - linkType: hard - -"merge2@npm:^1.3.0": - version: 1.4.1 - resolution: "merge2@npm:1.4.1" - checksum: 10c0/254a8a4605b58f450308fc474c82ac9a094848081bf4c06778200207820e5193726dc563a0d2c16468810516a5c97d9d3ea0ca6585d23c58ccfff2403e8dbbeb - languageName: node - linkType: hard - -"micromatch@npm:^4.0.4, micromatch@npm:^4.0.8": - version: 4.0.8 - resolution: "micromatch@npm:4.0.8" - dependencies: - braces: "npm:^3.0.3" - picomatch: "npm:^2.3.1" - checksum: 10c0/166fa6eb926b9553f32ef81f5f531d27b4ce7da60e5baf8c021d043b27a388fb95e46a8038d5045877881e673f8134122b59624d5cecbd16eb50a42e7a6b5ca8 - languageName: node - linkType: hard - -"mimic-function@npm:^5.0.0": - version: 5.0.1 - resolution: "mimic-function@npm:5.0.1" - checksum: 10c0/f3d9464dd1816ecf6bdf2aec6ba32c0728022039d992f178237d8e289b48764fee4131319e72eedd4f7f094e22ded0af836c3187a7edc4595d28dd74368fd81d - languageName: node - linkType: hard - -"minimatch@npm:10.2.4, minimatch@npm:^10.2.2": - version: 10.2.4 - resolution: "minimatch@npm:10.2.4" - dependencies: - brace-expansion: "npm:^5.0.2" - checksum: 10c0/35f3dfb7b99b51efd46afd378486889f590e7efb10e0f6a10ba6800428cf65c9a8dedb74427d0570b318d749b543dc4e85f06d46d2858bc8cac7e1eb49a95945 - languageName: node - linkType: hard - -"minimatch@npm:3.1.4": - version: 3.1.4 - resolution: "minimatch@npm:3.1.4" - dependencies: - brace-expansion: "npm:^1.1.7" - checksum: 10c0/868aab7e5f52570107eb283f021383be111cfeee0817a615f2a9ffe61fdc8fb86d535b9bf169fb8882261e7cb9da22b4d7b6f8b3402037f63558bab173f82212 - languageName: node - linkType: hard - -"minimatch@npm:^10.2.5": - version: 10.2.5 - resolution: "minimatch@npm:10.2.5" - dependencies: - brace-expansion: "npm:^5.0.5" - checksum: 10c0/6bb058bd6324104b9ec2f763476a35386d05079c1f5fe4fbf1f324a25237cd4534d6813ecd71f48208f4e635c1221899bef94c3c89f7df55698fe373aaae20fd - languageName: node - linkType: hard - -"minimist@npm:^1.2.0, minimist@npm:^1.2.6": - version: 1.2.8 - resolution: "minimist@npm:1.2.8" - checksum: 10c0/19d3fcdca050087b84c2029841a093691a91259a47def2f18222f41e7645a0b7c44ef4b40e88a1e58a40c84d2ef0ee6047c55594d298146d0eb3f6b737c20ce6 - languageName: node - linkType: hard - -"minipass-collect@npm:^2.0.1": - version: 2.0.1 - resolution: "minipass-collect@npm:2.0.1" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/5167e73f62bb74cc5019594709c77e6a742051a647fe9499abf03c71dca75515b7959d67a764bdc4f8b361cf897fbf25e2d9869ee039203ed45240f48b9aa06e - languageName: node - linkType: hard - -"minipass-fetch@npm:^5.0.0": - version: 5.0.2 - resolution: "minipass-fetch@npm:5.0.2" - dependencies: - iconv-lite: "npm:^0.7.2" - minipass: "npm:^7.0.3" - minipass-sized: "npm:^2.0.0" - minizlib: "npm:^3.0.1" - dependenciesMeta: - iconv-lite: - optional: true - checksum: 10c0/ce4ab9f21cfabaead2097d95dd33f485af8072fbc6b19611bce694965393453a1639d641c2bcf1c48f2ea7d41ea7fab8278373f1d0bee4e63b0a5b2cdd0ef649 - languageName: node - linkType: hard - -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/2a51b63feb799d2bb34669205eee7c0eaf9dce01883261a5b77410c9408aa447e478efd191b4de6fc1101e796ff5892f8443ef20d9544385819093dbb32d36bd - languageName: node - linkType: hard - -"minipass-pipeline@npm:^1.2.4": - version: 1.2.4 - resolution: "minipass-pipeline@npm:1.2.4" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10c0/cbda57cea20b140b797505dc2cac71581a70b3247b84480c1fed5ca5ba46c25ecc25f68bfc9e6dcb1a6e9017dab5c7ada5eab73ad4f0a49d84e35093e0c643f2 - languageName: node - linkType: hard - -"minipass-sized@npm:^2.0.0": - version: 2.0.0 - resolution: "minipass-sized@npm:2.0.0" - dependencies: - minipass: "npm:^7.1.2" - checksum: 10c0/f9201696a6f6d68610d04c9c83e3d2e5cb9c026aae1c8cbf7e17f386105cb79c1bb088dbc21bf0b1eb4f3fb5df384fd1e7aa3bf1f33868c416ae8c8a92679db8 - languageName: node - linkType: hard - -"minipass@npm:^3.0.0": - version: 3.3.6 - resolution: "minipass@npm:3.3.6" - dependencies: - yallist: "npm:^4.0.0" - checksum: 10c0/a114746943afa1dbbca8249e706d1d38b85ed1298b530f5808ce51f8e9e941962e2a5ad2e00eae7dd21d8a4aae6586a66d4216d1a259385e9d0358f0c1eba16c - languageName: node - linkType: hard - -"minipass@npm:^7.0.2, minipass@npm:^7.0.3, minipass@npm:^7.0.4, minipass@npm:^7.1.2, minipass@npm:^7.1.3": - version: 7.1.3 - resolution: "minipass@npm:7.1.3" - checksum: 10c0/539da88daca16533211ea5a9ee98dc62ff5742f531f54640dd34429e621955e91cc280a91a776026264b7f9f6735947629f920944e9c1558369e8bf22eb33fbb - languageName: node - linkType: hard - -"minizlib@npm:^3.0.1, minizlib@npm:^3.1.0": - version: 3.1.0 - resolution: "minizlib@npm:3.1.0" - dependencies: - minipass: "npm:^7.1.2" - checksum: 10c0/5aad75ab0090b8266069c9aabe582c021ae53eb33c6c691054a13a45db3b4f91a7fb1bd79151e6b4e9e9a86727b522527c0a06ec7d45206b745d54cd3097bcec - languageName: node - linkType: hard - -"ms@npm:^2.1.1, ms@npm:^2.1.3": - version: 2.1.3 - resolution: "ms@npm:2.1.3" - checksum: 10c0/d924b57e7312b3b63ad21fc5b3dc0af5e78d61a1fc7cfb5457edaf26326bf62be5307cc87ffb6862ef1c2b33b0233cdb5d4f01c4c958cc0d660948b65a287a48 - languageName: node - linkType: hard - -"msgpackr-extract@npm:^3.0.4": - version: 3.0.4 - resolution: "msgpackr-extract@npm:3.0.4" - dependencies: - "@msgpackr-extract/msgpackr-extract-darwin-arm64": "npm:3.0.4" - "@msgpackr-extract/msgpackr-extract-darwin-x64": "npm:3.0.4" - "@msgpackr-extract/msgpackr-extract-linux-arm": "npm:3.0.4" - "@msgpackr-extract/msgpackr-extract-linux-arm64": "npm:3.0.4" - "@msgpackr-extract/msgpackr-extract-linux-x64": "npm:3.0.4" - "@msgpackr-extract/msgpackr-extract-win32-x64": "npm:3.0.4" - node-gyp: "npm:latest" - node-gyp-build-optional-packages: "npm:5.2.2" - dependenciesMeta: - "@msgpackr-extract/msgpackr-extract-darwin-arm64": - optional: true - "@msgpackr-extract/msgpackr-extract-darwin-x64": - optional: true - "@msgpackr-extract/msgpackr-extract-linux-arm": - optional: true - "@msgpackr-extract/msgpackr-extract-linux-arm64": - optional: true - "@msgpackr-extract/msgpackr-extract-linux-x64": - optional: true - "@msgpackr-extract/msgpackr-extract-win32-x64": - optional: true - bin: - download-msgpackr-prebuilds: bin/download-prebuilds.js - checksum: 10c0/582a9d17abbf3019e600e948736695056280ce401fd0235ee2474e95f9952208b9f6cce4d0e355b03b7d3c5630e6c3d11fe5fc27fdedb2311cce48de464338d8 - languageName: node - linkType: hard - -"msgpackr@npm:^2.0.1": - version: 2.0.2 - resolution: "msgpackr@npm:2.0.2" - dependencies: - msgpackr-extract: "npm:^3.0.4" - dependenciesMeta: - msgpackr-extract: - optional: true - checksum: 10c0/158f37b1adc263c8351292d3d3513fc09831b8f15e8c3c634e6670cdf656d2c1ccbdcbf62c2c84f040b230cadace26d72c63f6898d7e39e86ae2f4c13fd05642 - languageName: node - linkType: hard - -"multipasta@npm:^0.2.7": - version: 0.2.7 - resolution: "multipasta@npm:0.2.7" - checksum: 10c0/15917ac88aeefa5b8afac44b90d1e9d0d0ec7148b51e0766f07a69a220ecebcb6404539a856c45aa85a3d7fe517bc58febe81437146705f17ecd2961dc0b9fa5 - languageName: node - linkType: hard - -"mz@npm:^2.7.0": - version: 2.7.0 - resolution: "mz@npm:2.7.0" - dependencies: - any-promise: "npm:^1.0.0" - object-assign: "npm:^4.0.1" - thenify-all: "npm:^1.0.0" - checksum: 10c0/103114e93f87362f0b56ab5b2e7245051ad0276b646e3902c98397d18bb8f4a77f2ea4a2c9d3ad516034ea3a56553b60d3f5f78220001ca4c404bd711bd0af39 - languageName: node - linkType: hard - -"nanoid@npm:^3.3.11, nanoid@npm:^3.3.6": - version: 3.3.11 - resolution: "nanoid@npm:3.3.11" - bin: - nanoid: bin/nanoid.cjs - checksum: 10c0/40e7f70b3d15f725ca072dfc4f74e81fcf1fbb02e491cf58ac0c79093adc9b0a73b152bcde57df4b79cd097e13023d7504acb38404a4da7bc1cd8e887b82fe0b - languageName: node - linkType: hard - -"napi-postinstall@npm:^0.3.0": - version: 0.3.2 - resolution: "napi-postinstall@npm:0.3.2" - bin: - napi-postinstall: lib/cli.js - checksum: 10c0/77c67eb9871d24afe7bad30e6115c441d099d6a0e42dc1c49c4a722ff682425e08dc6dd2b03eca10db9b547e724c38fb51325c35039e7ac10dcb714bb88d7326 - languageName: node - linkType: hard - -"natural-compare@npm:^1.4.0": - version: 1.4.0 - resolution: "natural-compare@npm:1.4.0" - checksum: 10c0/f5f9a7974bfb28a91afafa254b197f0f22c684d4a1731763dda960d2c8e375b36c7d690e0d9dc8fba774c537af14a7e979129bca23d88d052fbeb9466955e447 - languageName: node - linkType: hard - -"negotiator@npm:^1.0.0": - version: 1.0.0 - resolution: "negotiator@npm:1.0.0" - checksum: 10c0/4c559dd52669ea48e1914f9d634227c561221dd54734070791f999c52ed0ff36e437b2e07d5c1f6e32909fc625fe46491c16e4a8f0572567d4dd15c3a4fda04b - languageName: node - linkType: hard - -"next-themes@npm:^0.4.6": - version: 0.4.6 - resolution: "next-themes@npm:0.4.6" - peerDependencies: - react: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - react-dom: ^16.8 || ^17 || ^18 || ^19 || ^19.0.0-rc - checksum: 10c0/83590c11d359ce7e4ced14f6ea9dd7a691d5ce6843fe2dc520fc27e29ae1c535118478d03e7f172609c41b1ef1b8da6b8dd2d2acd6cd79cac1abbdbd5b99f2c4 - languageName: node - linkType: hard - -"next@npm:16.2.3": - version: 16.2.3 - resolution: "next@npm:16.2.3" - dependencies: - "@next/env": "npm:16.2.3" - "@next/swc-darwin-arm64": "npm:16.2.3" - "@next/swc-darwin-x64": "npm:16.2.3" - "@next/swc-linux-arm64-gnu": "npm:16.2.3" - "@next/swc-linux-arm64-musl": "npm:16.2.3" - "@next/swc-linux-x64-gnu": "npm:16.2.3" - "@next/swc-linux-x64-musl": "npm:16.2.3" - "@next/swc-win32-arm64-msvc": "npm:16.2.3" - "@next/swc-win32-x64-msvc": "npm:16.2.3" - "@swc/helpers": "npm:0.5.15" - baseline-browser-mapping: "npm:^2.9.19" - caniuse-lite: "npm:^1.0.30001579" - postcss: "npm:8.4.31" - sharp: "npm:^0.34.5" - styled-jsx: "npm:5.1.6" - peerDependencies: - "@opentelemetry/api": ^1.1.0 - "@playwright/test": ^1.51.1 - babel-plugin-react-compiler: "*" - react: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - react-dom: ^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0 - sass: ^1.3.0 - dependenciesMeta: - "@next/swc-darwin-arm64": - optional: true - "@next/swc-darwin-x64": - optional: true - "@next/swc-linux-arm64-gnu": - optional: true - "@next/swc-linux-arm64-musl": - optional: true - "@next/swc-linux-x64-gnu": - optional: true - "@next/swc-linux-x64-musl": - optional: true - "@next/swc-win32-arm64-msvc": - optional: true - "@next/swc-win32-x64-msvc": - optional: true - sharp: - optional: true - peerDependenciesMeta: - "@opentelemetry/api": - optional: true - "@playwright/test": - optional: true - babel-plugin-react-compiler: - optional: true - sass: - optional: true - bin: - next: dist/bin/next - checksum: 10c0/8a9d27fc773d69f7f471cf1a23bde2ab2950e0411ef3e0d5c1664ed9654e94c3304eae1c4283ec0fa4e70e7b3f4416913350e118e0c18e8b055693dc5d021883 - languageName: node - linkType: hard - -"node-gyp-build-optional-packages@npm:5.2.2": - version: 5.2.2 - resolution: "node-gyp-build-optional-packages@npm:5.2.2" - dependencies: - detect-libc: "npm:^2.0.1" - bin: - node-gyp-build-optional-packages: bin.js - node-gyp-build-optional-packages-optional: optional.js - node-gyp-build-optional-packages-test: build-test.js - checksum: 10c0/c81128c6f91873381be178c5eddcbdf66a148a6a89a427ce2bcd457593ce69baf2a8662b6d22cac092d24aa9c43c230dec4e69b3a0da604503f4777cd77e282b - languageName: node - linkType: hard - -"node-gyp@npm:latest": - version: 12.2.0 - resolution: "node-gyp@npm:12.2.0" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^15.0.0" - nopt: "npm:^9.0.0" - proc-log: "npm:^6.0.0" - semver: "npm:^7.3.5" - tar: "npm:^7.5.4" - tinyglobby: "npm:^0.2.12" - which: "npm:^6.0.0" - bin: - node-gyp: bin/node-gyp.js - checksum: 10c0/3ed046746a5a7d90950cd8b0547332b06598443f31fe213ef4332a7174c7b7d259e1704835feda79b87d3f02e59d7791842aac60642ede4396ab25fdf0f8f759 - languageName: node - linkType: hard - -"node-releases@npm:^2.0.19": - version: 2.0.20 - resolution: "node-releases@npm:2.0.20" - checksum: 10c0/24c5b1f5aa16d042c47a651ca2e022ca27320f95e4d2b76b9e543cc470eadd01032646383212ec373f1a3dd15cccce83d77c318ee99585366dbd25db4366abd8 - languageName: node - linkType: hard - -"node-releases@npm:^2.0.27": - version: 2.0.27 - resolution: "node-releases@npm:2.0.27" - checksum: 10c0/f1e6583b7833ea81880627748d28a3a7ff5703d5409328c216ae57befbced10ce2c991bea86434e8ec39003bd017f70481e2e5f8c1f7e0a7663241f81d6e00e2 - languageName: node - linkType: hard - -"nopt@npm:^9.0.0": - version: 9.0.0 - resolution: "nopt@npm:9.0.0" - dependencies: - abbrev: "npm:^4.0.0" - bin: - nopt: bin/nopt.js - checksum: 10c0/1822eb6f9b020ef6f7a7516d7b64a8036e09666ea55ac40416c36e4b2b343122c3cff0e2f085675f53de1d2db99a2a89a60ccea1d120bcd6a5347bf6ceb4a7fd - languageName: node - linkType: hard - -"normalize-path@npm:^3.0.0, normalize-path@npm:~3.0.0": - version: 3.0.0 - resolution: "normalize-path@npm:3.0.0" - checksum: 10c0/e008c8142bcc335b5e38cf0d63cfd39d6cf2d97480af9abdbe9a439221fd4d749763bab492a8ee708ce7a194bb00c9da6d0a115018672310850489137b3da046 - languageName: node - linkType: hard - -"normalize-range@npm:^0.1.2": - version: 0.1.2 - resolution: "normalize-range@npm:0.1.2" - checksum: 10c0/bf39b73a63e0a42ad1a48c2bd1bda5a07ede64a7e2567307a407674e595bcff0fa0d57e8e5f1e7fa5e91000797c7615e13613227aaaa4d6d6e87f5bd5cc95de6 - languageName: node - linkType: hard - -"object-assign@npm:^4.0.1, object-assign@npm:^4.1.1": - version: 4.1.1 - resolution: "object-assign@npm:4.1.1" - checksum: 10c0/1f4df9945120325d041ccf7b86f31e8bcc14e73d29171e37a7903050e96b81323784ec59f93f102ec635bcf6fa8034ba3ea0a8c7e69fa202b87ae3b6cec5a414 - languageName: node - linkType: hard - -"object-hash@npm:^3.0.0": - version: 3.0.0 - resolution: "object-hash@npm:3.0.0" - checksum: 10c0/a06844537107b960c1c8b96cd2ac8592a265186bfa0f6ccafe0d34eabdb526f6fa81da1f37c43df7ed13b12a4ae3457a16071603bcd39d8beddb5f08c37b0f47 - languageName: node - linkType: hard - -"object-inspect@npm:^1.13.3, object-inspect@npm:^1.13.4": - version: 1.13.4 - resolution: "object-inspect@npm:1.13.4" - checksum: 10c0/d7f8711e803b96ea3191c745d6f8056ce1f2496e530e6a19a0e92d89b0fa3c76d910c31f0aa270432db6bd3b2f85500a376a83aaba849a8d518c8845b3211692 - languageName: node - linkType: hard - -"object-keys@npm:^1.1.1": - version: 1.1.1 - resolution: "object-keys@npm:1.1.1" - checksum: 10c0/b11f7ccdbc6d406d1f186cdadb9d54738e347b2692a14439ca5ac70c225fa6db46db809711b78589866d47b25fc3e8dee0b4c722ac751e11180f9380e3d8601d - languageName: node - linkType: hard - -"object.assign@npm:^4.1.4, object.assign@npm:^4.1.7": - version: 4.1.7 - resolution: "object.assign@npm:4.1.7" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - has-symbols: "npm:^1.1.0" - object-keys: "npm:^1.1.1" - checksum: 10c0/3b2732bd860567ea2579d1567525168de925a8d852638612846bd8082b3a1602b7b89b67b09913cbb5b9bd6e95923b2ae73580baa9d99cb4e990564e8cbf5ddc - languageName: node - linkType: hard - -"object.entries@npm:^1.1.9": - version: 1.1.9 - resolution: "object.entries@npm:1.1.9" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.1.1" - checksum: 10c0/d4b8c1e586650407da03370845f029aa14076caca4e4d4afadbc69cfb5b78035fd3ee7be417141abdb0258fa142e59b11923b4c44d8b1255b28f5ffcc50da7db - languageName: node - linkType: hard - -"object.fromentries@npm:^2.0.8": - version: 2.0.8 - resolution: "object.fromentries@npm:2.0.8" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/cd4327e6c3369cfa805deb4cbbe919bfb7d3aeebf0bcaba291bb568ea7169f8f8cdbcabe2f00b40db0c20cd20f08e11b5f3a5a36fb7dd3fe04850c50db3bf83b - languageName: node - linkType: hard - -"object.groupby@npm:^1.0.3": - version: 1.0.3 - resolution: "object.groupby@npm:1.0.3" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.2" - checksum: 10c0/60d0455c85c736fbfeda0217d1a77525956f76f7b2495edeca9e9bbf8168a45783199e77b894d30638837c654d0cc410e0e02cbfcf445bc8de71c3da1ede6a9c - languageName: node - linkType: hard - -"object.values@npm:^1.1.6, object.values@npm:^1.2.1": - version: 1.2.1 - resolution: "object.values@npm:1.2.1" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/3c47814fdc64842ae3d5a74bc9d06bdd8d21563c04d9939bf6716a9c00596a4ebc342552f8934013d1ec991c74e3671b26710a0c51815f0b603795605ab6b2c9 - languageName: node - linkType: hard - -"optionator@npm:^0.9.3": - version: 0.9.4 - resolution: "optionator@npm:0.9.4" - dependencies: - deep-is: "npm:^0.1.3" - fast-levenshtein: "npm:^2.0.6" - levn: "npm:^0.4.1" - prelude-ls: "npm:^1.2.1" - type-check: "npm:^0.4.0" - word-wrap: "npm:^1.2.5" - checksum: 10c0/4afb687a059ee65b61df74dfe87d8d6815cd6883cb8b3d5883a910df72d0f5d029821f37025e4bccf4048873dbdb09acc6d303d27b8f76b1a80dd5a7d5334675 - languageName: node - linkType: hard - -"own-keys@npm:^1.0.1": - version: 1.0.1 - resolution: "own-keys@npm:1.0.1" - dependencies: - get-intrinsic: "npm:^1.2.6" - object-keys: "npm:^1.1.1" - safe-push-apply: "npm:^1.0.0" - checksum: 10c0/6dfeb3455bff92ec3f16a982d4e3e65676345f6902d9f5ded1d8265a6318d0200ce461956d6d1c70053c7fe9f9fe65e552faac03f8140d37ef0fdd108e67013a - languageName: node - linkType: hard - -"oxc-parser@npm:^0.132.0": - version: 0.132.0 - resolution: "oxc-parser@npm:0.132.0" - dependencies: - "@oxc-parser/binding-android-arm-eabi": "npm:0.132.0" - "@oxc-parser/binding-android-arm64": "npm:0.132.0" - "@oxc-parser/binding-darwin-arm64": "npm:0.132.0" - "@oxc-parser/binding-darwin-x64": "npm:0.132.0" - "@oxc-parser/binding-freebsd-x64": "npm:0.132.0" - "@oxc-parser/binding-linux-arm-gnueabihf": "npm:0.132.0" - "@oxc-parser/binding-linux-arm-musleabihf": "npm:0.132.0" - "@oxc-parser/binding-linux-arm64-gnu": "npm:0.132.0" - "@oxc-parser/binding-linux-arm64-musl": "npm:0.132.0" - "@oxc-parser/binding-linux-ppc64-gnu": "npm:0.132.0" - "@oxc-parser/binding-linux-riscv64-gnu": "npm:0.132.0" - "@oxc-parser/binding-linux-riscv64-musl": "npm:0.132.0" - "@oxc-parser/binding-linux-s390x-gnu": "npm:0.132.0" - "@oxc-parser/binding-linux-x64-gnu": "npm:0.132.0" - "@oxc-parser/binding-linux-x64-musl": "npm:0.132.0" - "@oxc-parser/binding-openharmony-arm64": "npm:0.132.0" - "@oxc-parser/binding-wasm32-wasi": "npm:0.132.0" - "@oxc-parser/binding-win32-arm64-msvc": "npm:0.132.0" - "@oxc-parser/binding-win32-ia32-msvc": "npm:0.132.0" - "@oxc-parser/binding-win32-x64-msvc": "npm:0.132.0" - "@oxc-project/types": "npm:^0.132.0" - dependenciesMeta: - "@oxc-parser/binding-android-arm-eabi": - optional: true - "@oxc-parser/binding-android-arm64": - optional: true - "@oxc-parser/binding-darwin-arm64": - optional: true - "@oxc-parser/binding-darwin-x64": - optional: true - "@oxc-parser/binding-freebsd-x64": - optional: true - "@oxc-parser/binding-linux-arm-gnueabihf": - optional: true - "@oxc-parser/binding-linux-arm-musleabihf": - optional: true - "@oxc-parser/binding-linux-arm64-gnu": - optional: true - "@oxc-parser/binding-linux-arm64-musl": - optional: true - "@oxc-parser/binding-linux-ppc64-gnu": - optional: true - "@oxc-parser/binding-linux-riscv64-gnu": - optional: true - "@oxc-parser/binding-linux-riscv64-musl": - optional: true - "@oxc-parser/binding-linux-s390x-gnu": - optional: true - "@oxc-parser/binding-linux-x64-gnu": - optional: true - "@oxc-parser/binding-linux-x64-musl": - optional: true - "@oxc-parser/binding-openharmony-arm64": - optional: true - "@oxc-parser/binding-wasm32-wasi": - optional: true - "@oxc-parser/binding-win32-arm64-msvc": - optional: true - "@oxc-parser/binding-win32-ia32-msvc": - optional: true - "@oxc-parser/binding-win32-x64-msvc": - optional: true - checksum: 10c0/f3a4c5b8e19bed6a7dac19f19c0d94e84f9969f7c93f57e8b7713351a68c7d0378fc9e29c6afbecd41ce93cf5c18bb216959ba495c2d13bd53b82007eaa58b70 - languageName: node - linkType: hard - -"oxc-resolver@npm:^11.19.1": - version: 11.19.1 - resolution: "oxc-resolver@npm:11.19.1" - dependencies: - "@oxc-resolver/binding-android-arm-eabi": "npm:11.19.1" - "@oxc-resolver/binding-android-arm64": "npm:11.19.1" - "@oxc-resolver/binding-darwin-arm64": "npm:11.19.1" - "@oxc-resolver/binding-darwin-x64": "npm:11.19.1" - "@oxc-resolver/binding-freebsd-x64": "npm:11.19.1" - "@oxc-resolver/binding-linux-arm-gnueabihf": "npm:11.19.1" - "@oxc-resolver/binding-linux-arm-musleabihf": "npm:11.19.1" - "@oxc-resolver/binding-linux-arm64-gnu": "npm:11.19.1" - "@oxc-resolver/binding-linux-arm64-musl": "npm:11.19.1" - "@oxc-resolver/binding-linux-ppc64-gnu": "npm:11.19.1" - "@oxc-resolver/binding-linux-riscv64-gnu": "npm:11.19.1" - "@oxc-resolver/binding-linux-riscv64-musl": "npm:11.19.1" - "@oxc-resolver/binding-linux-s390x-gnu": "npm:11.19.1" - "@oxc-resolver/binding-linux-x64-gnu": "npm:11.19.1" - "@oxc-resolver/binding-linux-x64-musl": "npm:11.19.1" - "@oxc-resolver/binding-openharmony-arm64": "npm:11.19.1" - "@oxc-resolver/binding-wasm32-wasi": "npm:11.19.1" - "@oxc-resolver/binding-win32-arm64-msvc": "npm:11.19.1" - "@oxc-resolver/binding-win32-ia32-msvc": "npm:11.19.1" - "@oxc-resolver/binding-win32-x64-msvc": "npm:11.19.1" - dependenciesMeta: - "@oxc-resolver/binding-android-arm-eabi": - optional: true - "@oxc-resolver/binding-android-arm64": - optional: true - "@oxc-resolver/binding-darwin-arm64": - optional: true - "@oxc-resolver/binding-darwin-x64": - optional: true - "@oxc-resolver/binding-freebsd-x64": - optional: true - "@oxc-resolver/binding-linux-arm-gnueabihf": - optional: true - "@oxc-resolver/binding-linux-arm-musleabihf": - optional: true - "@oxc-resolver/binding-linux-arm64-gnu": - optional: true - "@oxc-resolver/binding-linux-arm64-musl": - optional: true - "@oxc-resolver/binding-linux-ppc64-gnu": - optional: true - "@oxc-resolver/binding-linux-riscv64-gnu": - optional: true - "@oxc-resolver/binding-linux-riscv64-musl": - optional: true - "@oxc-resolver/binding-linux-s390x-gnu": - optional: true - "@oxc-resolver/binding-linux-x64-gnu": - optional: true - "@oxc-resolver/binding-linux-x64-musl": - optional: true - "@oxc-resolver/binding-openharmony-arm64": - optional: true - "@oxc-resolver/binding-wasm32-wasi": - optional: true - "@oxc-resolver/binding-win32-arm64-msvc": - optional: true - "@oxc-resolver/binding-win32-ia32-msvc": - optional: true - "@oxc-resolver/binding-win32-x64-msvc": - optional: true - checksum: 10c0/8ac4eaffa9c0bcbb9f4f4a2b43786457ec5a68684d8776cb78b5a15ce3d1a79d3e67262aa3c635f98a0c1cd6cd56a31fcb05bffb9a286100056e4ab06b928833 - languageName: node - linkType: hard - -"oxlint-plugin-react-doctor@npm:0.2.6": - version: 0.2.6 - resolution: "oxlint-plugin-react-doctor@npm:0.2.6" - dependencies: - "@typescript-eslint/types": "npm:^8.59.3" - eslint-scope: "npm:^9.1.2" - eslint-visitor-keys: "npm:^5.0.1" - checksum: 10c0/53ff5b80bc9a42e8578de9d6bac23a78e2304b39b9d31d576a7e7efa7dec04a45bb74babaf8c058197eced59e7b72c8490b39b6e637158562750eaedf89cf9f8 - languageName: node - linkType: hard - -"oxlint@npm:^1.66.0": - version: 1.67.0 - resolution: "oxlint@npm:1.67.0" - dependencies: - "@oxlint/binding-android-arm-eabi": "npm:1.67.0" - "@oxlint/binding-android-arm64": "npm:1.67.0" - "@oxlint/binding-darwin-arm64": "npm:1.67.0" - "@oxlint/binding-darwin-x64": "npm:1.67.0" - "@oxlint/binding-freebsd-x64": "npm:1.67.0" - "@oxlint/binding-linux-arm-gnueabihf": "npm:1.67.0" - "@oxlint/binding-linux-arm-musleabihf": "npm:1.67.0" - "@oxlint/binding-linux-arm64-gnu": "npm:1.67.0" - "@oxlint/binding-linux-arm64-musl": "npm:1.67.0" - "@oxlint/binding-linux-ppc64-gnu": "npm:1.67.0" - "@oxlint/binding-linux-riscv64-gnu": "npm:1.67.0" - "@oxlint/binding-linux-riscv64-musl": "npm:1.67.0" - "@oxlint/binding-linux-s390x-gnu": "npm:1.67.0" - "@oxlint/binding-linux-x64-gnu": "npm:1.67.0" - "@oxlint/binding-linux-x64-musl": "npm:1.67.0" - "@oxlint/binding-openharmony-arm64": "npm:1.67.0" - "@oxlint/binding-win32-arm64-msvc": "npm:1.67.0" - "@oxlint/binding-win32-ia32-msvc": "npm:1.67.0" - "@oxlint/binding-win32-x64-msvc": "npm:1.67.0" - peerDependencies: - oxlint-tsgolint: ">=0.22.1" - vite-plus: "*" - dependenciesMeta: - "@oxlint/binding-android-arm-eabi": - optional: true - "@oxlint/binding-android-arm64": - optional: true - "@oxlint/binding-darwin-arm64": - optional: true - "@oxlint/binding-darwin-x64": - optional: true - "@oxlint/binding-freebsd-x64": - optional: true - "@oxlint/binding-linux-arm-gnueabihf": - optional: true - "@oxlint/binding-linux-arm-musleabihf": - optional: true - "@oxlint/binding-linux-arm64-gnu": - optional: true - "@oxlint/binding-linux-arm64-musl": - optional: true - "@oxlint/binding-linux-ppc64-gnu": - optional: true - "@oxlint/binding-linux-riscv64-gnu": - optional: true - "@oxlint/binding-linux-riscv64-musl": - optional: true - "@oxlint/binding-linux-s390x-gnu": - optional: true - "@oxlint/binding-linux-x64-gnu": - optional: true - "@oxlint/binding-linux-x64-musl": - optional: true - "@oxlint/binding-openharmony-arm64": - optional: true - "@oxlint/binding-win32-arm64-msvc": - optional: true - "@oxlint/binding-win32-ia32-msvc": - optional: true - "@oxlint/binding-win32-x64-msvc": - optional: true - peerDependenciesMeta: - oxlint-tsgolint: - optional: true - vite-plus: - optional: true - bin: - oxlint: bin/oxlint - checksum: 10c0/2532bebc3ed26f04e14bad2932763d1b71990c9b0bc103ab830eda990a97b9cc195b286ca5f174034684f9b1c842cbdcfd47c99adfb9519193ef23d0d3892507 - languageName: node - linkType: hard - -"p-limit@npm:^3.0.2": - version: 3.1.0 - resolution: "p-limit@npm:3.1.0" - dependencies: - yocto-queue: "npm:^0.1.0" - checksum: 10c0/9db675949dbdc9c3763c89e748d0ef8bdad0afbb24d49ceaf4c46c02c77d30db4e0652ed36d0a0a7a95154335fab810d95c86153105bb73b3a90448e2bb14e1a - languageName: node - linkType: hard - -"p-locate@npm:^5.0.0": - version: 5.0.0 - resolution: "p-locate@npm:5.0.0" - dependencies: - p-limit: "npm:^3.0.2" - checksum: 10c0/2290d627ab7903b8b70d11d384fee714b797f6040d9278932754a6860845c4d3190603a0772a663c8cb5a7b21d1b16acb3a6487ebcafa9773094edc3dfe6009a - languageName: node - linkType: hard - -"p-map@npm:^7.0.2": - version: 7.0.4 - resolution: "p-map@npm:7.0.4" - checksum: 10c0/a5030935d3cb2919d7e89454d1ce82141e6f9955413658b8c9403cfe379283770ed3048146b44cde168aa9e8c716505f196d5689db0ae3ce9a71521a2fef3abd - languageName: node - linkType: hard - -"parent-module@npm:^1.0.0": - version: 1.0.1 - resolution: "parent-module@npm:1.0.1" - dependencies: - callsites: "npm:^3.0.0" - checksum: 10c0/c63d6e80000d4babd11978e0d3fee386ca7752a02b035fd2435960ffaa7219dc42146f07069fb65e6e8bf1caef89daf9af7535a39bddf354d78bf50d8294f556 - languageName: node - linkType: hard - -"path-exists@npm:^4.0.0": - version: 4.0.0 - resolution: "path-exists@npm:4.0.0" - checksum: 10c0/8c0bd3f5238188197dc78dced15207a4716c51cc4e3624c44fc97acf69558f5ebb9a2afff486fe1b4ee148e0c133e96c5e11a9aa5c48a3006e3467da070e5e1b - languageName: node - linkType: hard - -"path-key@npm:^3.1.0": - version: 3.1.1 - resolution: "path-key@npm:3.1.1" - checksum: 10c0/748c43efd5a569c039d7a00a03b58eecd1d75f3999f5a28303d75f521288df4823bc057d8784eb72358b2895a05f29a070bc9f1f17d28226cc4e62494cc58c4c - languageName: node - linkType: hard - -"path-parse@npm:^1.0.7": - version: 1.0.7 - resolution: "path-parse@npm:1.0.7" - checksum: 10c0/11ce261f9d294cc7a58d6a574b7f1b935842355ec66fba3c3fd79e0f036462eaf07d0aa95bb74ff432f9afef97ce1926c720988c6a7451d8a584930ae7de86e1 - languageName: node - linkType: hard - -"path-scurry@npm:^2.0.2": - version: 2.0.2 - resolution: "path-scurry@npm:2.0.2" - dependencies: - lru-cache: "npm:^11.0.0" - minipass: "npm:^7.1.2" - checksum: 10c0/b35ad37cf6557a87fd057121ce2be7695380c9138d93e87ae928609da259ea0a170fac6f3ef1eb3ece8a068e8b7f2f3adf5bb2374cf4d4a57fe484954fcc9482 - languageName: node - linkType: hard - -"picocolors@npm:^1.0.0, picocolors@npm:^1.1.1": - version: 1.1.1 - resolution: "picocolors@npm:1.1.1" - checksum: 10c0/e2e3e8170ab9d7c7421969adaa7e1b31434f789afb9b3f115f6b96d91945041ac3ceb02e9ec6fe6510ff036bcc0bf91e69a1772edc0b707e12b19c0f2d6bcf58 - languageName: node - linkType: hard - -"picomatch@npm:2.3.2": - version: 2.3.2 - resolution: "picomatch@npm:2.3.2" - checksum: 10c0/a554d1709e59be97d1acb9eaedbbc700a5c03dbd4579807baed95100b00420bc729335440ef15004ae2378984e2487a7c1cebd743cfdb72b6fa9ab69223c0d61 - languageName: node - linkType: hard - -"picomatch@npm:4.0.4": - version: 4.0.4 - resolution: "picomatch@npm:4.0.4" - checksum: 10c0/e2c6023372cc7b5764719a5ffb9da0f8e781212fa7ca4bd0562db929df8e117460f00dff3cb7509dacfc06b86de924b247f504d0ce1806a37fac4633081466b0 - languageName: node - linkType: hard - -"pify@npm:^2.3.0": - version: 2.3.0 - resolution: "pify@npm:2.3.0" - checksum: 10c0/551ff8ab830b1052633f59cb8adc9ae8407a436e06b4a9718bcb27dc5844b83d535c3a8512b388b6062af65a98c49bdc0dd523d8b2617b188f7c8fee457158dc - languageName: node - linkType: hard - -"pirates@npm:^4.0.1": - version: 4.0.7 - resolution: "pirates@npm:4.0.7" - checksum: 10c0/a51f108dd811beb779d58a76864bbd49e239fa40c7984cd11596c75a121a8cc789f1c8971d8bb15f0dbf9d48b76c05bb62fcbce840f89b688c0fa64b37e8478a - languageName: node - linkType: hard - -"portless@npm:0.11.1": - version: 0.11.1 - resolution: "portless@npm:0.11.1" - bin: - portless: dist/cli.js - checksum: 10c0/eeb50eba54a8b3120a5f240845fcb58f928af7c883c23f6daa576446423b8c459fa1b91ced6789ed90496b2ce4aa988f83934fbdd619fc3be7a5c8777e836866 - conditions: (os=darwin | os=linux | os=win32) - languageName: node - linkType: hard - -"possible-typed-array-names@npm:^1.0.0": - version: 1.1.0 - resolution: "possible-typed-array-names@npm:1.1.0" - checksum: 10c0/c810983414142071da1d644662ce4caebce890203eb2bc7bf119f37f3fe5796226e117e6cca146b521921fa6531072674174a3325066ac66fce089a53e1e5196 - languageName: node - linkType: hard - -"postcss-import@npm:^15.1.0": - version: 15.1.0 - resolution: "postcss-import@npm:15.1.0" - dependencies: - postcss-value-parser: "npm:^4.0.0" - read-cache: "npm:^1.0.0" - resolve: "npm:^1.1.7" - peerDependencies: - postcss: ^8.0.0 - checksum: 10c0/518aee5c83ea6940e890b0be675a2588db68b2582319f48c3b4e06535a50ea6ee45f7e63e4309f8754473245c47a0372632378d1d73d901310f295a92f26f17b - languageName: node - linkType: hard - -"postcss-js@npm:^4.0.1": - version: 4.1.0 - resolution: "postcss-js@npm:4.1.0" - dependencies: - camelcase-css: "npm:^2.0.1" - peerDependencies: - postcss: ^8.4.21 - checksum: 10c0/a3cf6e725f3e9ecd7209732f8844a0063a1380b718ccbcf93832b6ec2cd7e63ff70dd2fed49eb2483c7482296860a0f7badd3115b5d0fa05ea648eb6d9dfc9c6 - languageName: node - linkType: hard - -"postcss-load-config@npm:^4.0.2 || ^5.0 || ^6.0": - version: 6.0.1 - resolution: "postcss-load-config@npm:6.0.1" - dependencies: - lilconfig: "npm:^3.1.1" - 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 - checksum: 10c0/74173a58816dac84e44853f7afbd283f4ef13ca0b6baeba27701214beec33f9e309b128f8102e2b173e8d45ecba45d279a9be94b46bf48d219626aa9b5730848 - languageName: node - linkType: hard - -"postcss-nested@npm:^6.2.0": - version: 6.2.0 - resolution: "postcss-nested@npm:6.2.0" - dependencies: - postcss-selector-parser: "npm:^6.1.1" - peerDependencies: - postcss: ^8.2.14 - checksum: 10c0/7f9c3f2d764191a39364cbdcec350f26a312431a569c9ef17408021424726b0d67995ff5288405e3724bb7152a4c92f73c027e580ec91e798800ed3c52e2bc6e - languageName: node - linkType: hard - -"postcss-selector-parser@npm:^6.1.1, postcss-selector-parser@npm:^6.1.2": - version: 6.1.2 - resolution: "postcss-selector-parser@npm:6.1.2" - dependencies: - cssesc: "npm:^3.0.0" - util-deprecate: "npm:^1.0.2" - checksum: 10c0/523196a6bd8cf660bdf537ad95abd79e546d54180f9afb165a4ab3e651ac705d0f8b8ce6b3164fb9e3279ce482c5f751a69eb2d3a1e8eb0fd5e82294fb3ef13e - languageName: node - linkType: hard - -"postcss-value-parser@npm:^4.0.0, postcss-value-parser@npm:^4.2.0": - version: 4.2.0 - resolution: "postcss-value-parser@npm:4.2.0" - checksum: 10c0/f4142a4f56565f77c1831168e04e3effd9ffcc5aebaf0f538eee4b2d465adfd4b85a44257bb48418202a63806a7da7fe9f56c330aebb3cac898e46b4cbf49161 - languageName: node - linkType: hard - -"postcss@npm:8.4.31": - version: 8.4.31 - resolution: "postcss@npm:8.4.31" - dependencies: - nanoid: "npm:^3.3.6" - picocolors: "npm:^1.0.0" - source-map-js: "npm:^1.0.2" - checksum: 10c0/748b82e6e5fc34034dcf2ae88ea3d11fd09f69b6c50ecdd3b4a875cfc7cdca435c958b211e2cb52355422ab6fccb7d8f2f2923161d7a1b281029e4a913d59acf - languageName: node - linkType: hard - -"postcss@npm:^8.4.47, postcss@npm:^8.5.6": - version: 8.5.6 - resolution: "postcss@npm:8.5.6" - dependencies: - nanoid: "npm:^3.3.11" - picocolors: "npm:^1.1.1" - source-map-js: "npm:^1.2.1" - checksum: 10c0/5127cc7c91ed7a133a1b7318012d8bfa112da9ef092dddf369ae699a1f10ebbd89b1b9f25f3228795b84585c72aabd5ced5fc11f2ba467eedf7b081a66fad024 - languageName: node - linkType: hard - -"prelude-ls@npm:^1.2.1": - version: 1.2.1 - resolution: "prelude-ls@npm:1.2.1" - checksum: 10c0/b00d617431e7886c520a6f498a2e14c75ec58f6d93ba48c3b639cf241b54232d90daa05d83a9e9b9fef6baa63cb7e1e4602c2372fea5bc169668401eb127d0cd - languageName: node - linkType: hard - -"proc-log@npm:^6.0.0": - version: 6.1.0 - resolution: "proc-log@npm:6.1.0" - checksum: 10c0/4f178d4062733ead9d71a9b1ab24ebcecdfe2250916a5b1555f04fe2eda972a0ec76fbaa8df1ad9c02707add6749219d118a4fc46dc56bdfe4dde4b47d80bb82 - languageName: node - linkType: hard - -"prompts@npm:^2.4.2": - version: 2.4.2 - resolution: "prompts@npm:2.4.2" - dependencies: - kleur: "npm:^3.0.3" - sisteransi: "npm:^1.0.5" - checksum: 10c0/16f1ac2977b19fe2cf53f8411cc98db7a3c8b115c479b2ca5c82b5527cd937aa405fa04f9a5960abeb9daef53191b53b4d13e35c1f5d50e8718c76917c5f1ea4 - languageName: node - linkType: hard - -"prop-types@npm:^15.8.1": - version: 15.8.1 - resolution: "prop-types@npm:15.8.1" - dependencies: - loose-envify: "npm:^1.4.0" - object-assign: "npm:^4.1.1" - react-is: "npm:^16.13.1" - checksum: 10c0/59ece7ca2fb9838031d73a48d4becb9a7cc1ed10e610517c7d8f19a1e02fa47f7c27d557d8a5702bec3cfeccddc853579832b43f449e54635803f277b1c78077 - languageName: node - linkType: hard - -"punycode@npm:^2.1.0": - version: 2.3.1 - resolution: "punycode@npm:2.3.1" - checksum: 10c0/14f76a8206bc3464f794fb2e3d3cc665ae416c01893ad7a02b23766eb07159144ee612ad67af5e84fa4479ccfe67678c4feb126b0485651b302babf66f04f9e9 - languageName: node - linkType: hard - -"pure-rand@npm:^8.0.0": - version: 8.4.0 - resolution: "pure-rand@npm:8.4.0" - checksum: 10c0/6414bbc1c6f45fb774173431c7205e79783b77cfae0e2145e741b6999363554dbd2f4210d2a5bc08683e0b2f6823198c9308766b1d0911e1dccd7beb8842f860 - languageName: node - linkType: hard - -"queue-microtask@npm:^1.2.2": - version: 1.2.3 - resolution: "queue-microtask@npm:1.2.3" - checksum: 10c0/900a93d3cdae3acd7d16f642c29a642aea32c2026446151f0778c62ac089d4b8e6c986811076e1ae180a694cedf077d453a11b58ff0a865629a4f82ab558e102 - languageName: node - linkType: hard - -"react-doctor@npm:0.2.6": - version: 0.2.6 - resolution: "react-doctor@npm:0.2.6" - dependencies: - "@effect/platform-node-shared": "npm:4.0.0-beta.70" - agent-install: "npm:0.0.5" - conf: "npm:^15.1.0" - deslop-js: "npm:^0.0.12" - effect: "npm:4.0.0-beta.70" - oxlint: "npm:^1.66.0" - oxlint-plugin-react-doctor: "npm:0.2.6" - prompts: "npm:^2.4.2" - typescript: "npm:>=5.0.4 <7" - peerDependencies: - eslint-plugin-react-hooks: ^6 || ^7 - peerDependenciesMeta: - eslint-plugin-react-hooks: - optional: true - bin: - react-doctor: bin/react-doctor.js - checksum: 10c0/80804f5dd8252fd12c30a272bf0c2d5bc7db57be8f1de684f5840a816053efdf701ab5dff64b0e275c2129a1f086980287e4d5fd279c009d4f03b0fb6d5e8fdc - languageName: node - linkType: hard - -"react-dom@npm:19.2.3": - version: 19.2.3 - resolution: "react-dom@npm:19.2.3" - dependencies: - scheduler: "npm:^0.27.0" - peerDependencies: - react: ^19.2.3 - checksum: 10c0/dc43f7ede06f46f3acc16ee83107c925530de9b91d1d0b3824583814746ff4c498ea64fd65cd83aba363205268adff52e2827c582634ae7b15069deaeabc4892 - languageName: node - linkType: hard - -"react-is@npm:^16.13.1": - version: 16.13.1 - resolution: "react-is@npm:16.13.1" - checksum: 10c0/33977da7a5f1a287936a0c85639fec6ca74f4f15ef1e59a6bc20338fc73dc69555381e211f7a3529b8150a1f71e4225525b41b60b52965bda53ce7d47377ada1 - languageName: node - linkType: hard - -"react-phone-number-input@npm:^3.4.12": - version: 3.4.12 - resolution: "react-phone-number-input@npm:3.4.12" - dependencies: - classnames: "npm:^2.5.1" - country-flag-icons: "npm:^1.5.17" - input-format: "npm:^0.3.10" - libphonenumber-js: "npm:^1.11.20" - prop-types: "npm:^15.8.1" - peerDependencies: - react: ">=16.8" - react-dom: ">=16.8" - checksum: 10c0/96724e10c18c410602a1d03a93dfa9688b72a1f242891a1d565c4f77718f37463603b390360b8499320d5c5853feddb489bc17129c804a548f0c050f1bdef7e2 - languageName: node - linkType: hard - -"react-remove-scroll-bar@npm:^2.3.7": - version: 2.3.8 - resolution: "react-remove-scroll-bar@npm:2.3.8" - dependencies: - react-style-singleton: "npm:^2.2.2" - tslib: "npm:^2.0.0" - peerDependencies: - "@types/react": "*" - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - "@types/react": - optional: true - checksum: 10c0/9a0675c66cbb52c325bdbfaed80987a829c4504cefd8ff2dd3b6b3afc9a1500b8ec57b212e92c1fb654396d07bbe18830a8146fe77677d2a29ce40b5e1f78654 - languageName: node - linkType: hard - -"react-remove-scroll@npm:^2.6.3": - version: 2.7.1 - resolution: "react-remove-scroll@npm:2.7.1" - dependencies: - react-remove-scroll-bar: "npm:^2.3.7" - react-style-singleton: "npm:^2.2.3" - tslib: "npm:^2.1.0" - use-callback-ref: "npm:^1.3.3" - use-sidecar: "npm:^1.1.3" - 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 - checksum: 10c0/7ad8f6ffd3e2aedf9b3d79f0c9088a9a3d7c5332d80c923427a6d97fe0626fb4cb33a6d9174d19fad57d860be69c96f68497a0619c3a8af0e8a5332e49bdde31 - languageName: node - linkType: hard - -"react-style-singleton@npm:^2.2.2, react-style-singleton@npm:^2.2.3": - version: 2.2.3 - resolution: "react-style-singleton@npm:2.2.3" - dependencies: - get-nonce: "npm:^1.0.0" - tslib: "npm:^2.0.0" - 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 - checksum: 10c0/841938ff16d16a6b76895f4cb2e1fea957e5fe3b30febbf03a54892dae1c9153f2383e231dea0b3ba41192ad2f2849448fa859caccd288943bce32639e971bee - languageName: node - linkType: hard - -"react@npm:19.2.3": - version: 19.2.3 - resolution: "react@npm:19.2.3" - checksum: 10c0/094220b3ba3a76c1b668f972ace1dd15509b157aead1b40391d1c8e657e720c201d9719537375eff08f5e0514748c0319063392a6f000e31303aafc4471f1436 - languageName: node - linkType: hard - -"read-cache@npm:^1.0.0": - version: 1.0.0 - resolution: "read-cache@npm:1.0.0" - dependencies: - pify: "npm:^2.3.0" - checksum: 10c0/90cb2750213c7dd7c80cb420654344a311fdec12944e81eb912cd82f1bc92aea21885fa6ce442e3336d9fccd663b8a7a19c46d9698e6ca55620848ab932da814 - languageName: node - linkType: hard - -"readdirp@npm:~3.6.0": - version: 3.6.0 - resolution: "readdirp@npm:3.6.0" - dependencies: - picomatch: "npm:^2.2.1" - checksum: 10c0/6fa848cf63d1b82ab4e985f4cf72bd55b7dcfd8e0a376905804e48c3634b7e749170940ba77b32804d5fe93b3cc521aa95a8d7e7d725f830da6d93f3669ce66b - languageName: node - linkType: hard - -"reflect.getprototypeof@npm:^1.0.6, reflect.getprototypeof@npm:^1.0.9": - version: 1.0.10 - resolution: "reflect.getprototypeof@npm:1.0.10" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.9" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.7" - get-proto: "npm:^1.0.1" - which-builtin-type: "npm:^1.2.1" - checksum: 10c0/7facec28c8008876f8ab98e80b7b9cb4b1e9224353fd4756dda5f2a4ab0d30fa0a5074777c6df24e1e0af463a2697513b0a11e548d99cf52f21f7bc6ba48d3ac - languageName: node - linkType: hard - -"regexp.prototype.flags@npm:^1.5.3, regexp.prototype.flags@npm:^1.5.4": - version: 1.5.4 - resolution: "regexp.prototype.flags@npm:1.5.4" - dependencies: - call-bind: "npm:^1.0.8" - define-properties: "npm:^1.2.1" - es-errors: "npm:^1.3.0" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - set-function-name: "npm:^2.0.2" - checksum: 10c0/83b88e6115b4af1c537f8dabf5c3744032cb875d63bc05c288b1b8c0ef37cbe55353f95d8ca817e8843806e3e150b118bc624e4279b24b4776b4198232735a77 - languageName: node - linkType: hard - -"require-from-string@npm:^2.0.2": - version: 2.0.2 - resolution: "require-from-string@npm:2.0.2" - checksum: 10c0/aaa267e0c5b022fc5fd4eef49d8285086b15f2a1c54b28240fdf03599cbd9c26049fee3eab894f2e1f6ca65e513b030a7c264201e3f005601e80c49fb2937ce2 - languageName: node - linkType: hard - -"resolve-from@npm:^4.0.0": - version: 4.0.0 - resolution: "resolve-from@npm:4.0.0" - checksum: 10c0/8408eec31a3112ef96e3746c37be7d64020cda07c03a920f5024e77290a218ea758b26ca9529fd7b1ad283947f34b2291c1c0f6aa0ed34acfdda9c6014c8d190 - languageName: node - linkType: hard - -"resolve-pkg-maps@npm:^1.0.0": - version: 1.0.0 - resolution: "resolve-pkg-maps@npm:1.0.0" - checksum: 10c0/fb8f7bbe2ca281a73b7ef423a1cbc786fb244bd7a95cbe5c3fba25b27d327150beca8ba02f622baea65919a57e061eb5005204daa5f93ed590d9b77463a567ab - languageName: node - linkType: hard - -"resolve@npm:^1.1.7, resolve@npm:^1.22.8": - version: 1.22.11 - resolution: "resolve@npm:1.22.11" - dependencies: - is-core-module: "npm:^2.16.1" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/f657191507530f2cbecb5815b1ee99b20741ea6ee02a59c57028e9ec4c2c8d7681afcc35febbd554ac0ded459db6f2d8153382c53a2f266cee2575e512674409 - languageName: node - linkType: hard - -"resolve@npm:^1.22.4": - version: 1.22.10 - resolution: "resolve@npm:1.22.10" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/8967e1f4e2cc40f79b7e080b4582b9a8c5ee36ffb46041dccb20e6461161adf69f843b43067b4a375de926a2cd669157e29a29578191def399dd5ef89a1b5203 - languageName: node - linkType: hard - -"resolve@npm:^2.0.0-next.5": - version: 2.0.0-next.5 - resolution: "resolve@npm:2.0.0-next.5" - dependencies: - is-core-module: "npm:^2.13.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/a6c33555e3482ea2ec4c6e3d3bf0d78128abf69dca99ae468e64f1e30acaa318fd267fb66c8836b04d558d3e2d6ed875fe388067e7d8e0de647d3c21af21c43a - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^1.1.7#optional!builtin, resolve@patch:resolve@npm%3A^1.22.8#optional!builtin": - version: 1.22.11 - resolution: "resolve@patch:resolve@npm%3A1.22.11#optional!builtin::version=1.22.11&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.16.1" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/ee5b182f2e37cb1165465e58c6abc797fec0a80b5ba3231607beb4677db0c9291ac010c47cf092b6daa2b7f518d69a0e21888e7e2b633f68d501a874212a8c63 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": - version: 1.22.10 - resolution: "resolve@patch:resolve@npm%3A1.22.10#optional!builtin::version=1.22.10&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.16.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/52a4e505bbfc7925ac8f4cd91fd8c4e096b6a89728b9f46861d3b405ac9a1ccf4dcbf8befb4e89a2e11370dacd0160918163885cbc669369590f2f31f4c58939 - languageName: node - linkType: hard - -"resolve@patch:resolve@npm%3A^2.0.0-next.5#optional!builtin": - version: 2.0.0-next.5 - resolution: "resolve@patch:resolve@npm%3A2.0.0-next.5#optional!builtin::version=2.0.0-next.5&hash=c3c19d" - dependencies: - is-core-module: "npm:^2.13.0" - path-parse: "npm:^1.0.7" - supports-preserve-symlinks-flag: "npm:^1.0.0" - bin: - resolve: bin/resolve - checksum: 10c0/78ad6edb8309a2bfb720c2c1898f7907a37f858866ce11a5974643af1203a6a6e05b2fa9c53d8064a673a447b83d42569260c306d43628bff5bb101969708355 - languageName: node - linkType: hard - -"reusify@npm:^1.0.4": - version: 1.1.0 - resolution: "reusify@npm:1.1.0" - checksum: 10c0/4eff0d4a5f9383566c7d7ec437b671cc51b25963bd61bf127c3f3d3f68e44a026d99b8d2f1ad344afff8d278a8fe70a8ea092650a716d22287e8bef7126bb2fa - languageName: node - linkType: hard - -"run-parallel@npm:^1.1.9": - version: 1.2.0 - resolution: "run-parallel@npm:1.2.0" - dependencies: - queue-microtask: "npm:^1.2.2" - checksum: 10c0/200b5ab25b5b8b7113f9901bfe3afc347e19bb7475b267d55ad0eb86a62a46d77510cb0f232507c9e5d497ebda569a08a9867d0d14f57a82ad5564d991588b39 - languageName: node - linkType: hard - -"safe-array-concat@npm:^1.1.3": - version: 1.1.3 - resolution: "safe-array-concat@npm:1.1.3" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - get-intrinsic: "npm:^1.2.6" - has-symbols: "npm:^1.1.0" - isarray: "npm:^2.0.5" - checksum: 10c0/43c86ffdddc461fb17ff8a17c5324f392f4868f3c7dd2c6a5d9f5971713bc5fd755667212c80eab9567595f9a7509cc2f83e590ddaebd1bd19b780f9c79f9a8d - languageName: node - linkType: hard - -"safe-push-apply@npm:^1.0.0": - version: 1.0.0 - resolution: "safe-push-apply@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - isarray: "npm:^2.0.5" - checksum: 10c0/831f1c9aae7436429e7862c7e46f847dfe490afac20d0ee61bae06108dbf5c745a0de3568ada30ccdd3eeb0864ca8331b2eef703abd69bfea0745b21fd320750 - languageName: node - linkType: hard - -"safe-regex-test@npm:^1.0.3, safe-regex-test@npm:^1.1.0": - version: 1.1.0 - resolution: "safe-regex-test@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - is-regex: "npm:^1.2.1" - checksum: 10c0/f2c25281bbe5d39cddbbce7f86fca5ea9b3ce3354ea6cd7c81c31b006a5a9fff4286acc5450a3b9122c56c33eba69c56b9131ad751457b2b4a585825e6a10665 - languageName: node - linkType: hard - -"safer-buffer@npm:>= 2.1.2 < 3.0.0": - version: 2.1.2 - resolution: "safer-buffer@npm:2.1.2" - checksum: 10c0/7e3c8b2e88a1841c9671094bbaeebd94448111dd90a81a1f606f3f67708a6ec57763b3b47f06da09fc6054193e0e6709e77325415dc8422b04497a8070fa02d4 - languageName: node - linkType: hard - -"scheduler@npm:^0.27.0": - version: 0.27.0 - resolution: "scheduler@npm:0.27.0" - checksum: 10c0/4f03048cb05a3c8fddc45813052251eca00688f413a3cee236d984a161da28db28ba71bd11e7a3dd02f7af84ab28d39fb311431d3b3772fed557945beb00c452 - languageName: node - linkType: hard - -"semver@npm:^6.3.1": - version: 6.3.1 - resolution: "semver@npm:6.3.1" - bin: - semver: bin/semver.js - checksum: 10c0/e3d79b609071caa78bcb6ce2ad81c7966a46a7431d9d58b8800cfa9cb6a63699b3899a0e4bcce36167a284578212d9ae6942b6929ba4aa5015c079a67751d42d - languageName: node - linkType: hard - -"semver@npm:^7.3.5, semver@npm:^7.7.3": - version: 7.7.4 - resolution: "semver@npm:7.7.4" - bin: - semver: bin/semver.js - checksum: 10c0/5215ad0234e2845d4ea5bb9d836d42b03499546ddafb12075566899fc617f68794bb6f146076b6881d755de17d6c6cc73372555879ec7dce2c2feee947866ad2 - languageName: node - linkType: hard - -"semver@npm:^7.7.1": - version: 7.7.2 - resolution: "semver@npm:7.7.2" - bin: - semver: bin/semver.js - checksum: 10c0/aca305edfbf2383c22571cb7714f48cadc7ac95371b4b52362fb8eeffdfbc0de0669368b82b2b15978f8848f01d7114da65697e56cd8c37b0dab8c58e543f9ea - languageName: node - linkType: hard - -"semver@npm:^7.7.2": - version: 7.8.1 - resolution: "semver@npm:7.8.1" - bin: - semver: bin/semver.js - checksum: 10c0/92d6871d6347e1f99d0ba396a70f2545ccf2a032cda3d378fa0699edf7506b5c6d266aed55c8b88e72bd91a30d2351e4f39db479375374430fcdc4b58f4e3c1a - languageName: node - linkType: hard - -"set-function-length@npm:^1.2.2": - version: 1.2.2 - resolution: "set-function-length@npm:1.2.2" - dependencies: - define-data-property: "npm:^1.1.4" - es-errors: "npm:^1.3.0" - function-bind: "npm:^1.1.2" - get-intrinsic: "npm:^1.2.4" - gopd: "npm:^1.0.1" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/82850e62f412a258b71e123d4ed3873fa9377c216809551192bb6769329340176f109c2eeae8c22a8d386c76739855f78e8716515c818bcaef384b51110f0f3c - languageName: node - linkType: hard - -"set-function-name@npm:^2.0.2": - version: 2.0.2 - resolution: "set-function-name@npm:2.0.2" - dependencies: - define-data-property: "npm:^1.1.4" - es-errors: "npm:^1.3.0" - functions-have-names: "npm:^1.2.3" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/fce59f90696c450a8523e754abb305e2b8c73586452619c2bad5f7bf38c7b6b4651895c9db895679c5bef9554339cf3ef1c329b66ece3eda7255785fbe299316 - languageName: node - linkType: hard - -"set-proto@npm:^1.0.0": - version: 1.0.0 - resolution: "set-proto@npm:1.0.0" - dependencies: - dunder-proto: "npm:^1.0.1" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/ca5c3ccbba479d07c30460e367e66337cec825560b11e8ba9c5ebe13a2a0d6021ae34eddf94ff3dfe17a3104dc1f191519cb6c48378b503e5c3f36393938776a - languageName: node - linkType: hard - -"sharp@npm:^0.34.5": - version: 0.34.5 - resolution: "sharp@npm:0.34.5" - dependencies: - "@img/colour": "npm:^1.0.0" - "@img/sharp-darwin-arm64": "npm:0.34.5" - "@img/sharp-darwin-x64": "npm:0.34.5" - "@img/sharp-libvips-darwin-arm64": "npm:1.2.4" - "@img/sharp-libvips-darwin-x64": "npm:1.2.4" - "@img/sharp-libvips-linux-arm": "npm:1.2.4" - "@img/sharp-libvips-linux-arm64": "npm:1.2.4" - "@img/sharp-libvips-linux-ppc64": "npm:1.2.4" - "@img/sharp-libvips-linux-riscv64": "npm:1.2.4" - "@img/sharp-libvips-linux-s390x": "npm:1.2.4" - "@img/sharp-libvips-linux-x64": "npm:1.2.4" - "@img/sharp-libvips-linuxmusl-arm64": "npm:1.2.4" - "@img/sharp-libvips-linuxmusl-x64": "npm:1.2.4" - "@img/sharp-linux-arm": "npm:0.34.5" - "@img/sharp-linux-arm64": "npm:0.34.5" - "@img/sharp-linux-ppc64": "npm:0.34.5" - "@img/sharp-linux-riscv64": "npm:0.34.5" - "@img/sharp-linux-s390x": "npm:0.34.5" - "@img/sharp-linux-x64": "npm:0.34.5" - "@img/sharp-linuxmusl-arm64": "npm:0.34.5" - "@img/sharp-linuxmusl-x64": "npm:0.34.5" - "@img/sharp-wasm32": "npm:0.34.5" - "@img/sharp-win32-arm64": "npm:0.34.5" - "@img/sharp-win32-ia32": "npm:0.34.5" - "@img/sharp-win32-x64": "npm:0.34.5" - detect-libc: "npm:^2.1.2" - semver: "npm:^7.7.3" - dependenciesMeta: - "@img/sharp-darwin-arm64": - optional: true - "@img/sharp-darwin-x64": - optional: true - "@img/sharp-libvips-darwin-arm64": - optional: true - "@img/sharp-libvips-darwin-x64": - optional: true - "@img/sharp-libvips-linux-arm": - optional: true - "@img/sharp-libvips-linux-arm64": - optional: true - "@img/sharp-libvips-linux-ppc64": - optional: true - "@img/sharp-libvips-linux-riscv64": - optional: true - "@img/sharp-libvips-linux-s390x": - optional: true - "@img/sharp-libvips-linux-x64": - optional: true - "@img/sharp-libvips-linuxmusl-arm64": - optional: true - "@img/sharp-libvips-linuxmusl-x64": - optional: true - "@img/sharp-linux-arm": - optional: true - "@img/sharp-linux-arm64": - optional: true - "@img/sharp-linux-ppc64": - optional: true - "@img/sharp-linux-riscv64": - optional: true - "@img/sharp-linux-s390x": - optional: true - "@img/sharp-linux-x64": - optional: true - "@img/sharp-linuxmusl-arm64": - optional: true - "@img/sharp-linuxmusl-x64": - optional: true - "@img/sharp-wasm32": - optional: true - "@img/sharp-win32-arm64": - optional: true - "@img/sharp-win32-ia32": - optional: true - "@img/sharp-win32-x64": - optional: true - checksum: 10c0/fd79e29df0597a7d5704b8461c51f944ead91a5243691697be6e8243b966402beda53ddc6f0a53b96ea3cb8221f0b244aa588114d3ebf8734fb4aefd41ab802f - languageName: node - linkType: hard - -"shebang-command@npm:^2.0.0": - version: 2.0.0 - resolution: "shebang-command@npm:2.0.0" - dependencies: - shebang-regex: "npm:^3.0.0" - checksum: 10c0/a41692e7d89a553ef21d324a5cceb5f686d1f3c040759c50aab69688634688c5c327f26f3ecf7001ebfd78c01f3c7c0a11a7c8bfd0a8bc9f6240d4f40b224e4e - languageName: node - linkType: hard - -"shebang-regex@npm:^3.0.0": - version: 3.0.0 - resolution: "shebang-regex@npm:3.0.0" - checksum: 10c0/1dbed0726dd0e1152a92696c76c7f06084eb32a90f0528d11acd764043aacf76994b2fb30aa1291a21bd019d6699164d048286309a278855ee7bec06cf6fb690 - languageName: node - linkType: hard - -"side-channel-list@npm:^1.0.0": - version: 1.0.0 - resolution: "side-channel-list@npm:1.0.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - checksum: 10c0/644f4ac893456c9490ff388bf78aea9d333d5e5bfc64cfb84be8f04bf31ddc111a8d4b83b85d7e7e8a7b845bc185a9ad02c052d20e086983cf59f0be517d9b3d - languageName: node - linkType: hard - -"side-channel-map@npm:^1.0.1": - version: 1.0.1 - resolution: "side-channel-map@npm:1.0.1" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - checksum: 10c0/010584e6444dd8a20b85bc926d934424bd809e1a3af941cace229f7fdcb751aada0fb7164f60c2e22292b7fa3c0ff0bce237081fd4cdbc80de1dc68e95430672 - languageName: node - linkType: hard - -"side-channel-weakmap@npm:^1.0.2": - version: 1.0.2 - resolution: "side-channel-weakmap@npm:1.0.2" - dependencies: - call-bound: "npm:^1.0.2" - es-errors: "npm:^1.3.0" - get-intrinsic: "npm:^1.2.5" - object-inspect: "npm:^1.13.3" - side-channel-map: "npm:^1.0.1" - checksum: 10c0/71362709ac233e08807ccd980101c3e2d7efe849edc51455030327b059f6c4d292c237f94dc0685031dd11c07dd17a68afde235d6cf2102d949567f98ab58185 - languageName: node - linkType: hard - -"side-channel@npm:^1.1.0": - version: 1.1.0 - resolution: "side-channel@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - object-inspect: "npm:^1.13.3" - side-channel-list: "npm:^1.0.0" - side-channel-map: "npm:^1.0.1" - side-channel-weakmap: "npm:^1.0.2" - checksum: 10c0/cb20dad41eb032e6c24c0982e1e5a24963a28aa6122b4f05b3f3d6bf8ae7fd5474ef382c8f54a6a3ab86e0cac4d41a23bd64ede3970e5bfb50326ba02a7996e6 - languageName: node - linkType: hard - -"sisteransi@npm:^1.0.5": - version: 1.0.5 - resolution: "sisteransi@npm:1.0.5" - checksum: 10c0/230ac975cca485b7f6fe2b96a711aa62a6a26ead3e6fb8ba17c5a00d61b8bed0d7adc21f5626b70d7c33c62ff4e63933017a6462942c719d1980bb0b1207ad46 - languageName: node - linkType: hard - -"smart-buffer@npm:^4.2.0": - version: 4.2.0 - resolution: "smart-buffer@npm:4.2.0" - checksum: 10c0/a16775323e1404dd43fabafe7460be13a471e021637bc7889468eb45ce6a6b207261f454e4e530a19500cc962c4cc5348583520843b363f4193cee5c00e1e539 - languageName: node - linkType: hard - -"socks-proxy-agent@npm:^8.0.3": - version: 8.0.5 - resolution: "socks-proxy-agent@npm:8.0.5" - dependencies: - agent-base: "npm:^7.1.2" - debug: "npm:^4.3.4" - socks: "npm:^2.8.3" - checksum: 10c0/5d2c6cecba6821389aabf18728325730504bf9bb1d9e342e7987a5d13badd7a98838cc9a55b8ed3cb866ad37cc23e1086f09c4d72d93105ce9dfe76330e9d2a6 - languageName: node - linkType: hard - -"socks@npm:^2.8.3": - version: 2.8.7 - resolution: "socks@npm:2.8.7" - dependencies: - ip-address: "npm:^10.0.1" - smart-buffer: "npm:^4.2.0" - checksum: 10c0/2805a43a1c4bcf9ebf6e018268d87b32b32b06fbbc1f9282573583acc155860dc361500f89c73bfbb157caa1b4ac78059eac0ef15d1811eb0ca75e0bdadbc9d2 - languageName: node - linkType: hard - -"source-map-js@npm:^1.0.2, source-map-js@npm:^1.2.1": - version: 1.2.1 - resolution: "source-map-js@npm:1.2.1" - checksum: 10c0/7bda1fc4c197e3c6ff17de1b8b2c20e60af81b63a52cb32ec5a5d67a20a7d42651e2cb34ebe93833c5a2a084377e17455854fee3e21e7925c64a51b6a52b0faf - languageName: node - linkType: hard - -"ssri@npm:^13.0.0": - version: 13.0.1 - resolution: "ssri@npm:13.0.1" - dependencies: - minipass: "npm:^7.0.3" - checksum: 10c0/cf6408a18676c57ff2ed06b8a20dc64bb3e748e5c7e095332e6aecaa2b8422b1e94a739a8453bf65156a8a47afe23757ba4ab52d3ea3b62322dc40875763e17a - languageName: node - linkType: hard - -"stable-hash@npm:^0.0.5": - version: 0.0.5 - resolution: "stable-hash@npm:0.0.5" - checksum: 10c0/ca670cb6d172f1c834950e4ec661e2055885df32fee3ebf3647c5df94993b7c2666a5dbc1c9a62ee11fc5c24928579ec5e81bb5ad31971d355d5a341aab493b3 - languageName: node - linkType: hard - -"stop-iteration-iterator@npm:^1.1.0": - version: 1.1.0 - resolution: "stop-iteration-iterator@npm:1.1.0" - dependencies: - es-errors: "npm:^1.3.0" - internal-slot: "npm:^1.1.0" - checksum: 10c0/de4e45706bb4c0354a4b1122a2b8cc45a639e86206807ce0baf390ee9218d3ef181923fa4d2b67443367c491aa255c5fbaa64bb74648e3c5b48299928af86c09 - languageName: node - linkType: hard - -"string.prototype.includes@npm:^2.0.1": - version: 2.0.1 - resolution: "string.prototype.includes@npm:2.0.1" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.3" - checksum: 10c0/25ce9c9b49128352a2618fbe8758b46f945817a58a4420f4799419e40a8d28f116e176c7590d767d5327a61e75c8f32c86171063f48e389b9fdd325f1bd04ee5 - languageName: node - linkType: hard - -"string.prototype.matchall@npm:^4.0.12": - version: 4.0.12 - resolution: "string.prototype.matchall@npm:4.0.12" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.3" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.6" - es-errors: "npm:^1.3.0" - es-object-atoms: "npm:^1.0.0" - get-intrinsic: "npm:^1.2.6" - gopd: "npm:^1.2.0" - has-symbols: "npm:^1.1.0" - internal-slot: "npm:^1.1.0" - regexp.prototype.flags: "npm:^1.5.3" - set-function-name: "npm:^2.0.2" - side-channel: "npm:^1.1.0" - checksum: 10c0/1a53328ada73f4a77f1fdf1c79414700cf718d0a8ef6672af5603e709d26a24f2181208144aed7e858b1bcc1a0d08567a570abfb45567db4ae47637ed2c2f85c - languageName: node - linkType: hard - -"string.prototype.repeat@npm:^1.0.0": - version: 1.0.0 - resolution: "string.prototype.repeat@npm:1.0.0" - dependencies: - define-properties: "npm:^1.1.3" - es-abstract: "npm:^1.17.5" - checksum: 10c0/94c7978566cffa1327d470fd924366438af9b04b497c43a9805e476e2e908aa37a1fd34cc0911156c17556dab62159d12c7b92b3cc304c3e1281fe4c8e668f40 - languageName: node - linkType: hard - -"string.prototype.trim@npm:^1.2.10": - version: 1.2.10 - resolution: "string.prototype.trim@npm:1.2.10" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - define-data-property: "npm:^1.1.4" - define-properties: "npm:^1.2.1" - es-abstract: "npm:^1.23.5" - es-object-atoms: "npm:^1.0.0" - has-property-descriptors: "npm:^1.0.2" - checksum: 10c0/8a8854241c4b54a948e992eb7dd6b8b3a97185112deb0037a134f5ba57541d8248dd610c966311887b6c2fd1181a3877bffb14d873ce937a344535dabcc648f8 - languageName: node - linkType: hard - -"string.prototype.trimend@npm:^1.0.9": - version: 1.0.9 - resolution: "string.prototype.trimend@npm:1.0.9" - dependencies: - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.2" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/59e1a70bf9414cb4c536a6e31bef5553c8ceb0cf44d8b4d0ed65c9653358d1c64dd0ec203b100df83d0413bbcde38b8c5d49e14bc4b86737d74adc593a0d35b6 - languageName: node - linkType: hard - -"string.prototype.trimstart@npm:^1.0.8": - version: 1.0.8 - resolution: "string.prototype.trimstart@npm:1.0.8" - dependencies: - call-bind: "npm:^1.0.7" - define-properties: "npm:^1.2.1" - es-object-atoms: "npm:^1.0.0" - checksum: 10c0/d53af1899959e53c83b64a5fd120be93e067da740e7e75acb433849aa640782fb6c7d4cd5b84c954c84413745a3764df135a8afeb22908b86a835290788d8366 - languageName: node - linkType: hard - -"strip-bom@npm:^3.0.0": - version: 3.0.0 - resolution: "strip-bom@npm:3.0.0" - checksum: 10c0/51201f50e021ef16672593d7434ca239441b7b760e905d9f33df6e4f3954ff54ec0e0a06f100d028af0982d6f25c35cd5cda2ce34eaebccd0250b8befb90d8f1 - languageName: node - linkType: hard - -"strip-json-comments@npm:^3.1.1": - version: 3.1.1 - resolution: "strip-json-comments@npm:3.1.1" - checksum: 10c0/9681a6257b925a7fa0f285851c0e613cc934a50661fa7bb41ca9cbbff89686bb4a0ee366e6ecedc4daafd01e83eee0720111ab294366fe7c185e935475ebcecd - languageName: node - linkType: hard - -"stubborn-fs@npm:^2.0.0": - version: 2.0.0 - resolution: "stubborn-fs@npm:2.0.0" - dependencies: - stubborn-utils: "npm:^1.0.1" - checksum: 10c0/31a60c9b2a61ce380b688f2649acaeff63cb0f2503bb6820c3ccd4f3af584c6310a48efa41b40c16b1717f1728572ed887c2c88650955c776a088228797e8d0e - languageName: node - linkType: hard - -"stubborn-utils@npm:^1.0.1": - version: 1.0.2 - resolution: "stubborn-utils@npm:1.0.2" - checksum: 10c0/e65c5820d02c993df55c88e938796c2fb2f3a6d3dc247c961d1e4be4d6d88c355283f4b74157e89d1a1a761d66b5ae79560a416384241a7d3b4e8ba8f1ff5a78 - languageName: node - linkType: hard - -"styled-jsx@npm:5.1.6": - version: 5.1.6 - resolution: "styled-jsx@npm:5.1.6" - dependencies: - client-only: "npm:0.0.1" - peerDependencies: - react: ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" - peerDependenciesMeta: - "@babel/core": - optional: true - babel-plugin-macros: - optional: true - checksum: 10c0/ace50e7ea5ae5ae6a3b65a50994c51fca6ae7df9c7ecfd0104c36be0b4b3a9c5c1a2374d16e2a11e256d0b20be6d47256d768ecb4f91ab390f60752a075780f5 - languageName: node - linkType: hard - -"sucrase@npm:^3.35.0": - version: 3.35.1 - resolution: "sucrase@npm:3.35.1" - dependencies: - "@jridgewell/gen-mapping": "npm:^0.3.2" - commander: "npm:^4.0.0" - lines-and-columns: "npm:^1.1.6" - mz: "npm:^2.7.0" - pirates: "npm:^4.0.1" - tinyglobby: "npm:^0.2.11" - ts-interface-checker: "npm:^0.1.9" - bin: - sucrase: bin/sucrase - sucrase-node: bin/sucrase-node - checksum: 10c0/6fa22329c261371feb9560630d961ad0d0b9c87dce21ea74557c5f3ffbe5c1ee970ea8bcce9962ae9c90c3c47165ffa7dd41865c7414f5d8ea7a40755d612c5c - languageName: node - linkType: hard - -"supports-color@npm:^7.1.0": - version: 7.2.0 - resolution: "supports-color@npm:7.2.0" - dependencies: - has-flag: "npm:^4.0.0" - checksum: 10c0/afb4c88521b8b136b5f5f95160c98dee7243dc79d5432db7efc27efb219385bbc7d9427398e43dd6cc730a0f87d5085ce1652af7efbe391327bc0a7d0f7fc124 - languageName: node - linkType: hard - -"supports-preserve-symlinks-flag@npm:^1.0.0": - version: 1.0.0 - resolution: "supports-preserve-symlinks-flag@npm:1.0.0" - checksum: 10c0/6c4032340701a9950865f7ae8ef38578d8d7053f5e10518076e6554a9381fa91bd9c6850193695c141f32b21f979c985db07265a758867bac95de05f7d8aeb39 - languageName: node - linkType: hard - -"tagged-tag@npm:^1.0.0": - version: 1.0.0 - resolution: "tagged-tag@npm:1.0.0" - checksum: 10c0/91d25c9ffb86a91f20522cefb2cbec9b64caa1febe27ad0df52f08993ff60888022d771e868e6416cf2e72dab68449d2139e8709ba009b74c6c7ecd4000048d1 - languageName: node - linkType: hard - -"tailwind-merge@npm:^3.3.1": - version: 3.3.1 - resolution: "tailwind-merge@npm:3.3.1" - checksum: 10c0/b84c6a78d4669fa12bf5ab8f0cdc4400a3ce0a7c006511af4af4be70bb664a27466dbe13ee9e3b31f50ddf6c51d380e8192ce0ec9effce23ca729d71a9f63818 - languageName: node - linkType: hard - -"tailwindcss@npm:^3.4.19": - version: 3.4.19 - resolution: "tailwindcss@npm:3.4.19" - dependencies: - "@alloc/quick-lru": "npm:^5.2.0" - arg: "npm:^5.0.2" - chokidar: "npm:^3.6.0" - didyoumean: "npm:^1.2.2" - dlv: "npm:^1.1.3" - fast-glob: "npm:^3.3.2" - glob-parent: "npm:^6.0.2" - is-glob: "npm:^4.0.3" - jiti: "npm:^1.21.7" - lilconfig: "npm:^3.1.3" - micromatch: "npm:^4.0.8" - normalize-path: "npm:^3.0.0" - object-hash: "npm:^3.0.0" - picocolors: "npm:^1.1.1" - postcss: "npm:^8.4.47" - postcss-import: "npm:^15.1.0" - postcss-js: "npm:^4.0.1" - postcss-load-config: "npm:^4.0.2 || ^5.0 || ^6.0" - postcss-nested: "npm:^6.2.0" - postcss-selector-parser: "npm:^6.1.2" - resolve: "npm:^1.22.8" - sucrase: "npm:^3.35.0" - bin: - tailwind: lib/cli.js - tailwindcss: lib/cli.js - checksum: 10c0/e1063daccb9e5a508b357ec73b0011354204b2366b56496d6f0cc822733a55a0551502cb85856a2257ef9b676d0026616daaaa176d391f3216df57fbd693c581 - languageName: node - linkType: hard - -"tar@npm:^7.5.4": - version: 7.5.11 - resolution: "tar@npm:7.5.11" - dependencies: - "@isaacs/fs-minipass": "npm:^4.0.0" - chownr: "npm:^3.0.0" - minipass: "npm:^7.1.2" - minizlib: "npm:^3.1.0" - yallist: "npm:^5.0.0" - checksum: 10c0/b6bb420550ef50ef23356018155e956cd83282c97b6128d8d5cfe5740c57582d806a244b2ef0bf686a74ce526babe8b8b9061527623e935e850008d86d838929 - languageName: node - linkType: hard - -"thenify-all@npm:^1.0.0": - version: 1.6.0 - resolution: "thenify-all@npm:1.6.0" - dependencies: - thenify: "npm:>= 3.1.0 < 4" - checksum: 10c0/9b896a22735e8122754fe70f1d65f7ee691c1d70b1f116fda04fea103d0f9b356e3676cb789506e3909ae0486a79a476e4914b0f92472c2e093d206aed4b7d6b - languageName: node - linkType: hard - -"thenify@npm:>= 3.1.0 < 4": - version: 3.3.1 - resolution: "thenify@npm:3.3.1" - dependencies: - any-promise: "npm:^1.0.0" - checksum: 10c0/f375aeb2b05c100a456a30bc3ed07ef03a39cbdefe02e0403fb714b8c7e57eeaad1a2f5c4ecfb9ce554ce3db9c2b024eba144843cd9e344566d9fcee73b04767 - languageName: node - linkType: hard - -"tinyglobby@npm:^0.2.11, tinyglobby@npm:^0.2.12, tinyglobby@npm:^0.2.15": - version: 0.2.15 - resolution: "tinyglobby@npm:0.2.15" - dependencies: - fdir: "npm:^6.5.0" - picomatch: "npm:^4.0.3" - checksum: 10c0/869c31490d0d88eedb8305d178d4c75e7463e820df5a9b9d388291daf93e8b1eb5de1dad1c1e139767e4269fe75f3b10d5009b2cc14db96ff98986920a186844 - languageName: node - linkType: hard - -"tinyglobby@npm:^0.2.13": - version: 0.2.14 - resolution: "tinyglobby@npm:0.2.14" - dependencies: - fdir: "npm:^6.4.4" - picomatch: "npm:^4.0.2" - checksum: 10c0/f789ed6c924287a9b7d3612056ed0cda67306cd2c80c249fd280cf1504742b12583a2089b61f4abbd24605f390809017240e250241f09938054c9b363e51c0a6 - languageName: node - linkType: hard - -"to-regex-range@npm:^5.0.1": - version: 5.0.1 - resolution: "to-regex-range@npm:5.0.1" - dependencies: - is-number: "npm:^7.0.0" - checksum: 10c0/487988b0a19c654ff3e1961b87f471702e708fa8a8dd02a298ef16da7206692e8552a0250e8b3e8759270f62e9d8314616f6da274734d3b558b1fc7b7724e892 - languageName: node - linkType: hard - -"toml@npm:^4.1.1": - version: 4.1.1 - resolution: "toml@npm:4.1.1" - checksum: 10c0/077bc02ac1ce82091ea073f675d7e2a1df487d1b18bbc7e653daba4956d545954b7095e979b8792f0837339b901ee190ad4464342e5e377c36bbdeca8903e079 - languageName: node - linkType: hard - -"ts-api-utils@npm:^2.4.0": - version: 2.5.0 - resolution: "ts-api-utils@npm:2.5.0" - peerDependencies: - typescript: ">=4.8.4" - checksum: 10c0/767849383c114e7f1971fa976b20e73ac28fd0c70d8d65c0004790bf4d8f89888c7e4cf6d5949f9c1beae9bc3c64835bef77bbe27fddf45a3c7b60cebcf85c8c - languageName: node - linkType: hard - -"ts-interface-checker@npm:^0.1.9": - version: 0.1.13 - resolution: "ts-interface-checker@npm:0.1.13" - checksum: 10c0/232509f1b84192d07b81d1e9b9677088e590ac1303436da1e92b296e9be8e31ea042e3e1fd3d29b1742ad2c959e95afe30f63117b8f1bc3a3850070a5142fea7 - languageName: node - linkType: hard - -"tsconfig-paths@npm:^3.15.0": - version: 3.15.0 - resolution: "tsconfig-paths@npm:3.15.0" - dependencies: - "@types/json5": "npm:^0.0.29" - json5: "npm:^1.0.2" - minimist: "npm:^1.2.6" - strip-bom: "npm:^3.0.0" - checksum: 10c0/5b4f301a2b7a3766a986baf8fc0e177eb80bdba6e396792ff92dc23b5bca8bb279fc96517dcaaef63a3b49bebc6c4c833653ec58155780bc906bdbcf7dda0ef5 - languageName: node - linkType: hard - -"tslib@npm:2.7.0": - version: 2.7.0 - resolution: "tslib@npm:2.7.0" - checksum: 10c0/469e1d5bf1af585742128827000711efa61010b699cb040ab1800bcd3ccdd37f63ec30642c9e07c4439c1db6e46345582614275daca3e0f4abae29b0083f04a6 - languageName: node - linkType: hard - -"tslib@npm:^2.0.0, tslib@npm:^2.1.0, tslib@npm:^2.4.0, tslib@npm:^2.8.0": - version: 2.8.1 - resolution: "tslib@npm:2.8.1" - checksum: 10c0/9c4759110a19c53f992d9aae23aac5ced636e99887b51b9e61def52611732872ff7668757d4e4c61f19691e36f4da981cd9485e869b4a7408d689f6bf1f14e62 - languageName: node - linkType: hard - -"type-check@npm:^0.4.0, type-check@npm:~0.4.0": - version: 0.4.0 - resolution: "type-check@npm:0.4.0" - dependencies: - prelude-ls: "npm:^1.2.1" - checksum: 10c0/7b3fd0ed43891e2080bf0c5c504b418fbb3e5c7b9708d3d015037ba2e6323a28152ec163bcb65212741fa5d2022e3075ac3c76440dbd344c9035f818e8ecee58 - languageName: node - linkType: hard - -"type-fest@npm:^5.0.0": - version: 5.6.0 - resolution: "type-fest@npm:5.6.0" - dependencies: - tagged-tag: "npm:^1.0.0" - checksum: 10c0/5468a8ffda7f3904e6f7bbd8069eb8b6dd4bd9156e206df7a01d09a73e28cd1afedf74ead9d0fc12841c8c90074194859feca240511c50800962fde1bd9ddcbc - languageName: node - linkType: hard - -"typed-array-buffer@npm:^1.0.3": - version: 1.0.3 - resolution: "typed-array-buffer@npm:1.0.3" - dependencies: - call-bound: "npm:^1.0.3" - es-errors: "npm:^1.3.0" - is-typed-array: "npm:^1.1.14" - checksum: 10c0/1105071756eb248774bc71646bfe45b682efcad93b55532c6ffa4518969fb6241354e4aa62af679ae83899ec296d69ef88f1f3763657cdb3a4d29321f7b83079 - languageName: node - linkType: hard - -"typed-array-byte-length@npm:^1.0.3": - version: 1.0.3 - resolution: "typed-array-byte-length@npm:1.0.3" - dependencies: - call-bind: "npm:^1.0.8" - for-each: "npm:^0.3.3" - gopd: "npm:^1.2.0" - has-proto: "npm:^1.2.0" - is-typed-array: "npm:^1.1.14" - checksum: 10c0/6ae083c6f0354f1fce18b90b243343b9982affd8d839c57bbd2c174a5d5dc71be9eb7019ffd12628a96a4815e7afa85d718d6f1e758615151d5f35df841ffb3e - languageName: node - linkType: hard - -"typed-array-byte-offset@npm:^1.0.4": - version: 1.0.4 - resolution: "typed-array-byte-offset@npm:1.0.4" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - for-each: "npm:^0.3.3" - gopd: "npm:^1.2.0" - has-proto: "npm:^1.2.0" - is-typed-array: "npm:^1.1.15" - reflect.getprototypeof: "npm:^1.0.9" - checksum: 10c0/3d805b050c0c33b51719ee52de17c1cd8e6a571abdf0fffb110e45e8dd87a657e8b56eee94b776b13006d3d347a0c18a730b903cf05293ab6d92e99ff8f77e53 - languageName: node - linkType: hard - -"typed-array-length@npm:^1.0.7": - version: 1.0.7 - resolution: "typed-array-length@npm:1.0.7" - dependencies: - call-bind: "npm:^1.0.7" - for-each: "npm:^0.3.3" - gopd: "npm:^1.0.1" - is-typed-array: "npm:^1.1.13" - possible-typed-array-names: "npm:^1.0.0" - reflect.getprototypeof: "npm:^1.0.6" - checksum: 10c0/e38f2ae3779584c138a2d8adfa8ecf749f494af3cd3cdafe4e688ce51418c7d2c5c88df1bd6be2bbea099c3f7cea58c02ca02ed438119e91f162a9de23f61295 - languageName: node - linkType: hard - -"typescript-eslint@npm:^8.46.0": - version: 8.57.1 - resolution: "typescript-eslint@npm:8.57.1" - dependencies: - "@typescript-eslint/eslint-plugin": "npm:8.57.1" - "@typescript-eslint/parser": "npm:8.57.1" - "@typescript-eslint/typescript-estree": "npm:8.57.1" - "@typescript-eslint/utils": "npm:8.57.1" - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 || ^10.0.0 - typescript: ">=4.8.4 <6.0.0" - checksum: 10c0/be5a19738a785a2695e01874cbedbddbb63ea0a1c2eac331be7d251bda35116505f4d4d8de5a25a77a09392396247af4b89d2a793580217af4891e9e5036a716 - languageName: node - linkType: hard - -"typescript@npm:>=5.0.4 <7": - version: 5.9.3 - resolution: "typescript@npm:5.9.3" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/6bd7552ce39f97e711db5aa048f6f9995b53f1c52f7d8667c1abdc1700c68a76a308f579cd309ce6b53646deb4e9a1be7c813a93baaf0a28ccd536a30270e1c5 - languageName: node - linkType: hard - -"typescript@npm:^6.0.2": - version: 6.0.2 - resolution: "typescript@npm:6.0.2" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/4b860b0bf87cc0fee0f66d8ef2640b5a8a8a8c74d1129adb82e389e5f97124383823c47946bef8a73ede371461143a3aa8544399d2133c7b2e4f07e81860af7f - languageName: node - linkType: hard - -"typescript@npm:^6.0.3": - version: 6.0.3 - resolution: "typescript@npm:6.0.3" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/4a25ff5045b984370f48f196b3a0120779b1b343d40b9a68d114ea5e5fff099809b2bb777576991a63a5cd59cf7bffd96ff6fe10afcefbcb8bd6fb96ad4b6606 - languageName: node - linkType: hard - -"typescript@patch:typescript@npm%3A>=5.0.4 <7#optional!builtin": - version: 5.9.3 - resolution: "typescript@patch:typescript@npm%3A5.9.3#optional!builtin::version=5.9.3&hash=5786d5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/ad09fdf7a756814dce65bc60c1657b40d44451346858eea230e10f2e95a289d9183b6e32e5c11e95acc0ccc214b4f36289dcad4bf1886b0adb84d711d336a430 - languageName: node - linkType: hard - -"typescript@patch:typescript@npm%3A^6.0.2#optional!builtin": - version: 6.0.2 - resolution: "typescript@patch:typescript@npm%3A6.0.2#optional!builtin::version=6.0.2&hash=5786d5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/49f0b84fc6ca55653e77752b8a61beabc09ee3dae5d965c31596225aa6ef213c5727b1d2e895b900416dc603854ba0872ac4a812c2a4ed6793a601f9c675de02 - languageName: node - linkType: hard - -"typescript@patch:typescript@npm%3A^6.0.3#optional!builtin": - version: 6.0.3 - resolution: "typescript@patch:typescript@npm%3A6.0.3#optional!builtin::version=6.0.3&hash=5786d5" - bin: - tsc: bin/tsc - tsserver: bin/tsserver - checksum: 10c0/2f25c74e65663c248fa1ade2b8459d9ce5372ff9dad07067310f132966ebec1d93f6c42f0baf77a6b6a7a91460463f708e6887013aaade22111037457c6b25df - languageName: node - linkType: hard - -"uint8array-extras@npm:^1.5.0": - version: 1.5.0 - resolution: "uint8array-extras@npm:1.5.0" - checksum: 10c0/0e74641ac7dadb02eadefc1ccdadba6010e007757bda824960de3c72bbe2b04e6d3af75648441f412148c4103261d54fcb60be45a2863beb76643a55fddba3bd - languageName: node - linkType: hard - -"unbox-primitive@npm:^1.1.0": - version: 1.1.0 - resolution: "unbox-primitive@npm:1.1.0" - dependencies: - call-bound: "npm:^1.0.3" - has-bigints: "npm:^1.0.2" - has-symbols: "npm:^1.1.0" - which-boxed-primitive: "npm:^1.1.1" - checksum: 10c0/7dbd35ab02b0e05fe07136c72cb9355091242455473ec15057c11430129bab38b7b3624019b8778d02a881c13de44d63cd02d122ee782fb519e1de7775b5b982 - languageName: node - linkType: hard - -"uncrypto@npm:^0.1.3": - version: 0.1.3 - resolution: "uncrypto@npm:0.1.3" - checksum: 10c0/74a29afefd76d5b77bedc983559ceb33f5bbc8dada84ff33755d1e3355da55a4e03a10e7ce717918c436b4dfafde1782e799ebaf2aadd775612b49f7b5b2998e - languageName: node - linkType: hard - -"undici-types@npm:>=7.24.0 <7.24.7": - version: 7.24.6 - resolution: "undici-types@npm:7.24.6" - checksum: 10c0/d9cd8befb643ac904615c280a095ba4240531f6bb4a5e75a22a7483630ca8d3f1016d2ab6ace6ceda1f63b3a2db2fe037fafe121d6917a0187573aa548ff78ca - languageName: node - linkType: hard - -"undici-types@npm:~6.19.2": - version: 6.19.8 - resolution: "undici-types@npm:6.19.8" - checksum: 10c0/078afa5990fba110f6824823ace86073b4638f1d5112ee26e790155f481f2a868cc3e0615505b6f4282bdf74a3d8caad715fd809e870c2bb0704e3ea6082f344 - languageName: node - linkType: hard - -"undici-types@npm:~6.21.0": - version: 6.21.0 - resolution: "undici-types@npm:6.21.0" - checksum: 10c0/c01ed51829b10aa72fc3ce64b747f8e74ae9b60eafa19a7b46ef624403508a54c526ffab06a14a26b3120d055e1104d7abe7c9017e83ced038ea5cf52f8d5e04 - languageName: node - linkType: hard - -"unrs-resolver@npm:^1.6.2": - version: 1.11.1 - resolution: "unrs-resolver@npm:1.11.1" - dependencies: - "@unrs/resolver-binding-android-arm-eabi": "npm:1.11.1" - "@unrs/resolver-binding-android-arm64": "npm:1.11.1" - "@unrs/resolver-binding-darwin-arm64": "npm:1.11.1" - "@unrs/resolver-binding-darwin-x64": "npm:1.11.1" - "@unrs/resolver-binding-freebsd-x64": "npm:1.11.1" - "@unrs/resolver-binding-linux-arm-gnueabihf": "npm:1.11.1" - "@unrs/resolver-binding-linux-arm-musleabihf": "npm:1.11.1" - "@unrs/resolver-binding-linux-arm64-gnu": "npm:1.11.1" - "@unrs/resolver-binding-linux-arm64-musl": "npm:1.11.1" - "@unrs/resolver-binding-linux-ppc64-gnu": "npm:1.11.1" - "@unrs/resolver-binding-linux-riscv64-gnu": "npm:1.11.1" - "@unrs/resolver-binding-linux-riscv64-musl": "npm:1.11.1" - "@unrs/resolver-binding-linux-s390x-gnu": "npm:1.11.1" - "@unrs/resolver-binding-linux-x64-gnu": "npm:1.11.1" - "@unrs/resolver-binding-linux-x64-musl": "npm:1.11.1" - "@unrs/resolver-binding-wasm32-wasi": "npm:1.11.1" - "@unrs/resolver-binding-win32-arm64-msvc": "npm:1.11.1" - "@unrs/resolver-binding-win32-ia32-msvc": "npm:1.11.1" - "@unrs/resolver-binding-win32-x64-msvc": "npm:1.11.1" - napi-postinstall: "npm:^0.3.0" - dependenciesMeta: - "@unrs/resolver-binding-android-arm-eabi": - optional: true - "@unrs/resolver-binding-android-arm64": - optional: true - "@unrs/resolver-binding-darwin-arm64": - optional: true - "@unrs/resolver-binding-darwin-x64": - optional: true - "@unrs/resolver-binding-freebsd-x64": - optional: true - "@unrs/resolver-binding-linux-arm-gnueabihf": - optional: true - "@unrs/resolver-binding-linux-arm-musleabihf": - optional: true - "@unrs/resolver-binding-linux-arm64-gnu": - optional: true - "@unrs/resolver-binding-linux-arm64-musl": - optional: true - "@unrs/resolver-binding-linux-ppc64-gnu": - optional: true - "@unrs/resolver-binding-linux-riscv64-gnu": - optional: true - "@unrs/resolver-binding-linux-riscv64-musl": - optional: true - "@unrs/resolver-binding-linux-s390x-gnu": - optional: true - "@unrs/resolver-binding-linux-x64-gnu": - optional: true - "@unrs/resolver-binding-linux-x64-musl": - optional: true - "@unrs/resolver-binding-wasm32-wasi": - optional: true - "@unrs/resolver-binding-win32-arm64-msvc": - optional: true - "@unrs/resolver-binding-win32-ia32-msvc": - optional: true - "@unrs/resolver-binding-win32-x64-msvc": - optional: true - checksum: 10c0/c91b112c71a33d6b24e5c708dab43ab80911f2df8ee65b87cd7a18fb5af446708e98c4b415ca262026ad8df326debcc7ca6a801b2935504d87fd6f0b9d70dce1 - languageName: node - linkType: hard - -"update-browserslist-db@npm:^1.1.3": - version: 1.1.3 - resolution: "update-browserslist-db@npm:1.1.3" - dependencies: - escalade: "npm:^3.2.0" - picocolors: "npm:^1.1.1" - peerDependencies: - browserslist: ">= 4.21.0" - bin: - update-browserslist-db: cli.js - checksum: 10c0/682e8ecbf9de474a626f6462aa85927936cdd256fe584c6df2508b0df9f7362c44c957e9970df55dfe44d3623807d26316ea2c7d26b80bb76a16c56c37233c32 - languageName: node - linkType: hard - -"update-browserslist-db@npm:^1.2.0": - version: 1.2.3 - resolution: "update-browserslist-db@npm:1.2.3" - dependencies: - escalade: "npm:^3.2.0" - picocolors: "npm:^1.1.1" - peerDependencies: - browserslist: ">= 4.21.0" - bin: - update-browserslist-db: cli.js - checksum: 10c0/13a00355ea822388f68af57410ce3255941d5fb9b7c49342c4709a07c9f230bbef7f7499ae0ca7e0de532e79a82cc0c4edbd125f1a323a1845bf914efddf8bec - languageName: node - linkType: hard - -"uri-js@npm:^4.2.2": - version: 4.4.1 - resolution: "uri-js@npm:4.4.1" - dependencies: - punycode: "npm:^2.1.0" - checksum: 10c0/4ef57b45aa820d7ac6496e9208559986c665e49447cb072744c13b66925a362d96dd5a46c4530a6b8e203e5db5fe849369444440cb22ecfc26c679359e5dfa3c - languageName: node - linkType: hard - -"use-callback-ref@npm:^1.3.3": - version: 1.3.3 - resolution: "use-callback-ref@npm:1.3.3" - dependencies: - tslib: "npm:^2.0.0" - 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 - checksum: 10c0/f887488c6e6075cdad4962979da1714b217bcb1ee009a9e57ce9a844bcfc4c3a99e93983dfc2e5af9e0913824d24e730090ff255e902c516dcb58d2d3837e01c - languageName: node - linkType: hard - -"use-sidecar@npm:^1.1.3": - version: 1.1.3 - resolution: "use-sidecar@npm:1.1.3" - dependencies: - detect-node-es: "npm:^1.1.0" - tslib: "npm:^2.0.0" - 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 - checksum: 10c0/161599bf921cfaa41c85d2b01c871975ee99260f3e874c2d41c05890d41170297bdcf314bc5185e7a700de2034ac5b888e3efc8e9f35724f4918f53538d717c9 - languageName: node - linkType: hard - -"util-deprecate@npm:^1.0.2": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 10c0/41a5bdd214df2f6c3ecf8622745e4a366c4adced864bc3c833739791aeeeb1838119af7daed4ba36428114b5c67dcda034a79c882e97e43c03e66a4dd7389942 - languageName: node - linkType: hard - -"uuid@npm:^14.0.0": - version: 14.0.0 - resolution: "uuid@npm:14.0.0" - bin: - uuid: dist-node/bin/uuid - checksum: 10c0/a57ae7794c45005c1a9208989196c5baf79a7679c30f43c1bee9033a2c4d113a2cea216fa6fcc9663b08b0d55635df1a7c6eb7e7f3d21c3e50688c698fa39a50 - languageName: node - linkType: hard - -"web@workspace:.": - version: 0.0.0-use.local - resolution: "web@workspace:." - dependencies: - "@eslint/eslintrc": "npm:^3" - "@radix-ui/react-dialog": "npm:^1.1.15" - "@radix-ui/react-dropdown-menu": "npm:^2.1.16" - "@radix-ui/react-label": "npm:^2.1.7" - "@radix-ui/react-popover": "npm:^1.1.15" - "@radix-ui/react-scroll-area": "npm:^1.2.10" - "@radix-ui/react-slot": "npm:^1.2.3" - "@radix-ui/react-toast": "npm:^1.2.15" - "@types/canvas-confetti": "npm:^1.9.0" - "@types/minimatch": "npm:^6.0.0" - "@types/node": "npm:^20" - "@types/react": "npm:^19.2.7" - "@types/react-dom": "npm:^19.2.3" - "@upstash/ratelimit": "npm:2.0.6" - "@upstash/redis": "npm:1.35.3" - "@vercel/analytics": "npm:^1.5.0" - "@vercel/kv": "npm:3.0.0" - autoprefixer: "npm:^10.4.21" - canvas-confetti: "npm:^1.9.3" - class-variance-authority: "npm:^0.7.1" - clsx: "npm:^2.1.1" - cmdk: "npm:^1.1.1" - eslint: "npm:^9.39.2" - eslint-config-next: "npm:16.2.3" - ethers: "npm:6.13.4" - input-otp: "npm:^1.4.2" - lucide-react: "npm:^0.543.0" - next: "npm:16.2.3" - next-themes: "npm:^0.4.6" - portless: "npm:0.11.1" - postcss: "npm:^8.5.6" - react: "npm:19.2.3" - react-doctor: "npm:0.2.6" - react-dom: "npm:19.2.3" - react-phone-number-input: "npm:^3.4.12" - tailwind-merge: "npm:^3.3.1" - tailwindcss: "npm:^3.4.19" - typescript: "npm:^6.0.2" - zod: "npm:4.0.15" - languageName: unknown - linkType: soft - -"when-exit@npm:^2.1.4": - version: 2.1.5 - resolution: "when-exit@npm:2.1.5" - checksum: 10c0/7db41b28c98456b784c25780ca327653f233c6eb7b25d4ce251d04519828cbd609fb6d10548caf9031d4d6fab2999d6f6911c32e1731efab24c93a522573470d - languageName: node - linkType: hard - -"which-boxed-primitive@npm:^1.1.0, which-boxed-primitive@npm:^1.1.1": - version: 1.1.1 - resolution: "which-boxed-primitive@npm:1.1.1" - dependencies: - is-bigint: "npm:^1.1.0" - is-boolean-object: "npm:^1.2.1" - is-number-object: "npm:^1.1.1" - is-string: "npm:^1.1.1" - is-symbol: "npm:^1.1.1" - checksum: 10c0/aceea8ede3b08dede7dce168f3883323f7c62272b49801716e8332ff750e7ae59a511ae088840bc6874f16c1b7fd296c05c949b0e5b357bfe3c431b98c417abe - languageName: node - linkType: hard - -"which-builtin-type@npm:^1.2.1": - version: 1.2.1 - resolution: "which-builtin-type@npm:1.2.1" - dependencies: - call-bound: "npm:^1.0.2" - function.prototype.name: "npm:^1.1.6" - has-tostringtag: "npm:^1.0.2" - is-async-function: "npm:^2.0.0" - is-date-object: "npm:^1.1.0" - is-finalizationregistry: "npm:^1.1.0" - is-generator-function: "npm:^1.0.10" - is-regex: "npm:^1.2.1" - is-weakref: "npm:^1.0.2" - isarray: "npm:^2.0.5" - which-boxed-primitive: "npm:^1.1.0" - which-collection: "npm:^1.0.2" - which-typed-array: "npm:^1.1.16" - checksum: 10c0/8dcf323c45e5c27887800df42fbe0431d0b66b1163849bb7d46b5a730ad6a96ee8bfe827d078303f825537844ebf20c02459de41239a0a9805e2fcb3cae0d471 - languageName: node - linkType: hard - -"which-collection@npm:^1.0.2": - version: 1.0.2 - resolution: "which-collection@npm:1.0.2" - dependencies: - is-map: "npm:^2.0.3" - is-set: "npm:^2.0.3" - is-weakmap: "npm:^2.0.2" - is-weakset: "npm:^2.0.3" - checksum: 10c0/3345fde20964525a04cdf7c4a96821f85f0cc198f1b2ecb4576e08096746d129eb133571998fe121c77782ac8f21cbd67745a3d35ce100d26d4e684c142ea1f2 - languageName: node - linkType: hard - -"which-typed-array@npm:^1.1.16, which-typed-array@npm:^1.1.19": - version: 1.1.19 - resolution: "which-typed-array@npm:1.1.19" - dependencies: - available-typed-arrays: "npm:^1.0.7" - call-bind: "npm:^1.0.8" - call-bound: "npm:^1.0.4" - for-each: "npm:^0.3.5" - get-proto: "npm:^1.0.1" - gopd: "npm:^1.2.0" - has-tostringtag: "npm:^1.0.2" - checksum: 10c0/702b5dc878addafe6c6300c3d0af5983b175c75fcb4f2a72dfc3dd38d93cf9e89581e4b29c854b16ea37e50a7d7fca5ae42ece5c273d8060dcd603b2404bbb3f - languageName: node - linkType: hard - -"which@npm:^2.0.1": - version: 2.0.2 - resolution: "which@npm:2.0.2" - dependencies: - isexe: "npm:^2.0.0" - bin: - node-which: ./bin/node-which - checksum: 10c0/66522872a768b60c2a65a57e8ad184e5372f5b6a9ca6d5f033d4b0dc98aff63995655a7503b9c0a2598936f532120e81dd8cc155e2e92ed662a2b9377cc4374f - languageName: node - linkType: hard - -"which@npm:^6.0.0": - version: 6.0.1 - resolution: "which@npm:6.0.1" - dependencies: - isexe: "npm:^4.0.0" - bin: - node-which: bin/which.js - checksum: 10c0/7e710e54ea36d2d6183bee2f9caa27a3b47b9baf8dee55a199b736fcf85eab3b9df7556fca3d02b50af7f3dfba5ea3a45644189836df06267df457e354da66d5 - languageName: node - linkType: hard - -"word-wrap@npm:^1.2.5": - version: 1.2.5 - resolution: "word-wrap@npm:1.2.5" - checksum: 10c0/e0e4a1ca27599c92a6ca4c32260e8a92e8a44f4ef6ef93f803f8ed823f486e0889fc0b93be4db59c8d51b3064951d25e43d434e95dc8c960cc3a63d65d00ba20 - languageName: node - linkType: hard - -"ws@npm:8.17.1": - version: 8.17.1 - resolution: "ws@npm:8.17.1" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 10c0/f4a49064afae4500be772abdc2211c8518f39e1c959640457dcee15d4488628620625c783902a52af2dd02f68558da2868fd06e6fd0e67ebcd09e6881b1b5bfe - languageName: node - linkType: hard - -"ws@npm:^8.20.0": - version: 8.21.0 - resolution: "ws@npm:8.21.0" - peerDependencies: - bufferutil: ^4.0.1 - utf-8-validate: ">=5.0.2" - peerDependenciesMeta: - bufferutil: - optional: true - utf-8-validate: - optional: true - checksum: 10c0/ef4a243476283fc49bc7550966c4af4aa0eef56273837211e700de3b664e08604a760cdddcb5ba43c049140e74ccfec5b0ee0bb439e08c2adf9138902fdde5f9 - languageName: node - linkType: hard - -"yallist@npm:^3.0.2": - version: 3.1.1 - resolution: "yallist@npm:3.1.1" - checksum: 10c0/c66a5c46bc89af1625476f7f0f2ec3653c1a1791d2f9407cfb4c2ba812a1e1c9941416d71ba9719876530e3340a99925f697142989371b72d93b9ee628afd8c1 - languageName: node - linkType: hard - -"yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 10c0/2286b5e8dbfe22204ab66e2ef5cc9bbb1e55dfc873bbe0d568aa943eb255d131890dfd5bf243637273d31119b870f49c18fcde2c6ffbb7a7a092b870dc90625a - languageName: node - linkType: hard - -"yallist@npm:^5.0.0": - version: 5.0.0 - resolution: "yallist@npm:5.0.0" - checksum: 10c0/a499c81ce6d4a1d260d4ea0f6d49ab4da09681e32c3f0472dee16667ed69d01dae63a3b81745a24bd78476ec4fcf856114cb4896ace738e01da34b2c42235416 - languageName: node - linkType: hard - -"yaml@npm:^2.8.3": - version: 2.8.4 - resolution: "yaml@npm:2.8.4" - bin: - yaml: bin.mjs - checksum: 10c0/0a33a1fa28d4bc79f61a12ec7ef7a2bce0ce5f8e80c6eaecfb4a0c88c08767dd1ede372b6a3bcd70891213b8c9f3169b355c97e77026d3b3459e10d2cccaef1e - languageName: node - linkType: hard - -"yaml@npm:^2.9.0": - version: 2.9.0 - resolution: "yaml@npm:2.9.0" - bin: - yaml: bin.mjs - checksum: 10c0/f340718df45e97a9551b9bf9dac61c80050bc464513b710debfb5067c380c8472e3b67809cffacb4ab5ffb5e66ef9310816c88b05f371cec60abfedd8c88e0a2 - languageName: node - linkType: hard - -"yocto-queue@npm:^0.1.0": - version: 0.1.0 - resolution: "yocto-queue@npm:0.1.0" - checksum: 10c0/dceb44c28578b31641e13695d200d34ec4ab3966a5729814d5445b194933c096b7ced71494ce53a0e8820685d1d010df8b2422e5bf2cdea7e469d97ffbea306f - languageName: node - linkType: hard - -"zod-validation-error@npm:^3.5.0 || ^4.0.0": - version: 4.0.2 - resolution: "zod-validation-error@npm:4.0.2" - peerDependencies: - zod: ^3.25.0 || ^4.0.0 - checksum: 10c0/0ccfec48c46de1be440b719cd02044d4abb89ed0e14c13e637cd55bf29102f67ccdba373f25def0fc7130e5f15025be4d557a7edcc95d5a3811599aade689e1b - languageName: node - linkType: hard - -"zod@npm:4.0.15": - version: 4.0.15 - resolution: "zod@npm:4.0.15" - checksum: 10c0/c4d5b0c6668fe32fb6040d713d75dbf65e2e46cb68c77755b7b66426e8583d5dacf49a44f90beb6b12aa1aa2545cc0d3c186e368711021e11dd3c1f0addb9100 - languageName: node - linkType: hard - -"zod@npm:^3.25.0 || ^4.0.0": - version: 4.3.6 - resolution: "zod@npm:4.3.6" - checksum: 10c0/860d25a81ab41d33aa25f8d0d07b091a04acb426e605f396227a796e9e800c44723ed96d0f53a512b57be3d1520f45bf69c0cb3b378a232a00787a2609625307 - languageName: node - linkType: hard