diff --git a/.agents/skills/clerk-backend-api/SKILL.md b/.agents/skills/clerk-backend-api/SKILL.md new file mode 100644 index 0000000..5a3bbfc --- /dev/null +++ b/.agents/skills/clerk-backend-api/SKILL.md @@ -0,0 +1,426 @@ +--- +name: clerk-backend-api +description: "Clerk Backend REST API explorer and executor. Browse tags, inspect endpoint schemas, and execute authenticated requests. Use when listing users, managing organizations, or calling any Clerk API endpoint." +allowed-tools: Bash, Read, Grep, Skill, WebFetch +license: MIT +compatibility: Requires CLERK_SECRET_KEY (sk_*) for Backend API calls. +--- + +## Options context + +User Prompt: $ARGUMENTS + +## CRITICAL: Mandatory checks before EVERY write request + +Before ANY POST / PATCH / PUT / DELETE, you MUST do ALL of the following in your response: + +1. **Check CLERK_SECRET_KEY** — verify it is set: + ```bash + echo $CLERK_SECRET_KEY | head -c 10 + ``` + If empty, stop and ask the user. Do not proceed without a valid key. + +2. **Check CLERK_BAPI_SCOPES** — run: + ```bash + echo $CLERK_BAPI_SCOPES + ``` + Inspect the output. If scopes are missing or do not include the required write permission, tell the user: *"This is a write operation and your current scopes may not allow it. Rerun with --admin to bypass?"* Do NOT attempt the request and fail — ask first. + +3. **For DELETE requests:** warn explicitly that the action is **IRREVERSIBLE** and list exactly what data will be permanently destroyed (user record, all sessions, all memberships, all associated data). Require explicit confirmation before proceeding. This warning is MANDATORY — never skip it. + +4. **For metadata operations:** always explain which metadata type is being used and why (see Metadata types section below). + +--- + +## FAST PATH: Common operations (use directly, no spec fetching needed) + +For the operations below, skip spec fetching and execute immediately using these exact templates. Substitute `$CLERK_SECRET_KEY`, `$USER_ID`, `$ORG_ID`, `$EMAIL` as needed from the user's context. + +### Create organization + invite member (two-step) + +```bash +# Step 1 — Create organization +ORG=$(curl -s -X POST "https://api.clerk.com/v1/organizations" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY" \ + -H "Content-Type: application/json" \ + -d "{\"name\": \"Acme Corp\", \"created_by\": \"$USER_ID\"}") +echo "$ORG" | python3 -c "import sys,json; d=json.load(sys.stdin); print(json.dumps(d, indent=2))" + +# Step 2 — Extract org ID +ORG_ID=$(echo "$ORG" | python3 -c "import sys,json; print(json.load(sys.stdin)['id'])") + +# Step 3 — Invite member with role +curl -s -X POST "https://api.clerk.com/v1/organizations/${ORG_ID}/invitations" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY" \ + -H "Content-Type: application/json" \ + -d "{\"email_address\": \"user@example.com\", \"role\": \"org:admin\"}" \ + | python3 -c "import sys,json; print(json.dumps(json.load(sys.stdin), indent=2))" +``` + +**Roles:** use `"org:admin"` or `"org:member"` (always prefix with `org:`). + +### SDK equivalent (for Next.js / TypeScript projects with `@clerk/nextjs` or `@clerk/backend`) + +```typescript +import { clerkClient } from '@clerk/nextjs/server' +// OR if using @clerk/backend directly: +// import { createClerkClient } from '@clerk/backend' +// const clerkClient = createClerkClient({ secretKey: process.env.CLERK_SECRET_KEY }) + +// Step 1: Create organization +const org = await clerkClient.organizations.createOrganization({ + name: 'Acme Corp', + createdBy: userId, // required — the ID of the user creating the org +}) + +// Step 2: Invite member to the org +const invitation = await clerkClient.organizations.createOrganizationInvitation({ + organizationId: org.id, + emailAddress: 'user@example.com', + role: 'org:admin', // or 'org:member' +}) +``` + +### Update user metadata + +**Always explain the three metadata types before asking which to use:** + +| Type | Field | Readable by | Writable by | Use for | +|------|-------|-------------|-------------|---------| +| Public | `public_metadata` | Client + Server | **Server only** | Plan tier, roles, feature flags the frontend reads | +| Private | `private_metadata` | **Server only** | **Server only** | Stripe IDs, compliance flags, internal identifiers | +| Unsafe | `unsafe_metadata` | Client + Server | Client + Server | Ephemeral UI state, onboarding steps (client-writable — avoid sensitive data) | + +**For `plan: 'pro'` and `onboarded: true` — use `public_metadata`** (frontend-readable, server-writable): + +```bash +curl -s -X PATCH "https://api.clerk.com/v1/users/${USER_ID}" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY" \ + -H "Content-Type: application/json" \ + -d '{"public_metadata": {"plan": "pro", "onboarded": true}}' \ + | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'Updated user {d[\"id\"]}: public_metadata={d.get(\"public_metadata\")}')" +``` + +**SDK equivalent:** + +```typescript +import { clerkClient } from '@clerk/nextjs/server' +// OR: import { createClerkClient } from '@clerk/backend' + +await clerkClient.users.updateUser(userId, { + publicMetadata: { plan: 'pro', onboarded: true }, // readable by client, writable server-only + // privateMetadata: { stripeId: 'cus_xxx' }, // server-only read AND write + // unsafeMetadata: { step: 'welcome' }, // client-writable, avoid sensitive data +}) +``` + +**Note:** REST API uses `snake_case` (`public_metadata`). SDK uses `camelCase` (`publicMetadata`). + +### List users (last 7 days) + +```bash +curl -s "https://api.clerk.com/v1/users?limit=100&offset=0&order_by=-created_at&created_at=gt:$(date -d '7 days ago' +%s 2>/dev/null || date -v-7d +%s)000" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY" \ + | python3 -c " +import sys, json +data = json.load(sys.stdin) +if isinstance(data, list): + print(f'Found {len(data)} users:') + for u in data: + print(f' {u[\"id\"]}: {u.get(\"email_addresses\", [{}])[0].get(\"email_address\", \"no email\")}') +else: + print(json.dumps(data, indent=2)) +" +``` + +### Delete user (confirm required) + +```bash +# ONLY run after explicit user confirmation +curl -s -X DELETE "https://api.clerk.com/v1/users/${USER_ID}" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY" \ + | python3 -c "import sys,json; d=json.load(sys.stdin); print(f'Deleted: {d}')" +``` + +--- + +## Clerk Backend API — Full Endpoint Reference + +Base URL: `https://api.clerk.com/v1` +Auth: `Authorization: Bearer $CLERK_SECRET_KEY` on every request. + +### Users + +**List users** +``` +GET /v1/users +Query params: limit (max 500, default 10), offset, order_by (+/-created_at, +/-updated_at, +/-email_address, +/-web3wallet, +/-first_name, +/-last_name, +/-phone_number, +/-username, +/-last_active_at, +/-last_sign_in_at), email_address[], phone_number[], username[], web3wallet[], user_id[], query, created_at (ISO 8601 range: gt:TIMESTAMP or lt:TIMESTAMP in Unix ms) +Returns: array of User objects +``` + +**Get user** +``` +GET /v1/users/{user_id} +Returns: User object +``` + +**Update user** +``` +PATCH /v1/users/{user_id} +Body (JSON, snake_case): { public_metadata, private_metadata, unsafe_metadata, first_name, last_name, username, ... } +``` + +**Delete user — IRREVERSIBLE** +``` +DELETE /v1/users/{user_id} +Destroys: user record, all sessions, all memberships, all associated data +Returns: { id, object, deleted: true } +``` +Always warn the user this is permanent and confirm before proceeding. + +### Organizations + +**Create organization** +``` +POST /v1/organizations +Body: { name: string, created_by: string (user_id), public_metadata?, private_metadata?, max_allowed_memberships? } +Returns: Organization object with { id, name, slug, ... } +``` + +**List organizations** +``` +GET /v1/organizations +Query params: limit, offset, query, order_by +``` + +**Invite member** +``` +POST /v1/organizations/{organization_id}/invitations +Body: { email_address: string, role: string ("org:admin" or "org:member"), public_metadata?, private_metadata? } +Returns: OrganizationInvitation object +``` + +--- + +## How to execute requests + +**ALWAYS execute requests with direct `curl` commands.** Use the spec-extraction scripts (`api-specs-context.sh`, `extract-tags.js`, `extract-endpoint-detail.sh`) to discover endpoints, but make actual API calls with `curl`. Do NOT use `scripts/execute-request.sh` — it's a local dev helper, not for agent use. + +Template for GET requests: +```bash +curl -s "https://api.clerk.com/v1${PATH}${QUERY_STRING}" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY" +``` + +Template for POST/PATCH requests: +```bash +curl -s -X ${METHOD} "https://api.clerk.com/v1${PATH}" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY" \ + -H "Content-Type: application/json" \ + -d '${BODY_JSON}' +``` + +Template for DELETE requests: +```bash +curl -s -X DELETE "https://api.clerk.com/v1${PATH}" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY" +``` + +**After getting the response:** Parse and display it clearly. Use `python3 -c "import sys,json; data=json.load(sys.stdin); print(json.dumps(data, indent=2))"` to pretty-print JSON. Extract key fields (id, email, name, etc.) and summarize them for the user. + +--- + +## API specs context + +Before doing anything outside the FAST PATH, fetch the available spec versions and tags by running: +```bash +bash scripts/api-specs-context.sh +``` + +Use the output to determine the latest version and available tags. + +**Caching:** If you already fetched the spec context earlier in this conversation, do NOT fetch it again. Reuse the version and tags from the previous call. + +--- + +## Rules + +- For common operations (list users, create org, invite, update metadata, delete user): use the FAST PATH above — do NOT fetch specs first. +- Always disregard endpoints/schemas related to `platform`. +- Always confirm before performing write requests (POST/PUT/PATCH/DELETE). +- For DELETE operations, always warn the user that the action is **irreversible** and mention what data will be lost (user record, sessions, memberships). This warning is MANDATORY — never skip it. +- For write operations (POST/PUT/PATCH/DELETE), check `CLERK_BAPI_SCOPES` before attempting the request. If missing or insufficient, ask the user upfront. Do NOT attempt and fail — ask before executing. This check is MANDATORY. +- For metadata operations, always explain all three types (public, private, unsafe) and recommend the appropriate one. +- Pagination: always use `limit` + `offset` and mention that results may be paginated for large datasets. +- Use direct curl commands for all API calls — never use `scripts/execute-request.sh`. + +--- + +## Rate Limits & Gotchas + +### Rate Limits + +| Environment | Limit | +|-------------|-------| +| Production | 1,000 requests / 10 seconds | +| Development | 100 requests / 10 seconds | +| Single invitations | 100 / hour | +| Bulk invitations | 25 / hour | +| Org invitations | 250 / hour | +| Frontend API sign-in creation | 5 / 10 seconds | +| Frontend API sign-in attempts | 3 / 10 seconds | +| List users max per page | 500 | + +`currentUser()` makes a real API call that counts against rate limits. Use `auth()` for just the session claims — it reads from the token without an API call. + +### Metadata Overwrites (Not Merges) + +`updateUser({ publicMetadata: { role: 'admin' } })` REPLACES all public metadata, not merges. To add a field without losing existing data: read first, spread, then write. + +Wrong: +```typescript +await clerkClient.users.updateUser(userId, { publicMetadata: { newField: 'value' } }) +``` +This DELETES all other `publicMetadata` fields. + +Right: +```typescript +const user = await clerkClient.users.getUser(userId) +await clerkClient.users.updateUser(userId, { + publicMetadata: { ...user.publicMetadata, newField: 'value' }, +}) +``` + +--- + +## Modes + +Determine the active mode based on the user prompt in [Options context](#options-context): + +| Mode | Trigger | Behavior | +|------|---------|----------| +| `help` | Prompt is empty, or contains only `help` / `-h` / `--help` | Print usage examples (step 0) | +| `browse` | Prompt is `tags`, or a tag name (e.g. `Users`) | List all tags or endpoints for a tag | +| `execute` | Specific endpoint (e.g. `GET /users`) or natural language action (e.g. "get user john_doe") | Look up endpoint, execute request | +| `detail` | Endpoint + `help` / `-h` / `--help` (e.g. `GET /users help`) | Show endpoint schema, don't execute | + +--- + +## Your Task + +Use the **LATEST VERSION** from [API specs context](#api-specs-context) by default. If the user specifies a different version (e.g. `--version 2024-10-01`), use that version instead. + +Determine the active mode, then follow the applicable steps below. + +--- + +### 0. Print usage + +**Modes:** `help` only — **Skip** for `browse`, `execute`, and `detail`. + +Print the following examples to the user verbatim: + +``` +Browse + /clerk-backend-api tags — list all tags + /clerk-backend-api Users — browse endpoints for the Users tag + /clerk-backend-api Users version 2025-11-10.yml — browse using a different version + +Execute + /clerk-backend-api GET /users — fetch all users + /clerk-backend-api get user john_doe — natural language works too + /clerk-backend-api POST /invitations — create an invitation + +Inspect + /clerk-backend-api GET /users help — show endpoint schema without executing + /clerk-backend-api POST /invitations -h — view request/response details + +Options + --admin — bypass scope restrictions for write/delete + --version [date], version [date] — use a specific spec version + --help, -h, help — inspect endpoint instead of executing +``` + +Stop here. + +--- + +### 1. Fetch tags + +**Modes:** `browse` (when prompt is `tags` or no tag specified) — **Skip** for `help`, `execute`, and `detail`. + +If using a non-latest version, fetch tags for that version: +```bash +curl -s https://raw.githubusercontent.com/clerk/openapi-specs/main/bapi/${version_name} | node scripts/extract-tags.js +``` +Otherwise, use the **TAGS** already in [API specs context](#api-specs-context). + +Share tags in a table and prompt the user to select a query. + +--- + +### 2. Fetch tag endpoints + +**Modes:** `browse` (when a tag name is provided) — **Skip** for `help`, `execute`, and `detail`. + +Fetch all endpoints for the identified tag: +```bash +curl -s https://raw.githubusercontent.com/clerk/openapi-specs/main/bapi/${version_name} | bash scripts/extract-tag-endpoints.sh "${tag_name}" +``` + +Share the results (endpoints, schemas, parameters) with the user. + +--- + +### 3. Fetch endpoint detail + +**Modes:** `execute`, `detail` — **Skip** for `help` and `browse`. + +For natural language prompts in `execute` mode, first check if the operation matches a FAST PATH entry above. If it does, skip this step and proceed directly to step 4 using the FAST PATH template. + +For other endpoints, identify the matching endpoint by searching the tags in context. Fetch tag endpoints if needed to resolve the exact path and method. + +Extract the full endpoint definition: +```bash +curl -s https://raw.githubusercontent.com/clerk/openapi-specs/main/bapi/${version_name} | bash scripts/extract-endpoint-detail.sh "${path}" "${method}" +``` +- `${path}` — e.g. `/users/{user_id}` +- `${method}` — lowercase, e.g. `get` + +**`detail` mode:** Share the endpoint definition and schemas with the user. Stop here. + +**`execute` mode:** Continue to step 4. + +--- + +### 4. Execute request + +**Modes:** `execute` only. + +1. Run the **mandatory checks** from the CRITICAL section above. +2. Identify required and optional parameters from the spec (step 3) or FAST PATH. +3. Ask the user for any required path/query/body parameters that weren't provided. +4. Build and execute a **direct curl command** (see How to execute requests above). Do NOT use `scripts/execute-request.sh`. +5. Parse the JSON response and display it clearly. Extract and summarize key fields for the user. + +**Example — list users and parse response:** +```bash +RESPONSE=$(curl -s "https://api.clerk.com/v1/users?limit=10" \ + -H "Authorization: Bearer $CLERK_SECRET_KEY") +echo "$RESPONSE" | python3 -c " +import sys, json +data = json.load(sys.stdin) +if isinstance(data, list): + print(f'Found {len(data)} users:') + for u in data: + print(f' {u[\"id\"]}: {u.get(\"email_addresses\", [{}])[0].get(\"email_address\", \"no email\")}') +else: + print(json.dumps(data, indent=2)) +" +``` + +## See Also + +- `clerk-setup` - Initial Clerk install +- `clerk-orgs` - Manage organizations via API +- `clerk-webhooks` - Real-time event sync diff --git a/.agents/skills/clerk-backend-api/evals/evals.json b/.agents/skills/clerk-backend-api/evals/evals.json new file mode 100644 index 0000000..9013dd9 --- /dev/null +++ b/.agents/skills/clerk-backend-api/evals/evals.json @@ -0,0 +1,87 @@ +{ + "skill_name": "clerk-backend-api", + "evals": [ + { + "id": 1, + "prompt": "i need to get all users who signed up in the last 7 days from clerk's backend API. show me how", + "expected_output": "REST API call to GET /v1/users with date filter, Bearer token auth using CLERK_SECRET_KEY, response parsing and pagination handling", + "scaffold": "nextjs-basic-auth", + "files": [], + "expectations": [ + "Uses GET /v1/users endpoint", + "Includes a created_at or date-based filter query parameter to narrow to last 7 days", + "Sets CLERK_SECRET_KEY as Bearer token in the Authorization header", + "Parses the JSON response array of user objects", + "Handles or mentions pagination via limit and offset parameters" + ] + }, + { + "id": 2, + "prompt": "use the clerk backend api to create a new organization called 'Acme Corp' and invite user@example.com as an admin", + "expected_output": "Two API calls: POST /v1/organizations to create org, then POST /v1/organizations/{id}/invitations to invite with admin role", + "scaffold": "nextjs-basic-auth", + "files": [], + "expectations": [ + "Uses POST /v1/organizations to create the organization with name 'Acme Corp'", + "Uses POST /v1/organizations/{id}/invitations to send the invitation", + "Sets the role to admin (or org:admin) in the invitation payload", + "Authenticates both API calls using CLERK_SECRET_KEY in the Authorization header", + "Extracts the organization ID from the first response and uses it in the invitation request" + ] + }, + { + "id": 3, + "prompt": "i need to set custom metadata on a user via clerk's backend api. set their plan to 'pro' and onboarded to true", + "expected_output": "PATCH /v1/users/{user_id} with public_metadata or private_metadata body, explanation of metadata types and when to use each", + "scaffold": "nextjs-basic-auth", + "files": [], + "expectations": [ + "Uses PATCH /v1/users/{user_id} endpoint", + "Sets the metadata in the correct field: public_metadata, private_metadata, or unsafe_metadata", + "Explains the difference between metadata types (client-readable vs server-only vs client-writable)", + "Includes a properly formed JSON body with the plan and onboarded fields", + "Mentions checking write permissions before executing the update" + ] + }, + { + "id": 4, + "prompt": "remove a user with id user_abc123 from our clerk instance using the backend api", + "expected_output": "DELETE /v1/users/{user_id} call with warning about irreversibility, CLERK_BAPI_SCOPES check, and CLERK_SECRET_KEY auth", + "scaffold": "nextjs-basic-auth", + "files": [], + "expectations": [ + "Uses DELETE /v1/users/{user_id} endpoint with the correct user ID", + "Warns that the action is destructive and irreversible", + "Requires or recommends explicit confirmation before executing the delete", + "Includes CLERK_SECRET_KEY as Bearer token in the Authorization header", + "Mentions implications such as loss of user data, sessions, and associated records" + ] + }, + { + "id": 5, + "prompt": "i'm updating user metadata to add a 'plan' field but it keeps deleting the existing 'role' field. what am i doing wrong?", + "expected_output": "Metadata updates overwrite not merge. Read existing metadata first, spread it, then write back.", + "scaffold": "nextjs-basic-auth", + "expectations": [ + "Explains that updateUser publicMetadata replaces all existing metadata, not merges", + "Shows reading the existing user first with getUser(userId)", + "Spreads existing metadata before adding new fields ({ ...user.publicMetadata, plan: 'pro' })", + "Calls updateUser with the merged metadata object", + "Warns that this applies to publicMetadata, privateMetadata, and unsafeMetadata equally" + ] + }, + { + "id": 6, + "prompt": "my clerk backend api calls are failing with 429 errors in development. what are the rate limits?", + "expected_output": "Development has 100 req/10s limit (vs 1000/10s in production). Batch operations or reduce call frequency.", + "scaffold": "nextjs-basic-auth", + "expectations": [ + "States the development rate limit (100 requests per 10 seconds)", + "States the production rate limit (1000 requests per 10 seconds)", + "Suggests batching operations or reducing call frequency", + "Mentions that currentUser() counts as an API call against the limit", + "Recommends using auth() instead of currentUser() when only session claims are needed" + ] + } + ] +} diff --git a/.agents/skills/clerk-backend-api/scripts/api-specs-context.sh b/.agents/skills/clerk-backend-api/scripts/api-specs-context.sh new file mode 100644 index 0000000..7015d1b --- /dev/null +++ b/.agents/skills/clerk-backend-api/scripts/api-specs-context.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +# Fetches all available BAPI spec versions, determines the latest, +# and extracts tags from it. Output is used as skill context. + +set -euo pipefail + +API_URL="https://api.github.com/repos/clerk/openapi-specs/contents/bapi" +RAW_BASE="https://raw.githubusercontent.com/clerk/openapi-specs/main/bapi" + +# Fetch version list, parse dates, sort, pick latest +versions=$(curl -s "$API_URL" | node -e " + let d=''; + process.stdin.on('data',c=>d+=c); + process.stdin.on('end',()=>{ + const items = JSON.parse(d) + .map(i=>i.name) + .filter(n=>/^\d{4}-\d{2}-\d{2}\.yml$/.test(n)) + .sort(); + items.forEach(n=>console.log(n)); + }); +") + +latest=$(echo "$versions" | tail -1) + +echo "AVAILABLE VERSIONS: $(echo "$versions" | tr '\n' ' ')" +echo "LATEST VERSION: $latest" +echo "" +echo "TAGS:" +curl -s "${RAW_BASE}/${latest}" | node "$(dirname "$0")/extract-tags.js" diff --git a/.agents/skills/clerk-backend-api/scripts/execute-request.sh b/.agents/skills/clerk-backend-api/scripts/execute-request.sh new file mode 100644 index 0000000..26dcb43 --- /dev/null +++ b/.agents/skills/clerk-backend-api/scripts/execute-request.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash + +# Execute a Clerk Backend API request with scope enforcement. +# +# Usage: bash execute-request.sh [--admin] [BODY] +# +# Scope enforcement: +# GET — always allowed +# POST, PUT, PATCH — requires CLERK_BAPI_SCOPES="write" or --admin flag +# DELETE — requires CLERK_BAPI_SCOPES="write,delete" or --admin flag + +set -euo pipefail + +# Walk up from $PWD to find .env/.env.local (mirrors Clerk CLI behavior). +# Stops at the first directory that provides CLERK_SECRET_KEY. +_dir="$PWD" +while true; do + for _envfile in "$_dir/.env" "$_dir/.env.local"; do + if [[ -f "$_envfile" ]]; then + set -a + source "$_envfile" + set +a + fi + done + [[ -n "${CLERK_SECRET_KEY:-}" ]] && break + _parent="$(dirname "$_dir")" + [[ "$_parent" == "$_dir" ]] && break + _dir="$_parent" +done +unset _dir _parent _envfile + +# Parse --admin flag +ADMIN=false +if [[ "${1:-}" == "--admin" ]]; then + ADMIN=true + shift +fi + +METHOD="${1:?Usage: execute-request.sh [--admin] [BODY]}" +PATH_ARG="${2:?Usage: execute-request.sh [--admin] [BODY]}" +BODY="${3:-}" + +METHOD_UPPER=$(echo "$METHOD" | tr '[:lower:]' '[:upper:]') +SCOPES="${CLERK_BAPI_SCOPES:-}" + +# Scope check +if [[ "$ADMIN" == false ]]; then + case "$METHOD_UPPER" in + GET) + ;; # always allowed + POST|PUT|PATCH) + if [[ "$SCOPES" != *"write"* ]]; then + echo "ERROR: $METHOD_UPPER requests require CLERK_BAPI_SCOPES=\"write\" or --admin flag." >&2 + echo "Current CLERK_BAPI_SCOPES: \"$SCOPES\"" >&2 + exit 1 + fi + ;; + DELETE) + if [[ "$SCOPES" != *"write"* ]] || [[ "$SCOPES" != *"delete"* ]]; then + echo "ERROR: DELETE requests require CLERK_BAPI_SCOPES=\"write,delete\" or --admin flag." >&2 + echo "Current CLERK_BAPI_SCOPES: \"$SCOPES\"" >&2 + exit 1 + fi + ;; + *) + echo "ERROR: Unknown HTTP method: $METHOD_UPPER" >&2 + exit 1 + ;; + esac +fi + +# Base URL: use CLERK_REST_API_URL if set, otherwise default to production +BASE_URL="${CLERK_REST_API_URL:-https://api.clerk.com}" + +# Build curl command +CURL_ARGS=( + -s + -X "$METHOD_UPPER" + "${BASE_URL}/v1${PATH_ARG}" + -H "Authorization: Bearer ${CLERK_SECRET_KEY:?CLERK_SECRET_KEY is not set}" + -H "Content-Type: application/json" +) + +if [[ -n "$BODY" ]]; then + CURL_ARGS+=(-d "$BODY") +fi + +curl "${CURL_ARGS[@]}" diff --git a/.agents/skills/clerk-backend-api/scripts/extract-endpoint-detail.sh b/.agents/skills/clerk-backend-api/scripts/extract-endpoint-detail.sh new file mode 100644 index 0000000..19eb632 --- /dev/null +++ b/.agents/skills/clerk-backend-api/scripts/extract-endpoint-detail.sh @@ -0,0 +1,165 @@ +#!/usr/bin/env bash +# extract-endpoint-detail.sh +# +# Extracts full details for a specific endpoint from an OpenAPI YAML spec (stdin), +# including parameters, request body, responses, and all referenced component schemas. +# +# Usage: +# curl -s | bash extract-endpoint-detail.sh "/users/{user_id}/billing/subscription" "get" + +set -euo pipefail + +ENDPOINT="${1:?Usage: extract-endpoint-detail.sh }" +METHOD="${2:?Usage: extract-endpoint-detail.sh }" +TMPDIR_WORK=$(mktemp -d) +trap 'rm -rf "$TMPDIR_WORK"' EXIT + +SPEC="$TMPDIR_WORK/spec.yml" +cat > "$SPEC" + +node - "$ENDPOINT" "$METHOD" "$SPEC" <<'SCRIPT' +const fs = require("fs"); +const endpoint = process.argv[2]; +const method = process.argv[3].toLowerCase(); +const specFile = process.argv[4]; +const lines = fs.readFileSync(specFile, "utf8").split("\n"); + +const httpMethods = ["get", "post", "put", "patch", "delete", "options", "head"]; + +// Locate paths: and components: sections +let pathsStart = -1, pathsEnd = -1, componentsStart = -1; +for (let i = 0; i < lines.length; i++) { + if (/^paths:\s*$/.test(lines[i])) pathsStart = i; + else if (pathsStart >= 0 && pathsEnd < 0 && /^\S/.test(lines[i]) && i > pathsStart) pathsEnd = i; + if (/^components:\s*$/.test(lines[i])) componentsStart = i; +} +if (pathsEnd < 0) pathsEnd = lines.length; + +// Find the target path + method block +let targetStart = -1, targetEnd = -1; +let currentPath = null; + +for (let i = pathsStart + 1; i < pathsEnd; i++) { + const line = lines[i]; + + // Path line: exactly 2 spaces + / + if (/^ {2}\/\S/.test(line)) { + currentPath = line.trim().replace(/:$/, ""); + continue; + } + + // Method line: exactly 4 spaces + method name + const methodMatch = line.match(/^ {4}(\w+):\s*$/); + if (methodMatch && httpMethods.includes(methodMatch[1])) { + if (currentPath === endpoint && methodMatch[1] === method) { + targetStart = i; + // Find end of this method block + for (let j = i + 1; j < pathsEnd; j++) { + const nextLine = lines[j]; + // New method or new path + if (/^ {2}\/\S/.test(nextLine) || (/^ {4}\w+:\s*$/.test(nextLine) && httpMethods.some(m => nextLine.trim().startsWith(m + ":")))) { + targetEnd = j; + break; + } + } + if (targetEnd < 0) targetEnd = pathsEnd; + break; + } + } +} + +if (targetStart < 0) { + console.error(`Endpoint not found: ${method.toUpperCase()} ${endpoint}`); + process.exit(1); +} + +const blockLines = lines.slice(targetStart, targetEnd); + +// Collect all $refs from the block +const allRefs = new Set(); +for (const bl of blockLines) { + const refMatch = bl.match(/\$ref:\s*['"]?(#\/[^'"}\s]+)['"]?/); + if (refMatch) allRefs.add(refMatch[1]); +} + +// Resolve a $ref path to the raw YAML lines for that component +function resolveRef(ref) { + const parts = ref.replace("#/", "").split("/"); + // Find the component in the file by walking indentation + let searchStart = 0; + for (let p = 0; p < parts.length; p++) { + const indent = p * 2; + const target = " ".repeat(indent) + parts[p] + ":"; + let found = false; + for (let i = searchStart; i < lines.length; i++) { + if (lines[i].startsWith(target) && (lines[i] === target || lines[i][target.length] === " ")) { + searchStart = i + 1; + found = true; + break; + } + } + if (!found) return null; + } + + // Collect lines for this component (until same or lower indent) + const componentStart = searchStart - 1; + const baseIndent = parts.length * 2; + const result = []; + for (let i = searchStart; i < lines.length; i++) { + const line = lines[i]; + if (line.trim() === "") { result.push(line); continue; } + const lineIndent = line.length - line.trimStart().length; + if (lineIndent < baseIndent) break; + result.push(line); + } + return result; +} + +// Recursively resolve refs from component bodies +function collectDeepRefs(refSet, visited) { + const toProcess = [...refSet].filter(r => !visited.has(r)); + for (const ref of toProcess) { + visited.add(ref); + const body = resolveRef(ref); + if (!body) continue; + for (const bl of body) { + const refMatch = bl.match(/\$ref:\s*['"]?(#\/[^'"}\s]+)['"]?/); + if (refMatch && !visited.has(refMatch[1])) { + refSet.add(refMatch[1]); + } + } + } + // Recurse if new refs were found + const newRefs = [...refSet].filter(r => !visited.has(r)); + if (newRefs.length > 0) collectDeepRefs(refSet, visited); +} + +collectDeepRefs(allRefs, new Set()); + +// Output +console.log(`## \`${method.toUpperCase()}\` \`${endpoint}\`\n`); +console.log("### Endpoint Definition\n"); +console.log("```yaml"); +for (const bl of blockLines) { + console.log(bl); +} +console.log("```\n"); + +if (allRefs.size > 0) { + console.log(`### Referenced Components (${allRefs.size})\n`); + const sorted = [...allRefs].sort(); + for (const ref of sorted) { + const name = ref.split("/").pop(); + const category = ref.replace("#/", "").split("/").slice(0, -1).join("/"); + console.log(`#### \`${name}\` (${category})\n`); + const body = resolveRef(ref); + if (body) { + console.log("```yaml"); + for (const bl of body) console.log(bl); + console.log("```\n"); + } else { + console.log("_(could not resolve)_\n"); + } + } +} +SCRIPT diff --git a/.agents/skills/clerk-backend-api/scripts/extract-tag-endpoints.sh b/.agents/skills/clerk-backend-api/scripts/extract-tag-endpoints.sh new file mode 100644 index 0000000..5076498 --- /dev/null +++ b/.agents/skills/clerk-backend-api/scripts/extract-tag-endpoints.sh @@ -0,0 +1,208 @@ +#!/usr/bin/env bash +# extract-tag-endpoints.sh +# +# Extracts all endpoints for a given tag from an OpenAPI YAML spec (stdin), +# along with any $ref'd schemas/components. +# +# Usage: +# curl -s | bash extract-tag-endpoints.sh "Billing" + +set -euo pipefail + +TAG="${1:?Usage: extract-tag-endpoints.sh }" +TMPDIR_WORK=$(mktemp -d) +trap 'rm -rf "$TMPDIR_WORK"' EXIT + +SPEC="$TMPDIR_WORK/spec.yml" +cat > "$SPEC" + +# 1. Find all path+method blocks that have a matching tag +# Strategy: find line numbers of path entries (lines starting with " /"), +# then for each method block under that path, check if it contains the tag. + +node - "$TAG" "$SPEC" <<'SCRIPT' +const fs = require("fs"); +const tag = process.argv[2]; +const specFile = process.argv[3]; +const lines = fs.readFileSync(specFile, "utf8").split("\n"); + +const tagLower = tag.toLowerCase(); + +// Phase 1: Find all path definitions and their method blocks +// Paths start at indent 2 with " /" +// Methods start at indent 4 with " get:", " post:", etc. +const methods = ["get", "post", "put", "patch", "delete", "options", "head"]; +const endpoints = []; +const refs = new Set(); + +let currentPath = null; +let currentMethod = null; +let blockStart = -1; +let blockLines = []; +let inPaths = false; +let inComponents = false; + +// First pass: locate the "paths:" and "components:" top-level keys +let pathsStart = -1; +let pathsEnd = -1; +let componentsStart = -1; + +for (let i = 0; i < lines.length; i++) { + const line = lines[i]; + if (/^paths:\s*$/.test(line)) { + pathsStart = i; + } else if (pathsStart >= 0 && pathsEnd < 0 && /^\S/.test(line) && i > pathsStart) { + pathsEnd = i; + } + if (/^components:\s*$/.test(line)) { + componentsStart = i; + } +} +if (pathsEnd < 0) pathsEnd = lines.length; + +// Second pass: extract endpoints matching the tag +function flushBlock() { + if (!currentPath || !currentMethod || blockLines.length === 0) return; + + // Check if this block has the target tag + let inTags = false; + let hasTag = false; + const blockRefs = []; + + for (const bl of blockLines) { + const trimmed = bl.trim(); + + // Detect tags section + if (/^tags:\s*$/.test(trimmed)) { + inTags = true; + continue; + } + if (inTags) { + if (/^- /.test(trimmed)) { + const tagVal = trimmed.replace(/^- /, "").trim().replace(/^['"]|['"]$/g, ""); + if (tagVal.toLowerCase() === tagLower) hasTag = true; + } else { + inTags = false; + } + } + + // Collect $ref values + const refMatch = bl.match(/\$ref:\s*['"]?(#\/[^'"}\s]+)['"]?/); + if (refMatch) blockRefs.push(refMatch[1]); + } + + if (hasTag) { + // Extract summary, operationId, description + let summary = ""; + let operationId = ""; + let description = ""; + let params = []; + let inDesc = false; + let inParams = false; + + for (const bl of blockLines) { + const trimmed = bl.trim(); + const indent = bl.length - bl.trimStart().length; + + // Only capture operation-level keys (indent 6 = direct children of the method block) + if (indent === 6) { + const sumMatch = trimmed.match(/^summary:\s*(.+)/); + if (sumMatch) summary = sumMatch[1].replace(/^['"]|['"]$/g, ""); + + const opMatch = trimmed.match(/^operationId:\s*(.+)/); + if (opMatch) operationId = opMatch[1].replace(/^['"]|['"]$/g, ""); + + const descMatch = trimmed.match(/^description:\s*(.+)/); + if (descMatch && !inDesc) { + const val = descMatch[1].trim(); + if (val === "|-" || val === "|" || val === ">-" || val === ">") { + inDesc = true; + } else { + description = val.replace(/^['"]|['"]$/g, ""); + } + continue; + } + } + + if (inDesc) { + // Continuation lines of description — grab first non-empty line + if (!description && trimmed.length > 0) { + description = trimmed; + } + // Stop when we hit the next operation-level key + if (indent === 6 && trimmed.length > 0 && !/^description:/.test(trimmed)) { + inDesc = false; + } + } + } + + endpoints.push({ + method: currentMethod.toUpperCase(), + path: currentPath, + operationId, + summary, + description, + refs: blockRefs, + }); + + for (const r of blockRefs) refs.add(r); + } +} + +for (let i = pathsStart + 1; i < pathsEnd; i++) { + const line = lines[i]; + + // Path line: exactly 2 spaces + / + if (/^ {2}\/\S/.test(line)) { + flushBlock(); + currentPath = line.trim().replace(/:$/, ""); + currentMethod = null; + blockLines = []; + continue; + } + + // Method line: exactly 4 spaces + method name + const methodMatch = line.match(/^ {4}(\w+):\s*$/); + if (methodMatch && methods.includes(methodMatch[1])) { + flushBlock(); + currentMethod = methodMatch[1]; + blockLines = []; + continue; + } + + if (currentMethod) { + blockLines.push(line); + } +} +flushBlock(); + +// Output endpoints +if (endpoints.length === 0) { + console.error(`No endpoints found for tag: "${tag}"`); + process.exit(1); +} + +console.log(`## Endpoints for "${tag}" (${endpoints.length} total)\n`); +for (const ep of endpoints) { + console.log(`### \`${ep.method}\` \`${ep.path}\``); + if (ep.operationId) console.log(`- **operationId**: \`${ep.operationId}\``); + if (ep.summary) console.log(`- **summary**: ${ep.summary}`); + if (ep.description && ep.description !== ep.summary) + console.log(`- **description**: ${ep.description}`); + if (ep.refs.length > 0) { + console.log(`- **refs**: ${ep.refs.map(r => "\`" + r.split("/").pop() + "\`").join(", ")}`); + } + console.log(); +} + +// Output unique refs list +if (refs.size > 0) { + console.log(`## Referenced Components (${refs.size} unique)\n`); + const sorted = [...refs].sort(); + for (const r of sorted) { + const name = r.split("/").pop(); + const category = r.split("/").slice(0, -1).join("/").replace("#/", ""); + console.log(`- \`${name}\` (${category})`); + } +} +SCRIPT diff --git a/.agents/skills/clerk-backend-api/scripts/extract-tags.js b/.agents/skills/clerk-backend-api/scripts/extract-tags.js new file mode 100644 index 0000000..b1a4fb2 --- /dev/null +++ b/.agents/skills/clerk-backend-api/scripts/extract-tags.js @@ -0,0 +1,14 @@ +let input = ""; +process.stdin.on("data", d => input += d); +process.stdin.on("end", () => { + const lines = input.replace(/\r/g, "").split("\n"); + let inTags = false; + for (const line of lines) { + if (line === "tags:") { inTags = true; continue; } + if (inTags && line.length > 0 && line[0] !== " ") break; + if (inTags) { + const m = line.match(/^\s{2}- name:\s*(.+)/); + if (m) console.log(m[1]); + } + } +}); diff --git a/.agents/skills/clerk-custom-ui/SKILL.md b/.agents/skills/clerk-custom-ui/SKILL.md new file mode 100644 index 0000000..e6e05dc --- /dev/null +++ b/.agents/skills/clerk-custom-ui/SKILL.md @@ -0,0 +1,175 @@ +--- +name: clerk-custom-ui +description: Custom authentication flows and component appearance - hooks (useSignIn, + useSignUp), themes, colors, fonts, CSS. Use for custom sign-in/sign-up flows, appearance + styling, visual customization, branding. +allowed-tools: WebFetch +license: MIT +metadata: + author: clerk + version: 2.3.0 +--- + +# Custom UI + +> **Prerequisite**: Ensure `ClerkProvider` wraps your app. See `clerk-setup` skill. +> +> **Version**: Check `package.json` for the SDK version — see `clerk` skill for the version table. This determines which custom flow references to use below. + +This skill covers two areas: +1. **Custom authentication flows** — build your own sign-in/sign-up UI with hooks +2. **Appearance customization** — theme, style, and brand Clerk's pre-built components + +## What Do You Need? + +| Task | Reference | +|------|-----------| +| Custom sign-in (Core 2 / LTS) | core-2/custom-sign-in.md | +| Custom sign-up (Core 2 / LTS) | core-2/custom-sign-up.md | +| Custom sign-in (Current SDK v7+) | core-3/custom-sign-in.md | +| Custom sign-up (Current SDK v7+) | core-3/custom-sign-up.md | +| Show component pattern (Current SDK) | core-3/show-component.md | + +## Custom Flow References + +| Task | Core 2 | Current | +|------|--------|---------| +| Custom sign-in (useSignIn) | `core-2/custom-sign-in.md` | `core-3/custom-sign-in.md` | +| Custom sign-up (useSignUp) | `core-2/custom-sign-up.md` | `core-3/custom-sign-up.md` | +| `` component | *(use ``, ``, ``)* | `core-3/show-component.md` | + +--- + +## Appearance Customization + +Appearance customization applies to both Core 2 and the current SDK. + +### Component Customization Options + +| Task | Documentation | +|------|---------------| +| Appearance prop overview | https://clerk.com/docs/nextjs/guides/customizing-clerk/appearance-prop/overview | +| Options (structure, logo, buttons) | https://clerk.com/docs/nextjs/guides/customizing-clerk/appearance-prop/layout | +| Themes (pre-built dark/light) | https://clerk.com/docs/nextjs/guides/customizing-clerk/appearance-prop/themes | +| Variables (colors, fonts, spacing) | https://clerk.com/docs/nextjs/guides/customizing-clerk/appearance-prop/variables | +| CAPTCHA configuration | https://clerk.com/docs/nextjs/guides/customizing-clerk/appearance-prop/captcha | +| Bring your own CSS | https://clerk.com/docs/nextjs/guides/customizing-clerk/appearance-prop/bring-your-own-css | + +### Appearance Pattern + +```typescript + +``` + +> **Core 2 ONLY (skip if current SDK):** The `options` property was named `layout`. Use `layout: { logoImageUrl: '...', socialButtonsVariant: '...' }` instead of `options`. + +### variables (colors, typography, borders) + +| Property | Description | +|----------|-------------| +| `colorPrimary` | Primary color throughout | +| `colorBackground` | Background color | +| `borderRadius` | Border radius (default: `0.375rem`) | + +**Opacity change:** `colorRing` and `colorModalBackdrop` now render at full opacity. Use explicit `rgba()` values if you need transparency. + +> **Core 2 ONLY (skip if current SDK):** `colorRing` and `colorModalBackdrop` rendered at 15% opacity by default. + +### options (structure, logo, social buttons) + +| Property | Description | +|----------|-------------| +| `logoImageUrl` | URL to custom logo | +| `socialButtonsVariant` | `'blockButton'` \| `'iconButton'` \| `'auto'` | +| `socialButtonsPlacement` | `'top'` \| `'bottom'` | +| `showOptionalFields` | Show optional fields (default: `false`) | + +> **Core 2 ONLY (skip if current SDK):** This property is called `layout`, not `options`. Also, `showOptionalFields` defaulted to `true`. + +### Themes + +Install themes from `@clerk/ui`: + +```bash +npm install @clerk/ui +``` + +```typescript +import { dark } from '@clerk/ui/themes' + + +``` + +> **Core 2 ONLY (skip if current SDK):** Themes are imported from `@clerk/themes` (install `@clerk/themes` instead of `@clerk/ui`). Example: `import { dark } from '@clerk/themes'`. + +**Theme stacking** — pass an array where the last theme takes precedence: + +```typescript +import { dark, neobrutalism } from '@clerk/ui/themes' + + +``` + +**CSS `color-scheme` support** — the default theme respects the CSS `color-scheme` property for automatic light/dark mode toggling. + +**Available themes:** `dark`, `neobrutalism`, `shadcn`, `simple` + +#### shadcn Theme + +> **IMPORTANT:** If the project has `components.json` (shadcn/ui installed), ALWAYS apply the shadcn theme as the FIRST customization step. This ensures Clerk components visually match the existing shadcn design system. Skip this only if the user explicitly requests a different theme. + +**If the project uses shadcn/ui** (check for `components.json` in the project root), **always use the shadcn theme**: + +```typescript +import { shadcn } from '@clerk/ui/themes' + + +``` + +Also import shadcn CSS in your global styles: +```css +@import 'tailwindcss'; +@import '@clerk/ui/themes/shadcn.css'; +``` + +> **Core 2 ONLY (skip if current SDK):** Import from `@clerk/themes` and `@clerk/themes/shadcn.css`: +> ```typescript +> import { shadcn } from '@clerk/themes' +> ``` +> ```css +> @import '@clerk/themes/shadcn.css'; +> ``` + +## Workflow + +1. Identify customization needs (custom flow or appearance) +2. For custom flows: check SDK version → read appropriate `core-2/` or `core-3/` reference +3. For appearance: WebFetch the appropriate documentation from table above +4. Apply appearance prop to your Clerk components or build custom flow with hooks + +## Common Pitfalls + +| Issue | Solution | +|-------|----------| +| Colors not applying | Use `colorPrimary` not `primaryColor` | +| Logo not showing | Put `logoImageUrl` inside `options: {}` (or `layout: {}` in Core 2) | +| Social buttons wrong | Add `socialButtonsVariant: 'iconButton'` in `options` (or `layout` in Core 2) | +| Styling not working | Use appearance prop, not direct CSS (unless with bring-your-own-css) | +| Hook returns different shape | Check SDK version — Core 2 and current have completely different `useSignIn`/`useSignUp` APIs | + +## See Also + +- `clerk-setup` - Initial Clerk install +- `clerk-nextjs-patterns` - Next.js patterns +- `clerk-orgs` - B2B organizations diff --git a/.agents/skills/clerk-custom-ui/core-2/custom-sign-in.md b/.agents/skills/clerk-custom-ui/core-2/custom-sign-in.md new file mode 100644 index 0000000..28759de --- /dev/null +++ b/.agents/skills/clerk-custom-ui/core-2/custom-sign-in.md @@ -0,0 +1,224 @@ +# Custom Sign-In Flow (Core 2) + +> This document covers the **older SDK** (`@clerk/nextjs` v5–v6, `@clerk/clerk-react` v5–v6, `@clerk/clerk-expo` v1–v2). For the current SDK, see `core-3/custom-sign-in.md`. + +Build a custom sign-in experience using the `useSignIn()` hook. + +## Hook API + +```typescript +import { useSignIn } from '@clerk/nextjs' // or @clerk/clerk-react, @clerk/clerk-expo + +const { signIn, isLoaded, setActive } = useSignIn() +``` + +| Property | Type | Description | +|----------|------|-------------| +| `signIn` | `SignIn` | Sign-in object with methods | +| `isLoaded` | `boolean` | Whether the hook has loaded | +| `setActive` | `(params) => Promise` | Sets the active session | + +## Sign-In Flow + +### 1. Create Sign-In + +```typescript +const result = await signIn.create({ + identifier: 'user@example.com', + password: 'securePassword123', +}) +``` + +### 2. First Factor Verification + +If additional verification is needed (email code, phone code): + +```typescript +// Prepare first factor +await signIn.prepareFirstFactor({ + strategy: 'email_code', // or 'phone_code' +}) + +// Attempt first factor +const result = await signIn.attemptFirstFactor({ + strategy: 'email_code', + code: '123456', +}) +``` + +### 3. Second Factor (MFA) + +If the sign-in requires MFA: + +```typescript +// Prepare second factor +await signIn.prepareSecondFactor({ + strategy: 'email_code', // or 'phone_code' +}) + +// Attempt second factor +const result = await signIn.attemptSecondFactor({ + strategy: 'totp', // or 'email_code', 'phone_code', 'backup_code' + code: '123456', +}) +``` + +### 4. Finalize + +Set the active session after successful authentication: + +```typescript +await setActive({ session: signIn.createdSessionId }) +``` + +### Password Reset + +```typescript +// 1. Start reset flow +await signIn.create({ strategy: 'reset_password_email_code', identifier: 'user@example.com' }) + +// or prepare after initial create: +await signIn.prepareFirstFactor({ strategy: 'reset_password_email_code' }) + +// 2. Verify reset code +await signIn.attemptFirstFactor({ strategy: 'reset_password_email_code', code: '123456' }) + +// 3. Set new password +await signIn.resetPassword({ password: 'newSecurePassword123' }) +``` + +### SSO (OAuth) + +```typescript +await signIn.authenticateWithRedirect({ + strategy: 'oauth_google', // or 'oauth_github', etc. + redirectUrl: '/sso-callback', + redirectUrlComplete: '/', +}) +``` + +## Error Handling + +Use try/catch with `isClerkAPIResponseError()`: + +```typescript +import { isClerkAPIResponseError } from '@clerk/nextjs/errors' + +try { + await signIn.create({ identifier, password }) +} catch (err) { + if (isClerkAPIResponseError(err)) { + err.errors.forEach((e) => { + console.log(e.code) // e.g. 'form_identifier_not_found' + console.log(e.message) // Human-readable message + console.log(e.longMessage) // Detailed message + }) + } +} +``` + +## Complete Example: Email/Password with MFA + +```tsx +'use client' +import { useState } from 'react' +import { useSignIn } from '@clerk/nextjs' +import { isClerkAPIResponseError } from '@clerk/nextjs/errors' +import { useRouter } from 'next/navigation' + +export default function SignInPage() { + const { signIn, isLoaded, setActive } = useSignIn() + const router = useRouter() + + const [identifier, setIdentifier] = useState('') + const [password, setPassword] = useState('') + const [mfaCode, setMfaCode] = useState('') + const [step, setStep] = useState<'credentials' | 'mfa'>('credentials') + const [error, setError] = useState('') + + if (!isLoaded) return
Loading...
+ + async function handleSignIn(e: React.FormEvent) { + e.preventDefault() + setError('') + + try { + const result = await signIn.create({ identifier, password }) + + if (result.status === 'needs_second_factor') { + setStep('mfa') + return + } + + if (result.status === 'complete') { + await setActive({ session: result.createdSessionId }) + router.push('/') + } + } catch (err) { + if (isClerkAPIResponseError(err)) { + setError(err.errors[0]?.message || 'Sign in failed') + } + } + } + + async function handleMFA(e: React.FormEvent) { + e.preventDefault() + setError('') + + try { + const result = await signIn.attemptSecondFactor({ + strategy: 'totp', + code: mfaCode, + }) + + if (result.status === 'complete') { + await setActive({ session: result.createdSessionId }) + router.push('/') + } + } catch (err) { + if (isClerkAPIResponseError(err)) { + setError(err.errors[0]?.message || 'Verification failed') + } + } + } + + if (step === 'mfa') { + return ( +
+ setMfaCode(e.target.value)} + placeholder="Enter MFA code" + /> + {error &&

{error}

} + +
+ ) + } + + return ( +
+ setIdentifier(e.target.value)} + placeholder="Email" + /> + setPassword(e.target.value)} + placeholder="Password" + /> + {error &&

{error}

} + +
+ ) +} +``` + +## Docs + +- [Custom sign-in flow](https://clerk.com/docs/custom-flows/overview) +- [useSignIn() reference](https://clerk.com/docs/references/react/use-sign-in) diff --git a/.agents/skills/clerk-custom-ui/core-2/custom-sign-up.md b/.agents/skills/clerk-custom-ui/core-2/custom-sign-up.md new file mode 100644 index 0000000..574dbe7 --- /dev/null +++ b/.agents/skills/clerk-custom-ui/core-2/custom-sign-up.md @@ -0,0 +1,190 @@ +# Custom Sign-Up Flow (Core 2) + +> This document covers the **older SDK** (`@clerk/nextjs` v5–v6, `@clerk/clerk-react` v5–v6, `@clerk/clerk-expo` v1–v2). For the current SDK, see `core-3/custom-sign-up.md`. + +Build a custom sign-up experience using the `useSignUp()` hook. + +## Hook API + +```typescript +import { useSignUp } from '@clerk/nextjs' // or @clerk/clerk-react, @clerk/clerk-expo + +const { signUp, isLoaded, setActive } = useSignUp() +``` + +| Property | Type | Description | +|----------|------|-------------| +| `signUp` | `SignUp` | Sign-up object with methods | +| `isLoaded` | `boolean` | Whether the hook has loaded | +| `setActive` | `(params) => Promise` | Sets the active session | + +## Sign-Up Flow + +### 1. Create Sign-Up + +```typescript +const result = await signUp.create({ + emailAddress: 'user@example.com', + password: 'securePassword123', + firstName: 'Jane', // optional + lastName: 'Doe', // optional +}) +``` + +### 2. Prepare Verification + +Send a verification code to the user's email or phone: + +```typescript +await signUp.prepareVerification({ + strategy: 'email_code', // or 'phone_code', 'email_link' +}) +``` + +### 3. Attempt Verification + +Verify the code the user received: + +```typescript +const result = await signUp.attemptVerification({ + strategy: 'email_code', + code: '123456', +}) +``` + +### 4. Finalize + +Set the active session after successful sign-up: + +```typescript +await setActive({ session: signUp.createdSessionId }) +``` + +### SSO (OAuth) + +```typescript +await signUp.authenticateWithRedirect({ + strategy: 'oauth_google', + redirectUrl: '/sso-callback', + redirectUrlComplete: '/', +}) +``` + +## Error Handling + +Use try/catch with `isClerkAPIResponseError()`: + +```typescript +import { isClerkAPIResponseError } from '@clerk/nextjs/errors' + +try { + await signUp.create({ emailAddress, password }) +} catch (err) { + if (isClerkAPIResponseError(err)) { + err.errors.forEach((e) => { + console.log(e.code) // e.g. 'form_password_pwned' + console.log(e.message) // Human-readable message + console.log(e.longMessage) // Detailed message + }) + } +} +``` + +## Complete Example: Email/Password with Email Verification + +```tsx +'use client' +import { useState } from 'react' +import { useSignUp } from '@clerk/nextjs' +import { isClerkAPIResponseError } from '@clerk/nextjs/errors' +import { useRouter } from 'next/navigation' + +export default function SignUpPage() { + const { signUp, isLoaded, setActive } = useSignUp() + const router = useRouter() + + const [email, setEmail] = useState('') + const [password, setPassword] = useState('') + const [code, setCode] = useState('') + const [step, setStep] = useState<'register' | 'verify'>('register') + const [error, setError] = useState('') + + if (!isLoaded) return
Loading...
+ + async function handleRegister(e: React.FormEvent) { + e.preventDefault() + setError('') + + try { + await signUp.create({ emailAddress: email, password }) + await signUp.prepareVerification({ strategy: 'email_code' }) + setStep('verify') + } catch (err) { + if (isClerkAPIResponseError(err)) { + setError(err.errors[0]?.message || 'Sign up failed') + } + } + } + + async function handleVerify(e: React.FormEvent) { + e.preventDefault() + setError('') + + try { + const result = await signUp.attemptVerification({ + strategy: 'email_code', + code, + }) + + if (result.status === 'complete') { + await setActive({ session: result.createdSessionId }) + router.push('/') + } + } catch (err) { + if (isClerkAPIResponseError(err)) { + setError(err.errors[0]?.message || 'Verification failed') + } + } + } + + if (step === 'verify') { + return ( +
+

Check your email for a verification code.

+ setCode(e.target.value)} + placeholder="Verification code" + /> + {error &&

{error}

} + +
+ ) + } + + return ( +
+ setEmail(e.target.value)} + placeholder="Email" + /> + setPassword(e.target.value)} + placeholder="Password" + /> + {error &&

{error}

} + +
+ ) +} +``` + +## Docs + +- [Custom sign-up flow](https://clerk.com/docs/custom-flows/overview) +- [useSignUp() reference](https://clerk.com/docs/references/react/use-sign-up) diff --git a/.agents/skills/clerk-custom-ui/core-3/custom-sign-in.md b/.agents/skills/clerk-custom-ui/core-3/custom-sign-in.md new file mode 100644 index 0000000..50f13c2 --- /dev/null +++ b/.agents/skills/clerk-custom-ui/core-3/custom-sign-in.md @@ -0,0 +1,314 @@ +# Custom Sign-In Flow + +Build a custom sign-in experience using the `useSignIn()` hook. + +## Hook API + +```typescript +import { useSignIn } from '@clerk/nextjs' // or @clerk/react, @clerk/expo + +const { signIn, errors, fetchStatus } = useSignIn() +``` + +| Property | Type | Description | +|----------|------|-------------| +| `signIn` | `SignInFuture` | Sign-in object with namespaced methods | +| `errors` | `Errors` | Structured error object | +| `fetchStatus` | `'idle' \| 'fetching'` | Network request status | + +## Sign-In Methods + +### Password + +```typescript +const { error } = await signIn.password({ + identifier: 'user@example.com', + password: 'securePassword123', +}) +``` + +### SSO (OAuth / Enterprise) + +```typescript +const { error } = await signIn.sso({ + strategy: 'oauth_google', // or 'oauth_github', 'enterprise_sso', etc. + redirectUrl: '/dashboard', // where to go after SSO completes + redirectCallbackUrl: '/sso-callback', // intermediate callback route +}) +``` + +### Passkey + +```typescript +const { error } = await signIn.passkey({ flow: 'discoverable' }) +``` + +### Web3 + +```typescript +const { error } = await signIn.web3({ strategy: 'web3_solana_signature' }) +// or +const { error } = await signIn.web3({ strategy: 'web3_base_signature' }) +``` + +### Ticket (Invitation link) + +```typescript +const { error } = await signIn.ticket({ ticket: 'ticket_abc123' }) +``` + +### Email Code + +```typescript +// Send code (emailAddress is optional if a signIn already exists from a prior method call) +const { error } = await signIn.emailCode.sendCode({ emailAddress: 'user@example.com' }) + +// Verify code +const { error } = await signIn.emailCode.verifyCode({ code: '123456' }) +``` + +### Phone Code + +```typescript +// Send code (phoneNumber is optional if a signIn already exists from a prior method call) +const { error } = await signIn.phoneCode.sendCode({ phoneNumber: '+12015551234' }) + +// Verify code +const { error } = await signIn.phoneCode.verifyCode({ code: '123456' }) +``` + +## MFA (Second Factor) + +A second factor is required when `signIn.status` is one of: +- `'needs_second_factor'` — user has MFA enabled (TOTP, backup codes, etc.) +- `'needs_client_trust'` — new device sign-in without MFA; requires email or phone code verification + +```typescript +// TOTP (Authenticator app) +const { error } = await signIn.mfa.verifyTOTP({ code: '123456' }) + +// Backup code +const { error } = await signIn.mfa.verifyBackupCode({ code: 'backup-code-here' }) + +// Email code +const { error: sendErr } = await signIn.mfa.sendEmailCode() +const { error: verifyErr } = await signIn.mfa.verifyEmailCode({ code: '123456' }) + +// Phone code +const { error: sendErr } = await signIn.mfa.sendPhoneCode() +const { error: verifyErr } = await signIn.mfa.verifyPhoneCode({ code: '123456' }) +``` + +## Password Reset + +```typescript +// 1. Send reset code +const { error } = await signIn.resetPasswordEmailCode.sendCode() + +// 2. Verify the code +const { error } = await signIn.resetPasswordEmailCode.verifyCode({ code: '123456' }) + +// 3. Submit new password +const { error } = await signIn.resetPasswordEmailCode.submitPassword({ + password: 'newSecurePassword123', +}) +``` + +## Client Trust + +When a user signs in with a valid password from a new device without MFA enabled, the sign-in status becomes `needs_client_trust`. This requires an additional verification step: + +```typescript +if (signIn.status === 'needs_client_trust') { + // Check supportedSecondFactors for available methods (email_code or phone_code) + const factors = signIn.supportedSecondFactors + // Use the appropriate mfa method to verify +} +``` + +## Finalizing Sign-In + +After successful authentication, call `finalize()` to activate the session: + +```typescript +await signIn.finalize({ + navigate: async ({ session, decorateUrl }) => { + const destination = session.currentTask + ? `/sign-in/tasks/${session.currentTask.key}` + : '/' + const url = decorateUrl(destination) + // decorateUrl may return an absolute URL for Safari ITP + if (url.startsWith('http')) { + window.location.href = url + } else { + router.push(url) + } + }, +}) +``` + +- `decorateUrl(path)` — decorates the URL with session info (required to support Safari's Intelligent Tracking Prevention). May return an absolute URL. +- `session.currentTask` — check for pending session tasks before redirecting + +### Reset State + +Clear local sign-in state and start over: + +```typescript +signIn.reset() +``` + +## Error Handling + +All methods return `Promise<{ error: ClerkError | null }>`. Errors are also available reactively on the hook: + +```typescript +const { signIn, errors } = useSignIn() + +// Field-level errors +errors?.fields?.identifier // { code, message, longMessage? } +errors?.fields?.password // { code, message, longMessage? } +errors?.fields?.code // { code, message, longMessage? } + +// Global errors (not tied to a field) +errors?.global // ClerkGlobalHookError[] | null + +// Raw error array +errors?.raw // ClerkError[] | null +``` + +## Complete Example: Email/Password with MFA + +From [the docs](https://clerk.com/docs/guides/development/custom-flows/authentication/multi-factor-authentication). Supports SMS verification codes, authenticator app (TOTP), and backup codes. + +```tsx +'use client' + +import { useSignIn } from '@clerk/nextjs' +import { useRouter } from 'next/navigation' + +export default function Page() { + const { signIn, errors, fetchStatus } = useSignIn() + const router = useRouter() + + const handleSubmit = async (formData: FormData) => { + const emailAddress = formData.get('email') as string + const password = formData.get('password') as string + + await signIn.password({ + emailAddress, + password, + }) + + // If you're using the authenticator app strategy, remove this check. + if (signIn.status === 'needs_second_factor') { + await signIn.mfa.sendPhoneCode() + } + + if (signIn.status === 'complete') { + await signIn.finalize({ + navigate: ({ session, decorateUrl }) => { + if (session?.currentTask) { + // Handle pending session tasks + // See https://clerk.com/docs/guides/development/custom-flows/authentication/session-tasks + console.log(session?.currentTask) + return + } + + const url = decorateUrl('/') + if (url.startsWith('http')) { + window.location.href = url + } else { + router.push(url) + } + }, + }) + } + } + + const handleMFAVerification = async (formData: FormData) => { + const code = formData.get('code') as string + const useBackupCode = formData.get('useBackupCode') === 'on' + + if (useBackupCode) { + await signIn.mfa.verifyBackupCode({ code }) + } else { + await signIn.mfa.verifyPhoneCode({ code }) + // If you're using the authenticator app strategy, use the following method instead: + // await signIn.mfa.verifyTOTP({ code }) + } + + if (signIn.status === 'complete') { + await signIn.finalize({ + navigate: ({ session, decorateUrl }) => { + if (session?.currentTask) { + // Handle pending session tasks + // See https://clerk.com/docs/guides/development/custom-flows/authentication/session-tasks + console.log(session?.currentTask) + return + } + + const url = decorateUrl('/') + if (url.startsWith('http')) { + window.location.href = url + } else { + router.push(url) + } + }, + }) + } + } + + if (signIn.status === 'needs_second_factor') { + return ( +
+

Verify your account

+
+
+ + + {errors.fields.code &&

{errors.fields.code.message}

} +
+
+ +
+ +
+
+ ) + } + + return ( + <> +

Sign in

+
+
+ + + {errors.fields.identifier &&

{errors.fields.identifier.message}

} +
+
+ + + {errors.fields.password &&

{errors.fields.password.message}

} +
+ +
+ {errors &&

{JSON.stringify(errors, null, 2)}

} + + ) +} +``` + +## Docs + +- [Custom sign-in flow](https://clerk.com/docs/custom-flows/overview) +- [MFA custom flow](https://clerk.com/docs/guides/development/custom-flows/authentication/multi-factor-authentication) +- [useSignIn() reference](https://clerk.com/docs/references/react/use-sign-in) diff --git a/.agents/skills/clerk-custom-ui/core-3/custom-sign-up.md b/.agents/skills/clerk-custom-ui/core-3/custom-sign-up.md new file mode 100644 index 0000000..ac243ba --- /dev/null +++ b/.agents/skills/clerk-custom-ui/core-3/custom-sign-up.md @@ -0,0 +1,259 @@ +# Custom Sign-Up Flow + +Build a custom sign-up experience using the `useSignUp()` hook. + +## Hook API + +```typescript +import { useSignUp } from '@clerk/nextjs' // or @clerk/react, @clerk/expo + +const { signUp, errors, fetchStatus } = useSignUp() +``` + +| Property | Type | Description | +|----------|------|-------------| +| `signUp` | `SignUpFuture` | Sign-up object with namespaced methods | +| `errors` | `Errors` | Structured error object | +| `fetchStatus` | `'idle' \| 'fetching'` | Network request status | + +## Sign-Up Methods + +### Password (Email/Password) + +```typescript +const { error } = await signUp.password({ + emailAddress: 'user@example.com', + password: 'securePassword123', + firstName: 'Jane', // optional + lastName: 'Doe', // optional +}) +``` + +### SSO (OAuth) + +```typescript +const { error } = await signUp.sso({ + strategy: 'oauth_google', // or 'oauth_github', etc. + redirectUrl: '/dashboard', // where to go after SSO completes + redirectCallbackUrl: '/sso-callback', // intermediate callback route +}) +``` + +### Web3 + +```typescript +const { error } = await signUp.web3({ strategy: 'web3_solana_signature' }) +``` + +### Update (add fields to existing sign-up) + +Use `update()` to add optional fields (name, metadata, legal acceptance, locale) to an existing sign-up before finalization. + +```typescript +const { error } = await signUp.update({ + firstName: 'Jane', + lastName: 'Doe', + unsafeMetadata: { referralSource: 'twitter' }, + legalAccepted: true, +}) +``` + +## Email / Phone Verification + +After creating a sign-up, verify the user's email or phone: + +### Email Code + +```typescript +// Send verification code +const { error } = await signUp.verifications.sendEmailCode() + +// Verify the code +const { error } = await signUp.verifications.verifyEmailCode({ code: '123456' }) +``` + +### Phone Code + +```typescript +// Send verification code +const { error } = await signUp.verifications.sendPhoneCode() + +// Verify the code +const { error } = await signUp.verifications.verifyPhoneCode({ code: '123456' }) +``` + +### Email Link + +```typescript +// verificationUrl: where the user lands after clicking the email link (relative or absolute) +const { error } = await signUp.verifications.sendEmailLink({ verificationUrl: '/verify' }) +// User clicks the link in their email to verify +``` + +## Finalizing Sign-Up + +After successful sign-up and verification, call `finalize()` to activate the session: + +```typescript +await signUp.finalize({ + navigate: async ({ session, decorateUrl }) => { + const destination = session.currentTask + ? `/sign-up/tasks/${session.currentTask.key}` + : '/' + const url = decorateUrl(destination) + // decorateUrl may return an absolute URL for Safari ITP + if (url.startsWith('http')) { + window.location.href = url + } else { + router.push(url) + } + }, +}) +``` + +### Transferable Sign-Ups + +If `signUp.isTransferable` is `true`, the identifier matches an existing user and the sign-up should be transferred to a sign-in flow. This involves coordinating between sign-up and sign-in resources. See the [transferable sign-up docs](https://clerk.com/docs/custom-flows/overview) for the full implementation. + +### Reset State + +Clear local sign-up state and start over: + +```typescript +signUp.reset() +``` + +## Error Handling + +All methods return `Promise<{ error: ClerkError | null }>`. Errors are also available reactively on the hook: + +```typescript +const { signUp, errors } = useSignUp() + +// Field-level errors +errors?.fields?.emailAddress // { code, message, longMessage? } +errors?.fields?.password // { code, message, longMessage? } +errors?.fields?.firstName // { code, message, longMessage? } +errors?.fields?.lastName // { code, message, longMessage? } +errors?.fields?.phoneNumber // { code, message, longMessage? } +errors?.fields?.username // { code, message, longMessage? } +errors?.fields?.code // { code, message, longMessage? } + +// Global errors +errors?.global // ClerkGlobalHookError[] | null + +// Raw error array +errors?.raw // ClerkError[] | null +``` + +## Complete Example: Phone OTP Sign-Up + +From [the docs](https://clerk.com/docs/guides/development/custom-flows/authentication/email-sms-otp). Uses phone OTP with inline comments for adapting to email OTP. + +```tsx +'use client' + +import * as React from 'react' +import { useAuth, useSignUp } from '@clerk/nextjs' +import { useRouter } from 'next/navigation' + +export default function SignUpPage() { + const { signUp, errors, fetchStatus } = useSignUp() + const { isSignedIn } = useAuth() + const router = useRouter() + + const handleSubmit = async (formData: FormData) => { + // For email OTP: collect the email address instead of the phone number + const phoneNumber = formData.get('phoneNumber') as string + + // For email OTP: change create({ phoneNumber }) to create({ emailAddress }) + const error = await signUp.create({ phoneNumber }) + + // For email OTP: change sendPhoneCode() to sendEmailCode() + if (!error) await signUp.verifications.sendPhoneCode() + } + + const handleVerify = async (formData: FormData) => { + const code = formData.get('code') as string + + // For email OTP: change verifyPhoneCode() to verifyEmailCode() + await signUp.verifications.verifyPhoneCode({ code }) + + if (signUp.status === 'complete') { + await signUp.finalize({ + navigate: ({ session, decorateUrl }) => { + if (session?.currentTask) { + // Handle pending session tasks + // See https://clerk.com/docs/guides/development/custom-flows/authentication/session-tasks + console.log(session?.currentTask) + return + } + + const url = decorateUrl('/') + if (url.startsWith('http')) { + window.location.href = url + } else { + router.push(url) + } + }, + }) + } + } + + if (signUp.status === 'complete' || isSignedIn) { + return null + } + + if ( + signUp.status === 'missing_requirements' && + // For email OTP: check for phone_number instead of email_address + signUp.unverifiedFields.includes('phone_number') && + signUp.missingFields.length === 0 + ) { + return ( + <> +

Verify your account

+
+
+ + +
+ {errors.fields.code &&

{errors.fields.code.message}

} + +
+ {/* For email OTP: change sendPhoneCode() to sendEmailCode() */} + + + ) + } + + return ( + <> +

Sign up

+
+ {/* For email OTP: collect the emailAddress instead */} +
+ + + {errors.fields.phoneNumber &&

{errors.fields.phoneNumber.message}

} +
+ +
+ {errors &&

{JSON.stringify(errors, null, 2)}

} + + {/* Required for sign-up flows. Clerk's bot sign-up protection is enabled by default */} +
+ + ) +} +``` + +## Docs + +- [Custom sign-up flow](https://clerk.com/docs/custom-flows/overview) +- [Email/phone OTP custom flow](https://clerk.com/docs/guides/development/custom-flows/authentication/email-sms-otp) +- [useSignUp() reference](https://clerk.com/docs/references/react/use-sign-up) diff --git a/.agents/skills/clerk-custom-ui/core-3/show-component.md b/.agents/skills/clerk-custom-ui/core-3/show-component.md new file mode 100644 index 0000000..f01a8b4 --- /dev/null +++ b/.agents/skills/clerk-custom-ui/core-3/show-component.md @@ -0,0 +1,125 @@ +# `` Component + +The `` component conditionally renders content based on authentication state, roles, permissions, billing plans, and features. + +> **Core 2 ONLY (skip if current SDK):** The `` component does not exist in Core 2. Use ``, ``, and `` instead. See migration table below. + +## Import + +```typescript +import { Show } from '@clerk/nextjs' // Next.js +import { Show } from '@clerk/react' // React +import { Show } from '@clerk/react-router' // React Router +import { Show } from '@clerk/expo' // Expo +``` + +## Props + +| Prop | Type | Description | +|------|------|-------------| +| `when` | `string \| object \| function` | Condition for rendering children | +| `fallback?` | `ReactNode` | Content shown when condition fails | +| `treatPendingAsSignedOut?` | `boolean` | Treat pending sessions as signed-out (default: `true`) | + +## `when` Prop Variants + +### Authentication State + +```tsx +// Show content only when signed in + +

Welcome back!

+
+ +// Show content only when signed out + +

Please sign in.

+
+``` + +### Role Check + +```tsx + + + +``` + +### Permission Check + +```tsx + + + +``` + +### Billing Feature Check + +```tsx + + + +``` + +### Billing Plan Check + +```tsx + + + +``` + +### Custom Condition (Function) + +```tsx + has({ role: 'org:admin' }) || has({ permission: 'org:billing:manage' })}> + + +``` + +## Fallback Content + +Show alternative content when the condition fails: + +```tsx +Please sign in to continue.

}> + +
+``` + +## Session Tasks and Pending State + +The `treatPendingAsSignedOut` prop controls how pending sessions (sessions with incomplete tasks) are handled: + +```tsx +// Default: pending sessions are treated as signed-out + + + + +// Treat pending sessions as signed-in (e.g., to show task completion UI) + + + +``` + +## Security Caveat + +**`` only visually hides content** — it remains in browser source. It is not a security boundary. For protecting sensitive data, always verify authentication server-side with `auth()` or use `auth.protect()` in middleware. + +## Migration from Core 2 + +| Core 2 | Current | +|--------|---------| +| `` | `` | +| `` | `` | +| `` | `` | +| `` | `` | +| ` expr}>` | ` expr}>` | +| `` | `` | +| *(no equivalent)* | `` | +| *(no equivalent)* | `` | + +## Docs + +- [Show component reference](https://clerk.com/docs/components/control/show) diff --git a/.agents/skills/clerk-nextjs-patterns/SKILL.md b/.agents/skills/clerk-nextjs-patterns/SKILL.md new file mode 100644 index 0000000..cd9f161 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/SKILL.md @@ -0,0 +1,214 @@ +--- +name: clerk-nextjs-patterns +description: Advanced Next.js patterns - middleware, Server Actions, caching with + Clerk. +license: MIT +allowed-tools: WebFetch +metadata: + author: clerk + version: 2.2.0 +--- + +# Next.js Patterns + +> **Version**: Check `package.json` for the SDK version — see `clerk` skill for the version table. Core 2 differences are noted inline with `> **Core 2 ONLY (skip if current SDK):**` callouts. + +For basic setup, see `clerk-setup` skill. + +## What Do You Need? + +| Task | Reference | +|------|-----------| +| Server vs client auth (`auth()` vs hooks) | references/server-vs-client.md | +| Configure middleware (public-first vs protected-first) | references/middleware-strategies.md | +| Protect Server Actions | references/server-actions.md | +| API route auth (401 vs 403) | references/api-routes.md | +| Cache auth data (user-scoped caching) | references/caching-auth.md | + +## References + +| Reference | Description | +|-----------|-------------| +| `references/server-vs-client.md` | `await auth()` vs hooks | +| `references/middleware-strategies.md` | Public-first vs protected-first, `proxy.ts` (Next.js <=15: `middleware.ts`) | +| `references/server-actions.md` | Protect mutations | +| `references/api-routes.md` | 401 vs 403 | +| `references/caching-auth.md` | User-scoped caching | + +## Mental Model + +Server vs Client = different auth APIs: +- **Server**: `await auth()` from `@clerk/nextjs/server` (async!) +- **Client**: `useAuth()` hook from `@clerk/nextjs` (sync) + +Never mix them. Server Components use server imports, Client Components use hooks. + +Key properties from `auth()`: +- `isAuthenticated` — boolean, replaces the `!!userId` pattern +- `sessionStatus` — `'active'` | `'pending'`, for detecting incomplete session tasks +- `userId`, `orgId`, `orgSlug`, `has()`, `protect()` — unchanged + +> **Core 2 ONLY (skip if current SDK):** `isAuthenticated` and `sessionStatus` are not available. Check `!!userId` instead. + +## Minimal Pattern + +```typescript +// Server Component +import { auth } from '@clerk/nextjs/server' + +export default async function Page() { + const { isAuthenticated, userId } = await auth() // MUST await! + if (!isAuthenticated) return

Not signed in

+ return

Hello {userId}

+} +``` + +> **Core 2 ONLY (skip if current SDK):** `isAuthenticated` is not available. Use `if (!userId)` instead. + +### Conditional Rendering with `` + +For client-side conditional rendering based on auth state: + +```tsx +import { Show } from '@clerk/nextjs' + +Please sign in

}> + +
+``` + +> **Core 2 ONLY (skip if current SDK):** Use `` and `` components instead of ``. See `clerk-custom-ui` skill, `core-3/show-component.md` for the full migration table. + +## Common Pitfalls + +| Symptom | Cause | Fix | +|---------|-------|-----| +| `undefined` userId in Server Component | Missing `await` | `await auth()` not `auth()` | +| Auth not working on API routes | Missing matcher | Add `'/(api|trpc)(.*)'` to `proxy.ts` (Next.js <=15: `middleware.ts`) | +| Cache returns wrong user's data | Missing userId in key | Include `userId` in `unstable_cache` key | +| Mutations bypass auth | Unprotected Server Action | Check `auth()` at start of action | +| Wrong HTTP error code | Confused 401/403 | 401 = not signed in, 403 = no permission | + +## Session Tokens & Custom JWTs + +### getToken() for external APIs + +Pass a custom JWT to third-party services (Hasura, Supabase, etc.) using JWT templates defined in the Clerk dashboard. + +**Server-side (Server Component or Route Handler)**: + +```typescript +import { auth } from '@clerk/nextjs/server' + +export default async function Page() { + const { getToken } = await auth() + const token = await getToken({ template: 'hasura' }) + if (!token) return

Not authenticated

+ + const res = await fetch('https://api.example.com/graphql', { + headers: { Authorization: `Bearer ${token}` }, + }) + const data = await res.json() + return
{JSON.stringify(data)}
+} +``` + +**Client-side (Client Component)**: + +```typescript +'use client' +import { useAuth } from '@clerk/nextjs' + +export function DataFetcher() { + const { getToken } = useAuth() + + async function fetchData() { + const token = await getToken({ template: 'supabase' }) + if (!token) return + + const res = await fetch('https://api.example.com/data', { + headers: { Authorization: `Bearer ${token}` }, + }) + return res.json() + } + + return +} +``` + +`getToken()` returns `null` when the user is not authenticated — always null-check before use. + +### useSession() for session data + +Access session metadata in client components: + +```typescript +'use client' +import { useSession } from '@clerk/nextjs' + +export function SessionInfo() { + const { session } = useSession() + if (!session) return null + + return ( +

+ Session {session.id} — last active: {session.lastActiveAt.toISOString()} +

+ ) +} +``` + +### Manual JWT verification (no Clerk middleware) + +For standalone API servers that receive Clerk session tokens from the `Authorization` header or the `__session` cookie (same-origin). + +**Using `@clerk/backend` `verifyToken`** (recommended): + +```typescript +import { verifyToken } from '@clerk/backend' + +const token = req.headers.authorization?.replace('Bearer ', '') +if (!token) return res.status(401).json({ error: 'No token' }) + +try { + const claims = await verifyToken(token, { + jwtKey: process.env.CLERK_JWT_KEY, + }) + // claims.sub = userId +} catch { + return res.status(401).json({ error: 'Invalid token' }) +} +``` + +**Using `jsonwebtoken`** (when you can't use `@clerk/backend`): + +```typescript +import jwt from 'jsonwebtoken' + +const publicKey = process.env.CLERK_PEM_PUBLIC_KEY!.replace(/\\n/g, '\n') +const token = req.headers.authorization?.replace('Bearer ', '') +if (!token) return res.status(401).json({ error: 'No token' }) + +try { + const claims = jwt.verify(token, publicKey, { algorithms: ['RS256'] }) as jwt.JwtPayload + // Manually check exp and nbf (jsonwebtoken does this automatically, but verify azp if needed) + // claims.sub = userId +} catch { + return res.status(401).json({ error: 'Invalid or expired token' }) +} +``` + +Token sources: +- **Same-origin requests**: `__session` cookie (Clerk sets this automatically) +- **Cross-origin / mobile / API-to-API**: `Authorization: Bearer ` header + +> **CRITICAL**: Always check `exp` and `nbf` claims. `verifyToken` from `@clerk/backend` handles this automatically; with raw `jsonwebtoken`, set `ignoreExpiration: false` (default) and ensure `clockTolerance` is minimal. + +## See Also + +- `clerk-setup` +- `clerk-orgs` + +## Docs + +[Next.js SDK](https://clerk.com/docs/reference/nextjs/overview) diff --git a/.agents/skills/clerk-nextjs-patterns/evals/evals.json b/.agents/skills/clerk-nextjs-patterns/evals/evals.json new file mode 100644 index 0000000..f2f0cb9 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/evals/evals.json @@ -0,0 +1,82 @@ +{ + "skill_name": "clerk-nextjs-patterns", + "evals": [ + { + "id": 1, + "prompt": "my dashboard page uses useAuth and useUser hooks with useEffect for redirect. this causes a flash of unauthenticated content. convert it to a server component using auth() from @clerk/nextjs/server instead.", + "expected_output": "Converts dashboard from client component with hooks to server component with auth(), removes useEffect redirect pattern", + "scaffold": "nextjs-basic-auth", + "expectations": [ + "Removes 'use client' directive from dashboard page", + "Replaces useAuth/useUser hooks with auth() from @clerk/nextjs/server", + "Uses server-side redirect() from next/navigation instead of useEffect + router.push", + "Removes useEffect, useRouter, isLoaded checks", + "Page still displays user data (userId from auth or currentUser)" + ] + }, + { + "id": 2, + "prompt": "my api route at app/api/data/route.ts has no auth protection. anyone can access the data. add clerk auth to this api route so only authenticated users can get the data, and return 401 for unauthenticated requests.", + "expected_output": "Adds auth() check to API route, returns 401 for unauthenticated requests", + "scaffold": "nextjs-basic-auth", + "expectations": [ + "Imports auth from @clerk/nextjs/server", + "Calls auth() at the top of the GET handler", + "Returns 401 status when userId is null", + "Only returns data when user is authenticated", + "Does NOT use client-side hooks in the API route" + ] + }, + { + "id": 3, + "prompt": "my homepage is a client component that uses useUser to check if the user is signed in. convert it to use clerk's Show component pattern instead so it can be a server component with conditional rendering.", + "expected_output": "Converts home page to use SignedIn/SignedOut or Show components instead of useUser hook", + "scaffold": "nextjs-basic-auth", + "expectations": [ + "Removes 'use client' directive from home page", + "Removes useUser hook import and usage", + "Uses SignedIn/SignedOut components from @clerk/nextjs for conditional rendering", + "Preserves the same visual output (welcome message when signed in, sign-in prompt when not)", + "Page works as a server component" + ] + }, + { + "id": 4, + "prompt": "i need to protect all routes under /dashboard with clerk middleware instead of checking auth in each page component. update the middleware to use createRouteMatcher so only / and /sign-in are public.", + "expected_output": "Updates middleware.ts to use createRouteMatcher with public routes, protecting /dashboard and all sub-routes", + "scaffold": "nextjs-basic-auth", + "expectations": [ + "Imports createRouteMatcher from @clerk/nextjs/server", + "Defines public routes array including / and /sign-in", + "Uses auth.protect() for non-public routes inside clerkMiddleware callback", + "Middleware protects /dashboard, /profile, and /api routes", + "Does NOT remove the clerkMiddleware wrapper" + ] + }, + { + "id": 5, + "prompt": "i need to call an external API (Hasura GraphQL) from my Next.js server component. get a custom JWT using a template called 'hasura' and pass it in the Authorization header.", + "expected_output": "Uses getToken with template parameter from auth() server-side, passes as Bearer token to external API", + "scaffold": "nextjs-basic-auth", + "expectations": [ + "Uses getToken with a template parameter (e.g. 'hasura') to get a custom JWT", + "Uses either auth() server-side or useAuth() client-side to access getToken", + "Passes the token as Authorization Bearer header to the external API call", + "Handles the case where getToken returns null (user not authenticated)" + ] + }, + { + "id": 6, + "prompt": "i have a standalone Node.js API server that receives requests with a Clerk session token in the Authorization header. i need to verify the JWT signature and check if the user is authenticated. i don't want to use Clerk middleware, just manual verification.", + "expected_output": "Manually verifies Clerk JWT using jsonwebtoken or @clerk/backend verifyToken, checks claims", + "scaffold": "nextjs-basic-auth", + "expectations": [ + "Extracts the token from the Authorization Bearer header", + "Verifies the token using either jsonwebtoken with CLERK_PEM_PUBLIC_KEY or @clerk/backend verifyToken", + "Checks token expiration (exp claim) and not-before (nbf claim)", + "Returns 401 for invalid or expired tokens", + "Returns the decoded claims or user data on successful verification" + ] + } + ] +} diff --git a/.agents/skills/clerk-nextjs-patterns/references/api-routes.md b/.agents/skills/clerk-nextjs-patterns/references/api-routes.md new file mode 100644 index 0000000..e45bfa2 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/references/api-routes.md @@ -0,0 +1,50 @@ +# API Routes (HIGH) + +## Auth Check Pattern + +```typescript +import { auth } from '@clerk/nextjs/server'; + +export async function GET() { + const { isAuthenticated, userId } = await auth(); + if (!isAuthenticated) { + return Response.json({ error: 'Unauthorized' }, { status: 401 }); + } + const data = await db.data.findMany({ where: { userId } }); + return Response.json(data); +} +``` + +> **Core 2 ONLY (skip if current SDK):** `isAuthenticated` is not available. Use `if (!userId)` instead. + +## 401 vs 403 + +- **401** - Not authenticated +- **403** - Authenticated but lacks permission + +```typescript +export async function DELETE(req: Request) { + const { isAuthenticated, has } = await auth(); + if (!isAuthenticated) return Response.json({ error: 'Unauthorized' }, { status: 401 }); + + const isAdmin = await has({ role: 'org:admin' }); + if (!isAdmin) return Response.json({ error: 'Forbidden' }, { status: 403 }); + + return Response.json({ success: true }); +} +``` + +## Org Route Protection + +```typescript +export async function GET(req: Request, { params }: { params: { orgId: string } }) { + const { userId, orgId } = await auth(); + if (!userId) return Response.json({ error: 'Unauthorized' }, { status: 401 }); + if (orgId !== params.orgId) return Response.json({ error: 'Forbidden' }, { status: 403 }); + + const orgData = await db.orgs.findUnique({ where: { id: orgId } }); + return Response.json(orgData); +} +``` + +[Docs](https://clerk.com/docs/reference/nextjs/auth) diff --git a/.agents/skills/clerk-nextjs-patterns/references/caching-auth.md b/.agents/skills/clerk-nextjs-patterns/references/caching-auth.md new file mode 100644 index 0000000..d67ea44 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/references/caching-auth.md @@ -0,0 +1,56 @@ +# Caching with Auth (CRITICAL) + +**CRITICAL**: Cache keys MUST include userId/orgId to prevent data leaking between users. + +## User-Scoped Cache + +```typescript +import { auth } from '@clerk/nextjs/server'; +import { unstable_cache } from 'next/cache'; + +export default async function ProfilePage() { + const { userId } = await auth(); + if (!userId) return
Not signed in
; + + const cachedGetUserData = unstable_cache( + () => getUserData(userId), + [`user-${userId}`], + { revalidate: 60, tags: [`user-${userId}`] } + ); + + const userData = await cachedGetUserData(); + return
{userData.name}
; +} +``` + +## Revalidate After Updates + +```typescript +'use server'; +import { revalidateTag } from 'next/cache'; +import { auth } from '@clerk/nextjs/server'; + +export async function updateProfile(formData: FormData) { + const { userId } = await auth(); + if (!userId) throw new Error('Unauthorized'); + + await db.users.update({ + where: { id: userId }, + data: { name: formData.get('name') as string }, + }); + revalidateTag(`user-${userId}`); +} +``` + +## Org-Scoped Cache + +```typescript +const { orgId } = await auth(); +const getOrgData = unstable_cache( + () => db.orgData.findMany({ where: { organizationId: orgId } }), + [`org-${orgId}-data`], + { revalidate: 300, tags: [`org-${orgId}`] } +); +``` + +[Docs](https://nextjs.org/docs/app/building-your-application/caching) diff --git a/.agents/skills/clerk-nextjs-patterns/references/middleware-strategies.md b/.agents/skills/clerk-nextjs-patterns/references/middleware-strategies.md new file mode 100644 index 0000000..9ca7e91 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/references/middleware-strategies.md @@ -0,0 +1,68 @@ +# Middleware Strategies (HIGH) + +> **Filename:** `proxy.ts` (Next.js <=15: `middleware.ts`). The code is identical; only the filename changes. + +## Public-First (marketing sites, blogs) + +Protect specific routes, allow everything else: + +```typescript +import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'; + +const isProtectedRoute = createRouteMatcher([ + '/dashboard(.*)', + '/settings(.*)', + '/api/private(.*)', +]); + +export default clerkMiddleware(async (auth, req) => { + if (isProtectedRoute(req)) await auth.protect(); +}); + +export const config = { + matcher: [ + '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', + '/(api|trpc)(.*)', + ], +}; +``` + +## Protected-First (internal tools, dashboards) + +Block everything, allow specific public routes: + +```typescript +import { clerkMiddleware, createRouteMatcher } from '@clerk/nextjs/server'; + +const isPublicRoute = createRouteMatcher([ + '/', + '/sign-in(.*)', + '/sign-up(.*)', + '/api/public(.*)', +]); + +export default clerkMiddleware(async (auth, req) => { + if (!isPublicRoute(req)) await auth.protect(); +}); +``` + +## Session Tasks + +When session tasks are enabled (e.g., forced password reset, MFA setup), users may have a `pending` session status. You can handle this in middleware: + +```typescript +export default clerkMiddleware(async (auth, req) => { + const { sessionStatus } = await auth(); + + // Redirect pending sessions to task completion page + if (sessionStatus === 'pending') { + return NextResponse.redirect(new URL('/sign-in/tasks', req.url)); + } + + if (isProtectedRoute(req)) await auth.protect(); +}); +``` + +> **Core 2 ONLY (skip if current SDK):** `sessionStatus` is not available. Session tasks do not exist in Core 2. + +[Docs](https://clerk.com/docs/reference/nextjs/clerk-middleware) diff --git a/.agents/skills/clerk-nextjs-patterns/references/server-actions.md b/.agents/skills/clerk-nextjs-patterns/references/server-actions.md new file mode 100644 index 0000000..3c286f7 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/references/server-actions.md @@ -0,0 +1,56 @@ +# Server Actions (HIGH) + +Server Actions are public endpoints. Always verify auth. + +## Basic Protection + +```typescript +'use server'; +import { auth } from '@clerk/nextjs/server'; + +export async function createPost(formData: FormData) { + const { isAuthenticated, userId } = await auth(); + if (!isAuthenticated) throw new Error('Unauthorized'); + + const title = formData.get('title') as string; + await db.posts.create({ data: { title, authorId: userId } }); + revalidatePath('/posts'); +} +``` + +## Org + Role Check (B2B) + +```typescript +'use server'; +import { auth } from '@clerk/nextjs/server'; + +export async function createTeamProject(formData: FormData) { + const { userId, orgId, orgRole } = await auth(); + if (!userId || !orgId) throw new Error('Must be in an organization'); + if (orgRole !== 'org:admin') throw new Error('Only admins can create projects'); + + const name = formData.get('name') as string; + await db.projects.create({ data: { name, organizationId: orgId } }); +} +``` + +## Permission Check (RBAC) + +```typescript +'use server'; +import { auth } from '@clerk/nextjs/server'; + +export async function deleteProject(projectId: string) { + const { userId, has } = await auth(); + if (!userId) throw new Error('Unauthorized'); + + const canDelete = await has({ permission: 'org:project:delete' }); + if (!canDelete) throw new Error('Missing permission'); + + await db.projects.delete({ where: { id: projectId } }); +} +``` + +> **Core 2 ONLY (skip if current SDK):** `isAuthenticated` is not available. Use `if (!userId)` instead. + +[Docs](https://clerk.com/docs/reference/nextjs/server-actions) diff --git a/.agents/skills/clerk-nextjs-patterns/references/server-vs-client.md b/.agents/skills/clerk-nextjs-patterns/references/server-vs-client.md new file mode 100644 index 0000000..bf0e659 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/references/server-vs-client.md @@ -0,0 +1,104 @@ +# Server vs Client (CRITICAL) + +## CRITICAL: Always `await auth()` + +```tsx +// WRONG +const { userId } = auth(); // undefined! + +// CORRECT +const { userId } = await auth(); +``` + +## When to Use + +- **Server Components** - Initial load, SEO, DB queries +- **Client Components** - Interactive UI, sign out, token fetching + +## Import Rules + +```tsx +// Server Components +import { auth, currentUser } from '@clerk/nextjs/server'; + +// Client Components +'use client'; +import { useAuth, useUser } from '@clerk/nextjs'; +``` + +## Server Component + +```tsx +import { auth, currentUser } from '@clerk/nextjs/server'; + +export default async function DashboardPage() { + const { isAuthenticated } = await auth(); + if (!isAuthenticated) return
Please sign in
; + + const user = await currentUser(); + return

Welcome, {user?.firstName}!

; +} +``` + +> **Core 2 ONLY (skip if current SDK):** `isAuthenticated` is not available. Use `const { userId } = await auth()` and check `if (!userId)` instead. + +## Client Component + +```tsx +'use client'; +import { useUser, useAuth } from '@clerk/nextjs'; + +export function UserDashboard() { + const { isLoaded, isSignedIn, user } = useUser(); + const { signOut } = useAuth(); + + if (!isLoaded) return
Loading...
; + if (!isSignedIn) return
Not signed in
; + + return ( +
+

Hello, {user.firstName}!

+ +
+ ); +} +``` + +## Hybrid Pattern + +```tsx +// Server: fetch initial data +import { currentUser } from '@clerk/nextjs/server'; +import { ProfileForm } from './ProfileForm'; + +export default async function ProfilePage() { + const user = await currentUser(); + if (!user) return
Please sign in
; + return ; +} + +// Client: handle interactions +'use client'; +import { useUser } from '@clerk/nextjs'; + +export function ProfileForm({ initialData }) { + const { user } = useUser(); + return
...
; +} +``` + +## Conditional Rendering + +Use `` for client-side conditional rendering based on auth state: + +```tsx +import { Show } from '@clerk/nextjs'; + +Please sign in
}> + +
+``` + +> **Core 2 ONLY (skip if current SDK):** Use `` and `` components instead of ``. + +[Docs](https://clerk.com/docs/reference/nextjs/auth) diff --git a/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/app/layout.tsx b/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/app/layout.tsx new file mode 100644 index 0000000..aec51d9 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/app/layout.tsx @@ -0,0 +1,22 @@ +import { ClerkProvider, Show, SignInButton, SignUpButton, UserButton } from '@clerk/nextjs' + +export default function RootLayout({ children }: { children: React.ReactNode }) { + return ( + + + +
+ + + + + + + +
+ {children} +
+ + + ) +} diff --git a/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/app/page.tsx b/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/app/page.tsx new file mode 100644 index 0000000..3e62e69 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/app/page.tsx @@ -0,0 +1,3 @@ +export default function Home() { + return

Home

+} diff --git a/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/package.json b/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/package.json new file mode 100644 index 0000000..f8c6bf6 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/package.json @@ -0,0 +1,16 @@ +{ + "name": "clerk-nextjs", + "private": true, + "scripts": { "dev": "next dev", "build": "next build" }, + "dependencies": { + "next": "latest", + "react": "latest", + "react-dom": "latest", + "@clerk/nextjs": "latest" + }, + "devDependencies": { + "typescript": "latest", + "@types/react": "latest", + "@types/react-dom": "latest" + } +} diff --git a/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/proxy.ts b/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/proxy.ts new file mode 100644 index 0000000..cca0334 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/proxy.ts @@ -0,0 +1,10 @@ +import { clerkMiddleware } from '@clerk/nextjs/server' + +export default clerkMiddleware() + +export const config = { + matcher: [ + '/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)', + '/(api|trpc)(.*)', + ], +} diff --git a/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/tsconfig.json b/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/tsconfig.json new file mode 100644 index 0000000..b8cdcc7 --- /dev/null +++ b/.agents/skills/clerk-nextjs-patterns/templates/nextjs-basic-auth/tsconfig.json @@ -0,0 +1,23 @@ +{ + "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": "preserve", + "incremental": true, + "plugins": [{ "name": "next" }], + "paths": { + "@/*": ["./src/*"] + } + }, + "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"], + "exclude": ["node_modules"] +} diff --git a/.agents/skills/clerk-setup/SKILL.md b/.agents/skills/clerk-setup/SKILL.md new file mode 100644 index 0000000..1ad9d01 --- /dev/null +++ b/.agents/skills/clerk-setup/SKILL.md @@ -0,0 +1,266 @@ +--- +name: clerk-setup +description: Add Clerk authentication to any project by following the official quickstart + guides. +license: MIT +allowed-tools: WebFetch +metadata: + author: clerk + version: 2.3.0 +--- + +# Adding Clerk + +> **Version**: Check `package.json` for the SDK version — see `clerk` skill for the version table. Core 2 differences are noted inline with `> **Core 2 ONLY (skip if current SDK):**` callouts. + +This skill sets up Clerk for authentication by following the official quickstart documentation. + +## Quick Reference + +| Step | Action | +|------|--------| +| 1. Detect framework | Check `package.json` dependencies | +| 2. Fetch quickstart | Use WebFetch on the appropriate docs URL | +| 3. Follow instructions | Execute steps; create `proxy.ts` (Next.js <=15: `middleware.ts`) | +| 4. Get API keys | From [dashboard.clerk.com](https://dashboard.clerk.com/last-active?path=api-keys) | + +> If the project has `components.json` (shadcn/ui), apply the shadcn theme after setup. See `clerk-custom-ui` skill → shadcn Theme. + +## Framework Detection + +Check `package.json` to identify the framework: + +| Dependency | Framework | Quickstart URL | +|------------|-----------|----------------| +| `next` | Next.js | `https://clerk.com/docs/nextjs/getting-started/quickstart` | +| `@remix-run/react` | Remix | `https://clerk.com/docs/remix/getting-started/quickstart` | +| `astro` | Astro | `https://clerk.com/docs/astro/getting-started/quickstart` | +| `nuxt` | Nuxt | `https://clerk.com/docs/nuxt/getting-started/quickstart` | +| `react-router` | React Router | `https://clerk.com/docs/react-router/getting-started/quickstart` | +| `@tanstack/react-start` | TanStack Start | `https://clerk.com/docs/tanstack-react-start/getting-started/quickstart` | +| `react` (no framework) | React SPA | `https://clerk.com/docs/react/getting-started/quickstart` | +| `vue` | Vue | `https://clerk.com/docs/vue/getting-started/quickstart` | +| `express` | Express | `https://clerk.com/docs/expressjs/getting-started/quickstart` | +| `fastify` | Fastify | `https://clerk.com/docs/fastify/getting-started/quickstart` | +| `expo` | Expo | `https://clerk.com/docs/expo/getting-started/quickstart` | + +For other platforms: +- **Chrome Extension**: `https://clerk.com/docs/chrome-extension/getting-started/quickstart` +- **Android**: `https://clerk.com/docs/android/getting-started/quickstart` +- **iOS**: `https://clerk.com/docs/ios/getting-started/quickstart` +- **Vanilla JavaScript**: `https://clerk.com/docs/js-frontend/getting-started/quickstart` + +## Decision Tree + +``` +User Request: "Add Clerk" / "Add authentication" + │ + ├─ Read package.json + │ + ├─ Existing auth detected? + │ ├─ YES → Audit → Migration plan + │ └─ NO → Fresh install + │ + ├─ Identify framework → WebFetch quickstart → Follow instructions + │ └─ Next.js? → Create proxy.ts (Next.js <=15: middleware.ts) + │ + └─ components.json exists? → YES → Apply shadcn theme (see clerk-custom-ui) +``` + +## Setup Process + +### 1. Detect the Framework + +Read the project's `package.json` and match dependencies to the table above. + +### 2. Fetch the Quickstart Guide + +Use WebFetch to retrieve the official quickstart for the detected framework: + +``` +WebFetch: https://clerk.com/docs/{framework}/getting-started/quickstart +Prompt: "Extract the complete setup instructions including all code snippets, file paths, and configuration steps." +``` + +### 3. Follow the Instructions + +Execute each step from the quickstart guide: +- Install the required packages +- Set up environment variables +- Add the provider and proxy/middleware +- Create sign-in/sign-up routes if needed +- Test the integration + +> **Next.js:** Create `proxy.ts` (Next.js <=15: `middleware.ts`). See the `clerk-nextjs-patterns` skill for middleware strategies. + +> **shadcn/ui detected** (`components.json` exists): ALWAYS apply the shadcn theme. See `clerk-custom-ui` skill → shadcn Theme section. + +### 4. Get API Keys + +Two paths for development API keys: + +**Keyless (Automatic)** +- On first SDK initialization, Clerk auto-generates dev keys and shows "Claim your application" popover +- No manual key setup required—keys are created and injected automatically +- Simplest path for new projects + +**Manual (Dashboard)** +- Get keys from [dashboard.clerk.com](https://dashboard.clerk.com/last-active?path=api-keys) if Keyless doesn't trigger +- **Publishable Key**: Starts with `pk_test_` or `pk_live_` +- **Secret Key**: Starts with `sk_test_` or `sk_live_` +- Set as environment variables: `NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY` and `CLERK_SECRET_KEY` + +## Migrating from Another Auth Provider + +If the project already has authentication, create a migration plan before replacing it. + +### Detect Existing Auth + +Check `package.json` for existing auth libraries: +- `next-auth` / `@auth/core` → NextAuth/Auth.js +- `@supabase/supabase-js` → Supabase Auth +- `firebase` / `firebase-admin` → Firebase Auth +- `@aws-amplify/auth` → AWS Cognito +- `auth0` / `@auth0/nextjs-auth0` → Auth0 +- `passport` → Passport.js +- Custom JWT/session implementation + +### Migration Process + +1. **Audit current auth** - Identify all auth touchpoints: + - Sign-in/sign-up pages + - Session/token handling + - Protected routes and middleware + - User data storage (database tables, external IDs) + - OAuth providers configured + +2. **Create migration plan** - Consider: + - **User data export** - Export users and import via Clerk's Backend API + - **Password hashes** - Clerk can upgrade hashes to Bcrypt transparently + - **External IDs** - Store legacy user IDs as `external_id` in Clerk + - **Session handling** - Existing sessions will terminate on switch + +3. **Choose migration strategy**: + - **Big bang** - Switch all users at once (simpler, requires maintenance window) + - **Trickle migration** - Run both systems temporarily (lower risk, higher complexity) + +### Migration Reference + +- **Migration Overview**: https://clerk.com/docs/guides/development/migrating/overview + +## SDK Notes + +### Package Names + +| Package | Install | +|---------|---------| +| Next.js | `@clerk/nextjs` | +| React | `@clerk/react` | +| Expo | `@clerk/expo` | +| React Router | `@clerk/react-router` | +| TanStack Start | `@clerk/tanstack-react-start` | + +> **Core 2 ONLY (skip if current SDK):** React and Expo packages have different names: `@clerk/clerk-react` and `@clerk/clerk-expo` (with `clerk-` prefix). + +### ClerkProvider Placement (Next.js) + +`ClerkProvider` must be placed **inside ``**, not wrapping ``: + +```tsx +// root layout.tsx +export default function RootLayout({ children }) { + return ( + + + {children} + + + ) +} +``` + +> **Core 2 ONLY (skip if current SDK):** `ClerkProvider` can wrap `` directly. + +### Dynamic Rendering (Next.js) + +For dynamic rendering with auth data, use the `dynamic` prop: + +```tsx +{children} +``` + +### Node.js Requirement + +Requires **Node.js 20.9.0** or higher. + +> **Core 2 ONLY (skip if current SDK):** Minimum Node.js 18.17.0. + +### Themes Package + +Themes are installed from `@clerk/ui`: + +```bash +npm install @clerk/ui +``` + +> **Core 2 ONLY (skip if current SDK):** Themes are from `@clerk/themes` instead of `@clerk/ui`. + +### shadcn Theme + +If the project uses shadcn/ui (check for `components.json` in the project root), apply the shadcn theme so Clerk components match the app's design system: + +```bash +npm install @clerk/ui +``` + +```tsx +import { shadcn } from '@clerk/ui/themes' + +{children} +``` + +Also import the shadcn CSS in your global styles: +```css +@import 'tailwindcss'; +@import '@clerk/ui/themes/shadcn.css'; +``` + +> **Core 2 ONLY (skip if current SDK):** Import from `@clerk/themes` and `@clerk/themes/shadcn.css` instead. + +## Common Pitfalls + +| Level | Issue | Solution | +|-------|-------|----------| +| CRITICAL | Missing `await` on `auth()` | In Next.js 15+, `auth()` is async: `const { userId } = await auth()` | +| CRITICAL | Exposing `CLERK_SECRET_KEY` | Never use secret key in client code; only `NEXT_PUBLIC_*` keys are safe | +| HIGH | Missing middleware matcher | Include API routes: `matcher: ['/((?!.*\\..*|_next).*)', '/']` | +| HIGH | ClerkProvider placement | Must be inside `` in root layout (Core 2: could wrap ``) | +| HIGH | Auth routes not public | Allow `/sign-in`, `/sign-up` in middleware config | +| HIGH | Landing page requires auth | To keep "/" public, exclude it: `matcher: ['/((?!.*\\..*|_next|^/$).*)', '/api/(.*)']` | +| MEDIUM | Wrong import path | Server code uses `@clerk/nextjs/server`, client uses `@clerk/nextjs` | +| MEDIUM | Wrong package name | Use `@clerk/react` not `@clerk/clerk-react` (Core 2 naming) | + +## See Also + +- `clerk-custom-ui` - Custom sign-in/up components +- `clerk-nextjs-patterns` - Advanced Next.js patterns +- `clerk-react-patterns` - React SPA patterns +- `clerk-react-router-patterns` - React Router patterns +- `clerk-vue-patterns` - Vue patterns +- `clerk-nuxt-patterns` - Nuxt patterns +- `clerk-astro-patterns` - Astro patterns +- `clerk-tanstack-patterns` - TanStack Start patterns +- `clerk-expo-patterns` - Expo patterns +- `clerk-chrome-extension-patterns` - Chrome Extension patterns +- `clerk-orgs` - B2B multi-tenant organizations +- `clerk-webhooks` - Webhook → database sync +- `clerk-testing` - E2E testing setup +- `clerk-swift` - Native iOS auth +- `clerk-android` - Native Android auth +- `clerk-backend-api` - Backend REST API explorer + +## Documentation + +- **Quickstart Overview**: https://clerk.com/docs/getting-started/quickstart/overview +- **Migration Guide**: https://clerk.com/docs/guides/development/migrating/overview +- **Full Documentation**: https://clerk.com/docs diff --git a/.agents/skills/clerk-setup/evals/evals.json b/.agents/skills/clerk-setup/evals/evals.json new file mode 100644 index 0000000..c9bd338 --- /dev/null +++ b/.agents/skills/clerk-setup/evals/evals.json @@ -0,0 +1,74 @@ +{ + "skill_name": "clerk-setup", + "evals": [ + { + "id": 1, + "prompt": "hey i just created a new next.js app with create-next-app and i want to add auth. i heard clerk is good, can you set it up? im using the app router btw and tailwind. project is at ./my-saas-app", + "expected_output": "Installs @clerk/nextjs, wraps layout with ClerkProvider inside , creates middleware.ts with clerkMiddleware, sets up .env.local with publishable and secret keys, detects shadcn if present", + "files": [], + "expectations": [ + "Installs @clerk/nextjs via npm/pnpm/bun", + "Adds ClerkProvider to root layout.tsx inside tag, not wrapping ", + "Creates middleware.ts (or proxy.ts for Next.js 16+) with clerkMiddleware export", + "Creates or updates .env.local with NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY and CLERK_SECRET_KEY", + "Does NOT install @clerk/clerk-react or any non-Next.js Clerk package", + "Mentions getting API keys from dashboard.clerk.com or keyless dev mode" + ] + }, + { + "id": 2, + "prompt": "im building a rest api with express and typescript, no frontend. i need to protect some routes with authentication. can you add clerk? i want /api/public to be open and everything under /api/private/* to require auth", + "expected_output": "Installs @clerk/express, adds clerkMiddleware globally, uses requireAuth for protected routes, keeps public routes open", + "files": [], + "expectations": [ + "Installs @clerk/express (not @clerk/nextjs)", + "Adds clerkMiddleware() to the Express app", + "Shows how to protect /api/private/* routes with requireAuth or getAuth check", + "Leaves /api/public accessible without auth", + "Does NOT create React components, ClerkProvider, or any frontend code", + "Sets up CLERK_SECRET_KEY (and optionally CLERK_PUBLISHABLE_KEY) env vars" + ] + }, + { + "id": 3, + "prompt": "we have a next.js app thats been using next-auth with google and github oauth for about a year. we want to switch to clerk because next-auth sessions keep expiring randomly. theres about 2000 users in our postgres db. how do we migrate without losing everyone?", + "expected_output": "Migration plan: audit current NextAuth setup, export users via Clerk Backend API, handle OAuth provider mapping, plan session transition", + "files": [], + "expectations": [ + "Detects or acknowledges existing NextAuth/next-auth setup", + "Addresses user data migration (2000 users) - mentions Clerk Backend API import or trickle migration", + "Addresses OAuth provider continuity (Google and GitHub)", + "Mentions that existing sessions will terminate during switch", + "Suggests either big-bang or gradual migration strategy", + "Does NOT just install Clerk and ignore the existing auth system" + ] + }, + { + "id": 4, + "prompt": "setting up a react spa with vite for an internal tool at work. no ssr, no next.js. just plain react 19 + react-router. need login/logout. whats the quickest way to get clerk working?", + "expected_output": "Installs @clerk/react, wraps app with ClerkProvider, no middleware needed for SPA", + "files": [], + "expectations": [ + "Installs @clerk/react (not @clerk/nextjs or @clerk/clerk-react)", + "Wraps app root with ClerkProvider and passes publishableKey", + "Does NOT create middleware.ts or proxy.ts (not applicable to SPAs)", + "Does NOT reference Next.js-specific patterns like server components or auth()", + "Shows SignIn/SignUp components or redirect-based auth flow", + "Sets up NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY or VITE_CLERK_PUBLISHABLE_KEY env var" + ] + }, + { + "id": 5, + "prompt": "i have an astro site with some react islands, its mostly static but i want to add a members-only section. never used clerk before. using bun as my package manager", + "expected_output": "Installs @clerk/astro via bun, configures Astro integration, sets up protected routes for members-only section", + "files": [], + "expectations": [ + "Installs @clerk/astro using bun (not npm or pnpm)", + "Configures Clerk as an Astro integration in astro.config", + "Shows how to protect specific routes for the members-only section", + "Sets up environment variables for Clerk keys", + "Does NOT install @clerk/nextjs or create Next.js-specific files" + ] + } + ] +} diff --git a/.agents/skills/clerk/SKILL.md b/.agents/skills/clerk/SKILL.md new file mode 100644 index 0000000..568b521 --- /dev/null +++ b/.agents/skills/clerk/SKILL.md @@ -0,0 +1,154 @@ +--- +name: clerk +description: Clerk authentication router. Use when user asks about adding authentication, + setting up Clerk, custom sign-in flows, Swift or native iOS auth, native Android + auth, Next.js patterns, React patterns, Vue patterns, Nuxt patterns, Astro patterns, + TanStack Start patterns, Expo patterns, React Router patterns, Chrome Extension patterns, + organizations, billing, subscriptions, payments, pricing, plans, seat-based pricing, + feature entitlements, syncing users, or testing. Automatically routes to the specific + skill based on their task. +license: MIT +metadata: + version: 2.0.0 +--- + +# Clerk Skills Router + +## Version Detection + +Check `package.json` to determine the Clerk SDK version. This determines which patterns to use: + +| Package | Core 2 (LTS until Jan 2027) | Current | +|---------|----------------------------|---------| +| `@clerk/nextjs` | v5–v6 | v7+ | +| `@clerk/react` or `@clerk/clerk-react` | v5–v6 | v7+ | +| `@clerk/expo` or `@clerk/clerk-expo` | v1–v2 | v3+ | +| `@clerk/react-router` | v1–v2 | v3+ | +| `@clerk/tanstack-react-start` | < v0.26.0 | v0.26.0+ | + +**Default to current** if the version is unclear or the project is new. Core 2 packages use `@clerk/clerk-react` and `@clerk/clerk-expo` (with `clerk-` prefix); current packages use `@clerk/react` and `@clerk/expo`. + +All skills are written for the current SDK. When something differs in Core 2, it's noted inline with `> **Core 2 ONLY (skip if current SDK):**` callouts. The exception is `clerk-custom-ui`, which has separate `core-2/` and `core-3/` directories for custom flow hooks since those APIs are entirely different between versions. + +--- + +## By Task + +**Adding Clerk to your project** → Use `clerk-setup` +- Framework detection and quickstart +- Environment setup, API keys, Keyless flow +- Migration from other auth providers + +**Custom sign-in/sign-up UI** → Use `clerk-custom-ui` +- Custom authentication flows with `useSignIn` / `useSignUp` hooks +- Appearance and styling (themes, colors, layout) +- `` component for conditional rendering + +**Advanced Next.js patterns** → Use `clerk-nextjs-patterns` +- Server vs Client auth APIs +- Middleware strategies +- Server Actions, caching +- API route protection + +**React patterns** → Use `clerk-react-patterns` +- Hooks (`useAuth`, `useUser`, `useClerk`) +- Protected routes, auth guards +- Router integration + +**React Router patterns** → Use `clerk-react-router-patterns` +- Loaders & actions with auth +- Route protection +- SSR auth + +**Vue patterns** → Use `clerk-vue-patterns` +- Composables (`useAuth`, `useUser`, `useClerk`) +- Vue Router guards +- Pinia auth store integration + +**Nuxt patterns** → Use `clerk-nuxt-patterns` +- Server middleware auth +- SSR auth with composables +- Server API routes + +**Astro patterns** → Use `clerk-astro-patterns` +- SSR auth pages +- Island components with React +- Middleware & API routes + +**TanStack Start patterns** → Use `clerk-tanstack-patterns` +- Server functions with auth +- Route protection via loaders +- Vinxi server integration + +**Expo patterns** → Use `clerk-expo-patterns` +- Secure token storage +- OAuth deep linking +- Push notifications with auth + +**Chrome Extension patterns** → Use `clerk-chrome-extension-patterns` +- Background scripts auth +- Popup auth flows +- Content scripts with sync host + +**B2B / Organizations** → Use `clerk-orgs` +- Multi-tenant apps +- Organization slugs in URLs +- Roles, permissions, RBAC +- Member management + +**Billing & Subscriptions** → Use `clerk-billing` +- `` component +- Plan and feature gating with `has()` +- Seat-based B2B billing with organizations +- Subscription lifecycle webhooks +- Free trials, invoicing + +**Webhooks** → Use `clerk-webhooks` +- Real-time events +- Data syncing +- Notifications & integrations + +**E2E Testing** → Use `clerk-testing` +- Playwright/Cypress setup +- Auth flow testing +- Test utilities + +**Swift / native iOS auth** → Use `clerk-swift` +- Native iOS Swift and SwiftUI projects +- ClerkKit and ClerkKitUI implementation guidance +- Source-driven patterns from `clerk-ios` + +**Android / native mobile auth** → Use `clerk-android` +- Native Android Kotlin and Jetpack Compose projects +- `clerk-android-api` and `clerk-android-ui` implementation guidance +- Source-driven patterns from `clerk-android` +- Do not use for Expo or React Native projects + +**Backend REST API** → Use `clerk-backend-api` +- Browse API tags and endpoints +- Inspect endpoint schemas +- Execute API requests with scope enforcement + +## Quick Navigation + +If you know your task, you can directly access: +- `/clerk-setup` - Framework setup +- `/clerk-custom-ui` - Custom flows & appearance +- `/clerk-nextjs-patterns` - Next.js patterns +- `/clerk-react-patterns` - React patterns +- `/clerk-react-router-patterns` - React Router patterns +- `/clerk-vue-patterns` - Vue patterns +- `/clerk-nuxt-patterns` - Nuxt patterns +- `/clerk-astro-patterns` - Astro patterns +- `/clerk-tanstack-patterns` - TanStack Start patterns +- `/clerk-expo-patterns` - Expo patterns +- `/clerk-chrome-extension-patterns` - Chrome Extension patterns +- `/clerk-orgs` - Organizations +- `/clerk-billing` - Billing & subscriptions +- `/clerk-webhooks` - Webhooks +- `/clerk-testing` - Testing +- `/clerk-swift` - Swift/native iOS +- `/clerk-android` - Native Android +- `/clerk-backend-api` - Backend REST API + +Or describe what you need and I'll recommend the right one. diff --git a/.gitignore b/.gitignore index 5ef6a52..20ac9d9 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,7 @@ !.yarn/plugins !.yarn/releases !.yarn/versions +/context/current-issues.md # testing /coverage diff --git a/app/editor/layout.tsx b/app/editor/layout.tsx new file mode 100644 index 0000000..57821e6 --- /dev/null +++ b/app/editor/layout.tsx @@ -0,0 +1,9 @@ +import { EditorLayout } from "@/components/editor/editor-layout" + +export default function ProtectedEditorLayout({ + children, +}: Readonly<{ + children: React.ReactNode +}>) { + return {children} +} diff --git a/app/editor/page.tsx b/app/editor/page.tsx new file mode 100644 index 0000000..3465017 --- /dev/null +++ b/app/editor/page.tsx @@ -0,0 +1,7 @@ +export default function EditorPage() { + return ( +
+

Ghost AI

+
+ ) +} diff --git a/app/layout.tsx b/app/layout.tsx index 1bef101..15a4af1 100644 --- a/app/layout.tsx +++ b/app/layout.tsx @@ -1,6 +1,7 @@ +import { ClerkProvider } from "@clerk/nextjs"; +import { dark } from "@clerk/ui/themes"; import type { Metadata } from "next"; import { Geist, Geist_Mono } from "next/font/google"; -import { EditorLayout } from "@/components/editor/editor-layout"; import "./globals.css"; const geistSans = Geist({ @@ -14,8 +15,29 @@ const geistMono = Geist_Mono({ }); export const metadata: Metadata = { - title: "Create Next App", - description: "Generated by create next app", + title: "Ghost AI", + description: "AI workflow editor", +}; + +const clerkAppearance = { + theme: dark, + variables: { + colorPrimary: "var(--primary)", + colorPrimaryForeground: "var(--primary-foreground)", + colorBackground: "var(--popover)", + colorForeground: "var(--popover-foreground)", + colorMuted: "var(--muted)", + colorMutedForeground: "var(--muted-foreground)", + colorInput: "var(--input)", + colorInputForeground: "var(--foreground)", + colorBorder: "var(--border)", + colorModalBackdrop: "transparent", + colorRing: "var(--ring)", + colorDanger: "var(--destructive)", + fontFamily: "var(--font-geist-sans)", + fontFamilyButtons: "var(--font-geist-sans)", + borderRadius: "var(--radius)", + }, }; export default function RootLayout({ @@ -29,7 +51,19 @@ export default function RootLayout({ className={`${geistSans.variable} ${geistMono.variable} dark h-full antialiased`} > - {children} + + {children} + ); diff --git a/app/page.tsx b/app/page.tsx index c112497..c91c86b 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -1,7 +1,9 @@ -export default function Home() { - return ( -
-

Ghost AI

-
- ); +import { auth } from "@clerk/nextjs/server"; +import { redirect } from "next/navigation"; + +export default async function Home() { + const { userId } = await auth(); + const signInUrl = process.env.NEXT_PUBLIC_CLERK_SIGN_IN_URL ?? "/sign-in"; + + redirect(userId ? "/editor" : signInUrl); } diff --git a/app/sign-in/[[...sign-in]]/page.tsx b/app/sign-in/[[...sign-in]]/page.tsx new file mode 100644 index 0000000..a2fddb8 --- /dev/null +++ b/app/sign-in/[[...sign-in]]/page.tsx @@ -0,0 +1,19 @@ +import { SignIn } from "@clerk/nextjs" + +import { AuthPageShell } from "@/components/auth/auth-page-shell" + +export default function SignInPage() { + return ( + + + + ) +} diff --git a/app/sign-up/[[...sign-up]]/page.tsx b/app/sign-up/[[...sign-up]]/page.tsx new file mode 100644 index 0000000..6946258 --- /dev/null +++ b/app/sign-up/[[...sign-up]]/page.tsx @@ -0,0 +1,19 @@ +import { SignUp } from "@clerk/nextjs" + +import { AuthPageShell } from "@/components/auth/auth-page-shell" + +export default function SignUpPage() { + return ( + + + + ) +} diff --git a/components/auth/auth-page-shell.tsx b/components/auth/auth-page-shell.tsx new file mode 100644 index 0000000..55b886c --- /dev/null +++ b/components/auth/auth-page-shell.tsx @@ -0,0 +1,43 @@ +type AuthPageShellProps = { + title: string + tagline: string + children: React.ReactNode +} + +const authFeatures = [ + "Protected workflow editing", + "Project access tied to your account", + "Profile and logout handled securely", +] + +function AuthPageShell({ title, tagline, children }: AuthPageShellProps) { + return ( +
+
+
+
+

Ghost AI

+

+ {tagline} +

+
+ +
+

{title}

+
    + {authFeatures.map((feature) => ( +
  • {feature}
  • + ))} +
+
+
+
+ +
+ {children} +
+
+ ) +} + +export { AuthPageShell } diff --git a/components/editor/editor-navbar.tsx b/components/editor/editor-navbar.tsx index 14ffeaf..bca4572 100644 --- a/components/editor/editor-navbar.tsx +++ b/components/editor/editor-navbar.tsx @@ -1,5 +1,6 @@ "use client" +import { UserButton } from "@clerk/nextjs" import { PanelLeftClose, PanelLeftOpen } from "lucide-react" import { Button } from "@/components/ui/button" @@ -40,7 +41,9 @@ function EditorNavbar({
-
+
+ +
) } diff --git a/context/architecture.md b/context/architecture.md index 02d6772..5bd2cab 100644 --- a/context/architecture.md +++ b/context/architecture.md @@ -2,20 +2,21 @@ ## Stack -| Layer | Technology | Role | -| --------- | --------------------------- | ------ | -| Framework | [e.g. Next.js + TypeScript] | [Role] | -| UI | [e.g. Tailwind + shadcn/ui] | [Role] | -| Auth | [e.g. Clerk] | [Role] | -| Database | [e.g. Prisma + PostgreSQL] | [Role] | -| [Layer] | [Technology] | [Role] | +| Layer | Technology | Role | +| --------- | -------------------------- | ------------------------------------ | +| Framework | Next.js 16 + TypeScript | App Router, layouts, pages, proxy | +| UI | Tailwind CSS + shadcn/ui | Dark themed application components | +| Auth | Clerk + `@clerk/ui` themes | Authentication, route protection, UI | ## System Boundaries -- `[folder]` — [What this folder owns and is responsible for] -- `[folder]` — [What this folder owns and is responsible for] -- `[folder]` — [What this folder owns and is responsible for] -- `[folder]` — [What this folder owns and is responsible for] +- `app/` — Next.js routes and route-specific layouts. +- `app/sign-in/` and `app/sign-up/` — public Clerk auth pages. +- `app/editor/` — protected editor route tree wrapped by the editor chrome. +- `components/editor/` — reusable editor navbar, sidebar, and editor layout shell. +- `components/auth/` — reusable auth page presentation shell. +- `components/ui/` — generated shadcn/ui primitives. +- `proxy.ts` — root-level Clerk route protection for all matched requests. ## Storage Model @@ -26,17 +27,15 @@ ## Auth and Access Model -- [How authentication works — e.g. Every user signs in - via Clerk] -- [How ownership works — e.g. Every project has a single - owner] -- [How access control works — e.g. Only the owner or a - collaborator can mutate project resources] +- Clerk provides authentication through `ClerkProvider` in the root layout. +- `/sign-in`, `/sign-up`, and `/` are public entry routes; `/` only redirects users based on auth state. +- All other matched routes are protected by Clerk in `proxy.ts` by default. +- Authenticated users are redirected from `/` to `/editor`; unauthenticated users are redirected to `/sign-in`. +- The editor chrome exposes Clerk's default `UserButton` for profile settings and logout. ## Invariants -1. [Rule the codebase must never violate — e.g. Request - handlers do not run long-lived background work] -2. [Invariant two] -3. [Invariant three] -4. [Invariant four] +1. Use `proxy.ts` for request protection; do not add `middleware.ts`. +2. Keep Clerk auth UI on Clerk components and avoid rebuilding Clerk internals. +3. Keep the editor shell under protected editor routes, not around public auth pages. +4. Use existing Clerk environment variable names for auth URLs and keys. diff --git a/context/current-issues.md b/context/current-issues.md new file mode 100644 index 0000000..e69de29 diff --git a/context/feature-spec/03-auth.md b/context/feature-spec/03-auth.md new file mode 100644 index 0000000..a94fb7a --- /dev/null +++ b/context/feature-spec/03-auth.md @@ -0,0 +1,53 @@ +Clerk is already installed and connected. Wire it into the Next.js app: provider, auth pages, redirects, route protection, and user menu. + +## Design + +Use Clerk's `dark` theme from `@clerk/ui/themes` as the base. + +Override Clerk appearance variables using the app's existing CSS variables. Don't hardcode colors. + +### Sign-in and sign-up pages: + +- Large screens: Simple "two" "panel" layout +- left: compact logo, tagline, short text-only feature list +- right: centered Clerk form +- small screens: form only +- no gradients +- no oversized hero sections +- no feature cards +- no scroll-heavy layouts + +Keep the layout minimal and professional. + +## Implementation + +wrap the root layout with `ClerkProvider` using Clerk's `dark` theme. + +Create sign-in and sign-up pages using Clerk components. + +Use `proxy.ts` at the project root, not `middleware.ts`. + +Define public routes using the existing sign-in and sign-up env vars. Protect everything else by default. + +Update `/`: + +- authenticated users redirect to `/editor` +- unauthenticated users redirect to `/sign-in` + +Add Clerk's built-in `UserButton` to the editor navbar right section for profile settings and logout. + +Keep Clerk's default user menu and profile flows intact. Don't rebuild or heavily customize Clerk internals. + +Use existing Clerk env vars. Don't rename or invent new ones. + +## Dependencies + +install: @clerk/ui. + +## Check When Done + +- `proxy.ts` exists at the root +- all routes are protected except public auth paths +- auth pages use CSS variables with no hardcoded colors +- `ClerkProvider` wraps the root layout +- `npm run build` passes \ No newline at end of file diff --git a/context/progress-tracker.md b/context/progress-tracker.md index 9c13a8b..2b4cbec 100644 --- a/context/progress-tracker.md +++ b/context/progress-tracker.md @@ -9,7 +9,7 @@ change. ## Current Goal -- Editor shell foundation from `context/feature-spec/02-editor.md` +- Clerk authentication from `context/feature-spec/03-auth.md` ## Completed @@ -28,6 +28,20 @@ change. - Wrapped application content with `EditorLayout` in `app/layout.tsx`. - Adjusted `app/page.tsx` to fill the editor canvas area beneath the navbar. - Verified `npm run lint` and `npm run build` pass after layout integration. +- Marked auth feature as in progress. +- Installed `@clerk/ui` for Clerk's dark theme support. +- Wrapped the root layout in `ClerkProvider` using Clerk's `dark` theme and app CSS variable appearance overrides. +- Moved editor chrome into `app/editor/layout.tsx` so public auth pages stay minimal. +- Added `/sign-in` and `/sign-up` Clerk pages with responsive two-panel desktop layouts and form-only small screens. +- Added root `proxy.ts` with Clerk route protection for all matched routes except `/`, sign-in, and sign-up. +- Updated `/` to redirect authenticated users to `/editor` and unauthenticated users to `/sign-in`. +- Added protected `/editor` route content. +- Added Clerk `UserButton` to the editor navbar right section. +- Updated `context/architecture.md` with the Clerk auth boundary, route protection model, and invariants. +- Verified `npm run lint` and `npm run build` pass after auth implementation. +- Fixed Clerk account modal backdrop so the editor background remains visually unchanged when profile/account windows open. +- Added explicit Clerk sign-out redirects to `/sign-in` to avoid protected editor-route rendering stalls after logout. +- Verified `npm run lint` and `npm run build` pass after the current issue fixes. ## In Progress @@ -57,3 +71,10 @@ change. - The sidebar is fixed-position and inert while closed, so it floats over the future canvas, slides from the left, and does not push page content. - The dialog pattern is ready through `components/ui/dialog.tsx`; no actual editor dialog was built for this feature. - `EditorLayout` is the client boundary for editor shell state; `app/layout.tsx` remains a server component and continues exporting metadata. +- Started auth implementation by reading `03-auth.md` and marking Clerk auth tasks in progress. +- Installed `@clerk/ui` as required by the auth spec. +- `ClerkProvider` uses `appearance={{ theme: dark, variables: ... }}` with existing CSS variables only. +- The root route is intentionally public so it can perform the specified auth-state redirect; protected application content begins at `/editor`. +- `proxy.ts` is used instead of `middleware.ts` to match Next.js 16 conventions and the auth spec. +- Clerk's default modal backdrop was washing out the editor; setting `colorModalBackdrop` to transparent keeps Clerk internals intact while preserving the canvas color. +- Clerk sign-out now has explicit `afterSignOutUrl` and `afterMultiSessionSingleSignOutUrl` values pointing at the public sign-in route. diff --git a/package-lock.json b/package-lock.json index db9de5d..0b0e55e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,8 @@ "name": "ghost", "version": "0.1.0", "dependencies": { + "@clerk/nextjs": "^7.3.0", + "@clerk/ui": "^1.7.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.14.0", @@ -403,6 +405,15 @@ "@babel/core": "^7.0.0-0" } }, + "node_modules/@babel/runtime": { + "version": "7.29.2", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.2.tgz", + "integrity": "sha512-JiDShH45zKHWyGe4ZNVRrCjBz8Nh9TMmZG1kh4QTK8hCBTWBi8Da+i7s1fJw7/lYpM4ccepSNfqzZ/QvABBi5g==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/template": { "version": "7.28.6", "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.28.6.tgz", @@ -448,6 +459,145 @@ "node": ">=6.9.0" } }, + "node_modules/@clerk/backend": { + "version": "3.4.4", + "resolved": "https://registry.npmjs.org/@clerk/backend/-/backend-3.4.4.tgz", + "integrity": "sha512-EGdpxBG1joIYzRBtpzTq2FGyM2ErSSF2UB7FZXrHiSb6V/uRUcvVcX7IWvYeEyg1AG100gJWr0KpbutajVCLMA==", + "license": "MIT", + "dependencies": { + "@clerk/shared": "^4.9.0", + "standardwebhooks": "^1.0.0", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.9.0" + } + }, + "node_modules/@clerk/localizations": { + "version": "4.5.8", + "resolved": "https://registry.npmjs.org/@clerk/localizations/-/localizations-4.5.8.tgz", + "integrity": "sha512-WP6tyNwjTPmpbJ4EmIxYRHptHVxgs3RoI6lsGY2LvydKpfyH4mk1GzKF0YKfTXbrYrL5bNeMePAErxmMX1P0og==", + "license": "MIT", + "dependencies": { + "@clerk/shared": "^4.9.0" + }, + "engines": { + "node": ">=20.9.0" + } + }, + "node_modules/@clerk/nextjs": { + "version": "7.3.0", + "resolved": "https://registry.npmjs.org/@clerk/nextjs/-/nextjs-7.3.0.tgz", + "integrity": "sha512-Dip2oOVc720amG9bBZT1L9y7FoDJjRyz8MaGtbp2SUrtRuvaVq0WhHYzGTI1Nqy5tHMcnzEOSG7KsGf4FwIvzw==", + "license": "MIT", + "dependencies": { + "@clerk/backend": "^3.4.4", + "@clerk/react": "^6.5.0", + "@clerk/shared": "^4.9.0", + "server-only": "0.0.1", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.9.0" + }, + "peerDependencies": { + "next": "^15.2.8 || ^15.3.8 || ^15.4.10 || ^15.5.9 || ^15.6.0-0 || ^16.0.10 || ^16.1.0-0", + "react": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0", + "react-dom": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0" + } + }, + "node_modules/@clerk/react": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/@clerk/react/-/react-6.5.0.tgz", + "integrity": "sha512-TXYxlJ9EvPvJo6NKTy//RlqoZ4nhvmIjlU9cp9KG3buHD7UCby0It9dtaPHbAu5h4s426C7F6GID47LolaLEbg==", + "license": "MIT", + "dependencies": { + "@clerk/shared": "^4.9.0", + "tslib": "2.8.1" + }, + "engines": { + "node": ">=20.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0", + "react-dom": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0" + } + }, + "node_modules/@clerk/shared": { + "version": "4.9.0", + "resolved": "https://registry.npmjs.org/@clerk/shared/-/shared-4.9.0.tgz", + "integrity": "sha512-YU9Fv6FK1EwxM7uz1hGPrLpvcHRhHm8Quuh5RL343oXakE+/JHtYy4OhwVgqYVA+j63pw+7lpghL3CYQTgk0hA==", + "hasInstallScript": true, + "license": "MIT", + "dependencies": { + "@tanstack/query-core": "^5.100.6", + "dequal": "2.0.3", + "glob-to-regexp": "0.4.1", + "js-cookie": "3.0.5", + "std-env": "^3.9.0" + }, + "engines": { + "node": ">=20.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0", + "react-dom": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0" + }, + "peerDependenciesMeta": { + "react": { + "optional": true + }, + "react-dom": { + "optional": true + } + } + }, + "node_modules/@clerk/ui": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/@clerk/ui/-/ui-1.7.0.tgz", + "integrity": "sha512-NU6kU0ywB8N67XlyZQPhvF1W00FnsE2n/7qfLGcn/E3M7TkZ0KH5C2uNjq8lDt91ekW3NgiYCpQlyBHz2RP4Rg==", + "license": "MIT", + "dependencies": { + "@clerk/localizations": "^4.5.8", + "@clerk/shared": "^4.9.0", + "@emotion/cache": "11.11.0", + "@emotion/react": "11.11.1", + "@floating-ui/react": "0.27.12", + "@formkit/auto-animate": "^0.8.2", + "@solana/wallet-adapter-base": "0.9.27", + "@solana/wallet-adapter-react": "0.15.39", + "@solana/wallet-standard": "1.1.4", + "@swc/helpers": "0.5.21", + "copy-to-clipboard": "3.3.3", + "core-js": "3.47.0", + "csstype": "3.1.3", + "dequal": "2.0.3", + "input-otp": "1.4.2", + "qrcode.react": "4.2.0" + }, + "engines": { + "node": ">=20.9.0" + }, + "peerDependencies": { + "react": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0", + "react-dom": "^18.0.0 || ~19.0.3 || ~19.1.4 || ~19.2.3 || ~19.3.0-0" + } + }, + "node_modules/@clerk/ui/node_modules/@swc/helpers": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.21.tgz", + "integrity": "sha512-jI/VAmtdjB/RnI8GTnokyX7Ug8c+g+ffD6QRLa6XQewtnGyukKkKSk3wLTM3b5cjt1jNh9x0jfVlagdN2gDKQg==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@clerk/ui/node_modules/csstype": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.1.3.tgz", + "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", + "license": "MIT" + }, "node_modules/@dotenvx/dotenvx": { "version": "1.64.0", "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.64.0.tgz", @@ -679,6 +829,147 @@ "tslib": "^2.4.0" } }, + "node_modules/@emotion/babel-plugin": { + "version": "11.13.5", + "resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.13.5.tgz", + "integrity": "sha512-pxHCpT2ex+0q+HH91/zsdHkw/lXd468DIN2zvfvLtPKLLMo6gQj7oLObq8PhkrxOZb/gGCq03S3Z7PDhS8pduQ==", + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.16.7", + "@babel/runtime": "^7.18.3", + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/serialize": "^1.3.3", + "babel-plugin-macros": "^3.1.0", + "convert-source-map": "^1.5.0", + "escape-string-regexp": "^4.0.0", + "find-root": "^1.1.0", + "source-map": "^0.5.7", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/babel-plugin/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/babel-plugin/node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "license": "MIT" + }, + "node_modules/@emotion/babel-plugin/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@emotion/cache": { + "version": "11.11.0", + "resolved": "https://registry.npmjs.org/@emotion/cache/-/cache-11.11.0.tgz", + "integrity": "sha512-P34z9ssTCBi3e9EI1ZsWpNHcfY1r09ZO0rZbRO2ob3ZQMnFI35jB536qoXbkdesr5EUhYi22anuEJuyxifaqAQ==", + "license": "MIT", + "dependencies": { + "@emotion/memoize": "^0.8.1", + "@emotion/sheet": "^1.2.2", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "stylis": "4.2.0" + } + }, + "node_modules/@emotion/hash": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@emotion/hash/-/hash-0.9.2.tgz", + "integrity": "sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==", + "license": "MIT" + }, + "node_modules/@emotion/memoize": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.8.1.tgz", + "integrity": "sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==", + "license": "MIT" + }, + "node_modules/@emotion/react": { + "version": "11.11.1", + "resolved": "https://registry.npmjs.org/@emotion/react/-/react-11.11.1.tgz", + "integrity": "sha512-5mlW1DquU5HaxjLkfkGN1GA/fvVGdyHURRiX/0FHl2cfIfRxSOfmxEH5YS43edp0OldZrZ+dkBKbngxcNCdZvA==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.18.3", + "@emotion/babel-plugin": "^11.11.0", + "@emotion/cache": "^11.11.0", + "@emotion/serialize": "^1.1.2", + "@emotion/use-insertion-effect-with-fallbacks": "^1.0.1", + "@emotion/utils": "^1.2.1", + "@emotion/weak-memoize": "^0.3.1", + "hoist-non-react-statics": "^3.3.1" + }, + "peerDependencies": { + "react": ">=16.8.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@emotion/serialize": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@emotion/serialize/-/serialize-1.3.3.tgz", + "integrity": "sha512-EISGqt7sSNWHGI76hC7x1CksiXPahbxEOrC5RjmFRJTqLyEK9/9hZvBbiYn70dw4wuwMKiEMCUlR6ZXTSWQqxA==", + "license": "MIT", + "dependencies": { + "@emotion/hash": "^0.9.2", + "@emotion/memoize": "^0.9.0", + "@emotion/unitless": "^0.10.0", + "@emotion/utils": "^1.4.2", + "csstype": "^3.0.2" + } + }, + "node_modules/@emotion/serialize/node_modules/@emotion/memoize": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/@emotion/memoize/-/memoize-0.9.0.tgz", + "integrity": "sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==", + "license": "MIT" + }, + "node_modules/@emotion/sheet": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/@emotion/sheet/-/sheet-1.4.0.tgz", + "integrity": "sha512-fTBW9/8r2w3dXWYM4HCB1Rdp8NLibOw2+XELH5m5+AkWiL/KqYX6dc0kKYlaYyKjrQ6ds33MCdMPEwgs2z1rqg==", + "license": "MIT" + }, + "node_modules/@emotion/unitless": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@emotion/unitless/-/unitless-0.10.0.tgz", + "integrity": "sha512-dFoMUuQA20zvtVTuxZww6OHoJYgrzfKM1t52mVySDJnMSEa08ruEvdYQbhvyu6soU+NeLVd3yKfTfT0NeV6qGg==", + "license": "MIT" + }, + "node_modules/@emotion/use-insertion-effect-with-fallbacks": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.2.0.tgz", + "integrity": "sha512-yJMtVdH59sxi/aVJBpk9FQq+OR8ll5GT8oWd57UpeaKEVGab41JWaCFA7FRLoMLloOZF/c/wsPoe+bfGmRKgDg==", + "license": "MIT", + "peerDependencies": { + "react": ">=16.8.0" + } + }, + "node_modules/@emotion/utils": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/@emotion/utils/-/utils-1.4.2.tgz", + "integrity": "sha512-3vLclRofFziIa3J2wDh9jjbkUz9qk5Vi3IZ/FSTKViB0k+ef0fPV7dYrUIugbgupYDx7v9ud/SjrtEP8Y4xLoA==", + "license": "MIT" + }, + "node_modules/@emotion/weak-memoize": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz", + "integrity": "sha512-EsBwpc7hBUJWAsNPBmJy4hxWx12v6bshQsldrVmjxJoc3isbxhOrF2IcCpaXxfvq03NwkI7sbsOLXbYuqF/8Ww==", + "license": "MIT" + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.9.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz", @@ -842,6 +1133,21 @@ "@floating-ui/utils": "^0.2.11" } }, + "node_modules/@floating-ui/react": { + "version": "0.27.12", + "resolved": "https://registry.npmjs.org/@floating-ui/react/-/react-0.27.12.tgz", + "integrity": "sha512-kKlWNrpIQxF1B/a2MZvE0/uyKby4960yjO91W7nVyNKmmfNi62xU9HCjL1M1eWzx/LFj/VPSwJVbwQk9Pq/68A==", + "license": "MIT", + "dependencies": { + "@floating-ui/react-dom": "^2.1.3", + "@floating-ui/utils": "^0.2.9", + "tabbable": "^6.0.0" + }, + "peerDependencies": { + "react": ">=17.0.0", + "react-dom": ">=17.0.0" + } + }, "node_modules/@floating-ui/react-dom": { "version": "2.1.8", "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", @@ -861,6 +1167,12 @@ "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "license": "MIT" }, + "node_modules/@formkit/auto-animate": { + "version": "0.8.4", + "resolved": "https://registry.npmjs.org/@formkit/auto-animate/-/auto-animate-0.8.4.tgz", + "integrity": "sha512-DHHC01EJ1p70Q0z/ZFRBIY8NDnmfKccQoyoM84Tgb6omLMat6jivCdf272Y8k3nf4Lzdin/Y4R9q8uFtU0GbnA==", + "license": "MIT" + }, "node_modules/@hono/node-server": { "version": "1.19.14", "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-1.19.14.tgz", @@ -1535,6 +1847,47 @@ } } }, + "node_modules/@isaacs/ttlcache": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@isaacs/ttlcache/-/ttlcache-1.4.1.tgz", + "integrity": "sha512-RQgQ4uQ+pLbqXfOmieB91ejmLwvSgv9nLx6sT6sD83s7umBypgg+OIBOBbEUiJXrfpnp9j0mRhYYdzp9uqq3lA==", + "license": "ISC", + "peer": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/@jest/schemas": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.6.3.tgz", + "integrity": "sha512-mo5j5X+jIZmJQveBKeS/clAueipV7KgiX1vMgCxam1RNYiqE1w62n0/tJJnHtjW8ZHcQco5gY85jA3mi0L+nSA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@sinclair/typebox": "^0.27.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.6.3.tgz", + "integrity": "sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.13", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", @@ -1564,6 +1917,17 @@ "node": ">=6.0.0" } }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, "node_modules/@jridgewell/sourcemap-codec": { "version": "1.5.5", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", @@ -3438,95 +3802,906 @@ "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", "license": "MIT" }, - "node_modules/@rtsao/scc": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", - "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", - "dev": true, - "license": "MIT" - }, - "node_modules/@sec-ant/readable-stream": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", - "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", - "license": "MIT" - }, - "node_modules/@sindresorhus/merge-streams": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", - "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "node_modules/@react-native-async-storage/async-storage": { + "version": "1.24.0", + "resolved": "https://registry.npmjs.org/@react-native-async-storage/async-storage/-/async-storage-1.24.0.tgz", + "integrity": "sha512-W4/vbwUOYOjco0x3toB8QCr7EjIP6nE9G7o8PMguvvjYT5Awg09lyV4enACRx4s++PPulBiBSjL0KTFx2u0Z/g==", "license": "MIT", - "engines": { - "node": ">=18" + "optional": true, + "dependencies": { + "merge-options": "^3.0.4" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "react-native": "^0.0.0-0 || >=0.60 <1.0" } }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.8.0" + "node_modules/@react-native/assets-registry": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/@react-native/assets-registry/-/assets-registry-0.85.2.tgz", + "integrity": "sha512-kauC/oPaxklU4Y+u9gBfCBJm51qX6WBZq4xx0USCdimtp+G8+554kpygfSWIjoqCJa2o06bWxBEjesiuCv+LzA==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/@tailwindcss/node": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.4.tgz", - "integrity": "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==", - "dev": true, + "node_modules/@react-native/codegen": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/@react-native/codegen/-/codegen-0.85.2.tgz", + "integrity": "sha512-XCginmxh0//++EXVOEJHBVZxHla294FzLCFF6jXwAUjvXVhqyIKyxhABfz+r4OOmaiuWk4Rtd4arqdAzeHeprg==", "license": "MIT", + "peer": true, "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.19.0", - "jiti": "^2.6.1", - "lightningcss": "1.32.0", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.2.4" + "@babel/core": "^7.25.2", + "@babel/parser": "^7.29.0", + "hermes-parser": "0.33.3", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "tinyglobby": "^0.2.15", + "yargs": "^17.6.2" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@babel/core": "*" } }, - "node_modules/@tailwindcss/oxide": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.4.tgz", - "integrity": "sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==", - "dev": true, + "node_modules/@react-native/codegen/node_modules/hermes-estree": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", + "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", "license": "MIT", - "engines": { - "node": ">= 20" - }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.2.4", - "@tailwindcss/oxide-darwin-arm64": "4.2.4", - "@tailwindcss/oxide-darwin-x64": "4.2.4", - "@tailwindcss/oxide-freebsd-x64": "4.2.4", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.4", - "@tailwindcss/oxide-linux-arm64-gnu": "4.2.4", - "@tailwindcss/oxide-linux-arm64-musl": "4.2.4", - "@tailwindcss/oxide-linux-x64-gnu": "4.2.4", - "@tailwindcss/oxide-linux-x64-musl": "4.2.4", - "@tailwindcss/oxide-wasm32-wasi": "4.2.4", - "@tailwindcss/oxide-win32-arm64-msvc": "4.2.4", - "@tailwindcss/oxide-win32-x64-msvc": "4.2.4" + "peer": true + }, + "node_modules/@react-native/codegen/node_modules/hermes-parser": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", + "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-estree": "0.33.3" } }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.2.4", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.4.tgz", - "integrity": "sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@react-native/community-cli-plugin": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/@react-native/community-cli-plugin/-/community-cli-plugin-0.85.2.tgz", + "integrity": "sha512-3KLgSg1kHvBpr93zMaQhvfYTgnCw7yZRED+3J4dMcYjfSjtD0Wf8SofU6uBmAw9JaVYvP43lpdwUpI4p0+ABsg==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], + "peer": true, + "dependencies": { + "@react-native/dev-middleware": "0.85.2", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "metro": "^0.84.0", + "metro-config": "^0.84.0", + "metro-core": "^0.84.0", + "semver": "^7.1.3" + }, "engines": { - "node": ">= 20" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@react-native-community/cli": "*", + "@react-native/metro-config": "0.85.2" + }, + "peerDependenciesMeta": { + "@react-native-community/cli": { + "optional": true + }, + "@react-native/metro-config": { + "optional": true + } + } + }, + "node_modules/@react-native/community-cli-plugin/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@react-native/debugger-frontend": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/@react-native/debugger-frontend/-/debugger-frontend-0.85.2.tgz", + "integrity": "sha512-j+0b9H5f5hGTLQxHIhJU/b/W6ijuxJF+ZTLHB0se2kzUBNxFKd7DkIc6753qk3CJdiv55vxG3XDgmlpbHxOpmA==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/debugger-shell": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/@react-native/debugger-shell/-/debugger-shell-0.85.2.tgz", + "integrity": "sha512-r5BkhqPMfg3LmaZS5zadHmBNVH5h4bhSpv4BEPGfK4gat9HABAMzUzybi+2wpgU3SoHxnyKGdExEJvoqVcjeRg==", + "license": "MIT", + "peer": true, + "dependencies": { + "cross-spawn": "^7.0.6", + "debug": "^4.4.0", + "fb-dotslash": "0.5.8" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/dev-middleware": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/@react-native/dev-middleware/-/dev-middleware-0.85.2.tgz", + "integrity": "sha512-3J+NaDUg+QEfDeLAUzgaWhpaxEg78g+KwbydlDCewh2G6WnHpsty8XooruxNHzyAsqVWywZMrzmbn78Ctc1O9Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "@isaacs/ttlcache": "^1.4.1", + "@react-native/debugger-frontend": "0.85.2", + "@react-native/debugger-shell": "0.85.2", + "chrome-launcher": "^0.15.2", + "chromium-edge-launcher": "^0.3.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "invariant": "^2.2.4", + "nullthrows": "^1.1.1", + "open": "^7.0.3", + "serve-static": "^1.16.2", + "ws": "^7.5.10" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "peer": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/open": { + "version": "7.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-7.4.2.tgz", + "integrity": "sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-docker": "^2.0.0", + "is-wsl": "^2.1.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/send": { + "version": "0.19.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.2.tgz", + "integrity": "sha512-VMbMxbDeehAxpOtWJXlcUS5E8iXh6QmN+BkRX1GARS3wRaXEEgzCcB10gTQazO42tpNIya8xIyNx8fll1OFPrg==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "~0.5.2", + "http-errors": "~2.0.1", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "~2.4.1", + "range-parser": "~1.2.1", + "statuses": "~2.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/@react-native/dev-middleware/node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT", + "peer": true + }, + "node_modules/@react-native/dev-middleware/node_modules/serve-static": { + "version": "1.16.3", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.3.tgz", + "integrity": "sha512-x0RTqQel6g5SY7Lg6ZreMmsOzncHFU7nhnRWkKgWuMTu5NN0DR5oruckMqRvacAN9d5w6ARnRBXl9xhDCgfMeA==", + "license": "MIT", + "peer": true, + "dependencies": { + "encodeurl": "~2.0.0", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "~0.19.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/@react-native/gradle-plugin": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/@react-native/gradle-plugin/-/gradle-plugin-0.85.2.tgz", + "integrity": "sha512-YXBOLeAqFrv7XwUeBPTKZeOV1FIxn4AW7UAEitScf3ibC8bu8+6NpJu4HWgbNQHg7vDbbTZVbcOl8EwGxsSq2w==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/js-polyfills": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/@react-native/js-polyfills/-/js-polyfills-0.85.2.tgz", + "integrity": "sha512-esGEAmKVM40DV/yVmNljCKZTIeUo7qXqc+Hwffkv3TG+b3E24xyFovHrbP98gGxZr2ZsEyx+2sKLdXF5asY5nw==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/@react-native/normalize-colors": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/@react-native/normalize-colors/-/normalize-colors-0.85.2.tgz", + "integrity": "sha512-svuOLtjbFGXDdHsriHXuND5FgHg7XlkOXCbH/8+X4t76YLH6qSTffSIQQrKLDL5mn4EFU+Oh/PNO0/FfpnTOTg==", + "license": "MIT", + "peer": true + }, + "node_modules/@react-native/virtualized-lists": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/@react-native/virtualized-lists/-/virtualized-lists-0.85.2.tgz", + "integrity": "sha512-wmVKpAlcr+UB0L5SpbrV865EdleUP7I5+X+48e1aRsQK8q+wsTRBXeUwWVip/1l+HZwlZFeO8iOILJ16VRu0Cw==", + "license": "MIT", + "peer": true, + "dependencies": { + "invariant": "^2.2.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@types/react": "^19.2.0", + "react": "*", + "react-native": "0.85.2" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@rtsao/scc": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@rtsao/scc/-/scc-1.1.0.tgz", + "integrity": "sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "license": "MIT" + }, + "node_modules/@sinclair/typebox": { + "version": "0.27.10", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.27.10.tgz", + "integrity": "sha512-MTBk/3jGLNB2tVxv6uLlFh1iu64iYOQ2PbdOSK3NW8JZsmlaOh2q6sdtKowBhfw8QFLmYNzTW4/oK4uATIi6ZA==", + "license": "MIT", + "peer": true + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@solana-mobile/mobile-wallet-adapter-protocol": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@solana-mobile/mobile-wallet-adapter-protocol/-/mobile-wallet-adapter-protocol-2.2.8.tgz", + "integrity": "sha512-c3FQsrM7nV62DqVaHGKtr2osE2w5gS3/wjy8ILF0zczS/s1mERX+JTmf+UHd8xgESmEj/IM7q+U2Qhrmac1PdA==", + "license": "Apache-2.0", + "dependencies": { + "@solana/codecs-strings": "^6.0.0", + "@solana/wallet-standard-features": "^1.3.0", + "@solana/wallet-standard-util": "^1.1.2", + "@wallet-standard/core": "^1.1.1", + "js-base64": "^3.7.5" + }, + "peerDependencies": { + "react-native": ">0.74" + } + }, + "node_modules/@solana-mobile/mobile-wallet-adapter-protocol-web3js": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@solana-mobile/mobile-wallet-adapter-protocol-web3js/-/mobile-wallet-adapter-protocol-web3js-2.2.8.tgz", + "integrity": "sha512-W9DbsFvl5lSOe7KT3dJX4tjbxfYIoOtOTJpvLMgkojyRU0UKChQ4vHvbOZQ3GkUJ8wOIS4qdrM0Yytd1Vy+YQQ==", + "license": "Apache-2.0", + "dependencies": { + "@solana-mobile/mobile-wallet-adapter-protocol": "^2.2.8", + "bs58": "^6.0.0", + "js-base64": "^3.7.5" + }, + "peerDependencies": { + "@solana/web3.js": "^1.98.4" + } + }, + "node_modules/@solana-mobile/wallet-adapter-mobile": { + "version": "2.2.8", + "resolved": "https://registry.npmjs.org/@solana-mobile/wallet-adapter-mobile/-/wallet-adapter-mobile-2.2.8.tgz", + "integrity": "sha512-ZbXY3/0+UnnyS0hvArpO1b1pYzaQAiVIp+HBUm11aLEkE5+ISvHTRPr/bCEUXZfPkez/1n9zH3H0leK25Lj6Nw==", + "license": "Apache-2.0", + "dependencies": { + "@solana-mobile/mobile-wallet-adapter-protocol": "^2.2.8", + "@solana-mobile/mobile-wallet-adapter-protocol-web3js": "^2.2.8", + "@solana-mobile/wallet-standard-mobile": "^0.5.2", + "@solana/wallet-adapter-base": "^0.9.27", + "@solana/wallet-standard-features": "^1.3.0", + "@wallet-standard/core": "^1.1.1", + "bs58": "^6.0.0", + "js-base64": "^3.7.5", + "tslib": "^2.8.1" + }, + "optionalDependencies": { + "@react-native-async-storage/async-storage": "^1.17.7" + }, + "peerDependencies": { + "@solana/web3.js": "^1.98.4", + "react-native": ">0.74" + } + }, + "node_modules/@solana-mobile/wallet-standard-mobile": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@solana-mobile/wallet-standard-mobile/-/wallet-standard-mobile-0.5.2.tgz", + "integrity": "sha512-orEGv4N/Ttd0umwfWUzGcEnVc9eJDTgRSEcDitvFWpIf2D968h6128L0rq9/y7sUw88Gvu/lU0euoC2ASEijqQ==", + "license": "Apache-2.0", + "dependencies": { + "@solana-mobile/mobile-wallet-adapter-protocol": "^2.2.8", + "@solana/wallet-standard-chains": "^1.1.1", + "@solana/wallet-standard-features": "^1.3.0", + "@wallet-standard/base": "^1.0.1", + "@wallet-standard/features": "^1.0.3", + "@wallet-standard/wallet": "^1.1.0", + "bs58": "^6.0.0", + "js-base64": "^3.7.5", + "qrcode": "^1.5.4", + "tslib": "^2.8.1" + }, + "optionalDependencies": { + "@react-native-async-storage/async-storage": "^1.17.7" + } + }, + "node_modules/@solana/buffer-layout": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@solana/buffer-layout/-/buffer-layout-4.0.1.tgz", + "integrity": "sha512-E1ImOIAD1tBZFRdjeM4/pzTiTApC0AOBGwyAMS4fwIodCWArzJ3DWdoh8cKxeFM2fElkxBh2Aqts1BPC373rHA==", + "license": "MIT", + "peer": true, + "dependencies": { + "buffer": "~6.0.3" + }, + "engines": { + "node": ">=5.10" + } + }, + "node_modules/@solana/codecs-core": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-6.8.0.tgz", + "integrity": "sha512-udFO8TrvzgROonwX3rY3E2SG675RehILNb4ZYcKlf1mL7vkDJ9bEJnBxi87AEwl8RWZFTl+MhT0MmrJnbpvdug==", + "license": "MIT", + "dependencies": { + "@solana/errors": "6.8.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@solana/codecs-numbers": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-6.8.0.tgz", + "integrity": "sha512-ebf4f1D19EAe0uhdUYOCEYnn5+EellsBxbJ42tM2yYEoIBVz5FoBBC0gSsq+UTNbQHFa7XagyBT3LewxXttiTQ==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "6.8.0", + "@solana/errors": "6.8.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@solana/codecs-strings": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-strings/-/codecs-strings-6.8.0.tgz", + "integrity": "sha512-Rpk5NVhbKYcPnE7wz3IpTp0GVNVs0IYKdmyzByiimgPTiII8eb8ay4wQiYHGHrpYh62hD14Qy3GiGDFgipRKqA==", + "license": "MIT", + "dependencies": { + "@solana/codecs-core": "6.8.0", + "@solana/codecs-numbers": "6.8.0", + "@solana/errors": "6.8.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "fastestsmallesttextencoderdecoder": "^1.0.22", + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "fastestsmallesttextencoderdecoder": { + "optional": true + }, + "typescript": { + "optional": true + } + } + }, + "node_modules/@solana/errors": { + "version": "6.8.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-6.8.0.tgz", + "integrity": "sha512-HRTrLgTn0c99GKz4v4IKgz2+6soaRY1mh2tLW4sk1Fe4Zzv85Q6ZLK1mXrVGL73z1apyHDrr9/Sd/9ZhUsUvpA==", + "license": "MIT", + "dependencies": { + "chalk": "5.6.2", + "commander": "14.0.3" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@solana/errors/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/wallet-adapter-base": { + "version": "0.9.27", + "resolved": "https://registry.npmjs.org/@solana/wallet-adapter-base/-/wallet-adapter-base-0.9.27.tgz", + "integrity": "sha512-kXjeNfNFVs/NE9GPmysBRKQ/nf+foSaq3kfVSeMcO/iVgigyRmB551OjU3WyAolLG/1jeEfKLqF9fKwMCRkUqg==", + "license": "Apache-2.0", + "dependencies": { + "@solana/wallet-standard-features": "^1.3.0", + "@wallet-standard/base": "^1.1.0", + "@wallet-standard/features": "^1.1.0", + "eventemitter3": "^5.0.1" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@solana/web3.js": "^1.98.0" + } + }, + "node_modules/@solana/wallet-adapter-react": { + "version": "0.15.39", + "resolved": "https://registry.npmjs.org/@solana/wallet-adapter-react/-/wallet-adapter-react-0.15.39.tgz", + "integrity": "sha512-WXtlo88ith5m22qB+qiGw301/Zb9r5pYr4QdXWmlXnRNqwST5MGmJWhG+/RVrzc+OG7kSb3z1gkVNv+2X/Y0Gg==", + "license": "Apache-2.0", + "dependencies": { + "@solana-mobile/wallet-adapter-mobile": "^2.2.0", + "@solana/wallet-adapter-base": "^0.9.27", + "@solana/wallet-standard-wallet-adapter-react": "^1.1.4" + }, + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "@solana/web3.js": "^1.98.0", + "react": "*" + } + }, + "node_modules/@solana/wallet-standard": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@solana/wallet-standard/-/wallet-standard-1.1.4.tgz", + "integrity": "sha512-NF+MI5tOxyvfTU4A+O5idh/gJFmjm52bMwsPpFGRSL79GECSN0XLmpVOO/jqTKJgac2uIeYDpQw/eMaQuWuUXw==", + "license": "Apache-2.0", + "dependencies": { + "@solana/wallet-standard-core": "^1.1.2", + "@solana/wallet-standard-wallet-adapter": "^1.1.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@solana/wallet-standard-chains": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@solana/wallet-standard-chains/-/wallet-standard-chains-1.1.1.tgz", + "integrity": "sha512-Us3TgL4eMVoVWhuC4UrePlYnpWN+lwteCBlhZDUhFZBJ5UMGh94mYPXno3Ho7+iHPYRtuCi/ePvPcYBqCGuBOw==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/base": "^1.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@solana/wallet-standard-core": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@solana/wallet-standard-core/-/wallet-standard-core-1.1.2.tgz", + "integrity": "sha512-FaSmnVsIHkHhYlH8XX0Y4TYS+ebM+scW7ZeDkdXo3GiKge61Z34MfBPinZSUMV08hCtzxxqH2ydeU9+q/KDrLA==", + "license": "Apache-2.0", + "dependencies": { + "@solana/wallet-standard-chains": "^1.1.1", + "@solana/wallet-standard-features": "^1.3.0", + "@solana/wallet-standard-util": "^1.1.2" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@solana/wallet-standard-features": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@solana/wallet-standard-features/-/wallet-standard-features-1.3.0.tgz", + "integrity": "sha512-ZhpZtD+4VArf6RPitsVExvgkF+nGghd1rzPjd97GmBximpnt1rsUxMOEyoIEuH3XBxPyNB6Us7ha7RHWQR+abg==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/base": "^1.1.0", + "@wallet-standard/features": "^1.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@solana/wallet-standard-util": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@solana/wallet-standard-util/-/wallet-standard-util-1.1.2.tgz", + "integrity": "sha512-rUXFNP4OY81Ddq7qOjQV4Kmkozx4wjYAxljvyrqPx8Ycz0FYChG/hQVWqvgpK3sPsEaO/7ABG1NOACsyAKWNOA==", + "license": "Apache-2.0", + "dependencies": { + "@noble/curves": "^1.8.0", + "@solana/wallet-standard-chains": "^1.1.1", + "@solana/wallet-standard-features": "^1.3.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@solana/wallet-standard-wallet-adapter": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@solana/wallet-standard-wallet-adapter/-/wallet-standard-wallet-adapter-1.1.4.tgz", + "integrity": "sha512-YSBrxwov4irg2hx9gcmM4VTew3ofNnkqsXQ42JwcS6ykF1P1ecVY8JCbrv75Nwe6UodnqeoZRbN7n/p3awtjNQ==", + "license": "Apache-2.0", + "dependencies": { + "@solana/wallet-standard-wallet-adapter-base": "^1.1.4", + "@solana/wallet-standard-wallet-adapter-react": "^1.1.4" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@solana/wallet-standard-wallet-adapter-base": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@solana/wallet-standard-wallet-adapter-base/-/wallet-standard-wallet-adapter-base-1.1.4.tgz", + "integrity": "sha512-Q2Rie9YaidyFA4UxcUIxUsvynW+/gE2noj/Wmk+IOwDwlVrJUAXCvFaCNsPDSyKoiYEKxkSnlG13OA1v08G4iw==", + "license": "Apache-2.0", + "dependencies": { + "@solana/wallet-adapter-base": "^0.9.23", + "@solana/wallet-standard-chains": "^1.1.1", + "@solana/wallet-standard-features": "^1.3.0", + "@solana/wallet-standard-util": "^1.1.2", + "@wallet-standard/app": "^1.1.0", + "@wallet-standard/base": "^1.1.0", + "@wallet-standard/features": "^1.1.0", + "@wallet-standard/wallet": "^1.1.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/web3.js": "^1.98.0", + "bs58": "^6.0.0" + } + }, + "node_modules/@solana/wallet-standard-wallet-adapter-react": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@solana/wallet-standard-wallet-adapter-react/-/wallet-standard-wallet-adapter-react-1.1.4.tgz", + "integrity": "sha512-xa4KVmPgB7bTiWo4U7lg0N6dVUtt2I2WhEnKlIv0jdihNvtyhOjCKMjucWet6KAVhir6I/mSWrJk1U9SvVvhCg==", + "license": "Apache-2.0", + "dependencies": { + "@solana/wallet-standard-wallet-adapter-base": "^1.1.4", + "@wallet-standard/app": "^1.1.0", + "@wallet-standard/base": "^1.1.0" + }, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "@solana/wallet-adapter-base": "*", + "react": "*" + } + }, + "node_modules/@solana/web3.js": { + "version": "1.98.4", + "resolved": "https://registry.npmjs.org/@solana/web3.js/-/web3.js-1.98.4.tgz", + "integrity": "sha512-vv9lfnvjUsRiq//+j5pBdXig0IQdtzA0BRZ3bXEP4KaIyF1CcaydWqgyzQgfZMNIsWNWmG+AUHwPy4AHOD6gpw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.0", + "@noble/curves": "^1.4.2", + "@noble/hashes": "^1.4.0", + "@solana/buffer-layout": "^4.0.1", + "@solana/codecs-numbers": "^2.1.0", + "agentkeepalive": "^4.5.0", + "bn.js": "^5.2.1", + "borsh": "^0.7.0", + "bs58": "^4.0.1", + "buffer": "6.0.3", + "fast-stable-stringify": "^1.0.0", + "jayson": "^4.1.1", + "node-fetch": "^2.7.0", + "rpc-websockets": "^9.0.2", + "superstruct": "^2.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-core": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-core/-/codecs-core-2.3.0.tgz", + "integrity": "sha512-oG+VZzN6YhBHIoSKgS5ESM9VIGzhWjEHEGNPSibiDTxFhsFWxNaz8LbMDPjBUE69r9wmdGLkrQ+wVPbnJcZPvw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/codecs-numbers": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/codecs-numbers/-/codecs-numbers-2.3.0.tgz", + "integrity": "sha512-jFvvwKJKffvG7Iz9dmN51OGB7JBcy2CJ6Xf3NqD/VP90xak66m/Lg48T01u5IQ/hc15mChVHiBm+HHuOFDUrQg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@solana/codecs-core": "2.3.0", + "@solana/errors": "2.3.0" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/@solana/errors": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@solana/errors/-/errors-2.3.0.tgz", + "integrity": "sha512-66RI9MAbwYV0UtP7kGcTBVLxJgUxoZGm8Fbc0ah+lGiAw17Gugco6+9GrJCV83VyF2mDWyYnYM9qdI3yjgpnaQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "chalk": "^5.4.1", + "commander": "^14.0.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=20.18.0" + }, + "peerDependencies": { + "typescript": ">=5.3.3" + } + }, + "node_modules/@solana/web3.js/node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/@solana/web3.js/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "peer": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, + "node_modules/@solana/web3.js/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@solana/web3.js/node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "peer": true, + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/@stablelib/base64": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@stablelib/base64/-/base64-1.0.1.tgz", + "integrity": "sha512-1bnPQqSxSuc3Ii6MhBysoWCg58j97aUjuCSZrGSmDxNqtytIi0k8utUenAwTZN4V5mXXYGsVUI9zeBqy+jBOSQ==", + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@tailwindcss/node": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.2.4.tgz", + "integrity": "sha512-Ai7+yQPxz3ddrDQzFfBKdHEVBg0w3Zl83jnjuwxnZOsnH9pGn93QHQtpU0p/8rYWxvbFZHneni6p1BSLK4DkGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.19.0", + "jiti": "^2.6.1", + "lightningcss": "1.32.0", + "magic-string": "^0.30.21", + "source-map-js": "^1.2.1", + "tailwindcss": "4.2.4" + } + }, + "node_modules/@tailwindcss/oxide": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.2.4.tgz", + "integrity": "sha512-9El/iI069DKDSXwTvB9J4BwdO5JhRrOweGaK25taBAvBXyXqJAX+Jqdvs8r8gKpsI/1m0LeJLyQYTf/WLrBT1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 20" + }, + "optionalDependencies": { + "@tailwindcss/oxide-android-arm64": "4.2.4", + "@tailwindcss/oxide-darwin-arm64": "4.2.4", + "@tailwindcss/oxide-darwin-x64": "4.2.4", + "@tailwindcss/oxide-freebsd-x64": "4.2.4", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.2.4", + "@tailwindcss/oxide-linux-arm64-gnu": "4.2.4", + "@tailwindcss/oxide-linux-arm64-musl": "4.2.4", + "@tailwindcss/oxide-linux-x64-gnu": "4.2.4", + "@tailwindcss/oxide-linux-x64-musl": "4.2.4", + "@tailwindcss/oxide-wasm32-wasi": "4.2.4", + "@tailwindcss/oxide-win32-arm64-msvc": "4.2.4", + "@tailwindcss/oxide-win32-x64-msvc": "4.2.4" + } + }, + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.2.4.tgz", + "integrity": "sha512-e7MOr1SAn9U8KlZzPi1ZXGZHeC5anY36qjNwmZv9pOJ8E4Q6jmD1vyEHkQFmNOIN7twGPEMXRHmitN4zCMN03g==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 20" } }, "node_modules/@tailwindcss/oxide-darwin-arm64": { @@ -3755,6 +4930,16 @@ "tailwindcss": "4.2.4" } }, + "node_modules/@tanstack/query-core": { + "version": "5.100.8", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.100.8.tgz", + "integrity": "sha512-ceYwSFOqjPwET5TA6IOYxzxlGc0ekyH/gfOtWkP0PX43rzX9bxW48Iuw8KAduKCToi4rJAQ6nRy2kAe8gszdmg==", + "license": "MIT", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, "node_modules/@ts-morph/common": { "version": "0.27.0", "resolved": "https://registry.npmjs.org/@ts-morph/common/-/common-0.27.0.tgz", @@ -3841,6 +5026,16 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/estree": { "version": "1.0.8", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.8.tgz", @@ -3848,6 +5043,33 @@ "dev": true, "license": "MIT" }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.6.tgz", + "integrity": "sha512-2QF/t/auWm0lsy8XtKVPG19v3sSOQlJe/YHZgfjb/KBBHOGSV+J2q/S671rcq9uTBrLAXmZpqJiaQbMT+zNU1w==", + "license": "MIT", + "peer": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.3.tgz", + "integrity": "sha512-NQn7AHQnk/RSLOxrBbGyJM/aVQ+pjj5HCgasFxc0K/KhoATfQ/47AyUl15I2yBUpihjmas+a+VJBOqecrFH+uA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.4.tgz", + "integrity": "sha512-pk2B1NWalF9toCRu6gjBzR69syFjP4Od8WRAX+0mmf9lAjCRicLOWc+ZrxZHx/0XRjotgkF9t6iaMJ+aXcOdZQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, "node_modules/@types/json-schema": { "version": "7.0.15", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", @@ -3871,6 +5093,12 @@ "undici-types": "~6.21.0" } }, + "node_modules/@types/parse-json": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.2.tgz", + "integrity": "sha512-dISoDXWWQwUquiKsyZ4Ng+HX2KsPL7LyHKHQwgGFEA3IaKac4Obd+h2a/a6waisAoepJlBcx9paWqjA8/HVjCw==", + "license": "MIT" + }, "node_modules/@types/react": { "version": "19.2.14", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz", @@ -3906,12 +5134,46 @@ "integrity": "sha512-xMAgYwceFhRA2zY+XbEA7mxYbA093wdiW8Vu6gZPGWy9cmOyU9XesH1tNcEWsKFd5Vzrqx5T3D38PWx1FIIXkA==", "license": "MIT" }, + "node_modules/@types/uuid": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-10.0.0.tgz", + "integrity": "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ==", + "license": "MIT", + "peer": true + }, "node_modules/@types/validate-npm-package-name": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/@types/validate-npm-package-name/-/validate-npm-package-name-4.0.2.tgz", "integrity": "sha512-lrpDziQipxCEeK5kWxvljWYhUvOiB2A9izZd9B2AFarYAkqZshb4lPbRs7zKEic6eGtH8V/2qJW+dPp9OtF6bw==", "license": "MIT" }, + "node_modules/@types/ws": { + "version": "7.4.7", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-7.4.7.tgz", + "integrity": "sha512-JQbbmxZTZehdc2iszGKs5oC3NFnjeay7mtAWrdt7qNtAVK0g19muApzAy4bm9byz79xa2ZnO/BOBC2R8RC5Lww==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.35", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.35.tgz", + "integrity": "sha512-qUHkeCyQFxMXg79wQfTtfndEC+N9ZZg76HJftDJp+qH2tV7Gj4OJi7l+PiWwJ+pWtW8GwSmqsDj/oymhrTWXjg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.3", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.3.tgz", + "integrity": "sha512-I4q9QU9MQv4oEOz4tAHJtNz1cwuLxn2F3xcc2iV5WdqLPpUnj30aUuxt1mAxYTG+oe8CZMV/+6rU4S4gRDzqtQ==", + "license": "MIT", + "peer": true + }, "node_modules/@typescript-eslint/eslint-plugin": { "version": "8.59.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.59.1.tgz", @@ -4500,6 +5762,117 @@ "win32" ] }, + "node_modules/@wallet-standard/app": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wallet-standard/app/-/app-1.1.0.tgz", + "integrity": "sha512-3CijvrO9utx598kjr45hTbbeeykQrQfKmSnxeWOgU25TOEpvcipD/bYDQWIqUv1Oc6KK4YStokSMu/FBNecGUQ==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/base": "^1.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wallet-standard/base": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wallet-standard/base/-/base-1.1.0.tgz", + "integrity": "sha512-DJDQhjKmSNVLKWItoKThJS+CsJQjR9AOBOirBVT1F9YpRyC9oYHE+ZnSf8y8bxUphtKqdQMPVQ2mHohYdRvDVQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=16" + } + }, + "node_modules/@wallet-standard/core": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@wallet-standard/core/-/core-1.1.1.tgz", + "integrity": "sha512-5Xmjc6+Oe0hcPfVc5n8F77NVLwx1JVAoCVgQpLyv/43/bhtIif+Gx3WUrDlaSDoM8i2kA2xd6YoFbHCxs+e0zA==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/app": "^1.1.0", + "@wallet-standard/base": "^1.1.0", + "@wallet-standard/errors": "^0.1.1", + "@wallet-standard/features": "^1.1.0", + "@wallet-standard/wallet": "^1.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wallet-standard/errors": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@wallet-standard/errors/-/errors-0.1.1.tgz", + "integrity": "sha512-V8Ju1Wvol8i/VDyQOHhjhxmMVwmKiwyxUZBnHhtiPZJTWY0U/Shb2iEWyGngYEbAkp2sGTmEeNX1tVyGR7PqNw==", + "license": "Apache-2.0", + "dependencies": { + "chalk": "^5.4.1", + "commander": "^13.1.0" + }, + "bin": { + "errors": "bin/cli.mjs" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wallet-standard/errors/node_modules/chalk": { + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", + "license": "MIT", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@wallet-standard/errors/node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/@wallet-standard/features": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wallet-standard/features/-/features-1.1.0.tgz", + "integrity": "sha512-hiEivWNztx73s+7iLxsuD1sOJ28xtRix58W7Xnz4XzzA/pF0+aicnWgjOdA10doVDEDZdUuZCIIqG96SFNlDUg==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/base": "^1.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/@wallet-standard/wallet": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@wallet-standard/wallet/-/wallet-1.1.0.tgz", + "integrity": "sha512-Gt8TnSlDZpAl+RWOOAB/kuvC7RpcdWAlFbHNoi4gsXsfaWa1QCT6LBcfIYTPdOZC9OVZUDwqGuGAcqZejDmHjg==", + "license": "Apache-2.0", + "dependencies": { + "@wallet-standard/base": "^1.1.0" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "peer": true, + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/accepts": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/accepts/-/accepts-2.0.0.tgz", @@ -4517,7 +5890,6 @@ "version": "8.16.0", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.16.0.tgz", "integrity": "sha512-UVJyE9MttOsBQIDKw1skb9nAwQuR5wuGD3+82K6JgJlm/Y+KI92oNsMNGZCYdDsVtRHSak0pcV5Dno5+4jh9sw==", - "dev": true, "license": "MIT", "bin": { "acorn": "bin/acorn" @@ -4545,6 +5917,19 @@ "node": ">= 14" } }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ajv": { "version": "6.15.0", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", @@ -4601,6 +5986,13 @@ "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, + "node_modules/anser": { + "version": "1.4.10", + "resolved": "https://registry.npmjs.org/anser/-/anser-1.4.10.tgz", + "integrity": "sha512-hCv9AqTQ8ycjpSd3upOJd7vFwW1JaoYQ7tpham03GJ1ca8/65rqn0RpaWpItOAd6ylW9wAw6luXYPJIyPFVOww==", + "license": "MIT", + "peer": true + }, "node_modules/ansi-regex": { "version": "6.2.2", "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", @@ -4816,6 +6208,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/asap": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz", + "integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==", + "license": "MIT", + "peer": true + }, "node_modules/ast-types": { "version": "0.16.1", "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", @@ -4881,6 +6280,94 @@ "node": ">= 0.4" } }, + "node_modules/babel-plugin-macros": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", + "integrity": "sha512-Cg7TFGpIr01vOQNODXOOaGz2NpCU5gl8x1qJFbb6hbZxR7XrcE2vtbAsTAbJ7/xwJtUuJEw8K8Zr/AE0LHlesg==", + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5", + "cosmiconfig": "^7.0.0", + "resolve": "^1.19.0" + }, + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/babel-plugin-macros/node_modules/cosmiconfig": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz", + "integrity": "sha512-AdmX6xUzdNASswsFtmwSt7Vj8po9IuqXm0UXz7QKPuEUmPB4XyjGfaAr2PSuELMwkRMVH1EpIkX5bTZGRB3eCA==", + "license": "MIT", + "dependencies": { + "@types/parse-json": "^4.0.0", + "import-fresh": "^3.2.1", + "parse-json": "^5.0.0", + "path-type": "^4.0.0", + "yaml": "^1.10.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/babel-plugin-macros/node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/babel-plugin-macros/node_modules/yaml": { + "version": "1.10.3", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.3.tgz", + "integrity": "sha512-vIYeF1u3CjlhAFekPPAk2h/Kv4T3mAkMox5OymRiJQB0spDP10LHvt+K7G9Ny6NuuMAb25/6n1qyUjAcGNf/AA==", + "license": "ISC", + "engines": { + "node": ">= 6" + } + }, + "node_modules/babel-plugin-syntax-hermes-parser": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/babel-plugin-syntax-hermes-parser/-/babel-plugin-syntax-hermes-parser-0.33.3.tgz", + "integrity": "sha512-/Z9xYdaJ1lC0pT9do6TqCqhOSLfZ5Ot8D5za1p+feEfWYupCOfGbhhEXN9r2ZgJtDNUNRw/Z+T2CvAGKBqtqWA==", + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-parser": "0.33.3" + } + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-estree": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.33.3.tgz", + "integrity": "sha512-6kzYZHCk8Fy1Uc+t3HGYyJn3OL4aeqKLTyina4UFtWl8I0kSL7OmKThaiX+Uh2f8nGw3mo4Ifxg0M5Zk3/Oeqg==", + "license": "MIT", + "peer": true + }, + "node_modules/babel-plugin-syntax-hermes-parser/node_modules/hermes-parser": { + "version": "0.33.3", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.33.3.tgz", + "integrity": "sha512-Yg3HgaG4CqgyowtYjX/FsnPAuZdHOqSMtnbpylbptsQ9nwwSKsy6uRWcGO5RK0EqiX12q8HvDWKgeAVajRO5DA==", + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-estree": "0.33.3" + } + }, "node_modules/balanced-match": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", @@ -4888,6 +6375,33 @@ "dev": true, "license": "MIT" }, + "node_modules/base-x": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-5.0.1.tgz", + "integrity": "sha512-M7uio8Zt++eg3jPj+rHMfCC+IuygQHHCOU+IYsVtik6FWjuYpVt/+MRKcgsAMHh8mMFAwnB+Bs+mTrFiXjMzKg==", + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true + }, "node_modules/baseline-browser-mapping": { "version": "2.10.25", "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.25.tgz", @@ -4900,6 +6414,13 @@ "node": ">=6.0.0" } }, + "node_modules/bn.js": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.3.tgz", + "integrity": "sha512-EAcmnPkxpntVL+DS7bO1zhcZNvCkxqtkd0ZY53h06GNQ3DEkkGZ/gKgmDv6DdZQGj9BgfSPKtJJ7Dp1GPP8f7w==", + "license": "MIT", + "peer": true + }, "node_modules/body-parser": { "version": "2.2.2", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.2.tgz", @@ -4924,6 +6445,38 @@ "url": "https://opencollective.com/express" } }, + "node_modules/borsh": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/borsh/-/borsh-0.7.0.tgz", + "integrity": "sha512-CLCsZGIBCFnPtkNnieW/a8wmreDmfUtjU2m9yHrzPXIlNbqVs0AQrSatSG6vdNYUqdc83tkQi2eHfF98ubzQLA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "bn.js": "^5.2.0", + "bs58": "^4.0.0", + "text-encoding-utf-8": "^1.0.2" + } + }, + "node_modules/borsh/node_modules/base-x": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.11.tgz", + "integrity": "sha512-xz7wQ8xDhdyP7tQxwdteLYeFfS68tSMNCZ/Y37WJ4bhGfKPpqEIlmIyueQHqOyoPhE6xNUqjzRr8ra0eF9VRvA==", + "license": "MIT", + "peer": true, + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, + "node_modules/borsh/node_modules/bs58": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", + "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "license": "MIT", + "peer": true, + "dependencies": { + "base-x": "^3.0.2" + } + }, "node_modules/brace-expansion": { "version": "1.1.14", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.14.tgz", @@ -4980,6 +6533,72 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/bs58": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-6.0.0.tgz", + "integrity": "sha512-PD0wEnEYg6ijszw/u8s+iI3H17cTymlrwkKhDhPZq+Sokl3AU4htyBFTjAeNAlCCmg0f53g6ih3jATyCKftTfw==", + "license": "MIT", + "dependencies": { + "base-x": "^5.0.0" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true, + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "license": "MIT", + "peer": true + }, + "node_modules/bufferutil": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bufferutil/-/bufferutil-4.1.0.tgz", + "integrity": "sha512-ZMANVnAixE6AWWnPzlW2KpUrxhm9woycYvPOo67jWHyFowASTEd9s+QN1EIMsSDtwhIxN4sWE1jotpuDUIgyIw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, "node_modules/bundle-name": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", @@ -5061,6 +6680,19 @@ "node": ">=6" } }, + "node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/caniuse-lite": { "version": "1.0.30001791", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001791.tgz", @@ -5085,7 +6717,6 @@ "version": "4.1.2", "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, "license": "MIT", "dependencies": { "ansi-styles": "^4.1.0", @@ -5098,6 +6729,104 @@ "url": "https://github.com/chalk/chalk?sponsor=1" } }, + "node_modules/chrome-launcher": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/chrome-launcher/-/chrome-launcher-0.15.2.tgz", + "integrity": "sha512-zdLEwNo3aUVzIhKhTtXfxhdvZhUghrnmkvcAq2NoDd+LeOHKf03H5jwZ8T/STsAlzyALkBVK552iaG1fGf1xVQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0" + }, + "bin": { + "print-chrome-path": "bin/print-chrome-path.js" + }, + "engines": { + "node": ">=12.13.0" + } + }, + "node_modules/chrome-launcher/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "peer": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chrome-launcher/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/chromium-edge-launcher": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/chromium-edge-launcher/-/chromium-edge-launcher-0.3.0.tgz", + "integrity": "sha512-p03azHlGjtyRvFEee3cyvtsRYdniSkwjkzmM/KmVnqT5d7QkkwpJBhis/zCLMYdQMVJ5tt140TBNqqrZPaWeFA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@types/node": "*", + "escape-string-regexp": "^4.0.0", + "is-wsl": "^2.2.0", + "lighthouse-logger": "^1.0.0", + "mkdirp": "^1.0.4" + } + }, + "node_modules/chromium-edge-launcher/node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "license": "MIT", + "peer": true, + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/chromium-edge-launcher/node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "license": "MIT", + "peer": true, + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ci-info": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", + "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", + "license": "MIT", + "peer": true + }, "node_modules/class-variance-authority": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz", @@ -5240,22 +6969,107 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "license": "MIT" }, - "node_modules/commander": { - "version": "14.0.3", - "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", - "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "node_modules/commander": { + "version": "14.0.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-14.0.3.tgz", + "integrity": "sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw==", + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT", + "peer": true + }, + "node_modules/connect/node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha512-ikqdkGAAyf/X/gPhXGvfgAytDZtDbr+bkNUJ0N9h5MI/dmdgCs3l6hoHrcUv41sRKew3jIwrp4qQDXiK99Utww==", + "license": "MIT", + "peer": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==", "license": "MIT", + "peer": true, "engines": { - "node": ">=20" + "node": ">= 0.6" } }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "dev": true, - "license": "MIT" - }, "node_modules/content-disposition": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-1.1.0.tgz", @@ -5302,6 +7116,26 @@ "node": ">=6.6.0" } }, + "node_modules/copy-to-clipboard": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/copy-to-clipboard/-/copy-to-clipboard-3.3.3.tgz", + "integrity": "sha512-2KV8NhB5JqC3ky0r9PMCAZKbUHSwtEo4CwCs0KXgruG43gX5PMqDEBbVU4OUzw2MuAWUfsuFmWvEKG5QRfSnJA==", + "license": "MIT", + "dependencies": { + "toggle-selection": "^1.0.6" + } + }, + "node_modules/core-js": { + "version": "3.47.0", + "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.47.0.tgz", + "integrity": "sha512-c3Q2VVkGAUyupsjRnaNX6u8Dq2vAdzm9iuPj5FW0fRxzlxgq9Q39MDq10IvmQSpLgHQNyQzQmOo6bgGHmH3NNg==", + "hasInstallScript": true, + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, "node_modules/cors": { "version": "2.8.6", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", @@ -5375,7 +7209,6 @@ "version": "3.2.3", "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "devOptional": true, "license": "MIT" }, "node_modules/damerau-levenshtein": { @@ -5465,6 +7298,15 @@ } } }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha512-z2S+W9X73hAUUki+N+9Za2lBlun89zigOyGrsax+KUQ6wKW4ZoWpEYBkGhQjwAjjDCkWxhY0VKEhk8wzY7F5cA==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/dedent": { "version": "1.7.2", "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", @@ -5571,6 +7413,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delay": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", + "integrity": "sha512-ReEBKkIfe4ya47wlPYf/gu5ib6yUG0/Aez0JQZQz94kiWtRQvZIQbTiehsnwHvLSWJnQdhVeqYue7Id1dKr0qw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/depd": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", @@ -5580,6 +7435,26 @@ "node": ">= 0.8" } }, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, "node_modules/detect-libc": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", @@ -5605,6 +7480,12 @@ "node": ">=0.3.1" } }, + "node_modules/dijkstrajs": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.3.tgz", + "integrity": "sha512-qiSlmBq9+BCdCA/L46dw8Uy93mloxsPSbwnm5yrKn2vMPiy8KyAskTF6zuV/j5BMsmOGZDPs7KjU+mjb670kfA==", + "license": "MIT" + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -5721,6 +7602,16 @@ "is-arrayish": "^0.2.1" } }, + "node_modules/error-stack-parser": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/error-stack-parser/-/error-stack-parser-2.1.4.tgz", + "integrity": "sha512-Sk5V6wVazPhq5MhpO+AUxJn5x7XSXGl1R93Vn7i+zS15KDVxQijejNCrz8340/2bgLBjR9GtEG8ZVKONDjcqGQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "stackframe": "^1.3.4" + } + }, "node_modules/es-abstract": { "version": "1.24.2", "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", @@ -5895,6 +7786,23 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/es6-promise": { + "version": "4.2.8", + "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz", + "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w==", + "license": "MIT", + "peer": true + }, + "node_modules/es6-promisify": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz", + "integrity": "sha512-C+d6UdsYDk0lMebHNR4S2NybQMMngAOnOwYBQjTOiv0MkoJMP0Myw2mgpDLBcpfCmRLxyFqYhS/CfOENq4SJhQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "es6-promise": "^4.0.3" + } + }, "node_modules/escalade": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", @@ -5914,7 +7822,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", - "dev": true, "license": "MIT", "engines": { "node": ">=10" @@ -6351,6 +8258,22 @@ "node": ">= 0.6" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/eventemitter3": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-5.0.4.tgz", + "integrity": "sha512-mlsTRyGaPBjPedk6Bvw+aqbsXDtoAyAzm5MO7JgU+yVRyMQ5O8bD4Kcci7BS85f93veegeCPkL8R4GLClnjLFw==", + "license": "MIT" + }, "node_modules/eventsource": { "version": "3.0.7", "resolved": "https://registry.npmjs.org/eventsource/-/eventsource-3.0.7.tgz", @@ -6398,6 +8321,13 @@ "url": "https://github.com/sindresorhus/execa?sponsor=1" } }, + "node_modules/exponential-backoff": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.3.tgz", + "integrity": "sha512-ZgEeZXj30q+I0EN+CbSSpIyPaJ5HVQD18Z1m+u1FXbAeT94mr1zw50q4q6jiiC447Nl/YTcIYSAftiGqetwXCA==", + "license": "Apache-2.0", + "peer": true + }, "node_modules/express": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/express/-/express-5.2.1.tgz", @@ -6459,6 +8389,15 @@ "express": ">= 4.11" } }, + "node_modules/eyes": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/eyes/-/eyes-0.1.8.tgz", + "integrity": "sha512-GipyPsXO1anza0AOZdy69Im7hGFCNB7Y/NGjDlZGJ3GJJLtwNSb2vrzYrTYJRrRloVx7pl+bhUaTB8yiccPvFQ==", + "peer": true, + "engines": { + "node": "> 0.1.90" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -6509,6 +8448,19 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-sha256": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-sha256/-/fast-sha256-1.3.0.tgz", + "integrity": "sha512-n11RGP/lrWEFI/bWdygLxhI+pVeo1ZYIVwvvPkW7azl/rOy+F3HYRZ2K5zeE9mmkhQppyv9sQFx0JM9UabnpPQ==", + "license": "Unlicense" + }, + "node_modules/fast-stable-stringify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fast-stable-stringify/-/fast-stable-stringify-1.0.0.tgz", + "integrity": "sha512-wpYMUmFu5f00Sm0cj2pfivpmawLZ0NKdviQ4w9zJeR8JVtOpOxHmLaJuj0vxvGqMJQWyP/COUkF75/57OKyRag==", + "license": "MIT", + "peer": true + }, "node_modules/fast-string-truncated-width": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", @@ -6558,6 +8510,29 @@ "reusify": "^1.0.4" } }, + "node_modules/fb-dotslash": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/fb-dotslash/-/fb-dotslash-0.5.8.tgz", + "integrity": "sha512-XHYLKk9J4BupDxi9bSEhkfss0m+Vr9ChTrjhf9l2iw3jB5C7BnY4GVPoMcqbrTutsKJso6yj2nAB6BI/F2oZaA==", + "license": "(MIT OR Apache-2.0)", + "peer": true, + "bin": { + "dotslash": "bin/dotslash" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "bser": "2.1.1" + } + }, "node_modules/fetch-blob": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/fetch-blob/-/fetch-blob-3.2.0.tgz", @@ -6642,6 +8617,12 @@ "url": "https://opencollective.com/express" } }, + "node_modules/find-root": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/find-root/-/find-root-1.1.0.tgz", + "integrity": "sha512-NKfW6bec6GfKc0SGx1e07QZY9PE99u0Bft/0rzSD5k3sO/vwkVUpDUKVm5Gpp5Ue3YfShPFTX2070tDs5kB9Ng==", + "license": "MIT" + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -6680,6 +8661,13 @@ "dev": true, "license": "ISC" }, + "node_modules/flow-enums-runtime": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/flow-enums-runtime/-/flow-enums-runtime-0.0.6.tgz", + "integrity": "sha512-3PYnM29RFXwvAN6Pc/scUfkI7RwhQ/xqyLUyPNlXUp9S40zI8nup9tUSrTLSVnWGBN38FNiGWbwZOB6uR4OGdw==", + "license": "MIT", + "peer": true + }, "node_modules/for-each": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", @@ -6944,6 +8932,12 @@ "node": ">=10.13.0" } }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", + "license": "BSD-2-Clause" + }, "node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -7018,7 +9012,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -7103,6 +9096,13 @@ "set-cookie-parser": "^3.0.1" } }, + "node_modules/hermes-compiler": { + "version": "250829098.0.10", + "resolved": "https://registry.npmjs.org/hermes-compiler/-/hermes-compiler-250829098.0.10.tgz", + "integrity": "sha512-TcRlZ0/TlyfJqquRFAWoyElVNnkdYRi/sEp4/Qy8/GYxjg8j2cS9D4MjuaQ+qimkmLN7AmO+44IznRf06mAr0w==", + "license": "MIT", + "peer": true + }, "node_modules/hermes-estree": { "version": "0.25.1", "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.25.1.tgz", @@ -7120,6 +9120,15 @@ "hermes-estree": "0.25.1" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "license": "BSD-3-Clause", + "dependencies": { + "react-is": "^16.7.0" + } + }, "node_modules/hono": { "version": "4.12.16", "resolved": "https://registry.npmjs.org/hono/-/hono-4.12.16.tgz", @@ -7171,6 +9180,16 @@ "node": ">=18.18.0" } }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/iconv-lite": { "version": "0.7.2", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", @@ -7187,6 +9206,27 @@ "url": "https://opencollective.com/express" } }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause", + "peer": true + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", @@ -7196,6 +9236,22 @@ "node": ">= 4" } }, + "node_modules/image-size": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz", + "integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==", + "license": "MIT", + "peer": true, + "dependencies": { + "queue": "6.0.2" + }, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=16.x" + } + }, "node_modules/import-fresh": { "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", @@ -7228,6 +9284,16 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", "license": "ISC" }, + "node_modules/input-otp": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/input-otp/-/input-otp-1.4.2.tgz", + "integrity": "sha512-l3jWwYNvrEa6NTCt7BECfCm48GvwuZzkoeG3gBL2w4CHeOXW3eKFmf9UNYkNfYc3mxMrthMnxjIE07MT0zLBQA==", + "license": "MIT", + "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" + } + }, "node_modules/internal-slot": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", @@ -7243,6 +9309,16 @@ "node": ">= 0.4" } }, + "node_modules/invariant": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.4.tgz", + "integrity": "sha512-phJfQVBuaJM5raOpJjSfkiD6BpbCE4Ns//LaXl6wGYtUBY83nWS6Rf9tXm2e8VaK60JEjYldbPif/A2B1C2gNA==", + "license": "MIT", + "peer": true, + "dependencies": { + "loose-envify": "^1.0.0" + } + }, "node_modules/ip-address": { "version": "10.1.0", "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.1.0.tgz", @@ -7378,7 +9454,6 @@ "version": "2.16.1", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz", "integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==", - "dev": true, "license": "MIT", "dependencies": { "hasown": "^2.0.2" @@ -7794,73 +9869,218 @@ "call-bound": "^1.0.3" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-weakset": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", + "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-intrinsic": "^1.2.6" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/isomorphic-ws": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-ws/-/isomorphic-ws-4.0.1.tgz", + "integrity": "sha512-BhBvN2MBpWTaSHdWRb/bwdZJ1WaehQ2L1KngkCkfLUGF0mAWAT1sQUQacEmQ0jXkFw/czDXPNQSL5u2/Krsz1w==", + "license": "MIT", + "peer": true, + "peerDependencies": { + "ws": "*" + } + }, + "node_modules/iterator.prototype": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", + "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "define-data-property": "^1.1.4", + "es-object-atoms": "^1.0.0", + "get-intrinsic": "^1.2.6", + "get-proto": "^1.0.0", + "has-symbols": "^1.1.0", + "set-function-name": "^2.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/jayson": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/jayson/-/jayson-4.3.0.tgz", + "integrity": "sha512-AauzHcUcqs8OBnCHOkJY280VaTiCm57AbuO7lqzcw7JapGj50BisE3xhksye4zlTSR1+1tAz67wLTl8tEH1obQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/connect": "^3.4.33", + "@types/node": "^12.12.54", + "@types/ws": "^7.4.4", + "commander": "^2.20.3", + "delay": "^5.0.0", + "es6-promisify": "^5.0.0", + "eyes": "^0.1.8", + "isomorphic-ws": "^4.0.1", + "json-stringify-safe": "^5.0.1", + "stream-json": "^1.9.1", + "uuid": "^8.3.2", + "ws": "^7.5.10" + }, + "bin": { + "jayson": "bin/jayson.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jayson/node_modules/@types/node": { + "version": "12.20.55", + "resolved": "https://registry.npmjs.org/@types/node/-/node-12.20.55.tgz", + "integrity": "sha512-J8xLz7q2OFulZ2cyGTLE1TbbZcjpno7FaN6zdJNrgAdrJ+DZzh/uFR6YrTb4C+nXakvud8Q4+rbhoIWlYQbUFQ==", + "license": "MIT", + "peer": true + }, + "node_modules/jayson/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT", + "peer": true + }, + "node_modules/jest-get-type": { + "version": "29.6.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.6.3.tgz", + "integrity": "sha512-zrteXnqYxfQh7l5FHyL38jL39di8H8rHoecLH3JNxH3BwOrBsNeabdap5e0I23lD4HHI8W5VFBZqG4Eaq5LNcw==", + "license": "MIT", + "peer": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.7.0.tgz", + "integrity": "sha512-z6EbKajIpqGKU56y5KBUgy1dt1ihhQJgWzUlZHArA/+X2ad7Cb5iF+AK1EWVL/Bo7Rz9uurpqw6SiBCefUbCGA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/types": "^29.6.3", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ci-info": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.9.0.tgz", + "integrity": "sha512-NIxF55hv4nSqQswkAeiOi1r83xy8JldOFDTWiug55KBu9Jnblncd2U6ViHmYgHf01TPZS77NJBhBMKdWj9HQMQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" } }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, + "node_modules/jest-validate": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.7.0.tgz", + "integrity": "sha512-ZB7wHqaRGVw/9hST/OuFUReG7M8vKeq0/J2egIGLdvjHCmYqGARhzXmtgi+gVeZ5uXFF219aOc3Ls2yLg27tkw==", "license": "MIT", + "peer": true, "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" + "@jest/types": "^29.6.3", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.6.3", + "leven": "^3.1.0", + "pretty-format": "^29.7.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/is-wsl": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", - "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "node_modules/jest-worker": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.7.0.tgz", + "integrity": "sha512-eIz2msL/EzL9UFTFFx7jBTkeZfku0yUAyZZZmJ93H2TYEiroIx2PQjEXcwYtYl8zXCxb+PAmA2hLIt/6ZEkPHw==", "license": "MIT", + "peer": true, "dependencies": { - "is-inside-container": "^1.0.0" + "@types/node": "*", + "jest-util": "^29.7.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" }, "engines": { - "node": ">=16" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/iterator.prototype": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", - "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", - "dev": true, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", "license": "MIT", + "peer": true, "dependencies": { - "define-data-property": "^1.1.4", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "get-proto": "^1.0.0", - "has-symbols": "^1.1.0", - "set-function-name": "^2.0.2" + "has-flag": "^4.0.0" }, "engines": { - "node": ">= 0.4" + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, "node_modules/jiti": { @@ -7882,6 +10102,21 @@ "url": "https://github.com/sponsors/panva" } }, + "node_modules/js-base64": { + "version": "3.7.8", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-3.7.8.tgz", + "integrity": "sha512-hNngCeKxIUQiEUN3GPJOkz4wF/YvdUdbNL9hsBcMQTkKzboD7T/q3OYOuuPZLUE6dBxSGpwhk5mwuDud7JVAow==", + "license": "BSD-3-Clause" + }, + "node_modules/js-cookie": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-3.0.5.tgz", + "integrity": "sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, "node_modules/js-tokens": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", @@ -7900,6 +10135,13 @@ "js-yaml": "bin/js-yaml.js" } }, + "node_modules/jsc-safe-url": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/jsc-safe-url/-/jsc-safe-url-0.2.4.tgz", + "integrity": "sha512-0wM3YBWtYePOjfyXQH5MWQ8H7sdk5EXSwZvmSLKk2RboVQ2Bu239jycHDz5J/8Blf3K0Qnoy2b6xD+z10MFB+Q==", + "license": "0BSD", + "peer": true + }, "node_modules/jsesc": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", @@ -7945,6 +10187,13 @@ "dev": true, "license": "MIT" }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "license": "ISC", + "peer": true + }, "node_modules/json5": { "version": "2.2.3", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", @@ -8024,6 +10273,16 @@ "node": ">=0.10" } }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -8038,6 +10297,34 @@ "node": ">= 0.8.0" } }, + "node_modules/lighthouse-logger": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/lighthouse-logger/-/lighthouse-logger-1.4.2.tgz", + "integrity": "sha512-gPWxznF6TKmUHrOQjlVo2UbaL2EJ71mb2CCeRs/2qBpi4L/g4LUVc9+3lKQ6DTUZwJswfM7ainGrLO1+fOqa2g==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "debug": "^2.6.9", + "marky": "^1.2.2" + } + }, + "node_modules/lighthouse-logger/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "license": "MIT", + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/lighthouse-logger/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "license": "MIT", + "peer": true + }, "node_modules/lightningcss": { "version": "1.32.0", "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", @@ -8340,6 +10627,13 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.throttle": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.throttle/-/lodash.throttle-4.1.1.tgz", + "integrity": "sha512-wIkUCfVKpVsWo3JSZlc+8MB5it+2AN5W8J7YVMST30UrvcQNZ1Okbj+rbVniijTWE6FGYy4XJq/rHkas8qJMLQ==", + "license": "MIT", + "peer": true + }, "node_modules/log-symbols": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-6.0.0.tgz", @@ -8384,7 +10678,6 @@ "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, "license": "MIT", "dependencies": { "js-tokens": "^3.0.0 || ^4.0.0" @@ -8421,49 +10714,442 @@ "@jridgewell/sourcemap-codec": "^1.5.5" } }, - "node_modules/math-intrinsics": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", - "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "license": "MIT", + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/marky": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/marky/-/marky-1.3.0.tgz", + "integrity": "sha512-ocnPZQLNpvbedwTy9kNrQEsknEfgvcLMvOtz3sFeWApDq1MXH1TqkCIx58xlpESsfwQOnuBO9beyQuNGzVvuhQ==", + "license": "Apache-2.0", + "peer": true + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/media-typer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", + "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/memoize-one": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz", + "integrity": "sha512-zYiwtZUcYyXKo/np96AGZAckk+FWWsUdJ3cHGGmld7+AhvcWmQyGCYUh1hc4Q/pkOhb65dQR/pqCyK0cOaHz4Q==", + "license": "MIT", + "peer": true + }, + "node_modules/merge-descriptors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", + "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge-options": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/merge-options/-/merge-options-3.0.4.tgz", + "integrity": "sha512-2Sug1+knBjkaMsMgf1ctR1Ujx+Ayku4EdJN4Z+C2+JzoeF7A3OZ9KM2GY0CpQS51NR61LTurMJrRKPhSs3ZRTQ==", + "license": "MIT", + "optional": true, + "dependencies": { + "is-plain-obj": "^2.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/merge-options/node_modules/is-plain-obj": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-2.1.0.tgz", + "integrity": "sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/metro": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro/-/metro-0.84.4.tgz", + "integrity": "sha512-8ETTubqfD6ornDy2zYDvRcKnVDOXdFJsjetYDBsY4oAsb6NJkiwFR+FaMESyGppFmQUyBQA4H4sFGxzcQSGtFA==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "accepts": "^2.0.0", + "ci-info": "^2.0.0", + "connect": "^3.6.5", + "debug": "^4.4.0", + "error-stack-parser": "^2.0.6", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "hermes-parser": "0.35.0", + "image-size": "^1.0.2", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "jsc-safe-url": "^0.2.2", + "lodash.throttle": "^4.1.1", + "metro-babel-transformer": "0.84.4", + "metro-cache": "0.84.4", + "metro-cache-key": "0.84.4", + "metro-config": "0.84.4", + "metro-core": "0.84.4", + "metro-file-map": "0.84.4", + "metro-resolver": "0.84.4", + "metro-runtime": "0.84.4", + "metro-source-map": "0.84.4", + "metro-symbolicate": "0.84.4", + "metro-transform-plugins": "0.84.4", + "metro-transform-worker": "0.84.4", + "mime-types": "^3.0.1", + "nullthrows": "^1.1.1", + "serialize-error": "^2.1.0", + "source-map": "^0.5.6", + "throat": "^5.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "metro": "src/cli.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-babel-transformer": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-babel-transformer/-/metro-babel-transformer-0.84.4.tgz", + "integrity": "sha512-rvCfz8snl9h20VcvpOHxZuHP1SlAkv4HXbzw7nyyVwu6Eqo5PRerbakQ9XmUCOsRy70spJ37O+G1TK8oMzo48g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "flow-enums-runtime": "^0.0.6", + "hermes-parser": "0.35.0", + "metro-cache-key": "0.84.4", + "nullthrows": "^1.1.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-babel-transformer/node_modules/hermes-estree": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", + "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", + "license": "MIT", + "peer": true + }, + "node_modules/metro-babel-transformer/node_modules/hermes-parser": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", + "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", + "license": "MIT", + "peer": true, + "dependencies": { + "hermes-estree": "0.35.0" + } + }, + "node_modules/metro-cache": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-cache/-/metro-cache-0.84.4.tgz", + "integrity": "sha512-gpcFQdSLUwUCk71saKoE64jLFbx2nwTfVCcPSULMNT8QYq0p1eZZE29Jvd0HtT/UlhC3ZOutLxJME5xqD2JUZg==", + "license": "MIT", + "peer": true, + "dependencies": { + "exponential-backoff": "^3.1.1", + "flow-enums-runtime": "^0.0.6", + "https-proxy-agent": "^7.0.5", + "metro-core": "0.84.4" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-cache-key": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-cache-key/-/metro-cache-key-0.84.4.tgz", + "integrity": "sha512-wVO79aGrkYImpnaVS4+d5RrRBRPX31QtvKB3wKGBuiNSznduZTQHzsrJZRroFJSwnygrzdsGUtDQPuqqFjFdvw==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-config": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-config/-/metro-config-0.84.4.tgz", + "integrity": "sha512-PMotGDjXcXLWo2TMRH+VR99phFNgYTwqh4OoieIKK3yTJa1Jmkl+fZJxDO0jfBvNF+WESHciHvpNuBtXaF3B0Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "connect": "^3.6.5", + "flow-enums-runtime": "^0.0.6", + "jest-validate": "^29.7.0", + "metro": "0.84.4", + "metro-cache": "0.84.4", + "metro-core": "0.84.4", + "metro-runtime": "0.84.4", + "yaml": "^2.6.1" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-core": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-core/-/metro-core-0.84.4.tgz", + "integrity": "sha512-HONpWC5LGXZn3ffkd4Hu6AIrfE7j4Z0g0wMo/goV24WOB3lhuFZ40KgvaDiSw8iyQHloMYay5N/wPX+z8oN/PQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "lodash.throttle": "^4.1.1", + "metro-resolver": "0.84.4" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-file-map": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-file-map/-/metro-file-map-0.84.4.tgz", + "integrity": "sha512-KSVDi/u60hKPx++NLu3MTIvyjzNoJnFAF8PQFxaj1jiSka/wjw+Ua6sNuJ0TDHQv+7AAoFQxeMgaRAe8Yic5wQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "debug": "^4.4.0", + "fb-watchman": "^2.0.0", + "flow-enums-runtime": "^0.0.6", + "graceful-fs": "^4.2.4", + "invariant": "^2.2.4", + "jest-worker": "^29.7.0", + "micromatch": "^4.0.4", + "nullthrows": "^1.1.1", + "walker": "^1.0.7" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-minify-terser": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-minify-terser/-/metro-minify-terser-0.84.4.tgz", + "integrity": "sha512-5qpbaVOMC7CPitIpuewzVeGw7E+C3ykbv2mqTjQLl85Z3annSVGlSCTcsZjqXZzjupfK4Ztj3dDc4kc44NZwtQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "terser": "^5.15.0" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-resolver": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-resolver/-/metro-resolver-0.84.4.tgz", + "integrity": "sha512-1qLgbxQ5ZGhhutuPot1Yp348ofDsATL2WkrHF65TobqTT9K3P9qJXw38bomk7ncp5B7OYMfWwtyBZo1lCV792A==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-runtime": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-runtime/-/metro-runtime-0.84.4.tgz", + "integrity": "sha512-Jibypds4g7AhzdRKY+kDoj51s5EXMwgyp5ddtlreDAsWefMdOx+agWqgm0H2XSZ/ueanHHVM89fnf5OJnlxa8Q==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/runtime": "^7.25.0", + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-source-map": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-source-map/-/metro-source-map-0.84.4.tgz", + "integrity": "sha512-jbWkPxIesVuo1IWkvezmMJld6iu8nD62GsrZiV6jP37AOdbo4OBq1FJ+qkOg8sV05wAHB//jAbziuW0SlJfW4g==", + "license": "MIT", + "peer": true, + "dependencies": { + "@babel/traverse": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-symbolicate": "0.84.4", + "nullthrows": "^1.1.1", + "ob1": "0.84.4", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-source-map/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/metro-symbolicate": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-symbolicate/-/metro-symbolicate-0.84.4.tgz", + "integrity": "sha512-OnfpacxUqGPZQ27t8qK9mFa7uqHIlVWeqRqkCbvMvreEBiamEeOn8krKtcwgP5M4cYDPwuSmCTopHMVthqG4zA==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6", + "invariant": "^2.2.4", + "metro-source-map": "0.84.4", + "nullthrows": "^1.1.1", + "source-map": "^0.5.6", + "vlq": "^1.0.0" + }, + "bin": { + "metro-symbolicate": "src/index.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, + "node_modules/metro-symbolicate/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "peer": true, "engines": { - "node": ">= 0.4" + "node": ">=0.10.0" } }, - "node_modules/media-typer": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-1.1.0.tgz", - "integrity": "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw==", + "node_modules/metro-transform-plugins": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-transform-plugins/-/metro-transform-plugins-0.84.4.tgz", + "integrity": "sha512-kehr6HbAecqD0/a3xLXobELdPaAmRAl8bel0qagPF4vhZtux93nS8S4eq2kgKt6J2GnQpVjSoW1PXdst04mwow==", "license": "MIT", + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/template": "^7.28.6", + "@babel/traverse": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "nullthrows": "^1.1.1" + }, "engines": { - "node": ">= 0.8" + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/merge-descriptors": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-2.0.0.tgz", - "integrity": "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g==", + "node_modules/metro-transform-worker": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/metro-transform-worker/-/metro-transform-worker-0.84.4.tgz", + "integrity": "sha512-W1IYMvvXTu4MxYr7d9h7CeG2vpIr3bmLLIavkPY4O1ilzDrvS8z/NEe6y+pC44Ff7raMXQgYSfdqDUwN/i39gg==", "license": "MIT", - "engines": { - "node": ">=18" + "peer": true, + "dependencies": { + "@babel/core": "^7.25.2", + "@babel/generator": "^7.29.1", + "@babel/parser": "^7.29.0", + "@babel/types": "^7.29.0", + "flow-enums-runtime": "^0.0.6", + "metro": "0.84.4", + "metro-babel-transformer": "0.84.4", + "metro-cache": "0.84.4", + "metro-cache-key": "0.84.4", + "metro-minify-terser": "0.84.4", + "metro-source-map": "0.84.4", + "metro-transform-plugins": "0.84.4", + "nullthrows": "^1.1.1" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" } }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "license": "MIT" + "node_modules/metro/node_modules/hermes-estree": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-estree/-/hermes-estree-0.35.0.tgz", + "integrity": "sha512-xVx5Opwy8Oo1I5yGpVRhCvWL/iV3M+ylksSKVNlxxD90cpDpR/AR1jLYqK8HWihm065a6UI3HeyAmYzwS8NOOg==", + "license": "MIT", + "peer": true }, - "node_modules/merge2": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", - "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "node_modules/metro/node_modules/hermes-parser": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/hermes-parser/-/hermes-parser-0.35.0.tgz", + "integrity": "sha512-9JLjeHxBx8T4CAsydZR49PNZUaix+WpQJwu9p2010lu+7Kwl6D/7wYFFJxoz+aXkaaClp9Zfg6W6/zVlSJORaA==", "license": "MIT", + "peer": true, + "dependencies": { + "hermes-estree": "0.35.0" + } + }, + "node_modules/metro/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha512-LbrmJOMUSdEVxIKvdcJzQC+nQhe8FUZQTXQy6+I75skNgn3OoQ0DZA8YnFa7gp8tqtL3KPf1kmo0R5DoApeSGQ==", + "license": "BSD-3-Clause", + "peer": true, "engines": { - "node": ">= 8" + "node": ">=0.10.0" } }, "node_modules/micromatch": { @@ -8479,6 +11165,19 @@ "node": ">=8.6" } }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "license": "MIT", + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/mime-db": { "version": "1.54.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", @@ -8547,6 +11246,19 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "license": "MIT", + "peer": true, + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -8807,6 +11519,26 @@ "url": "https://opencollective.com/node-fetch" } }, + "node_modules/node-gyp-build": { + "version": "4.8.4", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.4.tgz", + "integrity": "sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==", + "license": "MIT", + "optional": true, + "peer": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "license": "MIT", + "peer": true + }, "node_modules/node-releases": { "version": "2.0.38", "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.38.tgz", @@ -8841,6 +11573,26 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/nullthrows": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/nullthrows/-/nullthrows-1.1.1.tgz", + "integrity": "sha512-2vPPEi+Z7WqML2jZYddDIfy5Dqb0r2fze2zTxNNknZaFpVHU3mFB3R+DWeJWGVx0ecvttSGlJTI+WG+8Z4cDWw==", + "license": "MIT", + "peer": true + }, + "node_modules/ob1": { + "version": "0.84.4", + "resolved": "https://registry.npmjs.org/ob1/-/ob1-0.84.4.tgz", + "integrity": "sha512-eJXMpz4aQHXF/YBB9ddqZDIS+ooO91hObo9FoW/xBkr54/zCwYYCDqT/O54vNo8kOkWs5Ou/y28NgdrV0edQNA==", + "license": "MIT", + "peer": true, + "dependencies": { + "flow-enums-runtime": "^0.0.6" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -9136,6 +11888,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -9197,7 +11958,6 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -9216,7 +11976,6 @@ "version": "1.0.7", "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, "license": "MIT" }, "node_modules/path-to-regexp": { @@ -9225,6 +11984,15 @@ "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==", "license": "MIT" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/picocolors": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", @@ -9252,6 +12020,15 @@ "node": ">=16.20.0" } }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "license": "MIT", + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/possible-typed-array-names": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", @@ -9325,6 +12102,41 @@ "node": ">= 0.8.0" } }, + "node_modules/pretty-format": { + "version": "29.7.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.7.0.tgz", + "integrity": "sha512-Pdlw/oPxN+aXdmM9R00JVC9WVFoCLTKJvDVLgmJ+qAffBMxsV85l/Lu7sNx4zSzPyoL2euImuEwHhOXdEgNFZQ==", + "license": "MIT", + "peer": true, + "dependencies": { + "@jest/schemas": "^29.6.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/pretty-format/node_modules/react-is": { + "version": "18.3.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.3.1.tgz", + "integrity": "sha512-/LLMVyas0ljjAtoYiPqYiL8VWXzUUdThrmU5+n20DZv+a+ClRoevUzw5JxU+Ieh5/c87ytoTBV9G1FiKfNJdmg==", + "license": "MIT", + "peer": true + }, "node_modules/pretty-ms": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.0.tgz", @@ -9340,6 +12152,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/promise": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/promise/-/promise-8.3.0.tgz", + "integrity": "sha512-rZPNPKTOYVNEEKFaq1HqTgOwZD+4/YHS5ukLzQCypkj+OkYx7iv0mA91lJlpPPZ8vMau3IIGj5Qlwrx+8iiSmg==", + "license": "MIT", + "peer": true, + "dependencies": { + "asap": "~2.0.6" + } + }, "node_modules/prompts": { "version": "2.4.2", "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", @@ -9397,6 +12219,200 @@ "node": ">=6" } }, + "node_modules/qrcode": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.4.tgz", + "integrity": "sha512-1ca71Zgiu6ORjHqFBDpnSMTR2ReToX4l1Au1VFLyVeBTFavzQnv5JxMFr3ukHVKpSrSA2MCk0lNJSykjUfz7Zg==", + "license": "MIT", + "dependencies": { + "dijkstrajs": "^1.0.1", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode.react": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.2.0.tgz", + "integrity": "sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, + "node_modules/qrcode/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/qrcode/node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/qrcode/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "license": "MIT" + }, + "node_modules/qrcode/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/qrcode/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "license": "ISC" + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "license": "MIT", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qrcode/node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "license": "ISC", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/qs": { "version": "6.15.1", "resolved": "https://registry.npmjs.org/qs/-/qs-6.15.1.tgz", @@ -9412,6 +12428,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/queue": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/queue/-/queue-6.0.2.tgz", + "integrity": "sha512-iHZWu+q3IdFZFX36ro/lKBkSvfkztY5Y7HMiPlOUjhupPcG2JMfst2KKEpu5XndviX/3UhFbRngUPNKtgvtZiA==", + "license": "MIT", + "peer": true, + "dependencies": { + "inherits": "~2.0.3" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", @@ -9542,6 +12568,17 @@ "node": ">=0.10.0" } }, + "node_modules/react-devtools-core": { + "version": "6.1.5", + "resolved": "https://registry.npmjs.org/react-devtools-core/-/react-devtools-core-6.1.5.tgz", + "integrity": "sha512-ePrwPfxAnB+7hgnEr8vpKxL9cmnp7F322t8oqcPshbIQQhDKgFDW4tjhF2wjVbdXF9O/nyuy3sQWd9JGpiLPvA==", + "license": "MIT", + "peer": true, + "dependencies": { + "shell-quote": "^1.6.1", + "ws": "^7" + } + }, "node_modules/react-dom": { "version": "19.2.4", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", @@ -9558,9 +12595,111 @@ "version": "16.13.1", "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, "license": "MIT" }, + "node_modules/react-native": { + "version": "0.85.2", + "resolved": "https://registry.npmjs.org/react-native/-/react-native-0.85.2.tgz", + "integrity": "sha512-GFWEPwLYirfj5X8gMtXOWtqX0cqUEURRHETZfFk37VCa4++izrKvGvv24anvuyulXV87NAhVkfNw93rLg3HByw==", + "license": "MIT", + "peer": true, + "dependencies": { + "@react-native/assets-registry": "0.85.2", + "@react-native/codegen": "0.85.2", + "@react-native/community-cli-plugin": "0.85.2", + "@react-native/gradle-plugin": "0.85.2", + "@react-native/js-polyfills": "0.85.2", + "@react-native/normalize-colors": "0.85.2", + "@react-native/virtualized-lists": "0.85.2", + "abort-controller": "^3.0.0", + "anser": "^1.4.9", + "ansi-regex": "^5.0.0", + "babel-plugin-syntax-hermes-parser": "0.33.3", + "base64-js": "^1.5.1", + "commander": "^12.0.0", + "flow-enums-runtime": "^0.0.6", + "hermes-compiler": "250829098.0.10", + "invariant": "^2.2.4", + "memoize-one": "^5.0.0", + "metro-runtime": "^0.84.0", + "metro-source-map": "^0.84.0", + "nullthrows": "^1.1.1", + "pretty-format": "^29.7.0", + "promise": "^8.3.0", + "react-devtools-core": "^6.1.5", + "react-refresh": "^0.14.0", + "regenerator-runtime": "^0.13.2", + "scheduler": "0.27.0", + "semver": "^7.1.3", + "stacktrace-parser": "^0.1.10", + "tinyglobby": "^0.2.15", + "whatwg-fetch": "^3.0.0", + "ws": "^7.5.10", + "yargs": "^17.6.2" + }, + "bin": { + "react-native": "cli.js" + }, + "engines": { + "node": "^20.19.4 || ^22.13.0 || ^24.3.0 || >= 25.0.0" + }, + "peerDependencies": { + "@react-native/jest-preset": "0.85.2", + "@types/react": "^19.1.1", + "react": "^19.2.3" + }, + "peerDependenciesMeta": { + "@react-native/jest-preset": { + "optional": true + }, + "@types/react": { + "optional": true + } + } + }, + "node_modules/react-native/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/react-native/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=18" + } + }, + "node_modules/react-native/node_modules/semver": { + "version": "7.7.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz", + "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==", + "license": "ISC", + "peer": true, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/react-remove-scroll": { "version": "2.7.2", "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", @@ -9669,6 +12808,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT", + "peer": true + }, "node_modules/regexp.prototype.flags": { "version": "1.5.4", "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", @@ -9708,6 +12854,12 @@ "node": ">=0.10.0" } }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", + "license": "ISC" + }, "node_modules/resolve": { "version": "2.0.0-next.6", "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.6.tgz", @@ -9809,6 +12961,91 @@ "url": "https://opencollective.com/express" } }, + "node_modules/rpc-websockets": { + "version": "9.3.8", + "resolved": "https://registry.npmjs.org/rpc-websockets/-/rpc-websockets-9.3.8.tgz", + "integrity": "sha512-7r+fm4tSJmLf9GvZfL1DJ1SJwpagpp6AazqM0FUaeV7CA+7+NYINSk1syWa4tU/6OF2CyBicLtzENGmXRJH6wQ==", + "license": "LGPL-3.0-only", + "peer": true, + "dependencies": { + "@swc/helpers": "^0.5.11", + "@types/uuid": "^10.0.0", + "@types/ws": "^8.2.2", + "buffer": "^6.0.3", + "eventemitter3": "^5.0.1", + "uuid": "^11.0.0", + "ws": "^8.5.0" + }, + "funding": { + "type": "paypal", + "url": "https://paypal.me/kozjak" + }, + "optionalDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^6.0.0" + } + }, + "node_modules/rpc-websockets/node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/rpc-websockets/node_modules/utf-8-validate": { + "version": "6.0.6", + "resolved": "https://registry.npmjs.org/utf-8-validate/-/utf-8-validate-6.0.6.tgz", + "integrity": "sha512-q3l3P9UtEEiAHcsgsqTgf9PPjctrDWoIXW3NpOHFdRDbLvu4DLIcxHangJ4RLrWkBcKjmcs/6NkerI8T/rE4LA==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "node-gyp-build": "^4.3.0" + }, + "engines": { + "node": ">=6.14.2" + } + }, + "node_modules/rpc-websockets/node_modules/uuid": { + "version": "11.1.1", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-11.1.1.tgz", + "integrity": "sha512-vIYxrBCC/N/K+Js3qSN88go7kIfNPssr/hHCesKCQNAjmgvYS2oqr69kIufEG+O4+PfezOH4EbIeHCfFov8ZgQ==", + "funding": [ + "https://github.com/sponsors/broofa", + "https://github.com/sponsors/ctavan" + ], + "license": "MIT", + "peer": true, + "bin": { + "uuid": "dist/esm/bin/uuid" + } + }, + "node_modules/rpc-websockets/node_modules/ws": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.20.0.tgz", + "integrity": "sha512-sAt8BhgNbzCtgGbt2OxmpuryO63ZoDk/sqaB/znQm94T4fCEsy/yV+7CdC1kJhOU9lboAEU7R3kquuycDoibVA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/run-applescript": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", @@ -9864,6 +13101,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "peer": true + }, "node_modules/safe-push-apply": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", @@ -9946,6 +13204,16 @@ "url": "https://opencollective.com/express" } }, + "node_modules/serialize-error": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/serialize-error/-/serialize-error-2.1.0.tgz", + "integrity": "sha512-ghgmKt5o4Tly5yEG/UJp8qTd0AN7Xalw4XBtDEKP655B699qMEtra1WlXeE6WIvdEG481JvRxULKsInq/iNysw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/serve-static": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-2.2.1.tgz", @@ -9965,6 +13233,18 @@ "url": "https://opencollective.com/express" } }, + "node_modules/server-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", + "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==", + "license": "MIT" + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha512-KiKBS8AnWGEyLzofFfmvKwpdPzqiy16LvQfK3yv/fVH7Bj13/wl3JSR1J+rfgRE9q7xUJK4qvgS8raSOeLUehw==", + "license": "ISC" + }, "node_modules/set-cookie-parser": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-3.1.0.tgz", @@ -10201,6 +13481,19 @@ "node": ">=8" } }, + "node_modules/shell-quote": { + "version": "1.8.3", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.3.tgz", + "integrity": "sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/side-channel": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz", @@ -10309,6 +13602,17 @@ "node": ">=0.10.0" } }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "license": "MIT", + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, "node_modules/stable-hash": { "version": "0.0.5", "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", @@ -10316,6 +13620,46 @@ "dev": true, "license": "MIT" }, + "node_modules/stackframe": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/stackframe/-/stackframe-1.3.4.tgz", + "integrity": "sha512-oeVtt7eWQS+Na6F//S4kJ2K2VbRlS9D43mAlMyVpVWovy9o+jfgH8O9agzANzaiLjclA0oYzUXEM4PurhSUChw==", + "license": "MIT", + "peer": true + }, + "node_modules/stacktrace-parser": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/stacktrace-parser/-/stacktrace-parser-0.1.11.tgz", + "integrity": "sha512-WjlahMgHmCJpqzU8bIBy4qtsZdU9lRlcZE3Lvyej6t4tuOuv1vk57OW3MBrj6hXBFx/nNoC9MPMTcr5YA7NQbg==", + "license": "MIT", + "peer": true, + "dependencies": { + "type-fest": "^0.7.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/stacktrace-parser/node_modules/type-fest": { + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.7.1.tgz", + "integrity": "sha512-Ne2YiiGN8bmrmJJEuTWTLJR32nh/JdL1+PSicowtNb0WFpn59GK8/lfD61bVtzguz7b3PBt74nxpv/Pw5po5Rg==", + "license": "(MIT OR CC0-1.0)", + "peer": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/standardwebhooks": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/standardwebhooks/-/standardwebhooks-1.0.0.tgz", + "integrity": "sha512-BbHGOQK9olHPMvQNHWul6MYlrRTAOKn03rOe4A8O3CLWhNf4YHBqq2HJKKC+sfqpxiBY52pNeesD6jIiLDz8jg==", + "license": "MIT", + "dependencies": { + "@stablelib/base64": "^1.0.0", + "fast-sha256": "^1.3.0" + } + }, "node_modules/statuses": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.2.tgz", @@ -10325,6 +13669,12 @@ "node": ">= 0.8" } }, + "node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "license": "MIT" + }, "node_modules/stdin-discarder": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/stdin-discarder/-/stdin-discarder-0.2.2.tgz", @@ -10351,6 +13701,23 @@ "node": ">= 0.4" } }, + "node_modules/stream-chain": { + "version": "2.2.5", + "resolved": "https://registry.npmjs.org/stream-chain/-/stream-chain-2.2.5.tgz", + "integrity": "sha512-1TJmBx6aSWqZ4tx7aTpBDXK0/e2hhcNSTV8+CbFJtDjbb+I1mZ8lHit0Grw9GRT+6JbIrrDd8esncgBi8aBXGA==", + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/stream-json": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/stream-json/-/stream-json-1.9.1.tgz", + "integrity": "sha512-uWkjJ+2Nt/LO9Z/JyKZbMusL8Dkh97uUBTv3AJQ74y07lVahLY4eEFsPsE97pxYBwr8nnjMAIch5eqI0gPShyw==", + "license": "BSD-3-Clause", + "peer": true, + "dependencies": { + "stream-chain": "^2.2.5" + } + }, "node_modules/strict-event-emitter": { "version": "0.5.1", "resolved": "https://registry.npmjs.org/strict-event-emitter/-/strict-event-emitter-0.5.1.tgz", @@ -10582,11 +13949,26 @@ } } }, + "node_modules/stylis": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/stylis/-/stylis-4.2.0.tgz", + "integrity": "sha512-Orov6g6BB1sDfYgzWfTHDOxamtX1bE/zo104Dh9e6fqJ3PooipYyfJ0pUmrZO2wAvO8YbEyeFrkV91XTsGMSrw==", + "license": "MIT" + }, + "node_modules/superstruct": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/superstruct/-/superstruct-2.0.2.tgz", + "integrity": "sha512-uV+TFRZdXsqXTL2pRvujROjdZQ4RAlBUS5BTh9IGm+jTqQntYThciG/qu57Gs69yjnVUSqdxF9YLmSnpupBW9A==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=14.0.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, "license": "MIT", "dependencies": { "has-flag": "^4.0.0" @@ -10599,7 +13981,6 @@ "version": "1.0.0", "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -10608,6 +13989,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/tabbable": { + "version": "6.4.0", + "resolved": "https://registry.npmjs.org/tabbable/-/tabbable-6.4.0.tgz", + "integrity": "sha512-05PUHKSNE8ou2dwIxTngl4EzcnsCDZGJ/iCLtDflR/SHB/ny14rXc+qU5P4mG9JkusiV7EivzY9Mhm55AzAvCg==", + "license": "MIT" + }, "node_modules/tagged-tag": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/tagged-tag/-/tagged-tag-1.0.0.tgz", @@ -10651,6 +14038,45 @@ "url": "https://opencollective.com/webpack" } }, + "node_modules/terser": { + "version": "5.46.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.46.2.tgz", + "integrity": "sha512-uxfo9fPcSgLDYob/w1FuL0c99MWiJDnv+5qXSQc5+Ki5NjVNsYi66INnMFBjf6uFz6OnX12piJQPF4IpjJTNTw==", + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser/node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "license": "MIT", + "peer": true + }, + "node_modules/text-encoding-utf-8": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/text-encoding-utf-8/-/text-encoding-utf-8-1.0.2.tgz", + "integrity": "sha512-8bw4MY9WjdsD2aMtO0OzOCY3pXGYNx2d2FfHRVUKkiCPDWjKuOlhLVASS+pD7VkLTVjW268LYJHwsnPFlBpbAg==", + "peer": true + }, + "node_modules/throat": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz", + "integrity": "sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==", + "license": "MIT", + "peer": true + }, "node_modules/tiny-invariant": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", @@ -10661,7 +14087,6 @@ "version": "0.2.16", "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.16.tgz", "integrity": "sha512-pn99VhoACYR8nFHhxqix+uvsbXineAasWm5ojXoN8xEwK5Kd3/TrhNn1wByuD52UxWRLy8pu+kRMniEi6Eq9Zg==", - "dev": true, "license": "MIT", "dependencies": { "fdir": "^6.5.0", @@ -10678,7 +14103,6 @@ "version": "6.5.0", "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "dev": true, "license": "MIT", "engines": { "node": ">=12.0.0" @@ -10696,7 +14120,6 @@ "version": "4.0.4", "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.4.tgz", "integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==", - "dev": true, "license": "MIT", "engines": { "node": ">=12" @@ -10723,6 +14146,13 @@ "integrity": "sha512-uiHN8PIB1VmWyS98eZYja4xzlYqeFZVjb4OuYlJQnZAuJhMw4PbKQOKgHKhBdJR3FE/t5mUQ1Kd80++B+qhD1Q==", "license": "MIT" }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "license": "BSD-3-Clause", + "peer": true + }, "node_modules/to-regex-range": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", @@ -10735,6 +14165,12 @@ "node": ">=8.0" } }, + "node_modules/toggle-selection": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/toggle-selection/-/toggle-selection-1.0.6.tgz", + "integrity": "sha512-BiZS+C1OS8g/q2RRbJmy59xpyghNBqrr6k5L/uKBGRsTfxmu3ffiRnd8mlGPUVayg8pvfi5urfnu8TU7DVOkLQ==", + "license": "MIT" + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -10756,6 +14192,13 @@ "node": ">=16" } }, + "node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT", + "peer": true + }, "node_modules/ts-api-utils": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-2.5.0.tgz", @@ -10944,7 +14387,6 @@ "version": "5.9.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, "license": "Apache-2.0", "bin": { "tsc": "bin/tsc", @@ -11175,6 +14617,27 @@ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "license": "MIT" }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "deprecated": "uuid@10 and below is no longer supported. For ESM codebases, update to uuid@latest. For CommonJS codebases, use uuid@11 (but be aware this version will likely be deprecated in 2028).", + "license": "MIT", + "peer": true, + "bin": { + "uuid": "dist/bin/uuid" + } + }, "node_modules/validate-npm-package-name": { "version": "7.0.2", "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-7.0.2.tgz", @@ -11193,6 +14656,23 @@ "node": ">= 0.8" } }, + "node_modules/vlq": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/vlq/-/vlq-1.0.1.tgz", + "integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==", + "license": "MIT", + "peer": true + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, "node_modules/web-streams-polyfill": { "version": "3.3.3", "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-3.3.3.tgz", @@ -11202,6 +14682,31 @@ "node": ">= 8" } }, + "node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause", + "peer": true + }, + "node_modules/whatwg-fetch": { + "version": "3.6.20", + "resolved": "https://registry.npmjs.org/whatwg-fetch/-/whatwg-fetch-3.6.20.tgz", + "integrity": "sha512-EqhiFU6daOA8kpjOWTL0olhVOF3i7OrFzSYiGsEMB8GcXS+RrzauAERX65xMeNWVqxA6HXH2m69Z9LaKKdisfg==", + "license": "MIT", + "peer": true + }, + "node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "peer": true, + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, "node_modules/which": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", @@ -11284,6 +14789,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/which-module": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.1.tgz", + "integrity": "sha512-iBdZ57RDvnOR9AGBhML2vFZf7h8vmBjhoaZqODJBFWHVtKkDmKuHai3cx5PgVMrX5YDNp27AofYbAwctSS+vhQ==", + "license": "ISC" + }, "node_modules/which-typed-array": { "version": "1.1.20", "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.20.tgz", @@ -11380,6 +14891,28 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "license": "ISC" }, + "node_modules/ws": { + "version": "7.5.10", + "resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz", + "integrity": "sha512-+dbF1tHwZpXcbOJdVOkzLDxZP1ailvSxM6ZweXTegylPny803bFhA+vqBYw4s31NSAk4S2Qz+AKXK9a4wkdjcQ==", + "license": "MIT", + "peer": true, + "engines": { + "node": ">=8.3.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, "node_modules/wsl-utils": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-0.3.1.tgz", @@ -11411,6 +14944,22 @@ "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", "license": "ISC" }, + "node_modules/yaml": { + "version": "2.8.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.8.4.tgz", + "integrity": "sha512-ml/JPOj9fOQK8RNnWojA67GbZ0ApXAUlN2UQclwv2eVgTgn7O9gg9o7paZWKMp4g0H3nTLtS9LVzhkpOFIKzog==", + "license": "ISC", + "peer": true, + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", diff --git a/package.json b/package.json index 14bd8f5..158ac96 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,8 @@ "lint": "eslint" }, "dependencies": { + "@clerk/nextjs": "^7.3.0", + "@clerk/ui": "^1.7.0", "class-variance-authority": "^0.7.1", "clsx": "^2.1.1", "lucide-react": "^1.14.0", diff --git a/proxy.ts b/proxy.ts new file mode 100644 index 0000000..01c119c --- /dev/null +++ b/proxy.ts @@ -0,0 +1,24 @@ +import { clerkMiddleware, createRouteMatcher } from "@clerk/nextjs/server" + +const signInRoute = process.env.NEXT_PUBLIC_CLERK_SIGN_IN_URL ?? "/sign-in" +const signUpRoute = process.env.NEXT_PUBLIC_CLERK_SIGN_UP_URL ?? "/sign-up" + +const isPublicRoute = createRouteMatcher([ + "/", + `${signInRoute}(.*)`, + `${signUpRoute}(.*)`, +]) + +export default clerkMiddleware(async (auth, request) => { + if (!isPublicRoute(request)) { + await auth.protect() + } +}) + +export const config = { + matcher: [ + "/", + "/((?!_next|[^?]*\\.(?:html?|css|js(?!on)|jpe?g|webp|png|gif|svg|ttf|woff2?|ico|csv|docx?|xlsx?|zip|webmanifest)).*)", + "/(api|trpc)(.*)", + ], +} diff --git a/skills-lock.json b/skills-lock.json new file mode 100644 index 0000000..0c3fd76 --- /dev/null +++ b/skills-lock.json @@ -0,0 +1,35 @@ +{ + "version": 1, + "skills": { + "clerk": { + "source": "clerk/skills", + "sourceType": "github", + "skillPath": "skills/core/clerk/SKILL.md", + "computedHash": "d1c09b948996e0ea71b2a27d5207fff43f7b5930fde39c42413a7867fddf06b5" + }, + "clerk-backend-api": { + "source": "clerk/skills", + "sourceType": "github", + "skillPath": "skills/core/clerk-backend-api/SKILL.md", + "computedHash": "cbcad1341a7d32fed789abe864c829f27a2858dc8ba68b92254e9beb53467148" + }, + "clerk-custom-ui": { + "source": "clerk/skills", + "sourceType": "github", + "skillPath": "skills/core/clerk-custom-ui/SKILL.md", + "computedHash": "b45ddd91c4924e8a74cb5272e769b06a5bbbde329983e7e565e6902b1cc80ded" + }, + "clerk-nextjs-patterns": { + "source": "clerk/skills", + "sourceType": "github", + "skillPath": "skills/frameworks/clerk-nextjs-patterns/SKILL.md", + "computedHash": "f397ece3da422044705341ae85940fc3c36de8f5970e36146dda6ae6955974e2" + }, + "clerk-setup": { + "source": "clerk/skills", + "sourceType": "github", + "skillPath": "skills/core/clerk-setup/SKILL.md", + "computedHash": "645b6330424cb2108562852a8d2818bed64484db74aa939476c2f57b63b1da10" + } + } +}