diff --git a/.env.example b/.env.example index c657f588..5e80f8fe 100644 --- a/.env.example +++ b/.env.example @@ -5,9 +5,10 @@ # ============================================ # Backend Server Configuration # ============================================ -PORT=5001 +PORT=5003 HOST=0.0.0.0 -# Comma-separated browser origins allowed to call the API +# Leave empty for same-origin deployments. Set an explicit comma-separated allowlist +# only when a browser origin must call the API cross-origin. CORS_ORIGIN=http://localhost:5173 # Required control-plane bearer token for all sensitive /api/* routes AUTH_TOKEN=change-me @@ -52,11 +53,11 @@ DEBUG=false # ============================================ # Frontend Configuration (Vite) # These are optional - frontend uses defaults if not set. -# If VITE_API_AUTH_TOKEN is omitted, the browser will prompt once and cache it in localStorage. +# If VITE_API_AUTH_TOKEN is omitted, the browser will prompt once, cache it in localStorage, and re-prompt if the cached token is rejected. # ============================================ -# VITE_API_URL=http://localhost:5001 +# VITE_API_URL=http://localhost:5003 # VITE_API_AUTH_TOKEN=change-me -# VITE_SERVER_PORT=5001 +# VITE_SERVER_PORT=5003 # VITE_OPENCODE_PORT=5551 # VITE_MAX_FILE_SIZE_MB=50 # VITE_MAX_UPLOAD_SIZE_MB=50 diff --git a/.github/workflows/validate.yml b/.github/workflows/validate.yml new file mode 100644 index 00000000..9c5965c6 --- /dev/null +++ b/.github/workflows/validate.yml @@ -0,0 +1,43 @@ +name: Validate + +on: + pull_request: + push: + branches: + - main + +concurrency: + group: validate-${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + validate: + runs-on: ubuntu-latest + permissions: + contents: read + + steps: + - name: Check out repository + uses: actions/checkout@v4 + + - name: Set up pnpm + uses: pnpm/action-setup@v4 + with: + version: 9.15.0 + + - name: Set up Node.js + uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - name: Set up Bun + uses: oven-sh/setup-bun@v2 + with: + bun-version: 1.2.23 + + - name: Install dependencies + run: pnpm install --frozen-lockfile + + - name: Validate workspace + run: pnpm validate diff --git a/AGENTS.md b/AGENTS.md index 5ba13ce0..00aed314 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -2,15 +2,15 @@ ## Commands -- `npm run dev` - Start both backend (5001) and frontend (5173) -- `npm run dev:backend` - Backend only: `bun --watch backend/src/index.ts` -- `npm run dev:frontend` - Frontend only: `cd frontend && vite` -- `npm run build` - Build both backend and frontend -- `npm run test` - Run backend tests: `cd backend && bun test` -- `cd backend && bun test ` - Run single test file -- `cd backend && vitest --ui` - Test UI with coverage -- `cd backend && vitest --coverage` - Coverage report -- `cd frontend && npm run lint` - Frontend linting +- `pnpm dev` - Start both backend (5003) and frontend (5173) +- `pnpm dev:backend` - Backend only: `bun --watch backend/src/index.ts` +- `pnpm dev:frontend` - Frontend only: `pnpm --filter frontend dev` +- `pnpm build` - Build both backend and frontend +- `pnpm test` - Run backend tests once in CI-safe mode +- `pnpm --filter backend test:watch` - Run backend tests in watch mode +- `pnpm --filter backend test:ui` - Open the Vitest UI +- `pnpm test:coverage` - Generate backend coverage for all backend source files +- `pnpm lint` - Frontend linting ## Code Style @@ -38,4 +38,4 @@ - DRY principles, follow existing patterns - ./opencode-src/ is reference only, never commit - Use shared types from workspace package -- OpenCode server runs on port 5551, backend API on port 5001 +- OpenCode server runs on port 5551, backend API on port 5003 diff --git a/Dockerfile b/Dockerfile index 18c03503..e3655ea6 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,37 +1,58 @@ -FROM node:20 AS base +FROM node:20-bookworm-slim AS base -RUN apt-get update && apt-get install -y \ - git \ - curl \ - lsof \ - ripgrep \ +ARG PNPM_VERSION=9.15.0 +ARG BUN_VERSION=1.2.21 + +ENV BUN_INSTALL=/root/.bun +ENV BUN_VERSION=${BUN_VERSION} +ENV PATH=/root/.bun/bin:/root/.local/bin:${PATH} + +RUN apt-get update && apt-get install -y --no-install-recommends \ ca-certificates \ - grep \ - gawk \ - sed \ - findutils \ coreutils \ - procps \ + curl \ + file \ + findutils \ + gawk \ + git \ + grep \ jq \ less \ + lsof \ + procps \ + ripgrep \ + sed \ tree \ - file \ && rm -rf /var/lib/apt/lists/* -RUN corepack enable && corepack prepare pnpm@9.15.0 --activate - -RUN curl -fsSL https://bun.sh/install | bash && \ - ln -s $HOME/.bun/bin/bun /usr/local/bin/bun +RUN corepack enable && corepack prepare pnpm@${PNPM_VERSION} --activate +RUN curl -fsSL https://bun.com/install | bash -s -- bun-v${BUN_VERSION} WORKDIR /app -FROM base AS metadata +FROM base AS deps + +COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./ +COPY shared/package.json ./shared/ +COPY backend/package.json ./backend/ +COPY frontend/package.json ./frontend/ + +RUN pnpm install --frozen-lockfile + +FROM base AS builder ARG BUILD_TIME=unknown ARG GIT_SHA=unknown ARG GIT_SHORT_SHA=unknown ARG GIT_DIRTY=false +ARG GIT_REF=local +ARG SOURCE_REPOSITORY=https://github.com/diamondplated/opencode-webui.git +ARG IMAGE_NAME=ghcr.io/diamondplated/opencode-webui +ARG PNPM_VERSION=9.15.0 +ARG BUN_VERSION=1.2.21 +ARG OPENCODE_VERSION=1.2.27 +COPY --from=deps /app ./ COPY . . RUN node <<'NODE' @@ -49,36 +70,28 @@ const buildInfo = { sha, shortSha, dirty, + ref: process.env.GIT_REF || 'unknown', + }, + source: { + repository: process.env.SOURCE_REPOSITORY || 'unknown', + image: process.env.IMAGE_NAME || 'opencode-webui', + }, + toolchain: { + node: process.version, + bun: process.env.BUN_VERSION || 'unknown', + pnpm: process.env.PNPM_VERSION || 'unknown', + opencode: process.env.OPENCODE_VERSION || 'unknown', }, } -fs.writeFileSync('/tmp/build-info.json', JSON.stringify(buildInfo, null, 2)) +fs.writeFileSync('/app/build-info.json', JSON.stringify(buildInfo, null, 2)) NODE -FROM base AS deps - -COPY package.json pnpm-workspace.yaml pnpm-lock.yaml ./ -COPY shared/package.json ./shared/ -COPY backend/package.json ./backend/ -COPY frontend/package.json ./frontend/ - -RUN pnpm install --frozen-lockfile - -FROM base AS builder - -COPY --from=deps /app ./ -COPY shared ./shared -COPY backend ./backend -COPY frontend/src ./frontend/src -COPY frontend/public ./frontend/public -COPY frontend/index.html frontend/vite.config.ts frontend/tsconfig*.json frontend/components.json frontend/eslint.config.js ./frontend/ - -RUN pnpm --filter frontend build +RUN pnpm run build FROM base AS runner -RUN curl -fsSL https://opencode.ai/install | bash && \ - ln -s $HOME/.opencode/bin/opencode /usr/local/bin/opencode +ARG OPENCODE_VERSION=1.2.27 ENV NODE_ENV=production ENV HOST=0.0.0.0 @@ -86,17 +99,14 @@ ENV PORT=5003 ENV OPENCODE_SERVER_PORT=5551 ENV DATABASE_PATH=/app/data/opencode.db ENV WORKSPACE_PATH=/workspace +ENV OPENCODE_VERSION=${OPENCODE_VERSION} -COPY --from=deps /app/node_modules ./node_modules -COPY --from=builder /app/shared ./shared -COPY --from=builder /app/backend ./backend +RUN npm install --global opencode-ai@${OPENCODE_VERSION} + +COPY --from=builder /app/backend/dist ./backend/dist COPY --from=builder /app/frontend/dist ./frontend/dist -COPY --from=metadata /tmp/build-info.json ./build-info.json +COPY --from=builder /app/build-info.json ./build-info.json COPY package.json pnpm-workspace.yaml ./ - -RUN mkdir -p /app/backend/node_modules/@opencode-webui && \ - ln -s /app/shared /app/backend/node_modules/@opencode-webui/shared - COPY --chmod=755 scripts/docker-entrypoint.sh /docker-entrypoint.sh RUN mkdir -p /workspace /app/data @@ -104,7 +114,7 @@ RUN mkdir -p /workspace /app/data EXPOSE 5003 HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \ - CMD curl -f http://localhost:5003/api/health || exit 1 + CMD curl -fsS http://localhost:5003/api/health/ready || exit 1 ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["bun", "backend/src/index.ts"] +CMD ["bun", "backend/dist/index.js"] diff --git a/README.md b/README.md index ee0f8961..0f082c28 100644 --- a/README.md +++ b/README.md @@ -85,33 +85,33 @@ git clone https://github.com/yourusername/opencode-webui.git cd opencode-webui # Start with Docker Compose (single container) -docker-compose up -d +docker compose up -d -# Access the application at http://localhost:5001 +# Access the application at http://127.0.0.1:5003 ``` The Docker setup automatically: -- Installs OpenCode if not present +- Installs pinned Bun/OpenCode toolchains during image build - Builds and serves frontend from backend - Sets up persistent volumes for workspace and database -- Includes health checks and auto-restart +- Publishes the API to loopback by default and uses readiness-based health checks **Docker Commands:** ```bash # Start container -docker-compose up -d +docker compose up -d # Stop and remove container -docker-compose down +docker compose down # Rebuild image -docker-compose build +docker compose build # View logs -docker-compose logs -f +docker compose logs -f # Restart container -docker-compose restart +docker compose restart # Access container shell docker exec -it opencode-web sh @@ -124,8 +124,8 @@ docker exec -it opencode-web sh git clone https://github.com/yourusername/opencode-webui.git cd opencode-webui -# Install dependencies (uses Bun workspaces) -bun install +# Install dependencies (uses pnpm workspaces) +pnpm install --frozen-lockfile # Copy environment configuration cp .env.example .env @@ -134,7 +134,16 @@ cp .env.example .env export AUTH_TOKEN=replace-this-with-a-long-random-token # Start development servers (backend + frontend) -npm run dev +pnpm dev +``` + +Useful validation commands: + +```bash +pnpm lint +pnpm test +pnpm build +pnpm validate ``` ### Phase 0 Security Gate @@ -142,7 +151,9 @@ npm run dev Sensitive control-plane routes now require a shared bearer token, while health endpoints stay public for diagnostics. - Set `AUTH_TOKEN` to a long random shared secret. -- Set `CORS_ORIGIN` to an explicit comma-separated allowlist of browser origins. -- Browser clients can either set `VITE_API_AUTH_TOKEN` ahead of time or enter the token once when prompted; the browser caches it in localStorage. -- API clients and automation can send `Authorization: Bearer `. - +- Leave `CORS_ORIGIN` empty for same-origin production deployments, or set it to an explicit comma-separated allowlist when a browser must call the API cross-origin. +- Direct runtime defaults bind the backend to `127.0.0.1` in production. Development still defaults to `0.0.0.0` for easier local testing. +- The container publishes `127.0.0.1:5003` by default. Override `HOST_BIND_ADDRESS=0.0.0.0` only when you intentionally want LAN exposure. +- Browser clients can either set `VITE_API_AUTH_TOKEN` ahead of time or enter the token once when prompted; the browser caches it in localStorage and re-prompts automatically if a cached token is rejected. +- API clients and automation can send `Authorization: Bearer `. Headerless browser transports such as `EventSource` and raw file/media URLs automatically fall back to `?access_token=...`. +- `/api/health/live` is liveness-only, `/api/health/ready` is the deploy/readiness gate, and `/api/health/build` now returns build provenance including git ref plus pinned toolchain versions. diff --git a/backend/package.json b/backend/package.json index d0c088b2..f9eeb59a 100644 --- a/backend/package.json +++ b/backend/package.json @@ -7,9 +7,9 @@ "dev": "bun --watch src/index.ts", "start": "bun src/index.ts", "build": "bun build src/index.ts --outdir=dist --target=bun", - "test": "vitest", + "test": "vitest run", "test:ui": "vitest --ui", - "test:coverage": "vitest --coverage", + "test:coverage": "vitest run --coverage", "test:watch": "vitest --watch" }, "dependencies": { @@ -22,6 +22,7 @@ "devDependencies": { "@types/better-sqlite3": "^7.6.13", "@types/bun": "latest", + "@vitest/coverage-v8": "^3.2.4", "@vitest/ui": "^3.2.4", "vitest": "^3.2.4" }, diff --git a/backend/src/index.ts b/backend/src/index.ts index f56b3cbe..bc4c3145 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -117,9 +117,11 @@ async function syncDefaultConfigToDisk(): Promise { if (defaultConfig) { const configPath = getOpenCodeConfigFilePath() - const configContent = JSON.stringify(defaultConfig.content, null, 2) - await writeFileContent(configPath, configContent) - logger.info(`Synced default config '${defaultConfig.name}' to: ${configPath}`) + const configContent = settingsService.getOpenCodeConfigContent(defaultConfig.name) + if (configContent) { + await writeFileContent(configPath, configContent) + logger.info(`Synced default config '${defaultConfig.name}' to: ${configPath}`) + } } else { logger.info('No default OpenCode config found in database') } @@ -155,7 +157,7 @@ app.route('/api/tts', createTTSRoutes(db)) app.all('/api/opencode/*', async (c) => { const request = c.req.raw - return proxyRequest(request) + return proxyRequest(request, db) }) const isProduction = ENV.SERVER.NODE_ENV === 'production' diff --git a/backend/src/routes/files.ts b/backend/src/routes/files.ts index a61acef1..c5637b45 100644 --- a/backend/src/routes/files.ts +++ b/backend/src/routes/files.ts @@ -1,26 +1,61 @@ import { Hono } from 'hono' +import { z } from 'zod' import * as fileService from '../services/files' import type { Database } from 'bun:sqlite' import { logger } from '../utils/logger' +import { HttpError } from '../utils/path-security' + +const LineRangeQuerySchema = z.object({ + startLine: z.coerce.number().int().min(0), + endLine: z.coerce.number().int().min(0), +}).refine(({ startLine, endLine }) => endLine >= startLine, { + message: 'endLine must be greater than or equal to startLine', + path: ['endLine'], +}) + +const CreateFileOrFolderSchema = z.object({ + type: z.enum(['file', 'folder']), + content: z.string().max(1_000_000).optional(), +}) + +const RenameOrMoveSchema = z.object({ + newPath: z.string().trim().min(1).max(2048), +}) + +const PatchRequestSchema = z.object({ + type: z.enum(['replace', 'insert', 'delete']), + startLine: z.number().int().min(0), + endLine: z.number().int().min(0).optional(), + content: z.string().optional(), +}) + +const PatchFileRequestSchema = z.object({ + patches: z.array(PatchRequestSchema).min(1).max(500).optional(), + newPath: z.string().trim().min(1).max(2048).optional(), +}).refine((value) => Boolean(value.patches?.length) || Boolean(value.newPath), { + message: 'Either patches or newPath is required', +}) + +function getRoutePath(requestPath: string): string { + return requestPath.replace(/^\/api\/files\/?/, '') +} export function createFileRoutes(_database: Database) { const app = new Hono() app.get('/*', async (c) => { try { - const userPath = c.req.path.replace(/^\/api\/files\//, '') || '' + const userPath = getRoutePath(c.req.path) const download = c.req.query('download') === 'true' const raw = c.req.query('raw') === 'true' const startLineParam = c.req.query('startLine') const endLineParam = c.req.query('endLine') if (startLineParam !== undefined && endLineParam !== undefined) { - const startLine = parseInt(startLineParam, 10) - const endLine = parseInt(endLineParam, 10) - - if (isNaN(startLine) || isNaN(endLine) || startLine < 0 || endLine < startLine) { - return c.json({ error: 'Invalid line range parameters' }, 400) - } + const { startLine, endLine } = LineRangeQuerySchema.parse({ + startLine: startLineParam, + endLine: endLineParam, + }) const result = await fileService.getFileRange(userPath, startLine, endLine) return c.json(result) @@ -52,13 +87,16 @@ export function createFileRoutes(_database: Database) { return c.json(result) } catch (error: any) { logger.error('Failed to get file:', error) + if (error instanceof z.ZodError) { + return c.json({ error: 'Invalid file request', details: error.issues }, 400) + } return c.json({ error: error.message || 'Failed to get file' }, error.statusCode || 500) } }) app.post('/*', async (c) => { try { - const path = c.req.path.replace(/^\/api\/files\//, '') || '' + const path = getRoutePath(c.req.path) const body = await c.req.parseBody() const file = body.file as File @@ -76,20 +114,23 @@ export function createFileRoutes(_database: Database) { app.put('/*', async (c) => { try { - const path = c.req.path.replace(/^\/api\/files\//, '') || '' - const body = await c.req.json() + const path = getRoutePath(c.req.path) + const body = CreateFileOrFolderSchema.parse(await c.req.json()) const result = await fileService.createFileOrFolder(path, body) return c.json(result) } catch (error: any) { logger.error('Failed to create file/folder:', error) + if (error instanceof z.ZodError) { + return c.json({ error: 'Invalid file create request', details: error.issues }, 400) + } return c.json({ error: error.message }, error.statusCode || 500) } }) app.delete('/*', async (c) => { try { - const path = c.req.path.replace(/^\/api\/files\//, '') || '' + const path = getRoutePath(c.req.path) await fileService.deleteFileOrFolder(path) return c.json({ success: true }) @@ -101,8 +142,8 @@ export function createFileRoutes(_database: Database) { app.patch('/*', async (c) => { try { - const path = c.req.path.replace(/^\/api\/files\//, '') || '' - const body = await c.req.json() + const path = getRoutePath(c.req.path) + const body = PatchFileRequestSchema.parse(await c.req.json()) if (body.patches && Array.isArray(body.patches)) { const result = await fileService.applyFilePatches(path, body.patches) @@ -113,9 +154,15 @@ export function createFileRoutes(_database: Database) { return c.json(result) } catch (error: any) { logger.error('Failed to patch file:', error) + if (error instanceof z.ZodError) { + return c.json({ error: 'Invalid file patch request', details: error.issues }, 400) + } + if (error instanceof HttpError) { + return c.json({ error: error.message }, error.statusCode) + } return c.json({ error: error.message }, error.statusCode || 500) } }) return app -} \ No newline at end of file +} diff --git a/backend/src/routes/health.ts b/backend/src/routes/health.ts index 9a76fb9d..9c80a63f 100644 --- a/backend/src/routes/health.ts +++ b/backend/src/routes/health.ts @@ -1,48 +1,109 @@ import { Hono } from 'hono' +import type { Context } from 'hono' import type { Database } from 'bun:sqlite' import { opencodeServerManager } from '../services/opencode-single-server' import { getBuildInfo } from '../services/build-info' -export function createHealthRoutes(db: Database) { +type HealthRoutesDependencies = { + checkOpencodeHealth?: () => Promise + getOpencodePort?: () => number + getBuildInfo?: typeof getBuildInfo +} + +type ComponentStatus = 'healthy' | 'unhealthy' + +type HealthSnapshot = { + status: 'healthy' | 'unhealthy' + timestamp: string + database: ComponentStatus + opencode: ComponentStatus + opencodePort: number + checks: { + database: { + status: ComponentStatus + } + opencode: { + status: ComponentStatus + port: number + } + } + build: ReturnType +} + +async function collectHealthSnapshot( + db: Database, + dependencies: Required, +): Promise { + const dbConnected = Boolean(db.prepare('SELECT 1').get()) + const opencodeHealthy = await dependencies.checkOpencodeHealth() + const opencodePort = dependencies.getOpencodePort() + const build = dependencies.getBuildInfo() + + return { + status: dbConnected && opencodeHealthy ? 'healthy' : 'unhealthy', + timestamp: new Date().toISOString(), + database: dbConnected ? 'healthy' : 'unhealthy', + opencode: opencodeHealthy ? 'healthy' : 'unhealthy', + opencodePort, + checks: { + database: { + status: dbConnected ? 'healthy' : 'unhealthy', + }, + opencode: { + status: opencodeHealthy ? 'healthy' : 'unhealthy', + port: opencodePort, + }, + }, + build, + } +} + +export function createHealthRoutes(db: Database, dependencies: HealthRoutesDependencies = {}) { const app = new Hono() + const resolvedDependencies: Required = { + checkOpencodeHealth: dependencies.checkOpencodeHealth ?? (() => opencodeServerManager.checkHealth()), + getOpencodePort: dependencies.getOpencodePort ?? (() => opencodeServerManager.getPort()), + getBuildInfo: dependencies.getBuildInfo ?? getBuildInfo, + } - app.get('/', async (c) => { + const handleReadiness = async (c: Context) => { try { - const dbCheck = db.prepare('SELECT 1').get() - const opencodeHealthy = await opencodeServerManager.checkHealth() - - const status = dbCheck && opencodeHealthy ? 'healthy' : 'degraded' - const build = getBuildInfo() - - return c.json({ - status, - timestamp: new Date().toISOString(), - database: dbCheck ? 'connected' : 'disconnected', - opencode: opencodeHealthy ? 'healthy' : 'unhealthy', - opencodePort: opencodeServerManager.getPort(), - build - }) + const snapshot = await collectHealthSnapshot(db, resolvedDependencies) + const statusCode = snapshot.status === 'healthy' ? 200 : 503 + return c.json(snapshot, statusCode) } catch (error) { return c.json({ status: 'unhealthy', timestamp: new Date().toISOString(), error: error instanceof Error ? error.message : 'Unknown error', - build: getBuildInfo() + build: resolvedDependencies.getBuildInfo(), }, 503) } + } + + app.get('/', handleReadiness) + app.get('/ready', handleReadiness) + + app.get('/live', (c) => { + return c.json({ + status: 'alive', + timestamp: new Date().toISOString(), + build: resolvedDependencies.getBuildInfo(), + }) }) app.get('/build', (c) => { - return c.json(getBuildInfo()) + return c.json(resolvedDependencies.getBuildInfo()) }) app.get('/processes', async (c) => { try { - const opencodeHealthy = await opencodeServerManager.checkHealth() + const opencodeHealthy = await resolvedDependencies.checkOpencodeHealth() + const opencodePort = resolvedDependencies.getOpencodePort() return c.json({ opencode: { - port: opencodeServerManager.getPort(), + port: opencodePort, healthy: opencodeHealthy }, timestamp: new Date().toISOString() diff --git a/backend/src/routes/providers.ts b/backend/src/routes/providers.ts index 9937ae5d..5ef437db 100644 --- a/backend/src/routes/providers.ts +++ b/backend/src/routes/providers.ts @@ -4,11 +4,13 @@ import { AuthService } from '../services/auth' import { GIT_CREDENTIAL_PROVIDER_ID } from '../services/git-credentials' import { SetCredentialRequestSchema } from '../../../shared/src/schemas/auth' import { logger } from '../utils/logger' +import { HttpError, ensureSafeIdentifier } from '../utils/path-security' export function createProvidersRoutes() { const app = new Hono() const authService = new AuthService() const oauthOnlyProviders = new Set(['github-copilot']) + const getProviderId = (value: string) => ensureSafeIdentifier(value, 'providerId', 128) app.get('/credentials', async (c) => { try { @@ -22,18 +24,24 @@ export function createProvidersRoutes() { app.get('/:id/credentials/status', async (c) => { try { - const providerId = c.req.param('id') + const providerId = getProviderId(c.req.param('id')) + if (providerId === GIT_CREDENTIAL_PROVIDER_ID) { + return c.json({ error: 'Provider not supported on this route' }, 404) + } const status = await authService.getStatus(providerId) return c.json(status) } catch (error) { logger.error('Failed to check credential status:', error) - return c.json({ error: 'Failed to check credential status' }, 500) + return c.json({ error: 'Failed to check credential status' }, error instanceof HttpError ? error.statusCode : 500) } }) app.post('/:id/credentials', async (c) => { try { - const providerId = c.req.param('id') + const providerId = getProviderId(c.req.param('id')) + if (providerId === GIT_CREDENTIAL_PROVIDER_ID) { + return c.json({ error: 'Provider not supported on this route' }, 404) + } if (oauthOnlyProviders.has(providerId)) { return c.json({ error: 'This provider uses device/OAuth login and cannot be configured with an API key.' }, 400) } @@ -48,18 +56,21 @@ export function createProvidersRoutes() { if (error instanceof z.ZodError) { return c.json({ error: 'Invalid request data', details: error.issues }, 400) } - return c.json({ error: 'Failed to set provider credentials' }, 500) + return c.json({ error: 'Failed to set provider credentials' }, error instanceof HttpError ? error.statusCode : 500) } }) app.delete('/:id/credentials', async (c) => { try { - const providerId = c.req.param('id') + const providerId = getProviderId(c.req.param('id')) + if (providerId === GIT_CREDENTIAL_PROVIDER_ID) { + return c.json({ error: 'Provider not supported on this route' }, 404) + } await authService.delete(providerId) return c.json({ success: true }) } catch (error) { logger.error('Failed to delete provider credentials:', error) - return c.json({ error: 'Failed to delete provider credentials' }, 500) + return c.json({ error: 'Failed to delete provider credentials' }, error instanceof HttpError ? error.statusCode : 500) } }) diff --git a/backend/src/routes/repos.ts b/backend/src/routes/repos.ts index 3a2c7c9c..7a37aeed 100644 --- a/backend/src/routes/repos.ts +++ b/backend/src/routes/repos.ts @@ -1,5 +1,6 @@ import { Hono } from 'hono' import type { Database } from 'bun:sqlite' +import { z } from 'zod' import * as db from '../db/queries' import * as repoService from '../services/repo' import * as gitOperations from '../services/git-operations' @@ -8,8 +9,30 @@ import { writeFileContent } from '../services/file-operations' import { opencodeServerManager } from '../services/opencode-single-server' import { logger } from '../utils/logger' import { withTransactionAsync } from '../db/transactions' -import { getOpenCodeConfigFilePath, getReposPath } from '@opencode-webui/shared' -import path from 'path' +import { getOpenCodeConfigFilePath } from '@opencode-webui/shared' +import { HttpError, ensurePositiveInteger, ensureSafeName, normalizeRelativePath } from '../utils/path-security' + +const CreateRepoSchema = z.object({ + repoUrl: z.string().trim().min(1).max(2048).optional(), + localPath: z.string().trim().min(1).max(255).optional(), + branch: z.string().trim().min(1).max(255).optional(), + openCodeConfigName: z.string().trim().min(1).max(255).optional(), + useWorktree: z.boolean().optional(), +}).refine((value) => value.repoUrl || value.localPath, { + message: 'Either repoUrl or localPath is required', +}) + +const SwitchConfigSchema = z.object({ + configName: z.string().trim().min(1).max(255), +}) + +const SwitchBranchSchema = z.object({ + branch: z.string().trim().min(1).max(255), +}) + +const DiffQuerySchema = z.object({ + path: z.string().trim().min(1).max(1024), +}) export function createRepoRoutes(database: Database) { const app = new Hono() @@ -17,11 +40,13 @@ export function createRepoRoutes(database: Database) { app.post('/', async (c) => { try { const body = await c.req.json() - const { repoUrl, localPath, branch, openCodeConfigName, useWorktree } = body - - if (!repoUrl && !localPath) { - return c.json({ error: 'Either repoUrl or localPath is required' }, 400) - } + const validated = CreateRepoSchema.parse(body) + const repoUrl = validated.repoUrl?.trim() + const localPath = validated.localPath?.trim() + const branch = validated.branch?.trim() + const openCodeConfigName = validated.openCodeConfigName + ? ensureSafeName(validated.openCodeConfigName, 'configName') + : undefined let repo if (localPath) { @@ -35,7 +60,7 @@ export function createRepoRoutes(database: Database) { database, repoUrl!, branch, - useWorktree + validated.useWorktree ?? false, ) } @@ -54,7 +79,10 @@ export function createRepoRoutes(database: Database) { return c.json(repo) } catch (error: any) { logger.error('Failed to create repo:', error) - return c.json({ error: error.message }, 500) + if (error instanceof z.ZodError) { + return c.json({ error: 'Invalid repository request', details: error.issues }, 400) + } + return c.json({ error: error.message }, error instanceof HttpError ? error.statusCode : 500) } }) @@ -76,7 +104,7 @@ export function createRepoRoutes(database: Database) { app.get('/:id', async (c) => { try { - const id = parseInt(c.req.param('id')) + const id = ensurePositiveInteger(c.req.param('id'), 'repo id') const repo = db.getRepoById(database, id) if (!repo) { @@ -88,13 +116,13 @@ export function createRepoRoutes(database: Database) { return c.json({ ...repo, currentBranch }) } catch (error: any) { logger.error('Failed to get repo:', error) - return c.json({ error: error.message }, 500) + return c.json({ error: error.message }, error instanceof HttpError ? error.statusCode : 500) } }) app.delete('/:id', async (c) => { try { - const id = parseInt(c.req.param('id')) + const id = ensurePositiveInteger(c.req.param('id'), 'repo id') const repo = db.getRepoById(database, id) if (!repo) { @@ -108,26 +136,26 @@ export function createRepoRoutes(database: Database) { return c.json({ success: true }) } catch (error: any) { logger.error('Failed to delete repo:', error) - return c.json({ error: error.message }, 500) + return c.json({ error: error.message }, error instanceof HttpError ? error.statusCode : 500) } }) app.post('/:id/pull', async (c) => { try { - const id = parseInt(c.req.param('id')) + const id = ensurePositiveInteger(c.req.param('id'), 'repo id') await repoService.pullRepo(database, id) const repo = db.getRepoById(database, id) return c.json(repo) } catch (error: any) { logger.error('Failed to pull repo:', error) - return c.json({ error: error.message }, 500) + return c.json({ error: error.message }, error instanceof HttpError ? error.statusCode : 500) } }) app.post('/:id/config/switch', async (c) => { try { - const id = parseInt(c.req.param('id')) + const id = ensurePositiveInteger(c.req.param('id'), 'repo id') const repo = db.getRepoById(database, id) if (!repo) { @@ -135,26 +163,23 @@ export function createRepoRoutes(database: Database) { } const body = await c.req.json() - const { configName } = body - - if (!configName) { - return c.json({ error: 'configName is required' }, 400) - } + const { configName } = SwitchConfigSchema.parse(body) const settingsService = new SettingsService(database) - const configContent = settingsService.getOpenCodeConfigContent(configName) + const safeConfigName = ensureSafeName(configName, 'configName') + const configContent = settingsService.getOpenCodeConfigContent(safeConfigName) if (!configContent) { - return c.json({ error: `Config '${configName}' not found` }, 404) + return c.json({ error: `Config '${safeConfigName}' not found` }, 404) } const openCodeConfigPath = getOpenCodeConfigFilePath() await writeFileContent(openCodeConfigPath, configContent) - db.updateRepoConfigName(database, id, configName) + db.updateRepoConfigName(database, id, safeConfigName) - logger.info(`Switched config for repo ${id} to '${configName}'`) + logger.info(`Switched config for repo ${id} to '${safeConfigName}'`) logger.info(`Updated OpenCode config: ${openCodeConfigPath}`) logger.info('Restarting OpenCode server due to workspace config change') @@ -165,13 +190,16 @@ export function createRepoRoutes(database: Database) { return c.json(updatedRepo) } catch (error: any) { logger.error('Failed to switch repo config:', error) - return c.json({ error: error.message }, 500) + if (error instanceof z.ZodError) { + return c.json({ error: 'Invalid config switch request', details: error.issues }, 400) + } + return c.json({ error: error.message }, error instanceof HttpError ? error.statusCode : 500) } }) app.post('/:id/branch/switch', async (c) => { try { - const id = parseInt(c.req.param('id')) + const id = ensurePositiveInteger(c.req.param('id'), 'repo id') const repo = db.getRepoById(database, id) if (!repo) { @@ -179,11 +207,7 @@ export function createRepoRoutes(database: Database) { } const body = await c.req.json() - const { branch } = body - - if (!branch) { - return c.json({ error: 'branch is required' }, 400) - } + const { branch } = SwitchBranchSchema.parse(body) await repoService.switchBranch(database, id, branch) @@ -193,13 +217,16 @@ export function createRepoRoutes(database: Database) { return c.json({ ...updatedRepo, currentBranch }) } catch (error: any) { logger.error('Failed to switch branch:', error) - return c.json({ error: error.message }, 500) + if (error instanceof z.ZodError) { + return c.json({ error: 'Invalid branch switch request', details: error.issues }, 400) + } + return c.json({ error: error.message }, error instanceof HttpError ? error.statusCode : 500) } }) app.get('/:id/branches', async (c) => { try { - const id = parseInt(c.req.param('id')) + const id = ensurePositiveInteger(c.req.param('id'), 'repo id') const repo = db.getRepoById(database, id) if (!repo) { @@ -211,37 +238,35 @@ export function createRepoRoutes(database: Database) { return c.json(branches) } catch (error: any) { logger.error('Failed to list branches:', error) - return c.json({ error: error.message }, 500) + return c.json({ error: error.message }, error instanceof HttpError ? error.statusCode : 500) } }) app.get('/:id/git/status', async (c) => { try { - const id = parseInt(c.req.param('id')) + const id = ensurePositiveInteger(c.req.param('id'), 'repo id') const repo = db.getRepoById(database, id) if (!repo) { return c.json({ error: 'Repo not found' }, 404) } - const repoPath = path.resolve(getReposPath(), repo.localPath) + const repoPath = await repoService.resolveRepoPath(repo.localPath) const status = await gitOperations.getGitStatus(repoPath) return c.json(status) } catch (error: any) { logger.error('Failed to get git status:', error) - return c.json({ error: error.message }, 500) + return c.json({ error: error.message }, error instanceof HttpError ? error.statusCode : 500) } }) app.get('/:id/git/diff', async (c) => { try { - const id = parseInt(c.req.param('id')) - const filePath = c.req.query('path') - - if (!filePath) { - return c.json({ error: 'path query parameter is required' }, 400) - } + const id = ensurePositiveInteger(c.req.param('id'), 'repo id') + const { path: filePath } = DiffQuerySchema.parse({ + path: c.req.query('path'), + }) const repo = db.getRepoById(database, id) @@ -249,13 +274,17 @@ export function createRepoRoutes(database: Database) { return c.json({ error: 'Repo not found' }, 404) } - const repoPath = path.resolve(getReposPath(), repo.localPath) - const diff = await gitOperations.getFileDiff(repoPath, filePath) + const repoPath = await repoService.resolveRepoPath(repo.localPath) + const normalizedFilePath = normalizeRelativePath(filePath, 'path') + const diff = await gitOperations.getFileDiff(repoPath, normalizedFilePath) return c.json(diff) } catch (error: any) { logger.error('Failed to get file diff:', error) - return c.json({ error: error.message }, 500) + if (error instanceof z.ZodError) { + return c.json({ error: 'Invalid diff request', details: error.issues }, 400) + } + return c.json({ error: error.message }, error instanceof HttpError ? error.statusCode : 500) } }) diff --git a/backend/src/routes/settings.ts b/backend/src/routes/settings.ts index 27bdc85e..cc3e7a1c 100644 --- a/backend/src/routes/settings.ts +++ b/backend/src/routes/settings.ts @@ -11,6 +11,7 @@ import { } from '../types/settings' import { logger } from '../utils/logger' import { opencodeServerManager } from '../services/opencode-single-server' +import { HttpError, ensureSafeIdentifier, ensureSafeName } from '../utils/path-security' const UpdateSettingsSchema = z.object({ preferences: UserPreferencesSchema.partial(), @@ -62,20 +63,24 @@ export function createSettingsRoutes(db: Database) { const app = new Hono() const settingsService = new SettingsService(db) + const getUserId = (value: string | undefined) => value ? ensureSafeIdentifier(value, 'userId', 64) : 'default' + const getConfigName = (value: string) => ensureSafeName(value, 'configName') + const getCommandName = (value: string) => ensureSafeName(decodeURIComponent(value), 'commandName') + app.get('/', async (c) => { try { - const userId = c.req.query('userId') || 'default' + const userId = getUserId(c.req.query('userId')) const settings = settingsService.getSettings(userId) return c.json(settingsService.toClientSettings(settings)) } catch (error) { logger.error('Failed to get settings:', error) - return c.json({ error: 'Failed to get settings' }, 500) + return c.json({ error: 'Failed to get settings' }, error instanceof HttpError ? error.statusCode : 500) } }) app.patch('/', async (c) => { try { - const userId = c.req.query('userId') || 'default' + const userId = getUserId(c.req.query('userId')) const body = await c.req.json() const validated = UpdateSettingsSchema.parse(body) @@ -86,40 +91,43 @@ export function createSettingsRoutes(db: Database) { if (error instanceof z.ZodError) { return c.json({ error: 'Invalid settings data', details: error.issues }, 400) } - return c.json({ error: 'Failed to update settings' }, 500) + return c.json({ error: 'Failed to update settings' }, error instanceof HttpError ? error.statusCode : 500) } }) app.delete('/', async (c) => { try { - const userId = c.req.query('userId') || 'default' + const userId = getUserId(c.req.query('userId')) const settings = settingsService.resetSettings(userId) return c.json(settingsService.toClientSettings(settings)) } catch (error) { logger.error('Failed to reset settings:', error) - return c.json({ error: 'Failed to reset settings' }, 500) + return c.json({ error: 'Failed to reset settings' }, error instanceof HttpError ? error.statusCode : 500) } }) // OpenCode Config routes app.get('/opencode-configs', async (c) => { try { - const userId = c.req.query('userId') || 'default' + const userId = getUserId(c.req.query('userId')) const configs = settingsService.getOpenCodeConfigs(userId) return c.json(configs) } catch (error) { logger.error('Failed to get OpenCode configs:', error) - return c.json({ error: 'Failed to get OpenCode configs' }, 500) + return c.json({ error: 'Failed to get OpenCode configs' }, error instanceof HttpError ? error.statusCode : 500) } }) app.post('/opencode-configs', async (c) => { try { - const userId = c.req.query('userId') || 'default' + const userId = getUserId(c.req.query('userId')) const body = await c.req.json() const validated = CreateOpenCodeConfigSchema.parse(body) - const config = settingsService.createOpenCodeConfig(validated, userId) + const config = settingsService.createOpenCodeConfig({ + ...validated, + name: getConfigName(validated.name), + }, userId) if (config.isDefault) { const configPath = getOpenCodeConfigFilePath() @@ -130,20 +138,20 @@ export function createSettingsRoutes(db: Database) { await patchOpenCodeConfig(config.content) } - return c.json(config) + return c.json(settingsService.getOpenCodeConfigByName(config.name, userId) ?? config) } catch (error) { logger.error('Failed to create OpenCode config:', error) if (error instanceof z.ZodError) { return c.json({ error: 'Invalid config data', details: error.issues }, 400) } - return c.json({ error: 'Failed to create OpenCode config' }, 500) + return c.json({ error: 'Failed to create OpenCode config' }, error instanceof HttpError ? error.statusCode : 500) } }) app.put('/opencode-configs/:name', async (c) => { try { - const userId = c.req.query('userId') || 'default' - const configName = c.req.param('name') + const userId = getUserId(c.req.query('userId')) + const configName = getConfigName(c.req.param('name')) const body = await c.req.json() const validated = UpdateOpenCodeConfigSchema.parse(body) @@ -167,20 +175,20 @@ export function createSettingsRoutes(db: Database) { } } - return c.json(config) + return c.json(settingsService.getOpenCodeConfigByName(configName, userId) ?? config) } catch (error) { logger.error('Failed to update OpenCode config:', error) if (error instanceof z.ZodError) { return c.json({ error: 'Invalid config data', details: error.issues }, 400) } - return c.json({ error: 'Failed to update OpenCode config' }, 500) + return c.json({ error: 'Failed to update OpenCode config' }, error instanceof HttpError ? error.statusCode : 500) } }) app.delete('/opencode-configs/:name', async (c) => { try { - const userId = c.req.query('userId') || 'default' - const configName = c.req.param('name') + const userId = getUserId(c.req.query('userId')) + const configName = getConfigName(c.req.param('name')) const deleted = settingsService.deleteOpenCodeConfig(configName, userId) if (!deleted) { @@ -190,14 +198,14 @@ export function createSettingsRoutes(db: Database) { return c.json({ success: true }) } catch (error) { logger.error('Failed to delete OpenCode config:', error) - return c.json({ error: 'Failed to delete OpenCode config' }, 500) + return c.json({ error: 'Failed to delete OpenCode config' }, error instanceof HttpError ? error.statusCode : 500) } }) app.post('/opencode-configs/:name/set-default', async (c) => { try { - const userId = c.req.query('userId') || 'default' - const configName = c.req.param('name') + const userId = getUserId(c.req.query('userId')) + const configName = getConfigName(c.req.param('name')) const config = settingsService.setDefaultOpenCodeConfig(configName, userId) if (!config) { @@ -211,16 +219,16 @@ export function createSettingsRoutes(db: Database) { await patchOpenCodeConfig(config.content) - return c.json(config) + return c.json(settingsService.getOpenCodeConfigByName(configName, userId) ?? config) } catch (error) { logger.error('Failed to set default OpenCode config:', error) - return c.json({ error: 'Failed to set default OpenCode config' }, 500) + return c.json({ error: 'Failed to set default OpenCode config' }, error instanceof HttpError ? error.statusCode : 500) } }) app.get('/opencode-configs/default', async (c) => { try { - const userId = c.req.query('userId') || 'default' + const userId = getUserId(c.req.query('userId')) const config = settingsService.getDefaultOpenCodeConfig(userId) if (!config) { @@ -230,7 +238,7 @@ export function createSettingsRoutes(db: Database) { return c.json(config) } catch (error) { logger.error('Failed to get default OpenCode config:', error) - return c.json({ error: 'Failed to get default OpenCode config' }, 500) + return c.json({ error: 'Failed to get default OpenCode config' }, error instanceof HttpError ? error.statusCode : 500) } }) @@ -248,18 +256,18 @@ export function createSettingsRoutes(db: Database) { // Custom Commands routes app.get('/custom-commands', async (c) => { try { - const userId = c.req.query('userId') || 'default' + const userId = getUserId(c.req.query('userId')) const settings = settingsService.getSettings(userId) return c.json(settings.preferences.customCommands) } catch (error) { logger.error('Failed to get custom commands:', error) - return c.json({ error: 'Failed to get custom commands' }, 500) + return c.json({ error: 'Failed to get custom commands' }, error instanceof HttpError ? error.statusCode : 500) } }) app.post('/custom-commands', async (c) => { try { - const userId = c.req.query('userId') || 'default' + const userId = getUserId(c.req.query('userId')) const body = await c.req.json() const validated = CreateCustomCommandSchema.parse(body) @@ -279,14 +287,14 @@ export function createSettingsRoutes(db: Database) { if (error instanceof z.ZodError) { return c.json({ error: 'Invalid command data', details: error.issues }, 400) } - return c.json({ error: 'Failed to create custom command' }, 500) + return c.json({ error: 'Failed to create custom command' }, error instanceof HttpError ? error.statusCode : 500) } }) app.put('/custom-commands/:name', async (c) => { try { - const userId = c.req.query('userId') || 'default' - const commandName = decodeURIComponent(c.req.param('name')) + const userId = getUserId(c.req.query('userId')) + const commandName = getCommandName(c.req.param('name')) const body = await c.req.json() const validated = UpdateCustomCommandSchema.parse(body) @@ -313,14 +321,14 @@ export function createSettingsRoutes(db: Database) { if (error instanceof z.ZodError) { return c.json({ error: 'Invalid command data', details: error.issues }, 400) } - return c.json({ error: 'Failed to update custom command' }, 500) + return c.json({ error: 'Failed to update custom command' }, error instanceof HttpError ? error.statusCode : 500) } }) app.delete('/custom-commands/:name', async (c) => { try { - const userId = c.req.query('userId') || 'default' - const commandName = decodeURIComponent(c.req.param('name')) + const userId = getUserId(c.req.query('userId')) + const commandName = getCommandName(c.req.param('name')) const settings = settingsService.getSettings(userId) const commandExists = settings.preferences.customCommands.some(cmd => cmd.name === commandName) @@ -336,7 +344,7 @@ export function createSettingsRoutes(db: Database) { return c.json({ success: true }) } catch (error) { logger.error('Failed to delete custom command:', error) - return c.json({ error: 'Failed to delete custom command' }, 500) + return c.json({ error: 'Failed to delete custom command' }, error instanceof HttpError ? error.statusCode : 500) } }) diff --git a/backend/src/routes/tts.ts b/backend/src/routes/tts.ts index 4197afd3..11b0f42d 100644 --- a/backend/src/routes/tts.ts +++ b/backend/src/routes/tts.ts @@ -7,6 +7,7 @@ import { join } from 'path' import { SettingsService } from '../services/settings' import { logger } from '../utils/logger' import { getWorkspacePath } from '@opencode-webui/shared' +import { HttpError, ensureSafeIdentifier } from '../utils/path-security' const TTS_CACHE_DIR = join(getWorkspacePath(), 'cache', 'tts') const CACHE_TTL_MS = 24 * 60 * 60 * 1000 @@ -80,12 +81,13 @@ export async function cleanupExpiredCache(): Promise { export function createTTSRoutes(db: Database) { const app = new Hono() + const getUserId = (value: string | undefined) => value ? ensureSafeIdentifier(value, 'userId', 64) : 'default' app.post('/synthesize', async (c) => { try { const body = await c.req.json() const { text } = TTSRequestSchema.parse(body) - const userId = c.req.query('userId') || 'default' + const userId = getUserId(c.req.query('userId')) const settingsService = new SettingsService(db) const settings = settingsService.getSettings(userId) @@ -155,12 +157,12 @@ export function createTTSRoutes(db: Database) { if (error instanceof z.ZodError) { return c.json({ error: 'Invalid request', details: error.issues }, 400) } - return c.json({ error: 'TTS synthesis failed' }, 500) + return c.json({ error: 'TTS synthesis failed' }, error instanceof HttpError ? error.statusCode : 500) } }) app.get('/status', async (c) => { - const userId = c.req.query('userId') || 'default' + const userId = getUserId(c.req.query('userId')) const settingsService = new SettingsService(db) const settings = settingsService.getSettings(userId) const ttsConfig = settings.preferences.tts diff --git a/backend/src/services/build-info.ts b/backend/src/services/build-info.ts index 9115853e..a4ff106d 100644 --- a/backend/src/services/build-info.ts +++ b/backend/src/services/build-info.ts @@ -8,6 +8,17 @@ type BuildInfo = { sha: string shortSha: string dirty: boolean + ref: string + } + source: { + repository: string + image: string + } + toolchain: { + node: string + bun: string + pnpm: string + opencode: string } } @@ -18,6 +29,17 @@ const DEFAULT_BUILD_INFO: BuildInfo = { sha: 'unknown', shortSha: 'unknown', dirty: false, + ref: 'unknown', + }, + source: { + repository: 'unknown', + image: 'unknown', + }, + toolchain: { + node: typeof process !== 'undefined' ? process.version : 'unknown', + bun: typeof process !== 'undefined' ? (process.versions.bun ?? 'unknown') : 'unknown', + pnpm: 'unknown', + opencode: 'unknown', }, } @@ -39,6 +61,23 @@ export function getBuildInfo(): BuildInfo { sha: typeof parsed.git?.sha === 'string' ? parsed.git.sha : DEFAULT_BUILD_INFO.git.sha, shortSha: typeof parsed.git?.shortSha === 'string' ? parsed.git.shortSha : DEFAULT_BUILD_INFO.git.shortSha, dirty: typeof parsed.git?.dirty === 'boolean' ? parsed.git.dirty : DEFAULT_BUILD_INFO.git.dirty, + ref: typeof parsed.git?.ref === 'string' ? parsed.git.ref : DEFAULT_BUILD_INFO.git.ref, + }, + source: { + repository: typeof parsed.source?.repository === 'string' + ? parsed.source.repository + : DEFAULT_BUILD_INFO.source.repository, + image: typeof parsed.source?.image === 'string' + ? parsed.source.image + : DEFAULT_BUILD_INFO.source.image, + }, + toolchain: { + node: typeof parsed.toolchain?.node === 'string' ? parsed.toolchain.node : DEFAULT_BUILD_INFO.toolchain.node, + bun: typeof parsed.toolchain?.bun === 'string' ? parsed.toolchain.bun : DEFAULT_BUILD_INFO.toolchain.bun, + pnpm: typeof parsed.toolchain?.pnpm === 'string' ? parsed.toolchain.pnpm : DEFAULT_BUILD_INFO.toolchain.pnpm, + opencode: typeof parsed.toolchain?.opencode === 'string' + ? parsed.toolchain.opencode + : DEFAULT_BUILD_INFO.toolchain.opencode, }, } } catch { diff --git a/backend/src/services/files.ts b/backend/src/services/files.ts index 3b3e4b5a..25a0451a 100644 --- a/backend/src/services/files.ts +++ b/backend/src/services/files.ts @@ -3,6 +3,7 @@ import path from 'path' import { createReadStream } from 'fs' import { createInterface } from 'readline' import { logger } from '../utils/logger' +import { resolveRelativePathWithinBase } from '../utils/path-security' import { readFileContent, @@ -38,7 +39,7 @@ interface FileUploadResult { } export async function getRawFileContent(userPath: string): Promise { - const validatedPath = validatePath(userPath) + await validatePath(userPath) logger.info(`Getting raw file content for path: ${userPath} -> ${validatedPath}`) try { @@ -60,7 +61,7 @@ export async function getRawFileContent(userPath: string): Promise { } export async function getFile(userPath: string): Promise { - const validatedPath = validatePath(userPath) + const validatedPath = await validatePath(userPath, { allowEmpty: true }) logger.info(`Getting file for path: ${userPath} -> ${validatedPath}`) try { @@ -148,9 +149,13 @@ export async function uploadFile(userPath: string, file: File): Promise { - const validatedPath = validatePath(userPath) + const validatedPath = await validatePath(userPath) if (body.type === 'folder') { await fs.mkdir(validatedPath, { recursive: true }) @@ -196,14 +201,14 @@ export async function createFileOrFolder(userPath: string, body: { type: 'file' } export async function deleteFileOrFolder(userPath: string): Promise { - const validatedPath = validatePath(userPath) + const validatedPath = await validatePath(userPath) await deletePath(validatedPath) } export async function renameOrMoveFile(userPath: string, body: { newPath: string }): Promise { - const oldValidatedPath = validatePath(userPath) - const newValidatedPath = validatePath(body.newPath) + const oldValidatedPath = await validatePath(userPath) + const newValidatedPath = await validatePath(body.newPath) // Create parent directory if needed await fs.mkdir(path.dirname(newValidatedPath), { recursive: true }) @@ -223,17 +228,14 @@ export async function renameOrMoveFile(userPath: string, body: { newPath: string } } -function validatePath(userPath: string): string { - const normalized = path.normalize(userPath).replace(/^(\.\.(\/|\\|$))+/, '') - const fullPath = path.join(SHARED_WORKSPACE_BASE, normalized) - const resolved = path.resolve(fullPath) - - const basePath = path.resolve(SHARED_WORKSPACE_BASE) - if (!resolved.startsWith(basePath)) { - throw { message: 'Path traversal detected', statusCode: 403 } - } - - return resolved +async function validatePath(userPath: string, options: { allowEmpty?: boolean } = {}): Promise { + const { resolvedPath } = await resolveRelativePathWithinBase( + SHARED_WORKSPACE_BASE, + userPath, + 'path', + options, + ) + return resolvedPath } function getMimeType(filePath: string, _content: Uint8Array): string { @@ -296,7 +298,7 @@ async function readFileLines(filePath: string, startLine: number, endLine: numbe } export async function getFileRange(userPath: string, startLine: number, endLine: number): Promise { - const validatedPath = validatePath(userPath) + const validatedPath = await validatePath(userPath) logger.info(`Getting file range for path: ${userPath} lines ${startLine}-${endLine}`) const exists = await fileExists(validatedPath) @@ -330,7 +332,7 @@ export async function getFileRange(userPath: string, startLine: number, endLine: } export async function getFileTotalLines(userPath: string): Promise { - const validatedPath = validatePath(userPath) + const validatedPath = await validatePath(userPath) const exists = await fileExists(validatedPath) if (!exists) { throw { message: 'File does not exist', statusCode: 404 } @@ -339,7 +341,7 @@ export async function getFileTotalLines(userPath: string): Promise { } export async function applyFilePatches(userPath: string, patches: PatchOperation[]): Promise<{ success: boolean; totalLines: number }> { - const validatedPath = validatePath(userPath) + const validatedPath = await validatePath(userPath) logger.info(`Applying ${patches.length} patches to: ${userPath}`) const exists = await fileExists(validatedPath) @@ -378,4 +380,4 @@ export async function applyFilePatches(userPath: string, patches: PatchOperation await fs.writeFile(validatedPath, lines.join('\n'), 'utf8') return { success: true, totalLines: lines.length } -} \ No newline at end of file +} diff --git a/backend/src/services/proxy.ts b/backend/src/services/proxy.ts index d9c2e597..0a02395e 100644 --- a/backend/src/services/proxy.ts +++ b/backend/src/services/proxy.ts @@ -1,5 +1,9 @@ import { logger } from '../utils/logger' -import { ENV } from '@opencode-webui/shared' +import { ENV, getReposPath } from '@opencode-webui/shared' +import type { Database } from 'bun:sqlite' +import * as db from '../db/queries' +import { assertPathWithinBase, HttpError } from '../utils/path-security' +import { sanitizeSecrets } from '../utils/secrets' const OPENCODE_SERVER_URL = `http://127.0.0.1:${ENV.OPENCODE.PORT}` @@ -29,6 +33,25 @@ function enrichProviderPayload(payload: unknown) { } } +async function validateProxyRequest(url: URL, database: Database): Promise { + const cleanPath = url.pathname.replace(/^\/api\/opencode/, '') + if (!cleanPath.startsWith('/')) { + throw new HttpError('Invalid proxy path', 400) + } + + const directory = url.searchParams.get('directory') + if (directory) { + await assertPathWithinBase(directory, getReposPath()) + + const trackedDirectories = new Set(db.listRepos(database).map((repo) => repo.fullPath)) + if (!trackedDirectories.has(directory)) { + throw new HttpError('Directory is not a tracked repository', 403) + } + } + + return cleanPath +} + export async function patchOpenCodeConfig(config: Record): Promise { try { const response = await fetch(`${OPENCODE_SERVER_URL}/config`, { @@ -50,15 +73,13 @@ export async function patchOpenCodeConfig(config: Record): Prom } } -export async function proxyRequest(request: Request) { +export async function proxyRequest(request: Request, database: Database) { const url = new URL(request.url) const path = url.pathname + url.search - // Remove /api/opencode prefix before forwarding to OpenCode server - const cleanPath = path.replace(/^\/api\/opencode/, '') - const targetUrl = `${OPENCODE_SERVER_URL}${cleanPath}` - try { + const cleanPath = await validateProxyRequest(url, database) + const targetUrl = `${OPENCODE_SERVER_URL}${cleanPath}` const headers: Record = {} request.headers.forEach((value, key) => { if (!['host', 'connection'].includes(key.toLowerCase())) { @@ -81,7 +102,19 @@ export async function proxyRequest(request: Request) { if (request.method === 'GET' && cleanPath === '/config/providers') { const payload = await response.json() - return new Response(JSON.stringify(enrichProviderPayload(payload)), { + return new Response(JSON.stringify(sanitizeSecrets(enrichProviderPayload(payload))), { + status: response.status, + statusText: response.statusText, + headers: { + ...responseHeaders, + 'content-type': 'application/json', + }, + }) + } + + if (request.method === 'GET' && cleanPath === '/config') { + const payload = await response.json() + return new Response(JSON.stringify(sanitizeSecrets(payload)), { status: response.status, statusText: response.statusText, headers: { @@ -97,6 +130,12 @@ export async function proxyRequest(request: Request) { headers: responseHeaders, }) } catch (error) { + if (error instanceof HttpError) { + return new Response(JSON.stringify({ error: error.message }), { + status: error.statusCode, + headers: { 'Content-Type': 'application/json' }, + }) + } logger.error(`Proxy request failed for ${path}:`, error) return new Response(JSON.stringify({ error: 'Proxy request failed' }), { status: 502, diff --git a/backend/src/services/repo.ts b/backend/src/services/repo.ts index 6025f4c7..056aabbd 100644 --- a/backend/src/services/repo.ts +++ b/backend/src/services/repo.ts @@ -1,4 +1,5 @@ import { executeCommand } from '../utils/process' +import fs from 'fs/promises' import { ensureDirectoryExists } from './file-operations' import * as db from '../db/queries' import type { Database } from 'bun:sqlite' @@ -7,6 +8,12 @@ import { logger } from '../utils/logger' import { getGitCredentialExecutionOptions } from './git-credentials' import { getReposPath } from '@opencode-webui/shared' import path from 'path' +import { + assertPathWithinBase, + HttpError, + normalizeRelativePath, + sanitizeDirectoryName, +} from '../utils/path-security' async function hasCommits(repoPath: string): Promise { try { @@ -40,8 +47,9 @@ export async function initLocalRepo( localPath: string, branch?: string ): Promise { - const normalizedPath = localPath.replace(/\/+$/, '') - const fullPath = path.resolve(getReposPath(), normalizedPath) + const normalizedPath = normalizeRepoLocalPath(localPath) + const fullPath = await resolveRepoPath(normalizedPath) + const normalizedBranch = branch ? await ensureValidGitBranch(branch) : undefined const existing = db.getRepoByLocalPath(database, normalizedPath) if (existing) { @@ -51,8 +59,8 @@ export async function initLocalRepo( const createRepoInput: CreateRepoInput = { localPath: normalizedPath, - branch: branch || undefined, - defaultBranch: branch || 'main', + branch: normalizedBranch, + defaultBranch: normalizedBranch || 'main', cloneStatus: 'cloning', clonedAt: Date.now(), isLocal: true, @@ -77,8 +85,8 @@ export async function initLocalRepo( logger.info(`Initializing git repository: ${fullPath}`) await executeCommand(['git', 'init'], fullPath) - if (branch && branch !== 'main') { - await executeCommand(['git', '-C', fullPath, 'checkout', '-b', branch]) + if (normalizedBranch && normalizedBranch !== 'main') { + await executeCommand(['git', '-C', fullPath, 'checkout', '-b', normalizedBranch]) } const isGitRepo = await executeCommand(['git', '-C', fullPath, 'rev-parse', '--git-dir']) @@ -104,7 +112,7 @@ export async function initLocalRepo( if (directoryCreated) { try { - await executeCommand(['rm', '-rf', normalizedPath], getReposPath()) + await removeRepoDirectory(normalizedPath) logger.info(`Rolled back directory: ${normalizedPath}`) } catch (fsError: any) { logger.error(`Failed to rollback directory ${normalizedPath}:`, fsError) @@ -121,28 +129,33 @@ export async function cloneRepo( branch?: string, useWorktree: boolean = false ): Promise { - const repoName = extractRepoName(repoUrl) + const normalizedRepoUrl = validateRepoUrl(repoUrl) + const normalizedBranch = branch ? await ensureValidGitBranch(branch) : undefined + const repoName = extractRepoName(normalizedRepoUrl) const baseRepoDirName = repoName - const worktreeDirName = branch && useWorktree ? `${repoName}-${branch.replace(/[\\/]/g, '-')}` : repoName + const worktreeDirName = normalizedBranch && useWorktree + ? sanitizeDirectoryName(`${repoName}-${normalizedBranch.replace(/[\\/]/g, '-')}`) + : repoName const localPath = worktreeDirName - const existing = db.getRepoByUrlAndBranch(database, repoUrl, branch) + const existing = db.getRepoByUrlAndBranch(database, normalizedRepoUrl, normalizedBranch) if (existing) { - logger.info(`Repo branch already exists: ${repoUrl}${branch ? `#${branch}` : ''}`) - return existing + logger.info(`Repo branch already exists: ${normalizedRepoUrl}${normalizedBranch ? `#${normalizedBranch}` : ''}`) + return existing } await ensureDirectoryExists(getReposPath()) - const baseRepoExists = await executeCommand(['bash', '-c', `test -d ${baseRepoDirName} && echo exists || echo missing`], path.resolve(getReposPath())) + const baseRepoPath = await resolveRepoPath(baseRepoDirName) + const baseRepoExists = await directoryExists(baseRepoPath) - const shouldUseWorktree = useWorktree && branch && baseRepoExists.trim() === 'exists' + const shouldUseWorktree = useWorktree && Boolean(normalizedBranch) && baseRepoExists const createRepoInput: CreateRepoInput = { - repoUrl, + repoUrl: normalizedRepoUrl, localPath, - branch: branch || undefined, - defaultBranch: branch || 'main', + branch: normalizedBranch, + defaultBranch: normalizedBranch || 'main', cloneStatus: 'cloning', clonedAt: Date.now(), } @@ -154,23 +167,19 @@ export async function cloneRepo( const repo = db.createRepo(database, createRepoInput) try { - const gitCredentialOptions = await getGitCredentialExecutionOptions(repoUrl) - - if (shouldUseWorktree) { - logger.info(`Creating worktree for branch: ${branch}`) - - const baseRepoPath = path.resolve(getReposPath(), baseRepoDirName) - const worktreePath = path.resolve(getReposPath(), worktreeDirName) - - await executeCommand(['git', '-C', baseRepoPath, 'fetch', '--all'], { - ...gitCredentialOptions, - }) - - await createWorktreeSafely(baseRepoPath, worktreePath, branch) + const gitCredentialOptions = await getGitCredentialExecutionOptions(normalizedRepoUrl) - const worktreeVerified = await executeCommand(['test', '-d', worktreePath]) - .then(() => true) - .catch(() => false) + if (shouldUseWorktree) { + logger.info(`Creating worktree for branch: ${normalizedBranch}`) + const worktreePath = await resolveRepoPath(worktreeDirName) + + await executeCommand(['git', '-C', baseRepoPath, 'fetch', '--all'], { + ...gitCredentialOptions, + }) + + await createWorktreeSafely(baseRepoPath, worktreePath, normalizedBranch!) + + const worktreeVerified = await directoryExists(worktreePath) if (!worktreeVerified) { throw new Error(`Worktree directory was not created at: ${worktreePath}`) @@ -178,16 +187,15 @@ export async function cloneRepo( logger.info(`Worktree verified at: ${worktreePath}`) - } else if (branch && baseRepoExists.trim() === 'exists' && useWorktree) { + } else if (normalizedBranch && baseRepoExists && useWorktree) { logger.info(`Base repo exists but worktree creation failed, cloning branch separately`) - const worktreeExists = await executeCommand(['bash', '-c', `test -d ${worktreeDirName} && echo exists || echo missing`], path.resolve(getReposPath())) - if (worktreeExists.trim() === 'exists') { + const worktreePath = await resolveRepoPath(worktreeDirName) + if (await directoryExists(worktreePath)) { logger.info(`Workspace directory exists, removing it: ${worktreeDirName}`) try { - await executeCommand(['rm', '-rf', worktreeDirName], getReposPath()) - const verifyRemoved = await executeCommand(['bash', '-c', `test -d ${worktreeDirName} && echo exists || echo removed`], getReposPath()) - if (verifyRemoved.trim() === 'exists') { + await removeRepoDirectory(worktreeDirName) + if (await directoryExists(worktreePath)) { throw new Error(`Failed to remove existing directory: ${worktreeDirName}`) } } catch (cleanupError: any) { @@ -197,7 +205,7 @@ export async function cloneRepo( } try { - const cloneCmd = ['git', 'clone', '-b', branch, repoUrl, worktreeDirName] + const cloneCmd = ['git', 'clone', '-b', normalizedBranch, normalizedRepoUrl, worktreeDirName] await executeCommand(cloneCmd, { cwd: getReposPath(), ...gitCredentialOptions, @@ -208,42 +216,42 @@ export async function cloneRepo( throw new Error(`Workspace directory ${worktreeDirName} already exists. Please delete it manually or contact support.`) } - logger.info(`Branch '${branch}' not found during clone, cloning default branch and creating branch locally`) - const cloneCmd = ['git', 'clone', repoUrl, worktreeDirName] + logger.info(`Branch '${normalizedBranch}' not found during clone, cloning default branch and creating branch locally`) + const cloneCmd = ['git', 'clone', normalizedRepoUrl, worktreeDirName] await executeCommand(cloneCmd, { cwd: getReposPath(), ...gitCredentialOptions, }) let localBranchExists = 'missing' try { - await executeCommand(['git', '-C', path.resolve(getReposPath(), worktreeDirName), 'rev-parse', '--verify', `refs/heads/${branch}`]) + await executeCommand(['git', '-C', await resolveRepoPath(worktreeDirName), 'rev-parse', '--verify', `refs/heads/${normalizedBranch}`]) localBranchExists = 'exists' } catch { localBranchExists = 'missing' } if (localBranchExists.trim() === 'missing') { - await executeCommand(['git', '-C', path.resolve(getReposPath(), worktreeDirName), 'checkout', '-b', branch]) + await executeCommand(['git', '-C', await resolveRepoPath(worktreeDirName), 'checkout', '-b', normalizedBranch]) } else { - await executeCommand(['git', '-C', path.resolve(getReposPath(), worktreeDirName), 'checkout', branch]) + await executeCommand(['git', '-C', await resolveRepoPath(worktreeDirName), 'checkout', normalizedBranch]) } } } else { - if (baseRepoExists.trim() === 'exists') { + if (baseRepoExists) { logger.info(`Repository directory already exists, verifying it's a valid git repo: ${baseRepoDirName}`) - const isValidRepo = await executeCommand(['git', '-C', path.resolve(getReposPath(), baseRepoDirName), 'rev-parse', '--git-dir'], path.resolve(getReposPath())).then(() => 'valid').catch(() => 'invalid') + const isValidRepo = await executeCommand(['git', '-C', baseRepoPath, 'rev-parse', '--git-dir'], path.resolve(getReposPath())).then(() => 'valid').catch(() => 'invalid') if (isValidRepo.trim() === 'valid') { - logger.info(`Valid repository found: ${repoUrl}`) + logger.info(`Valid repository found: ${normalizedRepoUrl}`) - if (branch) { - logger.info(`Switching to branch: ${branch}`) - await executeCommand(['git', '-C', path.resolve(getReposPath(), baseRepoDirName), 'fetch', '--all'], { + if (normalizedBranch) { + logger.info(`Switching to branch: ${normalizedBranch}`) + await executeCommand(['git', '-C', baseRepoPath, 'fetch', '--all'], { ...gitCredentialOptions, }) let remoteBranchExists = false try { - await executeCommand(['git', '-C', path.resolve(getReposPath(), baseRepoDirName), 'rev-parse', '--verify', `refs/remotes/origin/${branch}`]) + await executeCommand(['git', '-C', baseRepoPath, 'rev-parse', '--verify', `refs/remotes/origin/${normalizedBranch}`]) remoteBranchExists = true } catch { remoteBranchExists = false @@ -251,21 +259,21 @@ export async function cloneRepo( let localBranchExists = false try { - await executeCommand(['git', '-C', path.resolve(getReposPath(), baseRepoDirName), 'rev-parse', '--verify', `refs/heads/${branch}`]) + await executeCommand(['git', '-C', baseRepoPath, 'rev-parse', '--verify', `refs/heads/${normalizedBranch}`]) localBranchExists = true } catch { localBranchExists = false } if (localBranchExists) { - logger.info(`Checking out existing local branch: ${branch}`) - await executeCommand(['git', '-C', path.resolve(getReposPath(), baseRepoDirName), 'checkout', branch]) + logger.info(`Checking out existing local branch: ${normalizedBranch}`) + await executeCommand(['git', '-C', baseRepoPath, 'checkout', normalizedBranch]) } else if (remoteBranchExists) { - logger.info(`Checking out remote branch: ${branch}`) - await executeCommand(['git', '-C', path.resolve(getReposPath(), baseRepoDirName), 'checkout', '-b', branch, `origin/${branch}`]) + logger.info(`Checking out remote branch: ${normalizedBranch}`) + await executeCommand(['git', '-C', baseRepoPath, 'checkout', '-b', normalizedBranch, `origin/${normalizedBranch}`]) } else { - logger.info(`Creating new branch: ${branch}`) - await executeCommand(['git', '-C', path.resolve(getReposPath(), baseRepoDirName), 'checkout', '-b', branch]) + logger.info(`Creating new branch: ${normalizedBranch}`) + await executeCommand(['git', '-C', baseRepoPath, 'checkout', '-b', normalizedBranch]) } } @@ -273,19 +281,18 @@ export async function cloneRepo( return { ...repo, cloneStatus: 'ready' } } else { logger.warn(`Invalid repository directory found, removing and recloning: ${baseRepoDirName}`) - await executeCommand(['rm', '-rf', baseRepoDirName], getReposPath()) + await removeRepoDirectory(baseRepoDirName) } } - logger.info(`Cloning repo: ${repoUrl}${branch ? ` to branch ${branch}` : ''}`) + logger.info(`Cloning repo: ${normalizedRepoUrl}${normalizedBranch ? ` to branch ${normalizedBranch}` : ''}`) - const worktreeExists = await executeCommand(['bash', '-c', `test -d ${worktreeDirName} && echo exists || echo missing`], getReposPath()) - if (worktreeExists.trim() === 'exists') { + const worktreePath = await resolveRepoPath(worktreeDirName) + if (await directoryExists(worktreePath)) { logger.info(`Workspace directory exists, removing it: ${worktreeDirName}`) try { - await executeCommand(['rm', '-rf', worktreeDirName], getReposPath()) - const verifyRemoved = await executeCommand(['bash', '-c', `test -d ${worktreeDirName} && echo exists || echo removed`], getReposPath()) - if (verifyRemoved.trim() === 'exists') { + await removeRepoDirectory(worktreeDirName) + if (await directoryExists(worktreePath)) { throw new Error(`Failed to remove existing directory: ${worktreeDirName}`) } } catch (cleanupError: any) { @@ -295,9 +302,9 @@ export async function cloneRepo( } try { - const cloneCmd = branch - ? ['git', 'clone', '-b', branch, repoUrl, worktreeDirName] - : ['git', 'clone', repoUrl, worktreeDirName] + const cloneCmd = normalizedBranch + ? ['git', 'clone', '-b', normalizedBranch, normalizedRepoUrl, worktreeDirName] + : ['git', 'clone', normalizedRepoUrl, worktreeDirName] await executeCommand(cloneCmd, { cwd: getReposPath(), @@ -309,25 +316,25 @@ export async function cloneRepo( throw new Error(`Workspace directory ${worktreeDirName} already exists. Please delete it manually or contact support.`) } - if (branch && (error.message.includes('Remote branch') || error.message.includes('not found'))) { - logger.info(`Branch '${branch}' not found, cloning default branch and creating branch locally`) - const cloneCmd = ['git', 'clone', repoUrl, worktreeDirName] + if (normalizedBranch && (error.message.includes('Remote branch') || error.message.includes('not found'))) { + logger.info(`Branch '${normalizedBranch}' not found, cloning default branch and creating branch locally`) + const cloneCmd = ['git', 'clone', normalizedRepoUrl, worktreeDirName] await executeCommand(cloneCmd, { cwd: getReposPath(), ...gitCredentialOptions, }) let localBranchExists = 'missing' try { - await executeCommand(['git', '-C', path.resolve(getReposPath(), worktreeDirName), 'rev-parse', '--verify', `refs/heads/${branch}`]) + await executeCommand(['git', '-C', await resolveRepoPath(worktreeDirName), 'rev-parse', '--verify', `refs/heads/${normalizedBranch}`]) localBranchExists = 'exists' } catch { localBranchExists = 'missing' } if (localBranchExists.trim() === 'missing') { - await executeCommand(['git', '-C', path.resolve(getReposPath(), worktreeDirName), 'checkout', '-b', branch]) + await executeCommand(['git', '-C', await resolveRepoPath(worktreeDirName), 'checkout', '-b', normalizedBranch]) } else { - await executeCommand(['git', '-C', path.resolve(getReposPath(), worktreeDirName), 'checkout', branch]) + await executeCommand(['git', '-C', await resolveRepoPath(worktreeDirName), 'checkout', normalizedBranch]) } } else { throw error @@ -336,24 +343,24 @@ export async function cloneRepo( } db.updateRepoStatus(database, repo.id, 'ready') - logger.info(`Repo ready: ${repoUrl}${branch ? `#${branch}` : ''}${shouldUseWorktree ? ' (worktree)' : ''}`) + logger.info(`Repo ready: ${normalizedRepoUrl}${normalizedBranch ? `#${normalizedBranch}` : ''}${shouldUseWorktree ? ' (worktree)' : ''}`) return { ...repo, cloneStatus: 'ready' } } catch (error: any) { - logger.error(`Failed to create repo: ${repoUrl}${branch ? `#${branch}` : ''}`, error) + logger.error(`Failed to create repo: ${normalizedRepoUrl}${normalizedBranch ? `#${normalizedBranch}` : ''}`, error) db.deleteRepo(database, repo.id) throw error } } export async function getCurrentBranch(repo: Repo): Promise { - const repoPath = path.resolve(getReposPath(), repo.localPath) + const repoPath = await resolveRepoPath(repo.localPath) const branch = await safeGetCurrentBranch(repoPath) return branch || repo.branch || repo.defaultBranch || null } export async function listBranches(repo: Repo): Promise<{ local: string[], remote: string[], current: string | null }> { try { - const repoPath = path.resolve(getReposPath(), repo.localPath) + const repoPath = await resolveRepoPath(repo.localPath) if (!repo.isLocal) { await executeCommand(['git', '-C', repoPath, 'fetch', '--all']) @@ -397,15 +404,16 @@ export async function switchBranch(database: Database, repoId: number, branch: s } try { - const repoPath = path.resolve(getReposPath(), repo.localPath) + const normalizedBranch = await ensureValidGitBranch(branch) + const repoPath = await resolveRepoPath(repo.localPath) - logger.info(`Switching to branch: ${branch} in ${repo.localPath}`) + logger.info(`Switching to branch: ${normalizedBranch} in ${repo.localPath}`) await executeCommand(['git', '-C', repoPath, 'fetch', '--all']) let localBranchExists = false try { - await executeCommand(['git', '-C', repoPath, 'rev-parse', '--verify', `refs/heads/${branch}`]) + await executeCommand(['git', '-C', repoPath, 'rev-parse', '--verify', `refs/heads/${normalizedBranch}`]) localBranchExists = true } catch { localBranchExists = false @@ -413,24 +421,24 @@ export async function switchBranch(database: Database, repoId: number, branch: s let remoteBranchExists = false try { - await executeCommand(['git', '-C', repoPath, 'rev-parse', '--verify', `refs/remotes/origin/${branch}`]) + await executeCommand(['git', '-C', repoPath, 'rev-parse', '--verify', `refs/remotes/origin/${normalizedBranch}`]) remoteBranchExists = true } catch { remoteBranchExists = false } if (localBranchExists) { - logger.info(`Checking out existing local branch: ${branch}`) - await executeCommand(['git', '-C', repoPath, 'checkout', branch]) + logger.info(`Checking out existing local branch: ${normalizedBranch}`) + await executeCommand(['git', '-C', repoPath, 'checkout', normalizedBranch]) } else if (remoteBranchExists) { - logger.info(`Checking out remote branch: ${branch}`) - await executeCommand(['git', '-C', repoPath, 'checkout', '-b', branch, `origin/${branch}`]) + logger.info(`Checking out remote branch: ${normalizedBranch}`) + await executeCommand(['git', '-C', repoPath, 'checkout', '-b', normalizedBranch, `origin/${normalizedBranch}`]) } else { - logger.info(`Creating new branch: ${branch}`) - await executeCommand(['git', '-C', repoPath, 'checkout', '-b', branch]) + logger.info(`Creating new branch: ${normalizedBranch}`) + await executeCommand(['git', '-C', repoPath, 'checkout', '-b', normalizedBranch]) } - logger.info(`Successfully switched to branch: ${branch}`) + logger.info(`Successfully switched to branch: ${normalizedBranch}`) } catch (error: any) { logger.error(`Failed to switch branch for repo ${repoId}:`, error) throw error @@ -450,7 +458,7 @@ export async function pullRepo(database: Database, repoId: number): Promise 2048 || /[\0\r\n]/.test(normalized)) { + throw new HttpError('repoUrl contains invalid characters', 400) + } + return normalized +} + +function normalizeRepoLocalPath(localPath: string): string { + const normalized = normalizeRelativePath(localPath.replace(/\/+$/, ''), 'localPath') + if (normalized.includes('/')) { + throw new HttpError('localPath must be a single directory name', 400) + } + return sanitizeDirectoryName(normalized) +} + +export async function resolveRepoPath(localPath: string): Promise { + const normalizedPath = normalizeRepoLocalPath(localPath) + const resolvedBase = path.resolve(getReposPath()) + const resolvedPath = path.resolve(resolvedBase, normalizedPath) + await assertPathWithinBase(resolvedPath, resolvedBase) + return resolvedPath +} + +async function directoryExists(targetPath: string): Promise { + try { + const stats = await fs.stat(targetPath) + return stats.isDirectory() + } catch { + return false + } +} + +async function removeRepoDirectory(localPath: string): Promise { + const resolvedPath = await resolveRepoPath(localPath) + await fs.rm(resolvedPath, { recursive: true, force: true }) +} + +async function ensureValidGitBranch(branch: string): Promise { + const normalized = branch.trim() + if (!normalized) { + throw new HttpError('branch is required', 400) + } + + try { + await executeCommand(['git', 'check-ref-format', '--branch', normalized], { silent: true }) + } catch { + throw new HttpError('branch is invalid', 400) + } + return normalized +} + function extractRepoName(url: string): string { const match = url.match(/\/([^\/]+?)(\.git)?$/) - return match?.[1] ?? `repo-${Date.now()}` + return sanitizeDirectoryName(match?.[1] ?? `repo-${Date.now()}`) } export async function cleanupOrphanedDirectories(database: Database): Promise { try { const reposPath = getReposPath() await ensureDirectoryExists(reposPath) - - const dirResult = await executeCommand(['ls', '-1'], reposPath).catch(() => '') - const directories = dirResult.split('\n').filter(d => d.trim()) + + const directories = (await fs.readdir(reposPath, { withFileTypes: true })) + .filter((entry) => entry.isDirectory()) + .map((entry) => entry.name) if (directories.length === 0) { return @@ -568,7 +631,7 @@ export async function cleanupOrphanedDirectories(database: Database): Promise maxLength) { + throw new HttpError(`${label} is too long`, 400) + } + if (/[/\\\0\r\n]/.test(normalized)) { + throw new HttpError(`${label} contains invalid characters`, 400) + } + return normalized +} + +export function ensureSafeIdentifier(value: string, label: string, maxLength: number = 128): string { + const normalized = value.trim() + if (!normalized) { + throw new HttpError(`${label} is required`, 400) + } + if (normalized.length > maxLength) { + throw new HttpError(`${label} is too long`, 400) + } + if (!/^[A-Za-z0-9._-]+$/.test(normalized)) { + throw new HttpError(`${label} contains invalid characters`, 400) + } + return normalized +} + +export function ensurePositiveInteger(value: string, label: string): number { + const parsed = Number.parseInt(value, 10) + if (!Number.isSafeInteger(parsed) || parsed <= 0) { + throw new HttpError(`${label} must be a positive integer`, 400) + } + return parsed +} + +export function sanitizeDirectoryName(value: string): string { + const normalized = value + .trim() + .replace(/[^A-Za-z0-9._-]+/g, '-') + .replace(/-+/g, '-') + .replace(/^[-.]+|[-.]+$/g, '') + + if (!normalized) { + throw new HttpError('Unable to derive a safe directory name', 400) + } + + return normalized.slice(0, 120) +} + +function isPathInsideBase(targetPath: string, basePath: string): boolean { + const relative = path.relative(basePath, targetPath) + return relative === '' || (!relative.startsWith('..') && !path.isAbsolute(relative)) +} + +async function realpathOrResolved(targetPath: string): Promise { + try { + return await fs.realpath(targetPath) + } catch { + return path.resolve(targetPath) + } +} + +async function getNearestExistingPath(targetPath: string, basePath: string): Promise { + let current = path.resolve(targetPath) + const resolvedBase = path.resolve(basePath) + + while (isPathInsideBase(current, resolvedBase)) { + try { + await fs.lstat(current) + return current + } catch (error) { + if ((error as NodeJS.ErrnoException).code !== 'ENOENT') { + throw error + } + } + + if (current === resolvedBase) { + return resolvedBase + } + + const parent = path.dirname(current) + if (parent === current) { + break + } + current = parent + } + + return resolvedBase +} + +export async function assertPathWithinBase(targetPath: string, basePath: string): Promise { + const resolvedBase = await realpathOrResolved(basePath) + const resolvedTarget = path.resolve(targetPath) + + if (!isPathInsideBase(resolvedTarget, resolvedBase)) { + throw new HttpError('Path traversal detected', 403) + } + + const nearestExistingPath = await getNearestExistingPath(resolvedTarget, resolvedBase) + const realExistingPath = await realpathOrResolved(nearestExistingPath) + if (!isPathInsideBase(realExistingPath, resolvedBase)) { + throw new HttpError('Path escapes workspace boundary', 403) + } + + return resolvedTarget +} + +export async function resolveRelativePathWithinBase( + basePath: string, + relativePath: string, + label: string, + options: { allowEmpty?: boolean } = {}, +): Promise<{ normalizedPath: string; resolvedPath: string }> { + const normalizedPath = normalizeRelativePath(relativePath, label, options) + const resolvedBase = await realpathOrResolved(basePath) + const resolvedPath = path.resolve(resolvedBase, normalizedPath) + await assertPathWithinBase(resolvedPath, resolvedBase) + return { normalizedPath, resolvedPath } +} diff --git a/backend/src/utils/secrets.ts b/backend/src/utils/secrets.ts new file mode 100644 index 00000000..c6fae4c2 --- /dev/null +++ b/backend/src/utils/secrets.ts @@ -0,0 +1,62 @@ +const SECRET_KEYS = [ + 'apikey', + 'api_key', + 'token', + 'secret', + 'password', + 'access_token', + 'refresh_token', + 'clientsecret', + 'client_secret', +] + +export const SECRET_PLACEHOLDER = '********' + +function isPlainObject(value: unknown): value is Record { + return Boolean(value) && typeof value === 'object' && !Array.isArray(value) +} + +function isSecretKey(key: string): boolean { + const normalized = key.replace(/[^a-z0-9]+/gi, '').toLowerCase() + return SECRET_KEYS.includes(normalized) +} + +export function sanitizeSecrets(value: T): T { + if (Array.isArray(value)) { + return value.map((entry) => sanitizeSecrets(entry)) as T + } + + if (!isPlainObject(value)) { + return value + } + + return Object.fromEntries( + Object.entries(value).map(([key, entryValue]) => { + if (isSecretKey(key) && typeof entryValue === 'string' && entryValue.length > 0) { + return [key, SECRET_PLACEHOLDER] + } + return [key, sanitizeSecrets(entryValue)] + }), + ) as T +} + +export function restoreSanitizedSecrets(previousValue: T, incomingValue: T): T { + if (incomingValue === SECRET_PLACEHOLDER && typeof previousValue === 'string') { + return previousValue as T + } + + if (Array.isArray(previousValue) && Array.isArray(incomingValue)) { + return incomingValue.map((entry, index) => restoreSanitizedSecrets(previousValue[index], entry)) as T + } + + if (isPlainObject(previousValue) && isPlainObject(incomingValue)) { + return Object.fromEntries( + Object.entries(incomingValue).map(([key, entryValue]) => [ + key, + restoreSanitizedSecrets(previousValue[key], entryValue), + ]), + ) as T + } + + return incomingValue +} diff --git a/backend/test/routes/health.test.ts b/backend/test/routes/health.test.ts new file mode 100644 index 00000000..58f37523 --- /dev/null +++ b/backend/test/routes/health.test.ts @@ -0,0 +1,95 @@ +import { describe, expect, it, vi } from 'vitest' +import { createHealthRoutes } from '../../src/routes/health' + +const createMockDb = (shouldConnect = true) => ({ + prepare: vi.fn(() => ({ + get: vi.fn(() => { + if (!shouldConnect) { + throw new Error('db unavailable') + } + + return 1 + }), + })), +}) as any + +const buildInfo = { + packageVersion: '0.3.2', + buildTime: '2026-01-01T00:00:00.000Z', + git: { + sha: 'abc123', + shortSha: 'abc123', + dirty: false, + ref: 'refs/heads/main', + }, + source: { + repository: 'github.com/diamondplated/opencode-webui', + image: 'opencode-webui', + }, + toolchain: { + node: 'v20.0.0', + bun: '1.2.21', + pnpm: '9.15.0', + opencode: '1.2.27', + }, +} + +describe('health routes', () => { + it('returns healthy readiness when dependencies are up', async () => { + const app = createHealthRoutes(createMockDb(), { + checkOpencodeHealth: vi.fn().mockResolvedValue(true), + getOpencodePort: () => 5551, + getBuildInfo: () => buildInfo, + }) + + const response = await app.request('http://localhost/ready') + + expect(response.status).toBe(200) + await expect(response.json()).resolves.toMatchObject({ + status: 'healthy', + database: 'healthy', + opencode: 'healthy', + opencodePort: 5551, + build: buildInfo, + }) + }) + + it('returns 503 readiness when opencode is unavailable', async () => { + const app = createHealthRoutes(createMockDb(), { + checkOpencodeHealth: vi.fn().mockResolvedValue(false), + getOpencodePort: () => 5551, + getBuildInfo: () => buildInfo, + }) + + const response = await app.request('http://localhost/ready') + + expect(response.status).toBe(503) + await expect(response.json()).resolves.toMatchObject({ + status: 'unhealthy', + database: 'healthy', + opencode: 'unhealthy', + checks: { + opencode: { + status: 'unhealthy', + port: 5551, + }, + }, + }) + }) + + it('keeps liveness independent from readiness', async () => { + const app = createHealthRoutes(createMockDb(false), { + checkOpencodeHealth: vi.fn().mockResolvedValue(false), + getOpencodePort: () => 5551, + getBuildInfo: () => buildInfo, + }) + + const response = await app.request('http://localhost/live') + + expect(response.status).toBe(200) + await expect(response.json()).resolves.toMatchObject({ + status: 'alive', + build: buildInfo, + }) + }) +}) diff --git a/backend/test/services/settings.test.ts b/backend/test/services/settings.test.ts index 4f0e1860..53e66f9f 100644 --- a/backend/test/services/settings.test.ts +++ b/backend/test/services/settings.test.ts @@ -63,4 +63,96 @@ describe('SettingsService', () => { expect.any(Number) ) }) + + it('redacts TTS api keys in client settings responses', () => { + const selectQuery = { + get: vi.fn().mockReturnValue({ + preferences: JSON.stringify({ + theme: 'dark', + mode: 'build', + autoScroll: true, + showReasoning: false, + expandToolCalls: false, + keyboardShortcuts: {}, + customCommands: [], + customAgents: [], + tts: { + enabled: true, + endpoint: 'https://example.com/tts', + apiKey: 'sk-secret', + voice: 'alloy', + model: 'tts-1', + speed: 1, + }, + }), + updated_at: 123, + }), + } + + const mockDb = { + query: vi.fn(() => selectQuery), + } as any + + const service = new SettingsService(mockDb) + const clientSettings = service.toClientSettings(service.getSettings('default')) + + expect(clientSettings.preferences.tts?.apiKey).toBe('********') + }) + + it('preserves redacted TTS api keys when updating settings', () => { + const selectQuery = { + get: vi.fn().mockReturnValue({ + preferences: JSON.stringify({ + theme: 'dark', + mode: 'build', + autoScroll: true, + showReasoning: false, + expandToolCalls: false, + keyboardShortcuts: {}, + customCommands: [], + customAgents: [], + tts: { + enabled: true, + endpoint: 'https://example.com/tts', + apiKey: 'sk-secret', + voice: 'alloy', + model: 'tts-1', + speed: 1, + }, + }), + updated_at: 123, + }), + } + + const persistQuery = { + run: vi.fn(), + } + + const mockDb = { + query: vi.fn((sql: string) => sql.startsWith('SELECT preferences') ? selectQuery : persistQuery), + } as any + + const service = new SettingsService(mockDb) + service.updateSettings({ + tts: { + enabled: true, + endpoint: 'https://example.com/new-tts', + apiKey: '********', + voice: 'nova', + model: 'tts-1', + speed: 1.5, + }, + }, 'default') + + expect(persistQuery.run).toHaveBeenCalledWith( + 'default', + expect.stringContaining('sk-secret'), + expect.any(Number), + ) + expect(persistQuery.run).toHaveBeenCalledWith( + 'default', + expect.not.stringContaining('********'), + expect.any(Number), + ) + }) }) diff --git a/backend/test/utils/helpers.test.ts b/backend/test/utils/helpers.test.ts index 55d30295..01e22dc1 100644 --- a/backend/test/utils/helpers.test.ts +++ b/backend/test/utils/helpers.test.ts @@ -1,111 +1,51 @@ -import { describe, it, expect } from 'vitest' +import { describe, expect, it } from 'vitest' +import { CreateRepoRequestSchema, RepoSchema } from '@opencode-webui/shared/schemas' -describe('Process Helper Functions', () => { - describe('mapProcessState', () => { - it('should map "running" state correctly', () => { - const state = 'running' - const mapped = 'running' as const - - expect(mapped).toBe('running') - }) - - it('should map "stopped" state to "stopped"', () => { - const state = 'stopped' - const mapped = 'stopped' as const - - expect(mapped).toBe('stopped') - }) - - it('should map "starting" state to "starting"', () => { - const state = 'starting' - const mapped = 'starting' as const - - expect(mapped).toBe('starting') +describe('repo schemas', () => { + it('accepts HTTPS remotes when creating repositories', () => { + const result = CreateRepoRequestSchema.safeParse({ + repoUrl: 'https://github.com/octocat/hello-world.git', }) - it('should map unknown states to "error"', () => { - const state = 'unknown' - const mapped = 'error' as const - - expect(mapped).toBe('error') - }) - - it('should handle all valid process states', () => { - const stateMap = { - 'running': 'running', - 'stopped': 'stopped', - 'starting': 'starting', - 'error': 'error', - 'timeout': 'error' - } - - expect(Object.keys(stateMap).length).toBeGreaterThan(0) - }) + expect(result.success).toBe(true) }) - describe('generateSessionId', () => { - it('should generate unique session IDs', () => { - const id1 = 'session-abc123' - const id2 = 'session-def456' - - expect(id1).not.toBe(id2) - expect(id1).toMatch(/^session-/) - expect(id2).toMatch(/^session-/) + it('accepts SSH remotes when creating repositories', () => { + const result = CreateRepoRequestSchema.safeParse({ + repoUrl: 'git@github.com:octocat/hello-world.git', + branch: 'main', + useWorktree: true, }) - it('should use consistent prefix', () => { - const id = 'session-xyz789' - - expect(id.startsWith('session-')).toBe(true) - }) + expect(result.success).toBe(true) }) - describe('validateRepoUrl', () => { - it('should accept valid GitHub HTTPS URLs', () => { - const url = 'https://github.com/user/repo' - const isValid = true - - expect(isValid).toBe(true) + it('accepts local-path repositories without a remote URL', () => { + const result = CreateRepoRequestSchema.safeParse({ + localPath: '/workspace/opencode-webui', }) - it('should accept valid GitHub SSH URLs', () => { - const url = 'git@github.com:user/repo.git' - const isValid = true - - expect(isValid).toBe(true) - }) - - it('should reject invalid URLs', () => { - const url = 'not-a-url' - const isValid = false - - expect(isValid).toBe(false) - }) - - it('should accept GitLab URLs', () => { - const url = 'https://gitlab.com/user/repo' - const isValid = true - - expect(isValid).toBe(true) - }) + expect(result.success).toBe(true) }) - describe('sanitizeEnvVars', () => { - it('should filter out undefined values', () => { - const env = { - DEFINED: 'value', - UNDEFINED: undefined - } + it('rejects requests that provide neither a remote URL nor a local path', () => { + const result = CreateRepoRequestSchema.safeParse({}) - const sanitized = ['DEFINED=value'] + expect(result.success).toBe(false) + expect(result.error?.issues[0]?.path).toEqual(['repoUrl']) + }) - expect(sanitized).not.toContain('UNDEFINED') + it('accepts local repositories in persisted repo records', () => { + const result = RepoSchema.safeParse({ + id: 7, + localPath: '/workspace/opencode-webui', + fullPath: '/workspace/opencode-webui', + defaultBranch: 'main', + cloneStatus: 'ready', + clonedAt: Date.now(), + isLocal: true, }) - it('should preserve all defined values', () => { - const env = ['KEY1=value1', 'KEY2=value2', 'KEY3=value3'] - - expect(env.length).toBe(3) - }) + expect(result.success).toBe(true) }) -}) \ No newline at end of file +}) diff --git a/backend/test/utils/path-security.test.ts b/backend/test/utils/path-security.test.ts new file mode 100644 index 00000000..533a3e06 --- /dev/null +++ b/backend/test/utils/path-security.test.ts @@ -0,0 +1,45 @@ +import { afterEach, describe, expect, it } from 'vitest' +import fs from 'fs/promises' +import path from 'path' +import { + HttpError, + assertPathWithinBase, + normalizeRelativePath, + resolveRelativePathWithinBase, +} from '../../src/utils/path-security' + +const artifactsRoot = path.resolve(process.cwd(), 'backend/test-artifacts/path-security') + +afterEach(async () => { + await fs.rm(artifactsRoot, { recursive: true, force: true }) +}) + +describe('path-security helpers', () => { + it('rejects relative traversal paths', () => { + expect(() => normalizeRelativePath('../etc/passwd', 'path')).toThrow(HttpError) + }) + + it('rejects symlink escapes outside the workspace base', async () => { + const basePath = path.join(artifactsRoot, 'workspace') + const outsidePath = path.join(artifactsRoot, 'outside') + const symlinkPath = path.join(basePath, 'repo-link') + + await fs.mkdir(basePath, { recursive: true }) + await fs.mkdir(outsidePath, { recursive: true }) + await fs.symlink(outsidePath, symlinkPath) + + await expect(assertPathWithinBase(symlinkPath, basePath)).rejects.toMatchObject({ + statusCode: 403, + }) + }) + + it('allows files that stay inside the workspace base', async () => { + const basePath = path.join(artifactsRoot, 'workspace') + await fs.mkdir(path.join(basePath, 'repo'), { recursive: true }) + + await expect(resolveRelativePathWithinBase(basePath, 'repo/file.ts', 'path')).resolves.toMatchObject({ + normalizedPath: 'repo/file.ts', + resolvedPath: path.join(basePath, 'repo', 'file.ts'), + }) + }) +}) diff --git a/backend/vitest.config.ts b/backend/vitest.config.ts index 3364bdfd..eff655e1 100644 --- a/backend/vitest.config.ts +++ b/backend/vitest.config.ts @@ -5,22 +5,20 @@ export default defineConfig({ globals: true, environment: 'node', coverage: { + all: true, provider: 'v8', reporter: ['text', 'json', 'html'], + include: ['src/**/*.ts'], exclude: [ 'node_modules/', 'test/', '**/*.test.ts', '**/*.spec.ts', + '**/*.d.ts', + 'src/index.ts', '**/types/**', 'vitest.config.ts' - ], - thresholds: { - lines: 80, - functions: 80, - branches: 80, - statements: 80 - } + ] }, setupFiles: ['./test/setup.ts'] } diff --git a/docker-compose.yml b/docker-compose.yml index fc4a87b0..fad4670a 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -8,13 +8,20 @@ services: GIT_SHA: ${GIT_SHA:-unknown} GIT_SHORT_SHA: ${GIT_SHORT_SHA:-unknown} GIT_DIRTY: ${GIT_DIRTY:-false} + GIT_REF: ${GIT_REF:-local} + SOURCE_REPOSITORY: ${SOURCE_REPOSITORY:-https://github.com/diamondplated/opencode-webui.git} + IMAGE_NAME: ${IMAGE_NAME:-ghcr.io/diamondplated/opencode-webui} + BUN_VERSION: ${BUN_VERSION:-1.2.21} + OPENCODE_VERSION: ${OPENCODE_VERSION:-1.2.27} container_name: opencode-web ports: - - "5003:5003" + - "${HOST_BIND_ADDRESS:-127.0.0.1}:${PORT:-5003}:${PORT:-5003}" environment: - NODE_ENV=production - HOST=0.0.0.0 - - PORT=5003 + - PORT=${PORT:-5003} + - CORS_ORIGIN=${CORS_ORIGIN:-} + - AUTH_TOKEN=${AUTH_TOKEN:-} - OPENCODE_SERVER_PORT=5551 - DATABASE_PATH=/app/data/opencode.db - WORKSPACE_PATH=/workspace @@ -32,7 +39,7 @@ services: - opencode-data:/app/data restart: unless-stopped healthcheck: - test: ["CMD", "curl", "-f", "http://localhost:5003/api/health"] + test: ["CMD", "sh", "-c", "curl -fsS http://localhost:${PORT:-5003}/api/health/ready"] interval: 30s timeout: 3s retries: 3 diff --git a/frontend/src/api/build.ts b/frontend/src/api/build.ts index 15947065..e3ecf163 100644 --- a/frontend/src/api/build.ts +++ b/frontend/src/api/build.ts @@ -8,6 +8,17 @@ export interface BuildInfo { sha: string shortSha: string dirty: boolean + ref: string + } + source: { + repository: string + image: string + } + toolchain: { + node: string + bun: string + pnpm: string + opencode: string } } diff --git a/frontend/src/api/types.ts b/frontend/src/api/types.ts index 1de94ec8..e33d4f4b 100644 --- a/frontend/src/api/types.ts +++ b/frontend/src/api/types.ts @@ -1,6 +1,6 @@ export interface Repo { id: number - repoUrl: string + repoUrl?: string localPath: string fullPath: string branch?: string @@ -11,6 +11,7 @@ export interface Repo { lastPulled?: number openCodeConfigName?: string isWorktree?: boolean + isLocal?: boolean } import type { components } from './opencode-types' @@ -148,6 +149,19 @@ export interface SSESessionIdleEvent { } } +export interface SSESessionErrorEvent { + type: 'session.error' + properties: { + sessionID?: string + error?: unknown + } +} + +export interface SSEServerConnectedEvent { + type: 'server.connected' + properties: Record +} + export type SSEEvent = | SSEMessagePartUpdatedEvent | SSEMessageUpdatedEvent @@ -165,6 +179,8 @@ export type SSEEvent = | SSEFileWatcherUpdatedEvent | SSECommandExecutedEvent | SSESessionIdleEvent + | SSESessionErrorEvent + | SSEServerConnectedEvent export type ContentPart = | { type: 'text', content: string } diff --git a/frontend/src/components/layout/BuildProvenanceBadge.tsx b/frontend/src/components/layout/BuildProvenanceBadge.tsx index c145a2db..3cc2d9b7 100644 --- a/frontend/src/components/layout/BuildProvenanceBadge.tsx +++ b/frontend/src/components/layout/BuildProvenanceBadge.tsx @@ -27,6 +27,9 @@ export function BuildProvenanceBadge({ compact = false }: BuildProvenanceBadgePr "Diamondplated fork", version ? `v${version}` : null, shortSha ? `commit ${data?.git.sha}` : null, + data?.git.ref && data.git.ref !== "unknown" ? `ref ${data.git.ref}` : null, + data?.source.repository && data.source.repository !== "unknown" ? data.source.repository : null, + data?.toolchain.opencode && data.toolchain.opencode !== "unknown" ? `opencode ${data.toolchain.opencode}` : null, dirty ? "dirty build" : "clean build", ] .filter(Boolean) diff --git a/frontend/src/components/session/PermissionRequestDialog.tsx b/frontend/src/components/session/PermissionRequestDialog.tsx index c9a1d7bc..999fd54f 100644 --- a/frontend/src/components/session/PermissionRequestDialog.tsx +++ b/frontend/src/components/session/PermissionRequestDialog.tsx @@ -1,4 +1,4 @@ -import { useState } from 'react' +import { useEffect, useState } from 'react' import { Dialog, DialogContent, @@ -10,12 +10,13 @@ import { import { Button } from '@/components/ui/button' import type { Permission, PermissionResponse } from '@/api/types' import { cn } from '@/lib/utils' +import { showToast } from '@/lib/toast' interface PermissionRequestDialogProps { permission: Permission | null pendingCount: number onRespond: (permissionID: string, sessionID: string, response: PermissionResponse) => Promise - onDismiss: (permissionID: string) => void + onDismiss: (permissionID: string, options?: { resolved?: boolean }) => void } function getPermissionTypeLabel(type: string): string { @@ -65,17 +66,33 @@ export function PermissionRequestDialog({ }: PermissionRequestDialogProps) { const [isLoading, setIsLoading] = useState(false) const [loadingAction, setLoadingAction] = useState(null) + const [errorMessage, setErrorMessage] = useState(null) + + useEffect(() => { + setIsLoading(false) + setLoadingAction(null) + setErrorMessage(null) + }, [permission?.id]) if (!permission) return null const handleResponse = async (response: PermissionResponse) => { + setErrorMessage(null) setIsLoading(true) setLoadingAction(response) + try { await onRespond(permission.id, permission.sessionID, response) + onDismiss(permission.id, { resolved: true }) } catch (error) { console.error('Failed to respond to permission:', error) - onDismiss(permission.id) + const message = error instanceof Error + ? error.message + : 'Failed to send permission response. Please try again.' + setErrorMessage(message) + showToast.error('Failed to respond to permission', { + description: message, + }) } finally { setIsLoading(false) setLoadingAction(null) @@ -87,8 +104,16 @@ export function PermissionRequestDialog({ const hasMultiple = pendingCount > 1 return ( - {}}> - + { + if (!open && !isLoading) { + setErrorMessage(null) + onDismiss(permission.id) + } + }} + > + Permission Request @@ -121,6 +146,12 @@ export function PermissionRequestDialog({
Session: {permission.sessionID.slice(0, 12)}...
+ + {errorMessage && ( +
+ {errorMessage} +
+ )} diff --git a/frontend/src/components/session/SessionDetailHeader.tsx b/frontend/src/components/session/SessionDetailHeader.tsx index 98ba505c..d3ecee7e 100644 --- a/frontend/src/components/session/SessionDetailHeader.tsx +++ b/frontend/src/components/session/SessionDetailHeader.tsx @@ -7,7 +7,7 @@ import { Loader2, Settings, FolderOpen } from "lucide-react"; import { useState } from "react"; interface Repo { - id: number; + id?: number; repoUrl?: string | null; fullPath: string; localPath: string; @@ -21,7 +21,6 @@ interface SessionDetailHeaderProps { repo: Repo; sessionId: string; sessionTitle: string; - repoId: number; isConnected: boolean; isReconnecting?: boolean; opcodeUrl: string | null; @@ -35,7 +34,6 @@ export function SessionDetailHeader({ repo, sessionId, sessionTitle, - repoId, isConnected, isReconnecting, opcodeUrl, @@ -60,8 +58,12 @@ export function SessionDetailHeader({ ); } - const repoName = repo.repoUrl?.split("/").pop()?.replace(".git", "") || repo.localPath || "Repository"; + const repoName = repo.repoUrl?.split("/").pop()?.replace(".git", "") + || repo.fullPath.split('/').filter(Boolean).pop() + || repo.localPath + || "Repository"; const currentBranch = repo.currentBranch || "main"; + const backTarget = repo.id ? `/repos/${repo.id}` : '/'; const handleTitleClick = () => { setIsEditing(true); @@ -96,7 +98,7 @@ export function SessionDetailHeader({
- +
{isEditing ? (
@@ -134,13 +136,15 @@ export function SessionDetailHeader({ directory={repoDirectory} />
- + {repo.id && ( + + )}
{ + if (e.key === 'Tab' && !e.ctrlKey && !e.metaKey && !e.altKey) { + return + } + const shortcut = parseEventShortcut(e) if (!shortcut) return @@ -189,4 +193,4 @@ export function useKeyboardShortcuts(actions: ShortcutActions = {}) { document.addEventListener('keydown', handleKeyDown) return () => document.removeEventListener('keydown', handleKeyDown) }, [handleKeyDown]) -} \ No newline at end of file +} diff --git a/frontend/src/hooks/useOpenCode.ts b/frontend/src/hooks/useOpenCode.ts index 651b95f2..a9641e5c 100644 --- a/frontend/src/hooks/useOpenCode.ts +++ b/frontend/src/hooks/useOpenCode.ts @@ -162,36 +162,44 @@ export const useSendPrompt = (opcodeUrl: string | null | undefined, directory?: const client = useOpenCodeClient(opcodeUrl, directory); const queryClient = useQueryClient(); + type SendPromptVariables = { + sessionID: string; + prompt?: string; + parts?: ContentPart[]; + model?: string; + agent?: string; + }; + return useMutation({ - mutationFn: async ({ + onMutate: ({ sessionID, prompt, parts, - model, - agent, - }: { - sessionID: string; - prompt?: string; - parts?: ContentPart[]; - model?: string; - agent?: string; - }) => { - if (!client) throw new Error("No client available"); - + }: SendPromptVariables) => { const optimisticUserID = `optimistic_user_${Date.now()}_${Math.random()}`; - const contentParts = parts || [{ type: "text" as const, content: prompt || "", name: "" }]; - const userMessage = createOptimisticUserMessage( sessionID, contentParts, optimisticUserID, ); + queryClient.setQueryData( ["opencode", "messages", opcodeUrl, sessionID, directory], (old) => [...(old || []), userMessage], ); + return { optimisticUserID, sessionID }; + }, + mutationFn: async ({ + sessionID, + prompt, + parts, + model, + agent, + }: SendPromptVariables) => { + if (!client) throw new Error("No client available"); + const requestData: SendPromptRequest = { parts: parts?.map((part) => part.type === "text" @@ -223,23 +231,20 @@ export const useSendPrompt = (opcodeUrl: string | null | undefined, directory?: const response = await client.sendPrompt(sessionID, requestData); - return { optimisticUserID, response }; + return { response }; }, - onError: (_, variables) => { - const { sessionID } = variables; + onError: (_, variables, context) => { + const sessionID = context?.sessionID ?? variables.sessionID; + const optimisticUserID = context?.optimisticUserID; + queryClient.setQueryData( ["opencode", "messages", opcodeUrl, sessionID, directory], - (old) => old?.filter((msg) => !msg.info.id.startsWith("optimistic_")), + (old) => + old?.filter((msg) => msg.info.id !== optimisticUserID), ); }, - onSuccess: (data, variables) => { + onSuccess: (_, variables) => { const { sessionID } = variables; - const { optimisticUserID } = data; - - queryClient.setQueryData( - ["opencode", "messages", opcodeUrl, sessionID, directory], - (old) => old?.filter((msg) => msg.info.id !== optimisticUserID) || [], - ); queryClient.invalidateQueries({ queryKey: ["opencode", "session", opcodeUrl, sessionID, directory], @@ -263,52 +268,57 @@ export const useSendShell = (opcodeUrl: string | null | undefined, directory?: s const client = useOpenCodeClient(opcodeUrl, directory); const queryClient = useQueryClient(); + type SendShellVariables = { + sessionID: string; + command: string; + agent?: string; + }; + return useMutation({ - mutationFn: async ({ + onMutate: ({ sessionID, command, - agent, - }: { - sessionID: string; - command: string; - agent?: string; - }) => { - if (!client) throw new Error("No client available"); - + }: SendShellVariables) => { const optimisticUserID = `optimistic_user_${Date.now()}_${Math.random()}`; - const userMessage = createOptimisticUserMessage( sessionID, [{ type: "text" as const, content: command }], optimisticUserID, ); + queryClient.setQueryData( ["opencode", "messages", opcodeUrl, sessionID, directory], (old) => [...(old || []), userMessage], ); + return { optimisticUserID, sessionID }; + }, + mutationFn: async ({ + sessionID, + command, + agent, + }: SendShellVariables) => { + if (!client) throw new Error("No client available"); + const response = await client.sendShell(sessionID, { command, agent: agent || "general", }); - return { optimisticUserID, response }; + return { response }; }, - onError: (_, variables) => { - const { sessionID } = variables; + onError: (_, variables, context) => { + const sessionID = context?.sessionID ?? variables.sessionID; + const optimisticUserID = context?.optimisticUserID; + queryClient.setQueryData( ["opencode", "messages", opcodeUrl, sessionID, directory], - (old) => old?.filter((msg) => !msg.info.id.startsWith("optimistic_")), + (old) => + old?.filter((msg) => msg.info.id !== optimisticUserID), ); }, - onSuccess: (data, variables) => { + onSuccess: (_, variables) => { const { sessionID } = variables; - const { optimisticUserID } = data; - - queryClient.setQueryData( - ["opencode", "messages", opcodeUrl, sessionID, directory], - (old) => old?.filter((msg) => msg.info.id !== optimisticUserID) || [], - ); queryClient.invalidateQueries({ queryKey: ["opencode", "session", opcodeUrl, sessionID, directory], diff --git a/frontend/src/hooks/usePermissionRequests.ts b/frontend/src/hooks/usePermissionRequests.ts index a20205e4..b03daced 100644 --- a/frontend/src/hooks/usePermissionRequests.ts +++ b/frontend/src/hooks/usePermissionRequests.ts @@ -1,17 +1,37 @@ -import { useState, useEffect, useCallback } from 'react' +import { useReducer, useEffect, useCallback, useMemo } from 'react' import type { Permission } from '@/api/types' -type PermissionEventType = 'add' | 'remove' +type PermissionEventType = 'add' | 'remove' | 'clear-session' interface PermissionEvent { type: PermissionEventType permission?: Permission permissionID?: string + sessionID?: string + resolved?: boolean } type PermissionListener = (event: PermissionEvent) => void const listeners = new Set() +type PermissionStatus = 'dismissed' | 'resolved' + +interface PermissionLifecycleEntry { + status: PermissionStatus + updatedAt: number +} + +interface PermissionState { + permissions: Permission[] + lifecycle: Record +} + +type PermissionAction = + | { type: 'add'; permission: Permission; now: number } + | { type: 'remove'; permissionID: string; resolved?: boolean; now: number } + | { type: 'clear-session'; sessionID: string; now: number } + | { type: 'dismiss'; permissionID: string; now: number } + | { type: 'clear-all' } export const permissionEvents = { emit: (event: PermissionEvent) => { @@ -25,37 +45,146 @@ export const permissionEvents = { } } +const RESOLVED_PERMISSION_TTL_MS = 5 * 60 * 1000 + +const pruneLifecycle = (lifecycle: Record, now: number) => { + let nextLifecycle: Record | null = null + + for (const [permissionID, entry] of Object.entries(lifecycle)) { + if (entry.status === 'resolved' && now - entry.updatedAt > RESOLVED_PERMISSION_TTL_MS) { + if (!nextLifecycle) { + nextLifecycle = { ...lifecycle } + } + delete nextLifecycle[permissionID] + } + } + + return nextLifecycle ?? lifecycle +} + +const initialState: PermissionState = { + permissions: [], + lifecycle: {}, +} + +const permissionReducer = (state: PermissionState, action: PermissionAction): PermissionState => { + switch (action.type) { + case 'add': { + const lifecycle = pruneLifecycle(state.lifecycle, action.now) + const entry = lifecycle[action.permission.id] + if (entry?.status === 'resolved') { + return lifecycle === state.lifecycle ? state : { ...state, lifecycle } + } + + const existingIndex = state.permissions.findIndex((permission) => permission.id === action.permission.id) + const permissions = existingIndex < 0 + ? [...state.permissions, action.permission] + : state.permissions.map((permission, index) => + index === existingIndex ? action.permission : permission, + ) + + return { + permissions, + lifecycle, + } + } + + case 'remove': { + const lifecycle = pruneLifecycle(state.lifecycle, action.now) + const nextLifecycle = { ...lifecycle } + if (action.resolved) { + nextLifecycle[action.permissionID] = { status: 'resolved', updatedAt: action.now } + } else { + delete nextLifecycle[action.permissionID] + } + + return { + permissions: state.permissions.filter((permission) => permission.id !== action.permissionID), + lifecycle: nextLifecycle, + } + } + + case 'clear-session': { + const lifecycle = pruneLifecycle(state.lifecycle, action.now) + const removedPermissions = state.permissions.filter((permission) => permission.sessionID === action.sessionID) + if (removedPermissions.length === 0 && lifecycle === state.lifecycle) { + return state + } + + const nextLifecycle = { ...lifecycle } + for (const permission of removedPermissions) { + if (nextLifecycle[permission.id]?.status !== 'resolved') { + delete nextLifecycle[permission.id] + } + } + + return { + permissions: state.permissions.filter((permission) => permission.sessionID !== action.sessionID), + lifecycle: nextLifecycle, + } + } + + case 'dismiss': + return { + permissions: state.permissions, + lifecycle: { + ...pruneLifecycle(state.lifecycle, action.now), + [action.permissionID]: { + status: 'dismissed', + updatedAt: action.now, + }, + }, + } + + case 'clear-all': + return initialState + } +} + export function usePermissionRequests() { - const [permissions, setPermissions] = useState([]) + const [{ permissions, lifecycle }, dispatch] = useReducer(permissionReducer, initialState) useEffect(() => { const unsubscribe = permissionEvents.subscribe((event) => { + const now = Date.now() if (event.type === 'add' && event.permission) { - setPermissions(prev => { - const exists = prev.some(p => p.id === event.permission!.id) - if (exists) return prev - return [...prev, event.permission!] - }) + dispatch({ type: 'add', permission: event.permission, now }) } else if (event.type === 'remove' && event.permissionID) { - setPermissions(prev => prev.filter(p => p.id !== event.permissionID)) + dispatch({ type: 'remove', permissionID: event.permissionID, resolved: event.resolved, now }) + } else if (event.type === 'clear-session' && event.sessionID) { + dispatch({ type: 'clear-session', sessionID: event.sessionID, now }) } }) return unsubscribe }, []) - const currentPermission = permissions[0] || null + const activePermissions = useMemo( + () => + permissions.filter((permission) => { + const entry = lifecycle[permission.id] + return entry?.status !== 'dismissed' && entry?.status !== 'resolved' + }), + [lifecycle, permissions], + ) + + const currentPermission = activePermissions[0] || null + + const dismissPermission = useCallback((permissionID: string, options?: { resolved?: boolean }) => { + if (options?.resolved) { + dispatch({ type: 'remove', permissionID, resolved: true, now: Date.now() }) + return + } - const dismissPermission = useCallback((permissionID: string) => { - setPermissions(prev => prev.filter(p => p.id !== permissionID)) + dispatch({ type: 'dismiss', permissionID, now: Date.now() }) }, []) const clearAllPermissions = useCallback(() => { - setPermissions([]) + dispatch({ type: 'clear-all' }) }, []) return { currentPermission, - pendingCount: permissions.length, + pendingCount: activePermissions.length, dismissPermission, clearAllPermissions } diff --git a/frontend/src/hooks/useSSE.ts b/frontend/src/hooks/useSSE.ts index cdf571ce..0d7899e8 100644 --- a/frontend/src/hooks/useSSE.ts +++ b/frontend/src/hooks/useSSE.ts @@ -1,5 +1,6 @@ import { useEffect, useRef, useState, useCallback } from 'react' import { useQueryClient } from '@tanstack/react-query' +import type { Repo } from '@/api/types' import { useOpenCodeClient } from './useOpenCode' import type { SSEEvent, MessageListResponse } from '@/api/types' import { permissionEvents } from './usePermissionRequests' @@ -8,6 +9,8 @@ import { settingsApi } from '@/api/settings' const MAX_RECONNECT_DELAY = 30000 const INITIAL_RECONNECT_DELAY = 1000 +const RESYNC_DEBOUNCE_MS = 250 +const MIN_RESYNC_INTERVAL_MS = 2000 const invalidateRepoState = (queryClient: ReturnType, repoId: number | null | undefined) => { if (!repoId) return @@ -21,13 +24,31 @@ const invalidateRepoState = (queryClient: ReturnType, rep const getRepoIdFromDirectory = (queryClient: ReturnType, directory?: string): number | null => { if (!directory) return null - const repos = queryClient.getQueryData(['repos']) + const repos = queryClient.getQueryData(['repos']) if (!Array.isArray(repos)) return null const repo = repos.find((item) => item?.fullPath === directory || item?.localPath === directory) return typeof repo?.id === 'number' ? repo.id : null } +const isOptimisticUserMessage = (message: MessageListResponse[number]) => + message.info.role === 'user' && message.info.id.startsWith('optimistic_') + +const findBestOptimisticUserMessage = ( + messages: MessageListResponse, + createdAt?: number, +) => { + const optimisticMessages = messages.filter(isOptimisticUserMessage) + if (optimisticMessages.length === 0) return null + if (typeof createdAt !== 'number') return optimisticMessages[0] + + return optimisticMessages.reduce((bestMatch, candidate) => { + const bestDistance = Math.abs((bestMatch.info.time?.created ?? createdAt) - createdAt) + const candidateDistance = Math.abs((candidate.info.time?.created ?? createdAt) - createdAt) + return candidateDistance < bestDistance ? candidate : bestMatch + }) +} + const handleRestartServer = async () => { showToast.loading('Restarting OpenCode server...', { id: 'restart-server', @@ -64,7 +85,11 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) const eventSourceRef = useRef(null) const urlRef = useRef(null) const reconnectTimeoutRef = useRef | null>(null) + const repoInvalidationTimeoutRef = useRef | null>(null) const reconnectDelayRef = useRef(INITIAL_RECONNECT_DELAY) + const hasConnectedRef = useRef(false) + const shouldResyncRef = useRef(false) + const lastResyncAtRef = useRef(0) const mountedRef = useRef(true) const [isConnected, setIsConnected] = useState(false) const [error, setError] = useState(null) @@ -92,6 +117,45 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) setIsReconnecting(false) }, []) + const invalidateActiveOpencodeState = useCallback(() => { + const now = Date.now() + if (now - lastResyncAtRef.current < MIN_RESYNC_INTERVAL_MS) { + return + } + + lastResyncAtRef.current = now + queryClient.invalidateQueries({ + predicate: (query) => { + const [scope, resource, queryOpcodeUrl, , queryDirectory] = query.queryKey + if (scope !== 'opencode' || queryOpcodeUrl !== opcodeUrl) { + return false + } + + return ( + (resource === 'sessions' && query.queryKey[3] === directory) || + ((resource === 'session' || resource === 'messages' || resource === 'todos') && + queryDirectory === directory) + ) + }, + refetchType: 'active', + }) + + invalidateRepoState(queryClient, getRepoIdFromDirectory(queryClient, directory)) + }, [directory, opcodeUrl, queryClient]) + + const scheduleRepoInvalidation = useCallback(() => { + if (repoInvalidationTimeoutRef.current) return + + repoInvalidationTimeoutRef.current = setTimeout(() => { + repoInvalidationTimeoutRef.current = null + invalidateRepoState(queryClient, getRepoIdFromDirectory(queryClient, directory)) + }, RESYNC_DEBOUNCE_MS) + }, [directory, queryClient]) + + const buildEventSourceUrl = useCallback(() => { + return client?.getEventSourceURL() ?? null + }, [client]) + useEffect(() => { mountedRef.current = true @@ -105,7 +169,10 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) return } - const eventSourceUrl = client.getEventSourceURL() + const eventSourceUrl = buildEventSourceUrl() + if (!eventSourceUrl) { + return + } if (urlRef.current === eventSourceUrl && eventSourceRef.current) { return @@ -131,6 +198,7 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) case 'session.deleted': queryClient.invalidateQueries({ queryKey: ['opencode', 'sessions', opcodeUrl, directory] }) if ('sessionID' in event.properties) { + permissionEvents.emit({ type: 'clear-session', sessionID: event.properties.sessionID }) queryClient.invalidateQueries({ queryKey: ['opencode', 'session', opcodeUrl, event.properties.sessionID, directory] }) @@ -146,10 +214,20 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) const messageID = part.messageID const currentData = queryClient.getQueryData(['opencode', 'messages', opcodeUrl, sessionID, directory]) - if (!currentData) return + if (!currentData) { + queryClient.invalidateQueries({ + queryKey: ['opencode', 'messages', opcodeUrl, sessionID, directory], + }) + return + } const messageExists = currentData.some(msg => msg.info.id === messageID) - if (!messageExists) return + if (!messageExists) { + queryClient.invalidateQueries({ + queryKey: ['opencode', 'messages', opcodeUrl, sessionID, directory], + }) + return + } const updated = currentData.map(msg => { if (msg.info.id !== messageID) return msg @@ -191,10 +269,23 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) const messageExists = currentData.some(msg => msg.info.id === info.id) if (!messageExists) { - const filteredData = info.role === 'user' - ? currentData.filter(msg => !msg.info.id.startsWith('optimistic_')) - : currentData - queryClient.setQueryData(['opencode', 'messages', opcodeUrl, sessionID, directory], [...filteredData, { info, parts: [] }]) + const optimisticMatch = info.role === 'user' + ? findBestOptimisticUserMessage(currentData, info.time?.created) + : null + + if (optimisticMatch) { + queryClient.setQueryData( + ['opencode', 'messages', opcodeUrl, sessionID, directory], + currentData.map(msg => + msg.info.id === optimisticMatch.info.id + ? { info: { ...info }, parts: [...msg.parts] } + : msg, + ), + ) + return + } + + queryClient.setQueryData(['opencode', 'messages', opcodeUrl, sessionID, directory], [...currentData, { info, parts: [] }]) return } @@ -292,7 +383,30 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) case 'session.idle': case 'file.edited': case 'file.watcher.updated': - invalidateRepoState(queryClient, getRepoIdFromDirectory(queryClient, directory)) + scheduleRepoInvalidation() + if ('sessionID' in event.properties) { + permissionEvents.emit({ type: 'clear-session', sessionID: event.properties.sessionID }) + } + break + + case 'session.error': + if ('sessionID' in event.properties && event.properties.sessionID) { + permissionEvents.emit({ type: 'clear-session', sessionID: event.properties.sessionID }) + queryClient.invalidateQueries({ + queryKey: ['opencode', 'session', opcodeUrl, event.properties.sessionID, directory], + }) + queryClient.invalidateQueries({ + queryKey: ['opencode', 'messages', opcodeUrl, event.properties.sessionID, directory], + }) + queryClient.invalidateQueries({ + queryKey: ['opencode', 'todos', opcodeUrl, event.properties.sessionID, directory], + }) + } + break + + case 'server.connected': + shouldResyncRef.current = true + invalidateActiveOpencodeState() break case 'installation.update-available': @@ -327,7 +441,13 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) } try { - const eventSource = new EventSource(eventSourceUrl) + const nextEventSourceUrl = buildEventSourceUrl() + if (!nextEventSourceUrl) { + return + } + urlRef.current = nextEventSourceUrl + + const eventSource = new EventSource(nextEventSourceUrl) eventSourceRef.current = eventSource eventSource.onopen = () => { @@ -335,9 +455,13 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) setIsConnected(true) setError(null) resetReconnectDelay() - queryClient.invalidateQueries({ queryKey: ['opencode', 'sessions', opcodeUrl, directory] }) - queryClient.invalidateQueries({ queryKey: ['opencode', 'messages', opcodeUrl] }) - invalidateRepoState(queryClient, getRepoIdFromDirectory(queryClient, directory)) + const shouldResync = hasConnectedRef.current || shouldResyncRef.current + hasConnectedRef.current = true + shouldResyncRef.current = false + + if (shouldResync) { + invalidateActiveOpencodeState() + } } eventSource.onerror = () => { @@ -345,6 +469,7 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) setIsConnected(false) setError('Connection lost. Reconnecting...') + shouldResyncRef.current = hasConnectedRef.current if (eventSourceRef.current) { eventSourceRef.current.close() @@ -370,7 +495,16 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) } const handleReconnect = () => { - if (!eventSourceRef.current || eventSourceRef.current.readyState === EventSource.CLOSED) { + const nextEventSourceUrl = buildEventSourceUrl() + if (!nextEventSourceUrl) { + return + } + + if ( + !eventSourceRef.current + || eventSourceRef.current.readyState === EventSource.CLOSED + || urlRef.current !== nextEventSourceUrl + ) { resetReconnectDelay() connectSSE() } @@ -389,13 +523,17 @@ export const useSSE = (opcodeUrl: string | null | undefined, directory?: string) clearTimeout(reconnectTimeoutRef.current) reconnectTimeoutRef.current = null } + if (repoInvalidationTimeoutRef.current) { + clearTimeout(repoInvalidationTimeoutRef.current) + repoInvalidationTimeoutRef.current = null + } if (eventSourceRef.current) { eventSourceRef.current.close() eventSourceRef.current = null setIsConnected(false) } } - }, [client, queryClient, opcodeUrl, directory, scheduleReconnect, resetReconnectDelay]) + }, [client, queryClient, opcodeUrl, directory, scheduleReconnect, resetReconnectDelay, scheduleRepoInvalidation, invalidateActiveOpencodeState, buildEventSourceUrl]) return { isConnected, error, isReconnecting } } diff --git a/frontend/src/lib/http.ts b/frontend/src/lib/http.ts index f55528ad..9149ecce 100644 --- a/frontend/src/lib/http.ts +++ b/frontend/src/lib/http.ts @@ -1,11 +1,30 @@ import axios from 'axios' -import type { AxiosInstance, AxiosRequestConfig } from 'axios' +import type { AxiosError, AxiosInstance, AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios' import { API_AUTH_TOKEN } from '@/config' const STORAGE_KEY = 'opencode-webui.apiAuthToken' const PUBLIC_API_PREFIXES = ['/api/health'] -let cachedToken = API_AUTH_TOKEN?.trim() || null +type ApiAuthTokenSource = 'config' | 'storage' | 'prompt' + +interface ResolvedApiAuthToken { + value: string + source: ApiAuthTokenSource +} + +interface RequestAuthState { + token: ResolvedApiAuthToken | null + headerInjected: boolean +} + +interface AuthenticatedAxiosRequestConfig extends InternalAxiosRequestConfig { + _authRetry?: boolean + _authState?: RequestAuthState +} + +const configuredToken = API_AUTH_TOKEN?.trim() || null +let cachedToken = configuredToken +let cachedTokenSource: ApiAuthTokenSource | null = configuredToken ? 'config' : null const getBrowserOrigin = (): string => { return typeof window !== 'undefined' ? window.location.origin : 'http://localhost' @@ -54,29 +73,117 @@ const readStoredToken = (): string | null => { return stored || null } -export const getApiAuthToken = (options: { promptIfMissing?: boolean } = {}): string | null => { - if (cachedToken) { - return cachedToken +const persistToken = (token: string | null) => { + if (typeof window === 'undefined') { + return + } + + if (token) { + window.localStorage.setItem(STORAGE_KEY, token) + return + } + + window.localStorage.removeItem(STORAGE_KEY) +} + +const cacheToken = (token: string | null, source: ApiAuthTokenSource | null) => { + cachedToken = token + cachedTokenSource = token ? source : null +} + +const promptForToken = (): ResolvedApiAuthToken | null => { + if (typeof window === 'undefined') { + return null } - const storedToken = readStoredToken() - if (storedToken) { - cachedToken = storedToken - return storedToken + const enteredToken = window.prompt('Enter the OpenCode WebUI API token')?.trim() + if (!enteredToken) { + return null } - if (options.promptIfMissing && typeof window !== 'undefined') { - const enteredToken = window.prompt('Enter the OpenCode WebUI API token')?.trim() - if (enteredToken) { - window.localStorage.setItem(STORAGE_KEY, enteredToken) - cachedToken = enteredToken - return enteredToken + persistToken(enteredToken) + const resolved = { value: enteredToken, source: 'prompt' as const } + cacheToken(resolved.value, resolved.source) + return resolved +} + +const clearRetriableToken = (source: ApiAuthTokenSource | null | undefined) => { + if (!source || source === 'config') { + return + } + + persistToken(null) + if (cachedTokenSource === source) { + cacheToken(null, null) + } +} + +const resolveApiAuthToken = (options: { promptIfMissing?: boolean; forceRefresh?: boolean } = {}): ResolvedApiAuthToken | null => { + if (configuredToken) { + cacheToken(configuredToken, 'config') + return { value: configuredToken, source: 'config' } + } + + if (!options.forceRefresh && cachedToken) { + return cachedTokenSource ? { value: cachedToken, source: cachedTokenSource } : null + } + + if (!options.forceRefresh) { + const storedToken = readStoredToken() + if (storedToken) { + cacheToken(storedToken, 'storage') + return { value: storedToken, source: 'storage' } } } + if (options.promptIfMissing) { + return promptForToken() + } + return null } +const applyAuthHeader = (headers: Headers, token: ResolvedApiAuthToken | null): Headers => { + if (token && !headers.has('Authorization')) { + headers.set('Authorization', `Bearer ${token.value}`) + } + return headers +} + +const shouldRetryUnauthorized = (status: number, authState: RequestAuthState): boolean => { + return status === 401 + && authState.headerInjected + && authState.token?.source !== 'config' +} + +const resolveRequestAuthState = (hasAuthorizationHeader: boolean, options: { promptIfMissing?: boolean; forceRefresh?: boolean } = {}): RequestAuthState => { + if (hasAuthorizationHeader) { + return { token: null, headerInjected: false } + } + + const token = resolveApiAuthToken(options) + return { + token, + headerInjected: !!token, + } +} + +const createAuthenticatedRequest = (request: Request, options: { promptIfMissing?: boolean; forceRefresh?: boolean } = {}) => { + const headers = new Headers(request.headers) + const authState = resolveRequestAuthState(headers.has('Authorization'), options) + + return { + authState, + request: new Request(request, { + headers: applyAuthHeader(headers, authState.token), + }), + } +} + +export const getApiAuthToken = (options: { promptIfMissing?: boolean; forceRefresh?: boolean } = {}): string | null => { + return resolveApiAuthToken(options)?.value ?? null +} + export const buildAuthenticatedUrl = ( rawUrl: string, options: { promptIfMissing?: boolean; baseURL?: string } = {}, @@ -87,57 +194,103 @@ export const buildAuthenticatedUrl = ( return url.toString() } - const token = getApiAuthToken({ promptIfMissing: options.promptIfMissing }) + const token = resolveApiAuthToken({ promptIfMissing: options.promptIfMissing }) if (token && !url.searchParams.has('access_token')) { - url.searchParams.set('access_token', token) + url.searchParams.set('access_token', token.value) } return url.toString() } -const applyAuthHeader = (headers: Headers, token: string | null): Headers => { - if (token && !headers.has('Authorization')) { - headers.set('Authorization', `Bearer ${token}`) - } - return headers -} - export const apiFetch = async (input: RequestInfo | URL, init?: RequestInit): Promise => { - const request = input instanceof Request ? input : new Request(input, init) - const url = resolveRequestUrl(request) + const originalRequest = input instanceof Request ? input : new Request(input, init) + const url = resolveRequestUrl(originalRequest) if (!isProtectedApiUrl(url)) { - return fetch(request) + return fetch(originalRequest) + } + + const initialRequest = createAuthenticatedRequest(originalRequest.clone(), { promptIfMissing: true }) + const initialResponse = await fetch(initialRequest.request) + + if (!shouldRetryUnauthorized(initialResponse.status, initialRequest.authState)) { + return initialResponse } - const headers = applyAuthHeader( - new Headers(request.headers), - getApiAuthToken({ promptIfMissing: true }), - ) + clearRetriableToken(initialRequest.authState.token?.source) - return fetch(new Request(request, { headers })) + const retryRequest = createAuthenticatedRequest(originalRequest.clone(), { + promptIfMissing: true, + forceRefresh: true, + }) + + if (!retryRequest.authState.token) { + return initialResponse + } + + return fetch(retryRequest.request) } export const createApiClient = (config?: AxiosRequestConfig): AxiosInstance => { const client = axios.create(config) client.interceptors.request.use((requestConfig) => { - const url = resolveRequestUrl(requestConfig.url ?? '', requestConfig.baseURL ?? config?.baseURL) + const authenticatedConfig = requestConfig as AuthenticatedAxiosRequestConfig + const url = resolveRequestUrl(authenticatedConfig.url ?? '', authenticatedConfig.baseURL ?? config?.baseURL) if (!isProtectedApiUrl(url)) { - return requestConfig + authenticatedConfig._authState = undefined + return authenticatedConfig } - const token = getApiAuthToken({ promptIfMissing: true }) - if (token) { - const headers = requestConfig.headers instanceof axios.AxiosHeaders - ? requestConfig.headers - : new axios.AxiosHeaders(requestConfig.headers) - headers.set('Authorization', `Bearer ${token}`) - requestConfig.headers = headers + const headers = authenticatedConfig.headers instanceof axios.AxiosHeaders + ? authenticatedConfig.headers + : new axios.AxiosHeaders(authenticatedConfig.headers) + const authState = resolveRequestAuthState(headers.has('Authorization'), { promptIfMissing: true }) + + if (authState.headerInjected && authState.token) { + headers.set('Authorization', `Bearer ${authState.token.value}`) } - return requestConfig + authenticatedConfig.headers = headers + authenticatedConfig._authState = authState + + return authenticatedConfig + }) + + client.interceptors.response.use(undefined, async (error: AxiosError) => { + const response = error.response + const requestConfig = error.config as AuthenticatedAxiosRequestConfig | undefined + + if (!response || !requestConfig || requestConfig._authRetry || !requestConfig._authState) { + return Promise.reject(error) + } + + if (!shouldRetryUnauthorized(response.status, requestConfig._authState)) { + return Promise.reject(error) + } + + clearRetriableToken(requestConfig._authState.token?.source) + + const refreshedToken = resolveApiAuthToken({ + promptIfMissing: true, + forceRefresh: true, + }) + + if (!refreshedToken) { + return Promise.reject(error) + } + + const headers = requestConfig.headers instanceof axios.AxiosHeaders + ? requestConfig.headers + : new axios.AxiosHeaders(requestConfig.headers) + + headers.set('Authorization', `Bearer ${refreshedToken.value}`) + requestConfig.headers = headers + requestConfig._authRetry = true + requestConfig._authState = { token: refreshedToken, headerInjected: true } + + return client.request(requestConfig as AxiosRequestConfig) }) return client diff --git a/frontend/src/pages/SessionDetail.tsx b/frontend/src/pages/SessionDetail.tsx index 1166b1e8..74458e41 100644 --- a/frontend/src/pages/SessionDetail.tsx +++ b/frontend/src/pages/SessionDetail.tsx @@ -22,6 +22,17 @@ import { useRef, useCallback } from "react"; import { Loader2 } from "lucide-react"; import type { PermissionResponse } from "@/api/types"; +type ResolvedRepo = { + id?: number; + repoUrl?: string | null; + fullPath: string; + localPath: string; + currentBranch?: string; + isWorktree?: boolean; + isLocal?: boolean; + cloneStatus: 'ready' | 'cloning' | 'error'; +}; + export function SessionDetail() { const { id, sessionId } = useParams<{ id?: string; sessionId: string }>(); const navigate = useNavigate(); @@ -53,11 +64,20 @@ export function SessionDetail() { enabled: !routedRepo, }); - const repo = routedRepo ?? repos.find((candidate) => candidate.fullPath === directSession?.directory); + const matchedRepo = routedRepo ?? repos.find((candidate) => + candidate.fullPath === directSession?.directory || candidate.localPath === directSession?.directory, + ); const { currentPermission, pendingCount, dismissPermission } = usePermissionRequests(); - const repoDirectory = repo?.fullPath ?? directSession?.directory; + const repoDirectory = matchedRepo?.fullPath ?? directSession?.directory; + const repo: ResolvedRepo | null = matchedRepo ?? (repoDirectory + ? { + fullPath: repoDirectory, + localPath: repoDirectory, + cloneStatus: 'ready', + } + : null); const openCodeClient = useOpenCodeClient(opcodeUrl, repoDirectory); const { data: messages } = useMessages(opcodeUrl, sessionId, repoDirectory); @@ -133,11 +153,14 @@ export function SessionDetail() { permissionSessionID: string, response: PermissionResponse ) => { - if (!openCodeClient) return + if (!openCodeClient) { + throw new Error("Session connection is still loading. Please try again."); + } + await openCodeClient.respondToPermission(permissionSessionID, permissionID, response) }, [openCodeClient]); - const repoLoading = routedRepoLoading || (!routedRepo && reposLoading); + const repoLoading = routedRepoLoading || (!matchedRepo && !directSession?.directory && reposLoading); const sessionLoading = directSessionLoading || (Boolean(repoDirectory) && sessionWithRepoContextLoading); if (repoLoading || sessionLoading) { @@ -148,7 +171,7 @@ export function SessionDetail() { ); } - if (!repo || !sessionId) { + if (!repo || !repoDirectory || !sessionId) { return (
Session not found @@ -171,7 +194,6 @@ export function SessionDetail() { repo={repo} sessionId={sessionId} sessionTitle={session.title || "Untitled Session"} - repoId={repo?.id ?? routeRepoId ?? 0} isConnected={isConnected} isReconnecting={isReconnecting} opcodeUrl={opcodeUrl} @@ -250,7 +272,7 @@ export function SessionDetail() { isOpen={fileBrowserOpen} onClose={handleFileBrowserClose} basePath={repo.localPath} - repoName={repo.repoUrl?.split("/").pop()?.replace(".git", "") || repo.localPath || "Repository"} + repoName={repo.repoUrl?.split("/").pop()?.replace(".git", "") || repo.fullPath.split('/').filter(Boolean).pop() || "Repository"} initialSelectedFile={selectedFilePath} /> diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index b5c9a26f..d2ddd7c7 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -5,7 +5,7 @@ import tailwindcss from "@tailwindcss/vite"; export default defineConfig(({ mode }) => { const env = loadEnv(mode, path.resolve(__dirname, ".."), ""); - const backendPort = env.PORT || 5001; + const backendPort = env.PORT || 5003; return { envDir: path.resolve(__dirname, ".."), diff --git a/package.json b/package.json index ae05e745..38deec9b 100644 --- a/package.json +++ b/package.json @@ -12,14 +12,17 @@ "build": "pnpm run build:backend && pnpm run build:frontend", "build:backend": "pnpm --filter backend build", "build:frontend": "pnpm --filter frontend build", + "lint": "pnpm --filter frontend lint", "test": "pnpm run test:backend", "test:backend": "pnpm --filter backend test", + "test:coverage": "pnpm --filter backend test:coverage", + "validate": "pnpm test && pnpm build", "generate:openapi": "bun scripts/generate-openapi.ts", - "docker:build": "docker-compose build", - "docker:up": "docker-compose up -d", - "docker:down": "docker-compose down -v", - "docker:logs": "docker-compose logs -f", - "docker:restart": "docker-compose restart" + "docker:build": "docker compose build", + "docker:up": "docker compose up -d", + "docker:down": "docker compose down -v", + "docker:logs": "docker compose logs -f", + "docker:restart": "docker compose restart" }, "devDependencies": { "concurrently": "^9.1.0" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8bded584..80fe75bc 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1,4 +1,4 @@ -lockfileVersion: '6.0' +lockfileVersion: '9.0' settings: autoInstallPeers: true @@ -45,52 +45,55 @@ importers: version: 7.6.13 '@types/bun': specifier: latest - version: 1.3.3 + version: 1.3.11 + '@vitest/coverage-v8': + specifier: ^3.2.4 + version: 3.2.4(vitest@3.2.4) '@vitest/ui': specifier: ^3.2.4 version: 3.2.4(vitest@3.2.4) vitest: specifier: ^3.2.4 - version: 3.2.4(@vitest/ui@3.2.4) + version: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/ui@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2) frontend: dependencies: '@hookform/resolvers': specifier: ^5.2.2 - version: 5.2.2(react-hook-form@7.66.1) + version: 5.2.2(react-hook-form@7.66.1(react@19.2.0)) '@monaco-editor/react': specifier: ^4.7.0 - version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.0)(react@19.2.0) + version: 4.7.0(monaco-editor@0.55.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-checkbox': specifier: ^1.3.3 - version: 1.3.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) + version: 1.3.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-dialog': specifier: ^1.1.15 - version: 1.1.15(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) + version: 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-dropdown-menu': specifier: ^2.1.16 - version: 2.1.16(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) + version: 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-label': specifier: ^2.1.7 - version: 2.1.8(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) + version: 2.1.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-select': specifier: ^2.2.6 - version: 2.2.6(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) + version: 2.2.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-slider': specifier: ^1.3.6 - version: 1.3.6(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) + version: 1.3.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-slot': specifier: ^1.2.3 version: 1.2.4(@types/react@19.2.7)(react@19.2.0) '@radix-ui/react-switch': specifier: ^1.2.6 - version: 1.2.6(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) + version: 1.2.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@radix-ui/react-tabs': specifier: ^1.1.13 - version: 1.1.13(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) + version: 1.1.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) '@tailwindcss/vite': specifier: ^4.1.14 - version: 4.1.17(vite@7.2.4) + version: 4.1.17(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)) '@tanstack/react-query': specifier: ^5.90.5 version: 5.90.11(react@19.2.0) @@ -105,7 +108,7 @@ importers: version: 2.1.1 cmdk: specifier: ^1.1.1 - version: 1.1.1(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) + version: 1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) date-fns: specifier: ^4.1.0 version: 4.1.0 @@ -132,7 +135,7 @@ importers: version: 10.1.0(@types/react@19.2.7)(react@19.2.0) react-router-dom: specifier: ^7.9.4 - version: 7.9.6(react-dom@19.2.0)(react@19.2.0) + version: 7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) rehype-highlight: specifier: ^7.0.2 version: 7.0.2 @@ -144,7 +147,7 @@ importers: version: 4.0.1 sonner: specifier: ^2.0.7 - version: 2.0.7(react-dom@19.2.0)(react@19.2.0) + version: 2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0) tailwind-merge: specifier: ^3.3.1 version: 3.4.0 @@ -169,19 +172,19 @@ importers: version: 19.2.3(@types/react@19.2.7) '@vitejs/plugin-react': specifier: ^5.0.4 - version: 5.1.1(vite@7.2.4) + version: 5.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)) autoprefixer: specifier: ^10.4.21 version: 10.4.22(postcss@8.5.6) eslint: specifier: ^9.36.0 - version: 9.39.1 + version: 9.39.1(jiti@2.6.1) eslint-plugin-react-hooks: specifier: ^5.2.0 - version: 5.2.0(eslint@9.39.1) + version: 5.2.0(eslint@9.39.1(jiti@2.6.1)) eslint-plugin-react-refresh: specifier: ^0.4.22 - version: 0.4.24(eslint@9.39.1) + version: 0.4.24(eslint@9.39.1(jiti@2.6.1)) globals: specifier: ^16.4.0 version: 16.5.0 @@ -199,10 +202,10 @@ importers: version: 5.9.3 typescript-eslint: specifier: ^8.45.0 - version: 8.48.0(eslint@9.39.1)(typescript@5.9.3) + version: 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) vite: specifier: ^7.1.7 - version: 7.2.4(@types/node@24.10.1) + version: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2) shared: dependencies: @@ -220,591 +223,381 @@ importers: packages: - /@babel/code-frame@7.27.1: + '@ampproject/remapping@2.3.0': + resolution: {integrity: sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==} + engines: {node: '>=6.0.0'} + + '@babel/code-frame@7.27.1': resolution: {integrity: sha512-cjQ7ZlQ0Mv3b47hABuTevyTuYN4i+loJKGeV9flcCgIK37cCXRh+L1bd3iBHlynerhQ7BhCkn2BPbQUL+rGqFg==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-validator-identifier': 7.28.5 - js-tokens: 4.0.0 - picocolors: 1.1.1 - dev: true - /@babel/compat-data@7.28.5: + '@babel/compat-data@7.28.5': resolution: {integrity: sha512-6uFXyCayocRbqhZOB+6XcuZbkMNimwfVGFji8CTZnCzOHVGvDqzvitu1re2AU5LROliz7eQPhB8CpAMvnx9EjA==} engines: {node: '>=6.9.0'} - dev: true - /@babel/core@7.28.5: + '@babel/core@7.28.5': resolution: {integrity: sha512-e7jT4DxYvIDLk1ZHmU/m/mB19rex9sv0c2ftBtjSBv+kVM/902eh0fINUzD7UwLLNR+jU585GxUJ8/EBfAM5fw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-compilation-targets': 7.27.2 - '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) - '@babel/helpers': 7.28.4 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/remapping': 2.3.5 - convert-source-map: 2.0.0 - debug: 4.4.3(supports-color@10.2.2) - gensync: 1.0.0-beta.2 - json5: 2.2.3 - semver: 6.3.1 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/generator@7.28.5: + '@babel/generator@7.28.5': resolution: {integrity: sha512-3EwLFhZ38J4VyIP6WNtt2kUdW9dokXA9Cr4IVIFHuCpZ3H8/YFOl5JjZHisrn1fATPBmKKqXzDFvh9fUwHz6CQ==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - jsesc: 3.1.0 - dev: true - /@babel/helper-compilation-targets@7.27.2: + '@babel/helper-compilation-targets@7.27.2': resolution: {integrity: sha512-2+1thGUUWWjLTYTHZWK1n8Yga0ijBz1XAhUXcKy81rd5g6yh7hGqMp45v7cadSbEHc9G3OTv45SyneRN3ps4DQ==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/compat-data': 7.28.5 - '@babel/helper-validator-option': 7.27.1 - browserslist: 4.28.0 - lru-cache: 5.1.1 - semver: 6.3.1 - dev: true - /@babel/helper-globals@7.28.0: + '@babel/helper-globals@7.28.0': resolution: {integrity: sha512-+W6cISkXFa1jXsDEdYA8HeevQT/FULhxzR99pxphltZcVaugps53THCeiWA8SguxxpSp3gKPiuYfSWopkLQ4hw==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-module-imports@7.27.1: + '@babel/helper-module-imports@7.27.1': resolution: {integrity: sha512-0gSFWUPNXNopqtIPQvlD5WgXYI5GY2kP2cCvoT8kczjbfcfuIljTbcWrulD1CIPIX2gt1wghbDy08yE1p+/r3w==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/traverse': 7.28.5 - '@babel/types': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5): + '@babel/helper-module-transforms@7.28.3': resolution: {integrity: sha512-gytXUbs8k2sXS9PnQptz5o0QnpLL51SwASIORY6XaBKF88nsOT0Zw9szLqlSGQDP/4TljBAD5y98p2U1fqkdsw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-module-imports': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - '@babel/traverse': 7.28.5 - transitivePeerDependencies: - - supports-color - dev: true - /@babel/helper-plugin-utils@7.27.1: + '@babel/helper-plugin-utils@7.27.1': resolution: {integrity: sha512-1gn1Up5YXka3YYAHGKpbideQ5Yjf1tDa9qYcgysz+cNCXukyLl6DjPXhD3VRwSb8c0J9tA4b2+rHEZtc6R0tlw==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-string-parser@7.27.1: + '@babel/helper-string-parser@7.27.1': resolution: {integrity: sha512-qMlSxKbpRlAridDExk92nSobyDdpPijUq2DW6oDnUqd0iOGxmQjyqhMIihI9+zv4LPyZdRje2cavWPbCbWm3eA==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-validator-identifier@7.28.5: + '@babel/helper-validator-identifier@7.28.5': resolution: {integrity: sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helper-validator-option@7.27.1: + '@babel/helper-validator-option@7.27.1': resolution: {integrity: sha512-YvjJow9FxbhFFKDSuFnVCe2WxXk1zWc22fFePVNEaWJEu8IrZVlda6N0uHwzZrUM1il7NC9Mlp4MaJYbYd9JSg==} engines: {node: '>=6.9.0'} - dev: true - /@babel/helpers@7.28.4: + '@babel/helpers@7.28.4': resolution: {integrity: sha512-HFN59MmQXGHVyYadKLVumYsA9dBFun/ldYxipEjzA4196jpLZd8UjEEBLkbEkvfYreDqJhZxYAWFPtrfhNpj4w==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - dev: true - /@babel/parser@7.28.5: + '@babel/parser@7.28.5': resolution: {integrity: sha512-KKBU1VGYR7ORr3At5HAtUQ+TV3SzRCXmA/8OdDZiLDBIZxVyzXuztPjfLd3BV1PRAQGCMWWSHYhL0F8d5uHBDQ==} engines: {node: '>=6.0.0'} hasBin: true - dependencies: - '@babel/types': 7.28.5 - dev: true - /@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5): + '@babel/plugin-transform-react-jsx-self@7.27.1': resolution: {integrity: sha512-6UzkCs+ejGdZ5mFFC/OCUrv028ab2fp1znZmCZjAOBKiBK2jXD1O+BPSfX8X2qjJ75fZBMSnQn3Rq2mrBJK2mw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5): + '@babel/plugin-transform-react-jsx-source@7.27.1': resolution: {integrity: sha512-zbwoTsBruTeKB9hSq73ha66iFeJHuaFkUbwvqElnygoNbj/jHRsSeokowZFN3CZ64IvEqcmmkVe89OPXc7ldAw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 - dependencies: - '@babel/core': 7.28.5 - '@babel/helper-plugin-utils': 7.27.1 - dev: true - /@babel/template@7.27.2: + '@babel/template@7.27.2': resolution: {integrity: sha512-LPDZ85aEJyYSd18/DkjNh4/y1ntkE5KwUHWTiqgRxruuZL2F1yuHligVHLvcHY2vMHXttKFpJn6LwfI7cw7ODw==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - dev: true - /@babel/traverse@7.28.5: + '@babel/traverse@7.28.5': resolution: {integrity: sha512-TCCj4t55U90khlYkVV/0TfkJkAkUg3jZFA3Neb7unZT8CPok7iiRfaX0F+WnqWqt7OxhOn0uBKXCw4lbL8W0aQ==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/code-frame': 7.27.1 - '@babel/generator': 7.28.5 - '@babel/helper-globals': 7.28.0 - '@babel/parser': 7.28.5 - '@babel/template': 7.27.2 - '@babel/types': 7.28.5 - debug: 4.4.3(supports-color@10.2.2) - transitivePeerDependencies: - - supports-color - dev: true - /@babel/types@7.28.5: + '@babel/types@7.28.5': resolution: {integrity: sha512-qQ5m48eI/MFLQ5PxQj4PFaprjyCTLI37ElWMmNs0K8Lk3dVeOdNpB3ks8jc7yM5CDmVC73eMVk/trk3fgmrUpA==} engines: {node: '>=6.9.0'} - dependencies: - '@babel/helper-string-parser': 7.27.1 - '@babel/helper-validator-identifier': 7.28.5 - dev: true - /@esbuild/aix-ppc64@0.25.12: + '@bcoe/v8-coverage@1.0.2': + resolution: {integrity: sha512-6zABk/ECA/QYSCQ1NGiVwwbQerUCZ+TQbp64Q3AgmfNvurHH0j8TtXa1qbShXA6qqkpAj4V5W8pP6mLe1mcMqA==} + engines: {node: '>=18'} + + '@esbuild/aix-ppc64@0.25.12': resolution: {integrity: sha512-Hhmwd6CInZ3dwpuGTF8fJG6yoWmsToE+vYgD4nytZVxcu1ulHpUQRAB1UJ8+N1Am3Mz4+xOByoQoSZf4D+CpkA==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - requiresBuild: true - optional: true - /@esbuild/android-arm64@0.25.12: + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - requiresBuild: true - optional: true - /@esbuild/android-arm@0.25.12: + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] - requiresBuild: true - optional: true - /@esbuild/android-x64@0.25.12: + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] - requiresBuild: true - optional: true - /@esbuild/darwin-arm64@0.25.12: + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - requiresBuild: true - optional: true - /@esbuild/darwin-x64@0.25.12: + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - requiresBuild: true - optional: true - /@esbuild/freebsd-arm64@0.25.12: + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - requiresBuild: true - optional: true - /@esbuild/freebsd-x64@0.25.12: + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - requiresBuild: true - optional: true - /@esbuild/linux-arm64@0.25.12: + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - requiresBuild: true - optional: true - /@esbuild/linux-arm@0.25.12: + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] - requiresBuild: true - optional: true - /@esbuild/linux-ia32@0.25.12: + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - requiresBuild: true - optional: true - /@esbuild/linux-loong64@0.25.12: + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - requiresBuild: true - optional: true - /@esbuild/linux-mips64el@0.25.12: + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - requiresBuild: true - optional: true - /@esbuild/linux-ppc64@0.25.12: + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - requiresBuild: true - optional: true - /@esbuild/linux-riscv64@0.25.12: + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - requiresBuild: true - optional: true - /@esbuild/linux-s390x@0.25.12: + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - requiresBuild: true - optional: true - /@esbuild/linux-x64@0.25.12: + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] - requiresBuild: true - optional: true - /@esbuild/netbsd-arm64@0.25.12: + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - requiresBuild: true - optional: true - /@esbuild/netbsd-x64@0.25.12: + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - requiresBuild: true - optional: true - /@esbuild/openbsd-arm64@0.25.12: + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - requiresBuild: true - optional: true - /@esbuild/openbsd-x64@0.25.12: + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - requiresBuild: true - optional: true - /@esbuild/openharmony-arm64@0.25.12: + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - requiresBuild: true - optional: true - /@esbuild/sunos-x64@0.25.12: + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - requiresBuild: true - optional: true - /@esbuild/win32-arm64@0.25.12: + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - requiresBuild: true - optional: true - /@esbuild/win32-ia32@0.25.12: + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - requiresBuild: true - optional: true - /@esbuild/win32-x64@0.25.12: + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] - requiresBuild: true - optional: true - /@eslint-community/eslint-utils@4.9.0(eslint@9.39.1): + '@eslint-community/eslint-utils@4.9.0': resolution: {integrity: sha512-ayVFHdtZ+hsq1t2Dy24wCmGXGe4q9Gu3smhLYALJrr473ZH27MsnSL+LKUlimp4BWJqMDMLmPpx/Q9R3OAlL4g==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} peerDependencies: eslint: ^6.0.0 || ^7.0.0 || >=8.0.0 - dependencies: - eslint: 9.39.1 - eslint-visitor-keys: 3.4.3 - dev: true - /@eslint-community/regexpp@4.12.2: + '@eslint-community/regexpp@4.12.2': resolution: {integrity: sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew==} engines: {node: ^12.0.0 || ^14.0.0 || >=16.0.0} - dev: true - /@eslint/config-array@0.21.1: + '@eslint/config-array@0.21.1': resolution: {integrity: sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@eslint/object-schema': 2.1.7 - debug: 4.4.3(supports-color@10.2.2) - minimatch: 3.1.2 - transitivePeerDependencies: - - supports-color - dev: true - /@eslint/config-helpers@0.4.2: + '@eslint/config-helpers@0.4.2': resolution: {integrity: sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@eslint/core': 0.17.0 - dev: true - /@eslint/core@0.17.0: + '@eslint/core@0.17.0': resolution: {integrity: sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@types/json-schema': 7.0.15 - dev: true - /@eslint/eslintrc@3.3.1: + '@eslint/eslintrc@3.3.1': resolution: {integrity: sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - ajv: 6.12.6 - debug: 4.4.3(supports-color@10.2.2) - espree: 10.4.0 - globals: 14.0.0 - ignore: 5.3.2 - import-fresh: 3.3.1 - js-yaml: 4.1.1 - minimatch: 3.1.2 - strip-json-comments: 3.1.1 - transitivePeerDependencies: - - supports-color - dev: true - /@eslint/js@9.39.1: + '@eslint/js@9.39.1': resolution: {integrity: sha512-S26Stp4zCy88tH94QbBv3XCuzRQiZ9yXofEILmglYTh/Ug/a9/umqvgFtYBAo3Lp0nsI/5/qH1CCrbdK3AP1Tw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true - /@eslint/object-schema@2.1.7: + '@eslint/object-schema@2.1.7': resolution: {integrity: sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true - /@eslint/plugin-kit@0.4.1: + '@eslint/plugin-kit@0.4.1': resolution: {integrity: sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@eslint/core': 0.17.0 - levn: 0.4.1 - dev: true - /@floating-ui/core@1.7.3: + '@floating-ui/core@1.7.3': resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} - dependencies: - '@floating-ui/utils': 0.2.10 - dev: false - /@floating-ui/dom@1.7.4: + '@floating-ui/dom@1.7.4': resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} - dependencies: - '@floating-ui/core': 1.7.3 - '@floating-ui/utils': 0.2.10 - dev: false - /@floating-ui/react-dom@2.1.6(react-dom@19.2.0)(react@19.2.0): + '@floating-ui/react-dom@2.1.6': resolution: {integrity: sha512-4JX6rEatQEvlmgU80wZyq9RT96HZJa88q8hp0pBd+LrczeDI4o6uA2M+uvxngVHo4Ihr8uibXxH6+70zhAFrVw==} peerDependencies: react: '>=16.8.0' react-dom: '>=16.8.0' - dependencies: - '@floating-ui/dom': 1.7.4 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@floating-ui/utils@0.2.10: + '@floating-ui/utils@0.2.10': resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} - dev: false - /@hono/node-server@1.19.6(hono@4.10.6): + '@hono/node-server@1.19.6': resolution: {integrity: sha512-Shz/KjlIeAhfiuE93NDKVdZ7HdBVLQAfdbaXEaoAVO3ic9ibRSLGIQGkcBbFyuLr+7/1D5ZCINM8B+6IvXeMtw==} engines: {node: '>=18.14.1'} peerDependencies: hono: ^4 - dependencies: - hono: 4.10.6 - dev: false - /@hookform/resolvers@5.2.2(react-hook-form@7.66.1): + '@hookform/resolvers@5.2.2': resolution: {integrity: sha512-A/IxlMLShx3KjV/HeTcTfaMxdwy690+L/ZADoeaTltLx+CVuzkeVIPuybK3jrRfw7YZnmdKsVVHAlEPIAEUNlA==} peerDependencies: react-hook-form: ^7.55.0 - dependencies: - '@standard-schema/utils': 0.3.0 - react-hook-form: 7.66.1(react@19.2.0) - dev: false - /@humanfs/core@0.19.1: + '@humanfs/core@0.19.1': resolution: {integrity: sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==} engines: {node: '>=18.18.0'} - dev: true - /@humanfs/node@0.16.7: + '@humanfs/node@0.16.7': resolution: {integrity: sha512-/zUx+yOsIrG4Y43Eh2peDeKCxlRt/gET6aHfaKpuq267qXdYDFViVHfMaLyygZOnl0kGWxFIgsBy8QFuTLUXEQ==} engines: {node: '>=18.18.0'} - dependencies: - '@humanfs/core': 0.19.1 - '@humanwhocodes/retry': 0.4.3 - dev: true - /@humanwhocodes/module-importer@1.0.1: + '@humanwhocodes/module-importer@1.0.1': resolution: {integrity: sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==} engines: {node: '>=12.22'} - dev: true - /@humanwhocodes/retry@0.4.3: + '@humanwhocodes/retry@0.4.3': resolution: {integrity: sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ==} engines: {node: '>=18.18'} - dev: true - /@jridgewell/gen-mapping@0.3.13: + '@isaacs/cliui@8.0.2': + resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} + engines: {node: '>=12'} + + '@istanbuljs/schema@0.1.3': + resolution: {integrity: sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==} + engines: {node: '>=8'} + + '@jridgewell/gen-mapping@0.3.13': resolution: {integrity: sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - '@jridgewell/trace-mapping': 0.3.31 - /@jridgewell/remapping@2.3.5: + '@jridgewell/remapping@2.3.5': resolution: {integrity: sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==} - dependencies: - '@jridgewell/gen-mapping': 0.3.13 - '@jridgewell/trace-mapping': 0.3.31 - /@jridgewell/resolve-uri@3.1.2: + '@jridgewell/resolve-uri@3.1.2': resolution: {integrity: sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==} engines: {node: '>=6.0.0'} - /@jridgewell/sourcemap-codec@1.5.5: + '@jridgewell/sourcemap-codec@1.5.5': resolution: {integrity: sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==} - /@jridgewell/trace-mapping@0.3.31: + '@jridgewell/trace-mapping@0.3.31': resolution: {integrity: sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==} - dependencies: - '@jridgewell/resolve-uri': 3.1.2 - '@jridgewell/sourcemap-codec': 1.5.5 - /@monaco-editor/loader@1.7.0: + '@monaco-editor/loader@1.7.0': resolution: {integrity: sha512-gIwR1HrJrrx+vfyOhYmCZ0/JcWqG5kbfG7+d3f/C1LXk2EvzAbHSg3MQ5lO2sMlo9izoAZ04shohfKLVT6crVA==} - dependencies: - state-local: 1.0.7 - dev: false - /@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.0)(react@19.2.0): + '@monaco-editor/react@4.7.0': resolution: {integrity: sha512-cyzXQCtO47ydzxpQtCGSQGOC8Gk3ZUeBXFAxD+CWXYFo5OqZyZUonFl0DwUlTyAfRHntBfw2p3w4s9R6oe1eCA==} peerDependencies: monaco-editor: '>= 0.25.0 < 1' react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 react-dom: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - dependencies: - '@monaco-editor/loader': 1.7.0 - monaco-editor: 0.55.1 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@polka/url@1.0.0-next.29: + '@pkgjs/parseargs@0.11.0': + resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} + engines: {node: '>=14'} + + '@polka/url@1.0.0-next.29': resolution: {integrity: sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==} - dev: true - /@radix-ui/number@1.1.1: + '@radix-ui/number@1.1.1': resolution: {integrity: sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==} - dev: false - /@radix-ui/primitive@1.1.3: + '@radix-ui/primitive@1.1.3': resolution: {integrity: sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==} - dev: false - /@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-arrow@1.1.7': resolution: {integrity: sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==} peerDependencies: '@types/react': '*' @@ -816,15 +609,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-checkbox@1.3.3': resolution: {integrity: sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==} peerDependencies: '@types/react': '*' @@ -836,22 +622,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-collection@1.1.7': resolution: {integrity: sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==} peerDependencies: '@types/react': '*' @@ -863,18 +635,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-compose-refs@1.1.2': resolution: {integrity: sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==} peerDependencies: '@types/react': '*' @@ -882,12 +644,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-context@1.1.2(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-context@1.1.2': resolution: {integrity: sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==} peerDependencies: '@types/react': '*' @@ -895,12 +653,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-dialog@1.1.15': resolution: {integrity: sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==} peerDependencies: '@types/react': '*' @@ -912,28 +666,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - aria-hidden: 1.2.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.2.0) - dev: false - /@radix-ui/react-direction@1.1.1(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-direction@1.1.1': resolution: {integrity: sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==} peerDependencies: '@types/react': '*' @@ -941,12 +675,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-dismissable-layer@1.1.11': resolution: {integrity: sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==} peerDependencies: '@types/react': '*' @@ -958,19 +688,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-dropdown-menu@2.1.16': resolution: {integrity: sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==} peerDependencies: '@types/react': '*' @@ -982,21 +701,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-focus-guards@1.1.3': resolution: {integrity: sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==} peerDependencies: '@types/react': '*' @@ -1004,12 +710,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-focus-scope@1.1.7': resolution: {integrity: sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==} peerDependencies: '@types/react': '*' @@ -1021,17 +723,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-id@1.1.1(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-id@1.1.1': resolution: {integrity: sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==} peerDependencies: '@types/react': '*' @@ -1039,13 +732,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-label@2.1.8': resolution: {integrity: sha512-FmXs37I6hSBVDlO4y764TNz1rLgKwjJMQ0EGte6F3Cb3f4bIuHB/iLa/8I9VKkmOy+gNHq8rql3j686ACVV21A==} peerDependencies: '@types/react': '*' @@ -1057,15 +745,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-menu@2.1.16': resolution: {integrity: sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==} peerDependencies: '@types/react': '*' @@ -1077,32 +758,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - aria-hidden: 1.2.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.2.0) - dev: false - /@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-popper@1.2.8': resolution: {integrity: sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==} peerDependencies: '@types/react': '*' @@ -1114,24 +771,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/rect': 1.1.1 - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-portal@1.1.9': resolution: {integrity: sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==} peerDependencies: '@types/react': '*' @@ -1143,16 +784,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-presence@1.1.5': resolution: {integrity: sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==} peerDependencies: '@types/react': '*' @@ -1164,16 +797,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-primitive@2.1.3': resolution: {integrity: sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==} peerDependencies: '@types/react': '*' @@ -1185,15 +810,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-primitive@2.1.4': resolution: {integrity: sha512-9hQc4+GNVtJAIEPEqlYqW5RiYdrr8ea5XQ0ZOnD6fgru+83kqT15mq2OCcbe8KnjRZl5vF3ks69AKz3kh1jrhg==} peerDependencies: '@types/react': '*' @@ -1205,15 +823,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/react-slot': 1.2.4(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-roving-focus@1.1.11': resolution: {integrity: sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==} peerDependencies: '@types/react': '*' @@ -1225,23 +836,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-select@2.2.6': resolution: {integrity: sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==} peerDependencies: '@types/react': '*' @@ -1253,35 +849,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - aria-hidden: 1.2.6 - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.2.0) - dev: false - /@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-slider@1.3.6': resolution: {integrity: sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==} peerDependencies: '@types/react': '*' @@ -1293,25 +862,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/number': 1.1.1 - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-slot@1.2.3(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-slot@1.2.3': resolution: {integrity: sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==} peerDependencies: '@types/react': '*' @@ -1319,13 +871,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-slot@1.2.4(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-slot@1.2.4': resolution: {integrity: sha512-Jl+bCv8HxKnlTLVrcDE8zTMJ09R9/ukw4qBs/oZClOfoQk/cOTbDn+NceXfV7j09YPVQUryJPHurafcSg6EVKA==} peerDependencies: '@types/react': '*' @@ -1333,13 +880,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-switch@1.2.6': resolution: {integrity: sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==} peerDependencies: '@types/react': '*' @@ -1351,21 +893,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-tabs@1.1.13': resolution: {integrity: sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==} peerDependencies: '@types/react': '*' @@ -1377,22 +906,8 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/primitive': 1.1.3 - '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-use-callback-ref@1.1.1': resolution: {integrity: sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==} peerDependencies: '@types/react': '*' @@ -1400,12 +915,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-use-controllable-state@1.2.2': resolution: {integrity: sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==} peerDependencies: '@types/react': '*' @@ -1413,14 +924,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-use-effect-event@0.0.2': resolution: {integrity: sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==} peerDependencies: '@types/react': '*' @@ -1428,13 +933,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-use-escape-keydown@1.1.1': resolution: {integrity: sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==} peerDependencies: '@types/react': '*' @@ -1442,13 +942,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-use-layout-effect@1.1.1': resolution: {integrity: sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==} peerDependencies: '@types/react': '*' @@ -1456,12 +951,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-use-previous@1.1.1(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-use-previous@1.1.1': resolution: {integrity: sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==} peerDependencies: '@types/react': '*' @@ -1469,12 +960,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-use-rect@1.1.1(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-use-rect@1.1.1': resolution: {integrity: sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==} peerDependencies: '@types/react': '*' @@ -1482,13 +969,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@radix-ui/rect': 1.1.1 - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-use-size@1.1.1(@types/react@19.2.7)(react@19.2.0): + '@radix-ui/react-use-size@1.1.1': resolution: {integrity: sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==} peerDependencies: '@types/react': '*' @@ -1496,13 +978,8 @@ packages: peerDependenciesMeta: '@types/react': optional: true - dependencies: - '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@types/react': 19.2.7 - react: 19.2.0 - dev: false - /@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + '@radix-ui/react-visually-hidden@1.2.3': resolution: {integrity: sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==} peerDependencies: '@types/react': '*' @@ -1514,310 +991,197 @@ packages: optional: true '@types/react-dom': optional: true - dependencies: - '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@types/react': 19.2.7 - '@types/react-dom': 19.2.3(@types/react@19.2.7) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - dev: false - /@radix-ui/rect@1.1.1: + '@radix-ui/rect@1.1.1': resolution: {integrity: sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==} - dev: false - /@redocly/ajv@8.17.1: + '@redocly/ajv@8.17.1': resolution: {integrity: sha512-EDtsGZS964mf9zAUXAl9Ew16eYbeyAFWhsPr0fX6oaJxgd8rApYlPBf0joyhnUHz88WxrigyFtTaqqzXNzPgqw==} - dependencies: - fast-deep-equal: 3.1.3 - fast-uri: 3.1.0 - json-schema-traverse: 1.0.0 - require-from-string: 2.0.2 - dev: true - /@redocly/config@0.22.2: + '@redocly/config@0.22.2': resolution: {integrity: sha512-roRDai8/zr2S9YfmzUfNhKjOF0NdcOIqF7bhf4MVC5UxpjIysDjyudvlAiVbpPHp3eDRWbdzUgtkK1a7YiDNyQ==} - dev: true - /@redocly/openapi-core@1.34.5(supports-color@10.2.2): + '@redocly/openapi-core@1.34.5': resolution: {integrity: sha512-0EbE8LRbkogtcCXU7liAyC00n9uNG9hJ+eMyHFdUsy9lB/WGqnEBgwjA9q2cyzAVcdTkQqTBBU1XePNnN3OijA==} engines: {node: '>=18.17.0', npm: '>=9.5.0'} - dependencies: - '@redocly/ajv': 8.17.1 - '@redocly/config': 0.22.2 - colorette: 1.4.0 - https-proxy-agent: 7.0.6(supports-color@10.2.2) - js-levenshtein: 1.1.6 - js-yaml: 4.1.1 - minimatch: 5.1.6 - pluralize: 8.0.0 - yaml-ast-parser: 0.0.43 - transitivePeerDependencies: - - supports-color - dev: true - /@rolldown/pluginutils@1.0.0-beta.47: + '@rolldown/pluginutils@1.0.0-beta.47': resolution: {integrity: sha512-8QagwMH3kNCuzD8EWL8R2YPW5e4OrHNSAHRFDdmFqEwEaD/KcNKjVoumo+gP2vW5eKB2UPbM6vTYiGZX0ixLnw==} - dev: true - /@rollup/rollup-android-arm-eabi@4.53.3: + '@rollup/rollup-android-arm-eabi@4.53.3': resolution: {integrity: sha512-mRSi+4cBjrRLoaal2PnqH82Wqyb+d3HsPUN/W+WslCXsZsyHa9ZeQQX/pQsZaVIWDkPcpV6jJ+3KLbTbgnwv8w==} cpu: [arm] os: [android] - requiresBuild: true - optional: true - /@rollup/rollup-android-arm64@4.53.3: + '@rollup/rollup-android-arm64@4.53.3': resolution: {integrity: sha512-CbDGaMpdE9sh7sCmTrTUyllhrg65t6SwhjlMJsLr+J8YjFuPmCEjbBSx4Z/e4SmDyH3aB5hGaJUP2ltV/vcs4w==} cpu: [arm64] os: [android] - requiresBuild: true - optional: true - /@rollup/rollup-darwin-arm64@4.53.3: + '@rollup/rollup-darwin-arm64@4.53.3': resolution: {integrity: sha512-Nr7SlQeqIBpOV6BHHGZgYBuSdanCXuw09hon14MGOLGmXAFYjx1wNvquVPmpZnl0tLjg25dEdr4IQ6GgyToCUA==} cpu: [arm64] os: [darwin] - requiresBuild: true - optional: true - /@rollup/rollup-darwin-x64@4.53.3: + '@rollup/rollup-darwin-x64@4.53.3': resolution: {integrity: sha512-DZ8N4CSNfl965CmPktJ8oBnfYr3F8dTTNBQkRlffnUarJ2ohudQD17sZBa097J8xhQ26AwhHJ5mvUyQW8ddTsQ==} cpu: [x64] os: [darwin] - requiresBuild: true - optional: true - /@rollup/rollup-freebsd-arm64@4.53.3: + '@rollup/rollup-freebsd-arm64@4.53.3': resolution: {integrity: sha512-yMTrCrK92aGyi7GuDNtGn2sNW+Gdb4vErx4t3Gv/Tr+1zRb8ax4z8GWVRfr3Jw8zJWvpGHNpss3vVlbF58DZ4w==} cpu: [arm64] os: [freebsd] - requiresBuild: true - optional: true - /@rollup/rollup-freebsd-x64@4.53.3: + '@rollup/rollup-freebsd-x64@4.53.3': resolution: {integrity: sha512-lMfF8X7QhdQzseM6XaX0vbno2m3hlyZFhwcndRMw8fbAGUGL3WFMBdK0hbUBIUYcEcMhVLr1SIamDeuLBnXS+Q==} cpu: [x64] os: [freebsd] - requiresBuild: true - optional: true - /@rollup/rollup-linux-arm-gnueabihf@4.53.3: + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': resolution: {integrity: sha512-k9oD15soC/Ln6d2Wv/JOFPzZXIAIFLp6B+i14KhxAfnq76ajt0EhYc5YPeX6W1xJkAdItcVT+JhKl1QZh44/qw==} cpu: [arm] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-linux-arm-musleabihf@4.53.3: + '@rollup/rollup-linux-arm-musleabihf@4.53.3': resolution: {integrity: sha512-vTNlKq+N6CK/8UktsrFuc+/7NlEYVxgaEgRXVUVK258Z5ymho29skzW1sutgYjqNnquGwVUObAaxae8rZ6YMhg==} cpu: [arm] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-linux-arm64-gnu@4.53.3: + '@rollup/rollup-linux-arm64-gnu@4.53.3': resolution: {integrity: sha512-RGrFLWgMhSxRs/EWJMIFM1O5Mzuz3Xy3/mnxJp/5cVhZ2XoCAxJnmNsEyeMJtpK+wu0FJFWz+QF4mjCA7AUQ3w==} cpu: [arm64] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-linux-arm64-musl@4.53.3: + '@rollup/rollup-linux-arm64-musl@4.53.3': resolution: {integrity: sha512-kASyvfBEWYPEwe0Qv4nfu6pNkITLTb32p4yTgzFCocHnJLAHs+9LjUu9ONIhvfT/5lv4YS5muBHyuV84epBo/A==} cpu: [arm64] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-linux-loong64-gnu@4.53.3: + '@rollup/rollup-linux-loong64-gnu@4.53.3': resolution: {integrity: sha512-JiuKcp2teLJwQ7vkJ95EwESWkNRFJD7TQgYmCnrPtlu50b4XvT5MOmurWNrCj3IFdyjBQ5p9vnrX4JM6I8OE7g==} cpu: [loong64] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-linux-ppc64-gnu@4.53.3: + '@rollup/rollup-linux-ppc64-gnu@4.53.3': resolution: {integrity: sha512-EoGSa8nd6d3T7zLuqdojxC20oBfNT8nexBbB/rkxgKj5T5vhpAQKKnD+h3UkoMuTyXkP5jTjK/ccNRmQrPNDuw==} cpu: [ppc64] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-linux-riscv64-gnu@4.53.3: + '@rollup/rollup-linux-riscv64-gnu@4.53.3': resolution: {integrity: sha512-4s+Wped2IHXHPnAEbIB0YWBv7SDohqxobiiPA1FIWZpX+w9o2i4LezzH/NkFUl8LRci/8udci6cLq+jJQlh+0g==} cpu: [riscv64] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-linux-riscv64-musl@4.53.3: + '@rollup/rollup-linux-riscv64-musl@4.53.3': resolution: {integrity: sha512-68k2g7+0vs2u9CxDt5ktXTngsxOQkSEV/xBbwlqYcUrAVh6P9EgMZvFsnHy4SEiUl46Xf0IObWVbMvPrr2gw8A==} cpu: [riscv64] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-linux-s390x-gnu@4.53.3: + '@rollup/rollup-linux-s390x-gnu@4.53.3': resolution: {integrity: sha512-VYsFMpULAz87ZW6BVYw3I6sWesGpsP9OPcyKe8ofdg9LHxSbRMd7zrVrr5xi/3kMZtpWL/wC+UIJWJYVX5uTKg==} cpu: [s390x] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-linux-x64-gnu@4.53.3: + '@rollup/rollup-linux-x64-gnu@4.53.3': resolution: {integrity: sha512-3EhFi1FU6YL8HTUJZ51imGJWEX//ajQPfqWLI3BQq4TlvHy4X0MOr5q3D2Zof/ka0d5FNdPwZXm3Yyib/UEd+w==} cpu: [x64] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-linux-x64-musl@4.53.3: + '@rollup/rollup-linux-x64-musl@4.53.3': resolution: {integrity: sha512-eoROhjcc6HbZCJr+tvVT8X4fW3/5g/WkGvvmwz/88sDtSJzO7r/blvoBDgISDiCjDRZmHpwud7h+6Q9JxFwq1Q==} cpu: [x64] os: [linux] - requiresBuild: true - optional: true - /@rollup/rollup-openharmony-arm64@4.53.3: + '@rollup/rollup-openharmony-arm64@4.53.3': resolution: {integrity: sha512-OueLAWgrNSPGAdUdIjSWXw+u/02BRTcnfw9PN41D2vq/JSEPnJnVuBgw18VkN8wcd4fjUs+jFHVM4t9+kBSNLw==} cpu: [arm64] os: [openharmony] - requiresBuild: true - optional: true - /@rollup/rollup-win32-arm64-msvc@4.53.3: + '@rollup/rollup-win32-arm64-msvc@4.53.3': resolution: {integrity: sha512-GOFuKpsxR/whszbF/bzydebLiXIHSgsEUp6M0JI8dWvi+fFa1TD6YQa4aSZHtpmh2/uAlj/Dy+nmby3TJ3pkTw==} cpu: [arm64] os: [win32] - requiresBuild: true - optional: true - /@rollup/rollup-win32-ia32-msvc@4.53.3: + '@rollup/rollup-win32-ia32-msvc@4.53.3': resolution: {integrity: sha512-iah+THLcBJdpfZ1TstDFbKNznlzoxa8fmnFYK4V67HvmuNYkVdAywJSoteUszvBQ9/HqN2+9AZghbajMsFT+oA==} cpu: [ia32] os: [win32] - requiresBuild: true - optional: true - /@rollup/rollup-win32-x64-gnu@4.53.3: + '@rollup/rollup-win32-x64-gnu@4.53.3': resolution: {integrity: sha512-J9QDiOIZlZLdcot5NXEepDkstocktoVjkaKUtqzgzpt2yWjGlbYiKyp05rWwk4nypbYUNoFAztEgixoLaSETkg==} cpu: [x64] os: [win32] - requiresBuild: true - optional: true - /@rollup/rollup-win32-x64-msvc@4.53.3: + '@rollup/rollup-win32-x64-msvc@4.53.3': resolution: {integrity: sha512-UhTd8u31dXadv0MopwGgNOBpUVROFKWVQgAg5N1ESyCz8AuBcMqm4AuTjrwgQKGDfoFuz02EuMRHQIw/frmYKQ==} cpu: [x64] os: [win32] - requiresBuild: true - optional: true - /@standard-schema/utils@0.3.0: + '@standard-schema/utils@0.3.0': resolution: {integrity: sha512-e7Mew686owMaPJVNNLs55PUvgz371nKgwsc4vxE49zsODpJEnxgxRo2y/OKrqueavXgZNMDVj3DdHFlaSAeU8g==} - dev: false - /@tailwindcss/node@4.1.17: + '@tailwindcss/node@4.1.17': resolution: {integrity: sha512-csIkHIgLb3JisEFQ0vxr2Y57GUNYh447C8xzwj89U/8fdW8LhProdxvnVH6U8M2Y73QKiTIH+LWbK3V2BBZsAg==} - dependencies: - '@jridgewell/remapping': 2.3.5 - enhanced-resolve: 5.18.3 - jiti: 2.6.1 - lightningcss: 1.30.2 - magic-string: 0.30.21 - source-map-js: 1.2.1 - tailwindcss: 4.1.17 - dev: false - /@tailwindcss/oxide-android-arm64@4.1.17: + '@tailwindcss/oxide-android-arm64@4.1.17': resolution: {integrity: sha512-BMqpkJHgOZ5z78qqiGE6ZIRExyaHyuxjgrJ6eBO5+hfrfGkuya0lYfw8fRHG77gdTjWkNWEEm+qeG2cDMxArLQ==} engines: {node: '>= 10'} cpu: [arm64] os: [android] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide-darwin-arm64@4.1.17: + '@tailwindcss/oxide-darwin-arm64@4.1.17': resolution: {integrity: sha512-EquyumkQweUBNk1zGEU/wfZo2qkp/nQKRZM8bUYO0J+Lums5+wl2CcG1f9BgAjn/u9pJzdYddHWBiFXJTcxmOg==} engines: {node: '>= 10'} cpu: [arm64] os: [darwin] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide-darwin-x64@4.1.17: + '@tailwindcss/oxide-darwin-x64@4.1.17': resolution: {integrity: sha512-gdhEPLzke2Pog8s12oADwYu0IAw04Y2tlmgVzIN0+046ytcgx8uZmCzEg4VcQh+AHKiS7xaL8kGo/QTiNEGRog==} engines: {node: '>= 10'} cpu: [x64] os: [darwin] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide-freebsd-x64@4.1.17: + '@tailwindcss/oxide-freebsd-x64@4.1.17': resolution: {integrity: sha512-hxGS81KskMxML9DXsaXT1H0DyA+ZBIbyG/sSAjWNe2EDl7TkPOBI42GBV3u38itzGUOmFfCzk1iAjDXds8Oh0g==} engines: {node: '>= 10'} cpu: [x64] os: [freebsd] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17: + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': resolution: {integrity: sha512-k7jWk5E3ldAdw0cNglhjSgv501u7yrMf8oeZ0cElhxU6Y2o7f8yqelOp3fhf7evjIS6ujTI3U8pKUXV2I4iXHQ==} engines: {node: '>= 10'} cpu: [arm] os: [linux] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide-linux-arm64-gnu@4.1.17: + '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': resolution: {integrity: sha512-HVDOm/mxK6+TbARwdW17WrgDYEGzmoYayrCgmLEw7FxTPLcp/glBisuyWkFz/jb7ZfiAXAXUACfyItn+nTgsdQ==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide-linux-arm64-musl@4.1.17: + '@tailwindcss/oxide-linux-arm64-musl@4.1.17': resolution: {integrity: sha512-HvZLfGr42i5anKtIeQzxdkw/wPqIbpeZqe7vd3V9vI3RQxe3xU1fLjss0TjyhxWcBaipk7NYwSrwTwK1hJARMg==} engines: {node: '>= 10'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide-linux-x64-gnu@4.1.17: + '@tailwindcss/oxide-linux-x64-gnu@4.1.17': resolution: {integrity: sha512-M3XZuORCGB7VPOEDH+nzpJ21XPvK5PyjlkSFkFziNHGLc5d6g3di2McAAblmaSUNl8IOmzYwLx9NsE7bplNkwQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide-linux-x64-musl@4.1.17: + '@tailwindcss/oxide-linux-x64-musl@4.1.17': resolution: {integrity: sha512-k7f+pf9eXLEey4pBlw+8dgfJHY4PZ5qOUFDyNf7SI6lHjQ9Zt7+NcscjpwdCEbYi6FI5c2KDTDWyf2iHcCSyyQ==} engines: {node: '>= 10'} cpu: [x64] os: [linux] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide-wasm32-wasi@4.1.17: + '@tailwindcss/oxide-wasm32-wasi@4.1.17': resolution: {integrity: sha512-cEytGqSSoy7zK4JRWiTCx43FsKP/zGr0CsuMawhH67ONlH+T79VteQeJQRO/X7L0juEUA8ZyuYikcRBf0vsxhg==} engines: {node: '>=14.0.0'} cpu: [wasm32] - requiresBuild: true - dev: false - optional: true bundledDependencies: - '@napi-rs/wasm-runtime' - '@emnapi/core' @@ -1826,357 +1190,181 @@ packages: - '@emnapi/wasi-threads' - tslib - /@tailwindcss/oxide-win32-arm64-msvc@4.1.17: + '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': resolution: {integrity: sha512-JU5AHr7gKbZlOGvMdb4722/0aYbU+tN6lv1kONx0JK2cGsh7g148zVWLM0IKR3NeKLv+L90chBVYcJ8uJWbC9A==} engines: {node: '>= 10'} cpu: [arm64] os: [win32] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide-win32-x64-msvc@4.1.17: + '@tailwindcss/oxide-win32-x64-msvc@4.1.17': resolution: {integrity: sha512-SKWM4waLuqx0IH+FMDUw6R66Hu4OuTALFgnleKbqhgGU30DY20NORZMZUKgLRjQXNN2TLzKvh48QXTig4h4bGw==} engines: {node: '>= 10'} cpu: [x64] os: [win32] - requiresBuild: true - dev: false - optional: true - /@tailwindcss/oxide@4.1.17: + '@tailwindcss/oxide@4.1.17': resolution: {integrity: sha512-F0F7d01fmkQhsTjXezGBLdrl1KresJTcI3DB8EkScCldyKp3Msz4hub4uyYaVnk88BAS1g5DQjjF6F5qczheLA==} engines: {node: '>= 10'} - optionalDependencies: - '@tailwindcss/oxide-android-arm64': 4.1.17 - '@tailwindcss/oxide-darwin-arm64': 4.1.17 - '@tailwindcss/oxide-darwin-x64': 4.1.17 - '@tailwindcss/oxide-freebsd-x64': 4.1.17 - '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17 - '@tailwindcss/oxide-linux-arm64-gnu': 4.1.17 - '@tailwindcss/oxide-linux-arm64-musl': 4.1.17 - '@tailwindcss/oxide-linux-x64-gnu': 4.1.17 - '@tailwindcss/oxide-linux-x64-musl': 4.1.17 - '@tailwindcss/oxide-wasm32-wasi': 4.1.17 - '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 - '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 - dev: false - /@tailwindcss/vite@4.1.17(vite@7.2.4): + '@tailwindcss/vite@4.1.17': resolution: {integrity: sha512-4+9w8ZHOiGnpcGI6z1TVVfWaX/koK7fKeSYF3qlYg2xpBtbteP2ddBxiarL+HVgfSJGeK5RIxRQmKm4rTJJAwA==} peerDependencies: vite: ^5.2.0 || ^6 || ^7 - dependencies: - '@tailwindcss/node': 4.1.17 - '@tailwindcss/oxide': 4.1.17 - tailwindcss: 4.1.17 - vite: 7.2.4(@types/node@24.10.1) - dev: false - /@tanstack/query-core@5.90.11: + '@tanstack/query-core@5.90.11': resolution: {integrity: sha512-f9z/nXhCgWDF4lHqgIE30jxLe4sYv15QodfdPDKYAk7nAEjNcndy4dHz3ezhdUaR23BpWa4I2EH4/DZ0//Uf8A==} - dev: false - /@tanstack/react-query@5.90.11(react@19.2.0): + '@tanstack/react-query@5.90.11': resolution: {integrity: sha512-3uyzz01D1fkTLXuxF3JfoJoHQMU2fxsfJwE+6N5hHy0dVNoZOvwKP8Z2k7k1KDeD54N20apcJnG75TBAStIrBA==} peerDependencies: react: ^18 || ^19 - dependencies: - '@tanstack/query-core': 5.90.11 - react: 19.2.0 - dev: false - /@types/babel__core@7.20.5: + '@types/babel__core@7.20.5': resolution: {integrity: sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==} - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - '@types/babel__generator': 7.27.0 - '@types/babel__template': 7.4.4 - '@types/babel__traverse': 7.28.0 - dev: true - /@types/babel__generator@7.27.0: + '@types/babel__generator@7.27.0': resolution: {integrity: sha512-ufFd2Xi92OAVPYsy+P4n7/U7e68fex0+Ee8gSG9KX7eo084CWiQ4sdxktvdl0bOPupXtVJPY19zk6EwWqUQ8lg==} - dependencies: - '@babel/types': 7.28.5 - dev: true - /@types/babel__template@7.4.4: + '@types/babel__template@7.4.4': resolution: {integrity: sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==} - dependencies: - '@babel/parser': 7.28.5 - '@babel/types': 7.28.5 - dev: true - /@types/babel__traverse@7.28.0: + '@types/babel__traverse@7.28.0': resolution: {integrity: sha512-8PvcXf70gTDZBgt9ptxJ8elBeBjcLOAcOtoO/mPJjtji1+CdGbHgm77om1GrsPxsiE+uXIpNSK64UYaIwQXd4Q==} - dependencies: - '@babel/types': 7.28.5 - dev: true - /@types/better-sqlite3@7.6.13: + '@types/better-sqlite3@7.6.13': resolution: {integrity: sha512-NMv9ASNARoKksWtsq/SHakpYAYnhBrQgGD8zkLYk/jaK8jUGn08CfEdTRgYhMypUQAfzSP8W6gNLe0q19/t4VA==} - dependencies: - '@types/node': 24.10.1 - dev: true - /@types/bun@1.3.3: - resolution: {integrity: sha512-ogrKbJ2X5N0kWLLFKeytG0eHDleBYtngtlbu9cyBKFtNL3cnpDZkNdQj8flVf6WTZUX5ulI9AY1oa7ljhSrp+g==} - dependencies: - bun-types: 1.3.3 - dev: true + '@types/bun@1.3.11': + resolution: {integrity: sha512-5vPne5QvtpjGpsGYXiFyycfpDF2ECyPcTSsFBMa0fraoxiQyMJ3SmuQIGhzPg2WJuWxVBoxWJ2kClYTcw/4fAg==} - /@types/chai@5.2.3: + '@types/chai@5.2.3': resolution: {integrity: sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==} - dependencies: - '@types/deep-eql': 4.0.2 - assertion-error: 2.0.1 - dev: true - /@types/debug@4.1.12: + '@types/debug@4.1.12': resolution: {integrity: sha512-vIChWdVG3LG1SMxEvI/AK+FWJthlrqlTu7fbrlywTkkaONwk/UAGaULXRlf8vkzFBLVm0zkMdCquhL5aOjhXPQ==} - dependencies: - '@types/ms': 2.1.0 - dev: false - /@types/deep-eql@4.0.2: + '@types/deep-eql@4.0.2': resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} - dev: true - /@types/estree-jsx@1.0.5: + '@types/estree-jsx@1.0.5': resolution: {integrity: sha512-52CcUVNFyfb1A2ALocQw/Dd1BQFNmSdkuC3BkZ6iqhdMfQz7JWOFRuJFloOzjk+6WijU56m9oKXFAXc7o3Towg==} - dependencies: - '@types/estree': 1.0.8 - dev: false - /@types/estree@1.0.8: + '@types/estree@1.0.8': resolution: {integrity: sha512-dWHzHa2WqEXI/O1E9OjrocMTKJl2mSrEolh1Iomrv6U+JuNwaHXsXx9bLu5gG7BUWFIN0skIQJQ/L1rIex4X6w==} - /@types/hast@3.0.4: + '@types/hast@3.0.4': resolution: {integrity: sha512-WPs+bbQw5aCj+x6laNGWLH3wviHtoCv/P3+otBhbOhJgG8qtpdAMlTCxLtsTWA7LH1Oh/bFCHsBn0TPS5m30EQ==} - dependencies: - '@types/unist': 3.0.3 - dev: false - /@types/json-schema@7.0.15: + '@types/json-schema@7.0.15': resolution: {integrity: sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==} - dev: true - /@types/mdast@4.0.4: + '@types/mdast@4.0.4': resolution: {integrity: sha512-kGaNbPh1k7AFzgpud/gMdvIm5xuECykRR+JnWKQno9TAXVa6WIVCGTPvYGekIDL4uwCZQSYbUxNBSb1aUo79oA==} - dependencies: - '@types/unist': 3.0.3 - dev: false - /@types/ms@2.1.0: + '@types/ms@2.1.0': resolution: {integrity: sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==} - dev: false - /@types/node@24.10.1: + '@types/node@24.10.1': resolution: {integrity: sha512-GNWcUTRBgIRJD5zj+Tq0fKOJ5XZajIiBroOF0yvj2bSU1WvNdYS/dn9UxwsujGW4JX06dnHyjV2y9rRaybH0iQ==} - dependencies: - undici-types: 7.16.0 - /@types/react-dom@19.2.3(@types/react@19.2.7): + '@types/react-dom@19.2.3': resolution: {integrity: sha512-jp2L/eY6fn+KgVVQAOqYItbF0VY/YApe5Mz2F0aykSO8gx31bYCZyvSeYxCHKvzHG5eZjc+zyaS5BrBWya2+kQ==} peerDependencies: '@types/react': ^19.2.0 - dependencies: - '@types/react': 19.2.7 - /@types/react@19.2.7: + '@types/react@19.2.7': resolution: {integrity: sha512-MWtvHrGZLFttgeEj28VXHxpmwYbor/ATPYbBfSFZEIRK0ecCFLl2Qo55z52Hss+UV9CRN7trSeq1zbgx7YDWWg==} - dependencies: - csstype: 3.2.3 - /@types/trusted-types@2.0.7: + '@types/trusted-types@2.0.7': resolution: {integrity: sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==} - requiresBuild: true - dev: false - optional: true - /@types/unist@2.0.11: + '@types/unist@2.0.11': resolution: {integrity: sha512-CmBKiL6NNo/OqgmMn95Fk9Whlp2mtvIv+KNpQKN2F4SjvrEesubTRWGYSg+BnWZOnlCaSTU1sMpsBOzgbYhnsA==} - dev: false - /@types/unist@3.0.3: + '@types/unist@3.0.3': resolution: {integrity: sha512-ko/gIFJRv177XgZsZcBwnqJN5x/Gien8qNOn0D5bQU/zAzVf9Zt3BlcUiLqhV9y4ARk0GbT3tnUiPNgnTXzc/Q==} - dev: false - /@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0)(eslint@9.39.1)(typescript@5.9.3): + '@typescript-eslint/eslint-plugin@8.48.0': resolution: {integrity: sha512-XxXP5tL1txl13YFtrECECQYeZjBZad4fyd3cFV4a19LkAY/bIp9fev3US4S5fDVV2JaYFiKAZ/GRTOLer+mbyQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: '@typescript-eslint/parser': ^8.48.0 eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - dependencies: - '@eslint-community/regexpp': 4.12.2 - '@typescript-eslint/parser': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/type-utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.48.0 - eslint: 9.39.1 - graphemer: 1.4.0 - ignore: 7.0.5 - natural-compare: 1.4.0 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/parser@8.48.0(eslint@9.39.1)(typescript@5.9.3): + '@typescript-eslint/parser@8.48.0': resolution: {integrity: sha512-jCzKdm/QK0Kg4V4IK/oMlRZlY+QOcdjv89U2NgKHZk1CYTj82/RVSx1mV/0gqCVMJ/DA+Zf/S4NBWNF8GQ+eqQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - dependencies: - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) - '@typescript-eslint/visitor-keys': 8.48.0 - debug: 4.4.3(supports-color@10.2.2) - eslint: 9.39.1 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/project-service@8.48.0(typescript@5.9.3): + '@typescript-eslint/project-service@8.48.0': resolution: {integrity: sha512-Ne4CTZyRh1BecBf84siv42wv5vQvVmgtk8AuiEffKTUo3DrBaGYZueJSxxBZ8fjk/N3DrgChH4TOdIOwOwiqqw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - dependencies: - '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) - '@typescript-eslint/types': 8.48.0 - debug: 4.4.3(supports-color@10.2.2) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/scope-manager@8.48.0: + '@typescript-eslint/scope-manager@8.48.0': resolution: {integrity: sha512-uGSSsbrtJrLduti0Q1Q9+BF1/iFKaxGoQwjWOIVNJv0o6omrdyR8ct37m4xIl5Zzpkp69Kkmvom7QFTtue89YQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/visitor-keys': 8.48.0 - dev: true - /@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.9.3): + '@typescript-eslint/tsconfig-utils@8.48.0': resolution: {integrity: sha512-WNebjBdFdyu10sR1M4OXTt2OkMd5KWIL+LLfeH9KhgP+jzfDV/LI3eXzwJ1s9+Yc0Kzo2fQCdY/OpdusCMmh6w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - dependencies: - typescript: 5.9.3 - dev: true - /@typescript-eslint/type-utils@8.48.0(eslint@9.39.1)(typescript@5.9.3): + '@typescript-eslint/type-utils@8.48.0': resolution: {integrity: sha512-zbeVaVqeXhhab6QNEKfK96Xyc7UQuoFWERhEnj3mLVnUWrQnv15cJNseUni7f3g557gm0e46LZ6IJ4NJVOgOpw==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - dependencies: - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - debug: 4.4.3(supports-color@10.2.2) - eslint: 9.39.1 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/types@8.48.0: + '@typescript-eslint/types@8.48.0': resolution: {integrity: sha512-cQMcGQQH7kwKoVswD1xdOytxQR60MWKM1di26xSUtxehaDs/32Zpqsu5WJlXTtTTqyAVK8R7hvsUnIXRS+bjvA==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true - /@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.3): + '@typescript-eslint/typescript-estree@8.48.0': resolution: {integrity: sha512-ljHab1CSO4rGrQIAyizUS6UGHHCiAYhbfcIZ1zVJr5nMryxlXMVWS3duFPSKvSUbFPwkXMFk1k0EMIjub4sRRQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: typescript: '>=4.8.4 <6.0.0' - dependencies: - '@typescript-eslint/project-service': 8.48.0(typescript@5.9.3) - '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/visitor-keys': 8.48.0 - debug: 4.4.3(supports-color@10.2.2) - minimatch: 9.0.5 - semver: 7.7.3 - tinyglobby: 0.2.15 - ts-api-utils: 2.1.0(typescript@5.9.3) - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/utils@8.48.0(eslint@9.39.1)(typescript@5.9.3): + '@typescript-eslint/utils@8.48.0': resolution: {integrity: sha512-yTJO1XuGxCsSfIVt1+1UrLHtue8xz16V8apzPYI06W0HbEbEWHxHXgZaAgavIkoh+GeV6hKKd5jm0sS6OYxWXQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} peerDependencies: eslint: ^8.57.0 || ^9.0.0 typescript: '>=4.8.4 <6.0.0' - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) - '@typescript-eslint/scope-manager': 8.48.0 - '@typescript-eslint/types': 8.48.0 - '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) - eslint: 9.39.1 - typescript: 5.9.3 - transitivePeerDependencies: - - supports-color - dev: true - /@typescript-eslint/visitor-keys@8.48.0: + '@typescript-eslint/visitor-keys@8.48.0': resolution: {integrity: sha512-T0XJMaRPOH3+LBbAfzR2jalckP1MSG/L9eUtY0DEzUyVaXJ/t6zN0nR7co5kz0Jko/nkSYCBRkz1djvjajVTTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - '@typescript-eslint/types': 8.48.0 - eslint-visitor-keys: 4.2.1 - dev: true - /@ungap/structured-clone@1.3.0: + '@ungap/structured-clone@1.3.0': resolution: {integrity: sha512-WmoN8qaIAo7WTYWbAZuG8PYEhn5fkz7dZrqTBZ7dtt//lL2Gwms1IcnQ5yHqjDfX8Ft5j4YzDM23f87zBfDe9g==} - dev: false - /@vitejs/plugin-react@5.1.1(vite@7.2.4): + '@vitejs/plugin-react@5.1.1': resolution: {integrity: sha512-WQfkSw0QbQ5aJ2CHYw23ZGkqnRwqKHD/KYsMeTkZzPT4Jcf0DcBxBtwMJxnu6E7oxw5+JC6ZAiePgh28uJ1HBA==} engines: {node: ^20.19.0 || >=22.12.0} peerDependencies: vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 - dependencies: - '@babel/core': 7.28.5 - '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) - '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) - '@rolldown/pluginutils': 1.0.0-beta.47 - '@types/babel__core': 7.20.5 - react-refresh: 0.18.0 - vite: 7.2.4(@types/node@24.10.1) - transitivePeerDependencies: - - supports-color - dev: true - /@vitest/expect@3.2.4: + '@vitest/coverage-v8@3.2.4': + resolution: {integrity: sha512-EyF9SXU6kS5Ku/U82E259WSnvg6c8KTjppUncuNdm5QHpe17mwREHnjDzozC8x9MZ0xfBUFSaLkRv4TMA75ALQ==} + peerDependencies: + '@vitest/browser': 3.2.4 + vitest: 3.2.4 + peerDependenciesMeta: + '@vitest/browser': + optional: true + + '@vitest/expect@3.2.4': resolution: {integrity: sha512-Io0yyORnB6sikFlt8QW5K7slY4OjqNX9jmJQ02QDda8lyM6B5oNgVWoSoKPac8/kgnCUzuHQKrSLtu/uOqqrig==} - dependencies: - '@types/chai': 5.2.3 - '@vitest/spy': 3.2.4 - '@vitest/utils': 3.2.4 - chai: 5.3.3 - tinyrainbow: 2.0.0 - dev: true - /@vitest/mocker@3.2.4(vite@7.2.4): + '@vitest/mocker@3.2.4': resolution: {integrity: sha512-46ryTE9RZO/rfDd7pEqFl7etuyzekzEhUbTW3BvmeO/BcCMEgq59BKhek3dXDWgAj4oMK6OZi+vRr1wPW6qjEQ==} peerDependencies: msw: ^2.4.9 @@ -2186,375 +1374,228 @@ packages: optional: true vite: optional: true - dependencies: - '@vitest/spy': 3.2.4 - estree-walker: 3.0.3 - magic-string: 0.30.21 - vite: 7.2.4(@types/node@24.10.1) - dev: true - /@vitest/pretty-format@3.2.4: + '@vitest/pretty-format@3.2.4': resolution: {integrity: sha512-IVNZik8IVRJRTr9fxlitMKeJeXFFFN0JaB9PHPGQ8NKQbGpfjlTx9zO4RefN8gp7eqjNy8nyK3NZmBzOPeIxtA==} - dependencies: - tinyrainbow: 2.0.0 - dev: true - /@vitest/runner@3.2.4: + '@vitest/runner@3.2.4': resolution: {integrity: sha512-oukfKT9Mk41LreEW09vt45f8wx7DordoWUZMYdY/cyAk7w5TWkTRCNZYF7sX7n2wB7jyGAl74OxgwhPgKaqDMQ==} - dependencies: - '@vitest/utils': 3.2.4 - pathe: 2.0.3 - strip-literal: 3.1.0 - dev: true - /@vitest/snapshot@3.2.4: + '@vitest/snapshot@3.2.4': resolution: {integrity: sha512-dEYtS7qQP2CjU27QBC5oUOxLE/v5eLkGqPE0ZKEIDGMs4vKWe7IjgLOeauHsR0D5YuuycGRO5oSRXnwnmA78fQ==} - dependencies: - '@vitest/pretty-format': 3.2.4 - magic-string: 0.30.21 - pathe: 2.0.3 - dev: true - /@vitest/spy@3.2.4: + '@vitest/spy@3.2.4': resolution: {integrity: sha512-vAfasCOe6AIK70iP5UD11Ac4siNUNJ9i/9PZ3NKx07sG6sUxeag1LWdNrMWeKKYBLlzuK+Gn65Yd5nyL6ds+nw==} - dependencies: - tinyspy: 4.0.4 - dev: true - /@vitest/ui@3.2.4(vitest@3.2.4): + '@vitest/ui@3.2.4': resolution: {integrity: sha512-hGISOaP18plkzbWEcP/QvtRW1xDXF2+96HbEX6byqQhAUbiS5oH6/9JwW+QsQCIYON2bI6QZBF+2PvOmrRZ9wA==} peerDependencies: vitest: 3.2.4 - dependencies: - '@vitest/utils': 3.2.4 - fflate: 0.8.2 - flatted: 3.3.3 - pathe: 2.0.3 - sirv: 3.0.2 - tinyglobby: 0.2.15 - tinyrainbow: 2.0.0 - vitest: 3.2.4(@vitest/ui@3.2.4) - dev: true - /@vitest/utils@3.2.4: + '@vitest/utils@3.2.4': resolution: {integrity: sha512-fB2V0JFrQSMsCo9HiSq3Ezpdv4iYaXRG1Sx8edX3MwxfyNn83mKiGzOcH+Fkxt4MHxr3y42fQi1oeAInqgX2QA==} - dependencies: - '@vitest/pretty-format': 3.2.4 - loupe: 3.2.1 - tinyrainbow: 2.0.0 - dev: true - /acorn-jsx@5.3.2(acorn@8.15.0): + acorn-jsx@5.3.2: resolution: {integrity: sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==} peerDependencies: acorn: ^6.0.0 || ^7.0.0 || ^8.0.0 - dependencies: - acorn: 8.15.0 - dev: true - /acorn@8.15.0: + acorn@8.15.0: resolution: {integrity: sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==} engines: {node: '>=0.4.0'} hasBin: true - dev: true - /agent-base@7.1.4: + agent-base@7.1.4: resolution: {integrity: sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==} engines: {node: '>= 14'} - dev: true - /ajv@6.12.6: + ajv@6.12.6: resolution: {integrity: sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==} - dependencies: - fast-deep-equal: 3.1.3 - fast-json-stable-stringify: 2.1.0 - json-schema-traverse: 0.4.1 - uri-js: 4.4.1 - dev: true - /ansi-colors@4.1.3: + ansi-colors@4.1.3: resolution: {integrity: sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==} engines: {node: '>=6'} - dev: true - /ansi-regex@5.0.1: + ansi-regex@5.0.1: resolution: {integrity: sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==} engines: {node: '>=8'} - dev: true - /ansi-styles@4.3.0: + ansi-regex@6.2.2: + resolution: {integrity: sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==} + engines: {node: '>=12'} + + ansi-styles@4.3.0: resolution: {integrity: sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==} engines: {node: '>=8'} - dependencies: - color-convert: 2.0.1 - dev: true - /argparse@2.0.1: + ansi-styles@6.2.3: + resolution: {integrity: sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==} + engines: {node: '>=12'} + + argparse@2.0.1: resolution: {integrity: sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==} - dev: true - /aria-hidden@1.2.6: + aria-hidden@1.2.6: resolution: {integrity: sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==} engines: {node: '>=10'} - dependencies: - tslib: 2.8.1 - dev: false - /assertion-error@2.0.1: + assertion-error@2.0.1: resolution: {integrity: sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==} engines: {node: '>=12'} - dev: true - /asynckit@0.4.0: + ast-v8-to-istanbul@0.3.12: + resolution: {integrity: sha512-BRRC8VRZY2R4Z4lFIL35MwNXmwVqBityvOIwETtsCSwvjl0IdgFsy9NhdaA6j74nUdtJJlIypeRhpDam19Wq3g==} + + asynckit@0.4.0: resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} - dev: false - /autoprefixer@10.4.22(postcss@8.5.6): + autoprefixer@10.4.22: resolution: {integrity: sha512-ARe0v/t9gO28Bznv6GgqARmVqcWOV3mfgUPn9becPHMiD3o9BwlRgaeccZnwTpZ7Zwqrm+c1sUSsMxIzQzc8Xg==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: postcss: ^8.1.0 - dependencies: - browserslist: 4.28.0 - caniuse-lite: 1.0.30001757 - fraction.js: 5.3.4 - normalize-range: 0.1.2 - picocolors: 1.1.1 - postcss: 8.5.6 - postcss-value-parser: 4.2.0 - dev: true - /axios@1.13.2: + axios@1.13.2: resolution: {integrity: sha512-VPk9ebNqPcy5lRGuSlKx752IlDatOjT9paPlm8A7yOuW2Fbvp4X3JznJtT4f0GzGLLiWE9W8onz51SqLYwzGaA==} - dependencies: - follow-redirects: 1.15.11 - form-data: 4.0.5 - proxy-from-env: 1.1.0 - transitivePeerDependencies: - - debug - dev: false - /bail@2.0.2: + bail@2.0.2: resolution: {integrity: sha512-0xO6mYd7JB2YesxDKplafRpsiOzPt9V02ddPCLbY1xYGPOX24NTyN50qnUxgCPcSoYMhKpAuBTjQoRZCAkUDRw==} - dev: false - /balanced-match@1.0.2: + balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true - /baseline-browser-mapping@2.8.31: + balanced-match@4.0.4: + resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} + engines: {node: 18 || 20 || >=22} + + baseline-browser-mapping@2.8.31: resolution: {integrity: sha512-a28v2eWrrRWPpJSzxc+mKwm0ZtVx/G8SepdQZDArnXYU/XS+IF6mp8aB/4E+hH1tyGCoDo3KlUCdlSxGDsRkAw==} hasBin: true - dev: true - /brace-expansion@1.1.12: + brace-expansion@1.1.12: resolution: {integrity: sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==} - dependencies: - balanced-match: 1.0.2 - concat-map: 0.0.1 - dev: true - /brace-expansion@2.0.2: + brace-expansion@2.0.2: resolution: {integrity: sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==} - dependencies: - balanced-match: 1.0.2 - dev: true - /browserslist@4.28.0: + brace-expansion@5.0.5: + resolution: {integrity: sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==} + engines: {node: 18 || 20 || >=22} + + browserslist@4.28.0: resolution: {integrity: sha512-tbydkR/CxfMwelN0vwdP/pLkDwyAASZ+VfWm4EOwlB6SWhx1sYnWLqo8N5j0rAzPfzfRaxt0mM/4wPU/Su84RQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} hasBin: true - dependencies: - baseline-browser-mapping: 2.8.31 - caniuse-lite: 1.0.30001757 - electron-to-chromium: 1.5.260 - node-releases: 2.0.27 - update-browserslist-db: 1.1.4(browserslist@4.28.0) - dev: true - /bun-types@1.3.3: - resolution: {integrity: sha512-z3Xwlg7j2l9JY27x5Qn3Wlyos8YAp0kKRlrePAOjgjMGS5IG6E7Jnlx736vH9UVI4wUICwwhC9anYL++XeOgTQ==} - dependencies: - '@types/node': 24.10.1 - dev: true + bun-types@1.3.11: + resolution: {integrity: sha512-1KGPpoxQWl9f6wcZh57LvrPIInQMn2TQ7jsgxqpRzg+l0QPOFvJVH7HmvHo/AiPgwXy+/Thf6Ov3EdVn1vOabg==} - /cac@6.7.14: + cac@6.7.14: resolution: {integrity: sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==} engines: {node: '>=8'} - dev: true - /call-bind-apply-helpers@1.0.2: + call-bind-apply-helpers@1.0.2: resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - function-bind: 1.1.2 - dev: false - /callsites@3.1.0: + callsites@3.1.0: resolution: {integrity: sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==} engines: {node: '>=6'} - dev: true - /caniuse-lite@1.0.30001757: + caniuse-lite@1.0.30001757: resolution: {integrity: sha512-r0nnL/I28Zi/yjk1el6ilj27tKcdjLsNqAOZr0yVjWPrSQyHgKI2INaEWw21bAQSv2LXRt1XuCS/GomNpWOxsQ==} - dev: true - /ccount@2.0.1: + ccount@2.0.1: resolution: {integrity: sha512-eyrF0jiFpY+3drT6383f1qhkbGsLSifNAjA61IUjZjmLCWjItY6LB9ft9YhoDgwfmclB2zhu51Lc7+95b8NRAg==} - dev: false - /chai@5.3.3: + chai@5.3.3: resolution: {integrity: sha512-4zNhdJD/iOjSH0A05ea+Ke6MU5mmpQcbQsSOkgdaUMJ9zTlDTD/GYlwohmIE2u0gaxHYiVHEn1Fw9mZ/ktJWgw==} engines: {node: '>=18'} - dependencies: - assertion-error: 2.0.1 - check-error: 2.1.1 - deep-eql: 5.0.2 - loupe: 3.2.1 - pathval: 2.0.1 - dev: true - /chalk@4.1.2: + chalk@4.1.2: resolution: {integrity: sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==} engines: {node: '>=10'} - dependencies: - ansi-styles: 4.3.0 - supports-color: 7.2.0 - dev: true - /change-case@5.4.4: + change-case@5.4.4: resolution: {integrity: sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==} - dev: true - /character-entities-html4@2.1.0: + character-entities-html4@2.1.0: resolution: {integrity: sha512-1v7fgQRj6hnSwFpq1Eu0ynr/CDEw0rXo2B61qXrLNdHZmPKgb7fqS1a2JwF0rISo9q77jDI8VMEHoApn8qDoZA==} - dev: false - /character-entities-legacy@3.0.0: + character-entities-legacy@3.0.0: resolution: {integrity: sha512-RpPp0asT/6ufRm//AJVwpViZbGM/MkjQFxJccQRHmISF/22NBtsHqAWmL+/pmkPWoIUJdWyeVleTl1wydHATVQ==} - dev: false - /character-entities@2.0.2: + character-entities@2.0.2: resolution: {integrity: sha512-shx7oQ0Awen/BRIdkjkvz54PnEEI/EjwXDSIZp86/KKdbafHh1Df/RYGBhn4hbe2+uKC9FnT5UCEdyPz3ai9hQ==} - dev: false - /character-reference-invalid@2.0.1: + character-reference-invalid@2.0.1: resolution: {integrity: sha512-iBZ4F4wRbyORVsu0jPV7gXkOsGYjGHPmAyv+HiHG8gi5PtC9KI2j1+v8/tlibRvjoWX027ypmG/n0HtO5t7unw==} - dev: false - /check-error@2.1.1: + check-error@2.1.1: resolution: {integrity: sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==} engines: {node: '>= 16'} - dev: true - /class-variance-authority@0.7.1: + class-variance-authority@0.7.1: resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} - dependencies: - clsx: 2.1.1 - dev: false - /cliui@8.0.1: + cliui@8.0.1: resolution: {integrity: sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==} engines: {node: '>=12'} - dependencies: - string-width: 4.2.3 - strip-ansi: 6.0.1 - wrap-ansi: 7.0.0 - dev: true - /clsx@2.1.1: + clsx@2.1.1: resolution: {integrity: sha512-eYm0QWBtUrBWZWG0d386OGAw16Z995PiOVo2B7bjWSbHedGl5e0ZWaq65kOGgUSNesEIDkB9ISbTg/JK9dhCZA==} engines: {node: '>=6'} - dev: false - /cmdk@1.1.1(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0): + cmdk@1.1.1: resolution: {integrity: sha512-Vsv7kFaXm+ptHDMZ7izaRsP70GgrW9NBNGswt9OZaVBLlE0SNpDq8eu/VGXyF9r7M0azK3Wy7OlYXsuyYLFzHg==} peerDependencies: react: ^18 || ^19 || ^19.0.0-rc react-dom: ^18 || ^19 || ^19.0.0-rc - dependencies: - '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) - '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3)(@types/react@19.2.7)(react-dom@19.2.0)(react@19.2.0) - react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) - transitivePeerDependencies: - - '@types/react' - - '@types/react-dom' - dev: false - /color-convert@2.0.1: + color-convert@2.0.1: resolution: {integrity: sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==} engines: {node: '>=7.0.0'} - dependencies: - color-name: 1.1.4 - dev: true - /color-name@1.1.4: + color-name@1.1.4: resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==} - dev: true - /colorette@1.4.0: + colorette@1.4.0: resolution: {integrity: sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==} - dev: true - /combined-stream@1.0.8: + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} - dependencies: - delayed-stream: 1.0.0 - dev: false - /comma-separated-tokens@2.0.3: + comma-separated-tokens@2.0.3: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} - dev: false - /concat-map@0.0.1: + concat-map@0.0.1: resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} - dev: true - /concurrently@9.2.1: + concurrently@9.2.1: resolution: {integrity: sha512-fsfrO0MxV64Znoy8/l1vVIjjHa29SZyyqPgQBwhiDcaW8wJc2W3XWVOGx4M3oJBnv/zdUZIIp1gDeS98GzP8Ng==} engines: {node: '>=18'} hasBin: true - dependencies: - chalk: 4.1.2 - rxjs: 7.8.2 - shell-quote: 1.8.3 - supports-color: 8.1.1 - tree-kill: 1.2.2 - yargs: 17.7.2 - dev: true - /convert-source-map@2.0.0: + convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} - dev: true - /cookie@1.0.2: + cookie@1.0.2: resolution: {integrity: sha512-9Kr/j4O16ISv8zBBhJoi4bXOYNTkFLOqSL3UDB0njXxCXNezjeyVrJyGOWtgfs/q2km1gwBcfH8q1yEGoMYunA==} engines: {node: '>=18'} - dev: false - /cross-spawn@7.0.6: + cross-spawn@7.0.6: resolution: {integrity: sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==} engines: {node: '>= 8'} - dependencies: - path-key: 3.1.1 - shebang-command: 2.0.0 - which: 2.0.2 - dev: true - /csstype@3.2.3: + csstype@3.2.3: resolution: {integrity: sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==} - /date-fns@4.1.0: + date-fns@4.1.0: resolution: {integrity: sha512-Ukq0owbQXxa/U3EGtsdVBkR1w7KOQ5gIBqdH2hkvknzZPYvBxb/aa6E8L7tmjFtkwZBu3UXBbjIgPo/Ez4xaNg==} - dev: false - /debug@4.4.3(supports-color@10.2.2): + debug@4.4.3: resolution: {integrity: sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==} engines: {node: '>=6.0'} peerDependencies: @@ -2562,211 +1603,130 @@ packages: peerDependenciesMeta: supports-color: optional: true - dependencies: - ms: 2.1.3 - supports-color: 10.2.2 - /decode-named-character-reference@1.2.0: + decode-named-character-reference@1.2.0: resolution: {integrity: sha512-c6fcElNV6ShtZXmsgNgFFV5tVX2PaV4g+MOAkb8eXHvn6sryJBrZa9r0zV6+dtTyoCKxtDy5tyQ5ZwQuidtd+Q==} - dependencies: - character-entities: 2.0.2 - dev: false - /deep-eql@5.0.2: + deep-eql@5.0.2: resolution: {integrity: sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==} engines: {node: '>=6'} - dev: true - /deep-is@0.1.4: + deep-is@0.1.4: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} - dev: true - /delayed-stream@1.0.0: + delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} - dev: false - /dequal@2.0.3: + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} - dev: false - /detect-libc@2.1.2: + detect-libc@2.1.2: resolution: {integrity: sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==} engines: {node: '>=8'} - dev: false - /detect-node-es@1.1.0: + detect-node-es@1.1.0: resolution: {integrity: sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==} - dev: false - /devlop@1.1.0: + devlop@1.1.0: resolution: {integrity: sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA==} - dependencies: - dequal: 2.0.3 - dev: false - /diff@8.0.2: + diff@8.0.2: resolution: {integrity: sha512-sSuxWU5j5SR9QQji/o2qMvqRNYRDOcBTgsJ/DeCf4iSN4gW+gNMXM7wFIP+fdXZxoNiAnHUTGjCr+TSWXdRDKg==} engines: {node: '>=0.3.1'} - dev: false - /dompurify@3.2.7: + dompurify@3.2.7: resolution: {integrity: sha512-WhL/YuveyGXJaerVlMYGWhvQswa7myDG17P7Vu65EWC05o8vfeNbvNf4d/BOvH99+ZW+LlQsc1GDKMa1vNK6dw==} - optionalDependencies: - '@types/trusted-types': 2.0.7 - dev: false - /dotenv@17.2.3: + dotenv@17.2.3: resolution: {integrity: sha512-JVUnt+DUIzu87TABbhPmNfVdBDt18BLOWjMUFJMSi/Qqg7NTYtabbvSNJGOJ7afbRuv9D/lngizHtP7QyLQ+9w==} engines: {node: '>=12'} - dev: false - /dunder-proto@1.0.1: + dunder-proto@1.0.1: resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.2 - es-errors: 1.3.0 - gopd: 1.2.0 - dev: false - /electron-to-chromium@1.5.260: + eastasianwidth@0.2.0: + resolution: {integrity: sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==} + + electron-to-chromium@1.5.260: resolution: {integrity: sha512-ov8rBoOBhVawpzdre+Cmz4FB+y66Eqrk6Gwqd8NGxuhv99GQ8XqMAr351KEkOt7gukXWDg6gJWEMKgL2RLMPtA==} - dev: true - /emoji-regex@8.0.0: + emoji-regex@8.0.0: resolution: {integrity: sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==} - dev: true - /enhanced-resolve@5.18.3: + emoji-regex@9.2.2: + resolution: {integrity: sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==} + + enhanced-resolve@5.18.3: resolution: {integrity: sha512-d4lC8xfavMeBjzGr2vECC3fsGXziXZQyJxD868h2M/mBI3PwAuODxAkLkq5HYuvrPYcUtiLzsTo8U3PgX3Ocww==} engines: {node: '>=10.13.0'} - dependencies: - graceful-fs: 4.2.11 - tapable: 2.3.0 - dev: false - /entities@6.0.1: + entities@6.0.1: resolution: {integrity: sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==} engines: {node: '>=0.12'} - dev: false - /es-define-property@1.0.1: + es-define-property@1.0.1: resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} engines: {node: '>= 0.4'} - dev: false - /es-errors@1.3.0: + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} - dev: false - /es-module-lexer@1.7.0: + es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - dev: true - /es-object-atoms@1.1.1: + es-object-atoms@1.1.1: resolution: {integrity: sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==} engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - dev: false - /es-set-tostringtag@2.1.0: + es-set-tostringtag@2.1.0: resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} engines: {node: '>= 0.4'} - dependencies: - es-errors: 1.3.0 - get-intrinsic: 1.3.0 - has-tostringtag: 1.0.2 - hasown: 2.0.2 - dev: false - /esbuild@0.25.12: + esbuild@0.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} hasBin: true - requiresBuild: true - optionalDependencies: - '@esbuild/aix-ppc64': 0.25.12 - '@esbuild/android-arm': 0.25.12 - '@esbuild/android-arm64': 0.25.12 - '@esbuild/android-x64': 0.25.12 - '@esbuild/darwin-arm64': 0.25.12 - '@esbuild/darwin-x64': 0.25.12 - '@esbuild/freebsd-arm64': 0.25.12 - '@esbuild/freebsd-x64': 0.25.12 - '@esbuild/linux-arm': 0.25.12 - '@esbuild/linux-arm64': 0.25.12 - '@esbuild/linux-ia32': 0.25.12 - '@esbuild/linux-loong64': 0.25.12 - '@esbuild/linux-mips64el': 0.25.12 - '@esbuild/linux-ppc64': 0.25.12 - '@esbuild/linux-riscv64': 0.25.12 - '@esbuild/linux-s390x': 0.25.12 - '@esbuild/linux-x64': 0.25.12 - '@esbuild/netbsd-arm64': 0.25.12 - '@esbuild/netbsd-x64': 0.25.12 - '@esbuild/openbsd-arm64': 0.25.12 - '@esbuild/openbsd-x64': 0.25.12 - '@esbuild/openharmony-arm64': 0.25.12 - '@esbuild/sunos-x64': 0.25.12 - '@esbuild/win32-arm64': 0.25.12 - '@esbuild/win32-ia32': 0.25.12 - '@esbuild/win32-x64': 0.25.12 - /escalade@3.2.0: + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} - dev: true - /escape-string-regexp@4.0.0: + escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - dev: true - /escape-string-regexp@5.0.0: + escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} engines: {node: '>=12'} - dev: false - /eslint-plugin-react-hooks@5.2.0(eslint@9.39.1): + eslint-plugin-react-hooks@5.2.0: resolution: {integrity: sha512-+f15FfK64YQwZdJNELETdn5ibXEUQmW1DZL6KXhNnc2heoy/sg9VJJeT7n8TlMWouzWqSWavFkIhHyIbIAEapg==} engines: {node: '>=10'} peerDependencies: eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 || ^9.0.0 - dependencies: - eslint: 9.39.1 - dev: true - /eslint-plugin-react-refresh@0.4.24(eslint@9.39.1): + eslint-plugin-react-refresh@0.4.24: resolution: {integrity: sha512-nLHIW7TEq3aLrEYWpVaJ1dRgFR+wLDPN8e8FpYAql/bMV2oBEfC37K0gLEGgv9fy66juNShSMV8OkTqzltcG/w==} peerDependencies: eslint: '>=8.40' - dependencies: - eslint: 9.39.1 - dev: true - /eslint-scope@8.4.0: + eslint-scope@8.4.0: resolution: {integrity: sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - esrecurse: 4.3.0 - estraverse: 5.3.0 - dev: true - /eslint-visitor-keys@3.4.3: + eslint-visitor-keys@3.4.3: resolution: {integrity: sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} - dev: true - /eslint-visitor-keys@4.2.1: + eslint-visitor-keys@4.2.1: resolution: {integrity: sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dev: true - /eslint@9.39.1: + eslint@9.39.1: resolution: {integrity: sha512-BhHmn2yNOFA9H9JmmIVKJmd288g9hrVRDkdoIgRCRuSySRUHH7r/DI6aAXW9T1WwUuY3DFgrcaqB+deURBLR5g==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} hasBin: true @@ -2775,114 +1735,53 @@ packages: peerDependenciesMeta: jiti: optional: true - dependencies: - '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1) - '@eslint-community/regexpp': 4.12.2 - '@eslint/config-array': 0.21.1 - '@eslint/config-helpers': 0.4.2 - '@eslint/core': 0.17.0 - '@eslint/eslintrc': 3.3.1 - '@eslint/js': 9.39.1 - '@eslint/plugin-kit': 0.4.1 - '@humanfs/node': 0.16.7 - '@humanwhocodes/module-importer': 1.0.1 - '@humanwhocodes/retry': 0.4.3 - '@types/estree': 1.0.8 - ajv: 6.12.6 - chalk: 4.1.2 - cross-spawn: 7.0.6 - debug: 4.4.3(supports-color@10.2.2) - escape-string-regexp: 4.0.0 - eslint-scope: 8.4.0 - eslint-visitor-keys: 4.2.1 - espree: 10.4.0 - esquery: 1.6.0 - esutils: 2.0.3 - fast-deep-equal: 3.1.3 - file-entry-cache: 8.0.0 - find-up: 5.0.0 - glob-parent: 6.0.2 - ignore: 5.3.2 - imurmurhash: 0.1.4 - is-glob: 4.0.3 - json-stable-stringify-without-jsonify: 1.0.1 - lodash.merge: 4.6.2 - minimatch: 3.1.2 - natural-compare: 1.4.0 - optionator: 0.9.4 - transitivePeerDependencies: - - supports-color - dev: true - /espree@10.4.0: + espree@10.4.0: resolution: {integrity: sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - dependencies: - acorn: 8.15.0 - acorn-jsx: 5.3.2(acorn@8.15.0) - eslint-visitor-keys: 4.2.1 - dev: true - /esquery@1.6.0: + esquery@1.6.0: resolution: {integrity: sha512-ca9pw9fomFcKPvFLXhBKUK90ZvGibiGOvRJNbjljY7s7uq/5YO4BOzcYtJqExdx99rF6aAcnRxHmcUHcz6sQsg==} engines: {node: '>=0.10'} - dependencies: - estraverse: 5.3.0 - dev: true - /esrecurse@4.3.0: + esrecurse@4.3.0: resolution: {integrity: sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==} engines: {node: '>=4.0'} - dependencies: - estraverse: 5.3.0 - dev: true - /estraverse@5.3.0: + estraverse@5.3.0: resolution: {integrity: sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==} engines: {node: '>=4.0'} - dev: true - /estree-util-is-identifier-name@3.0.0: + estree-util-is-identifier-name@3.0.0: resolution: {integrity: sha512-hFtqIDZTIUZ9BXLb8y4pYGyk6+wekIivNVTcmvk8NoOh+VeRn5y6cEHzbURrWbfp1fIqdVipilzj+lfaadNZmg==} - dev: false - /estree-walker@3.0.3: + estree-walker@3.0.3: resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} - dependencies: - '@types/estree': 1.0.8 - dev: true - /esutils@2.0.3: + esutils@2.0.3: resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} engines: {node: '>=0.10.0'} - dev: true - /expect-type@1.2.2: + expect-type@1.2.2: resolution: {integrity: sha512-JhFGDVJ7tmDJItKhYgJCGLOWjuK9vPxiXoUFLwLDc99NlmklilbiQJwoctZtt13+xMw91MCk/REan6MWHqDjyA==} engines: {node: '>=12.0.0'} - dev: true - /extend@3.0.2: + extend@3.0.2: resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==} - dev: false - /fast-deep-equal@3.1.3: + fast-deep-equal@3.1.3: resolution: {integrity: sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==} - dev: true - /fast-json-stable-stringify@2.1.0: + fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} - dev: true - /fast-levenshtein@2.0.6: + fast-levenshtein@2.0.6: resolution: {integrity: sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==} - dev: true - /fast-uri@3.1.0: + fast-uri@3.1.0: resolution: {integrity: sha512-iPeeDKJSWf4IEOasVVrknXpaBV0IApz/gp7S2bb7Z4Lljbl2MGJRqInZiUrQwV16cpzw/D3S5j5Julj/gT52AA==} - dev: true - /fdir@6.5.0(picomatch@4.0.3): + fdir@6.5.0: resolution: {integrity: sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==} engines: {node: '>=12.0.0'} peerDependencies: @@ -2890,41 +1789,26 @@ packages: peerDependenciesMeta: picomatch: optional: true - dependencies: - picomatch: 4.0.3 - /fflate@0.8.2: + fflate@0.8.2: resolution: {integrity: sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==} - dev: true - /file-entry-cache@8.0.0: + file-entry-cache@8.0.0: resolution: {integrity: sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==} engines: {node: '>=16.0.0'} - dependencies: - flat-cache: 4.0.1 - dev: true - /find-up@5.0.0: + find-up@5.0.0: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} - dependencies: - locate-path: 6.0.0 - path-exists: 4.0.0 - dev: true - /flat-cache@4.0.1: + flat-cache@4.0.1: resolution: {integrity: sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==} engines: {node: '>=16'} - dependencies: - flatted: 3.3.3 - keyv: 4.5.4 - dev: true - /flatted@3.3.3: + flatted@3.3.3: resolution: {integrity: sha512-GX+ysw4PBCz0PzosHDepZGANEuFCMLrnRTiEy9McGjmkCQYwRq4A/X786G/fjM/+OjsWSU1ZrY5qyARZmO/uwg==} - dev: true - /follow-redirects@1.15.11: + follow-redirects@1.15.11: resolution: {integrity: sha512-deG2P0JfjrTxl50XGCDyfI97ZGVCxIpfKYmfyrQ54n5FO/0gfIES8C/Psl6kWVDolizcaaxZJnTS0QSMxvnsBQ==} engines: {node: '>=4.0'} peerDependencies: @@ -2932,599 +1816,3109 @@ packages: peerDependenciesMeta: debug: optional: true - dev: false - /form-data@4.0.5: + foreground-child@3.3.1: + resolution: {integrity: sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==} + engines: {node: '>=14'} + + form-data@4.0.5: resolution: {integrity: sha512-8RipRLol37bNs2bhoV67fiTEvdTrbMUYcFTiy3+wuuOnUog2QBHCZWXDRijWQfAkhBj2Uf5UnVaiWwA5vdd82w==} engines: {node: '>= 6'} - dependencies: - asynckit: 0.4.0 - combined-stream: 1.0.8 - es-set-tostringtag: 2.1.0 - hasown: 2.0.2 - mime-types: 2.1.35 - dev: false - /fraction.js@5.3.4: + fraction.js@5.3.4: resolution: {integrity: sha512-1X1NTtiJphryn/uLQz3whtY6jK3fTqoE3ohKs0tT+Ujr1W59oopxmoEh7Lu5p6vBaPbgoM0bzveAW4Qi5RyWDQ==} - dev: true - /fsevents@2.3.3: + fsevents@2.3.3: resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} os: [darwin] - requiresBuild: true - optional: true - /function-bind@1.1.2: + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} - dev: false - /gensync@1.0.0-beta.2: + gensync@1.0.0-beta.2: resolution: {integrity: sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==} engines: {node: '>=6.9.0'} - dev: true - /get-caller-file@2.0.5: + get-caller-file@2.0.5: resolution: {integrity: sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==} engines: {node: 6.* || 8.* || >= 10.*} - dev: true - /get-intrinsic@1.3.0: + get-intrinsic@1.3.0: resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} engines: {node: '>= 0.4'} - dependencies: - call-bind-apply-helpers: 1.0.2 - es-define-property: 1.0.1 - es-errors: 1.3.0 - es-object-atoms: 1.1.1 - function-bind: 1.1.2 - get-proto: 1.0.1 - gopd: 1.2.0 - has-symbols: 1.1.0 - hasown: 2.0.2 - math-intrinsics: 1.1.0 - dev: false - /get-nonce@1.0.1: + get-nonce@1.0.1: resolution: {integrity: sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==} engines: {node: '>=6'} - dev: false - /get-proto@1.0.1: + get-proto@1.0.1: resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} engines: {node: '>= 0.4'} - dependencies: - dunder-proto: 1.0.1 - es-object-atoms: 1.1.1 - dev: false - /glob-parent@6.0.2: + glob-parent@6.0.2: resolution: {integrity: sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==} engines: {node: '>=10.13.0'} - dependencies: - is-glob: 4.0.3 - dev: true - /globals@14.0.0: + glob@10.5.0: + resolution: {integrity: sha512-DfXN8DfhJ7NH3Oe7cFmu3NCu1wKbkReJ8TorzSAFbSKrlNaQSKfIzqYqVY8zlbs2NLBbWpRiU52GX2PbaBVNkg==} + deprecated: Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me + hasBin: true + + globals@14.0.0: resolution: {integrity: sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==} engines: {node: '>=18'} - dev: true - /globals@16.5.0: + globals@16.5.0: resolution: {integrity: sha512-c/c15i26VrJ4IRt5Z89DnIzCGDn9EcebibhAOjw5ibqEHsE1wLUgkPn9RDmNcUKyU87GeaL633nyJ+pplFR2ZQ==} engines: {node: '>=18'} - dev: true - /gopd@1.2.0: + gopd@1.2.0: resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} engines: {node: '>= 0.4'} - dev: false - /graceful-fs@4.2.11: + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} - dev: false - /graphemer@1.4.0: + graphemer@1.4.0: resolution: {integrity: sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==} - dev: true - /has-flag@4.0.0: + has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} - dev: true - /has-symbols@1.1.0: + has-symbols@1.1.0: resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} engines: {node: '>= 0.4'} - dev: false - /has-tostringtag@1.0.2: + has-tostringtag@1.0.2: resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} engines: {node: '>= 0.4'} - dependencies: - has-symbols: 1.1.0 - dev: false - /hasown@2.0.2: + hasown@2.0.2: resolution: {integrity: sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==} engines: {node: '>= 0.4'} - dependencies: - function-bind: 1.1.2 - dev: false - /hast-util-from-parse5@8.0.3: + hast-util-from-parse5@8.0.3: resolution: {integrity: sha512-3kxEVkEKt0zvcZ3hCRYI8rqrgwtlIOFMWkbclACvjlDw8Li9S2hk/d51OI0nr/gIpdMHNepwgOKqZ/sy0Clpyg==} - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - devlop: 1.1.0 - hastscript: 9.0.1 - property-information: 7.1.0 - vfile: 6.0.3 - vfile-location: 5.0.3 - web-namespaces: 2.0.1 - dev: false - /hast-util-is-element@3.0.0: + hast-util-is-element@3.0.0: resolution: {integrity: sha512-Val9mnv2IWpLbNPqc/pUem+a7Ipj2aHacCwgNfTiK0vJKl0LF+4Ba4+v1oPHFpf3bLYmreq0/l3Gud9S5OH42g==} - dependencies: - '@types/hast': 3.0.4 - dev: false - /hast-util-parse-selector@4.0.0: + hast-util-parse-selector@4.0.0: resolution: {integrity: sha512-wkQCkSYoOGCRKERFWcxMVMOcYE2K1AaNLU8DXS9arxnLOUEWbOXKXiJUNzEpqZ3JOKpnha3jkFrumEjVliDe7A==} - dependencies: - '@types/hast': 3.0.4 - dev: false - /hast-util-raw@9.1.0: + hast-util-raw@9.1.0: resolution: {integrity: sha512-Y8/SBAHkZGoNkpzqqfCldijcuUKh7/su31kEBp67cFY09Wy0mTRgtsLYsiIxMJxlu0f6AA5SUTbDR8K0rxnbUw==} - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - '@ungap/structured-clone': 1.3.0 - hast-util-from-parse5: 8.0.3 - hast-util-to-parse5: 8.0.0 - html-void-elements: 3.0.0 - mdast-util-to-hast: 13.2.1 - parse5: 7.3.0 - unist-util-position: 5.0.0 - unist-util-visit: 5.0.0 - vfile: 6.0.3 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - dev: false - /hast-util-to-jsx-runtime@2.3.6: + hast-util-to-jsx-runtime@2.3.6: resolution: {integrity: sha512-zl6s8LwNyo1P9uw+XJGvZtdFF1GdAkOg8ujOw+4Pyb76874fLps4ueHXDhXWdk6YHQ6OgUtinliG7RsYvCbbBg==} - dependencies: - '@types/estree': 1.0.8 - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - comma-separated-tokens: 2.0.3 - devlop: 1.1.0 - estree-util-is-identifier-name: 3.0.0 - hast-util-whitespace: 3.0.0 - mdast-util-mdx-expression: 2.0.1 - mdast-util-mdx-jsx: 3.2.0 - mdast-util-mdxjs-esm: 2.0.1 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - style-to-js: 1.1.21 - unist-util-position: 5.0.0 - vfile-message: 4.0.3 - transitivePeerDependencies: - - supports-color - dev: false - /hast-util-to-parse5@8.0.0: + hast-util-to-parse5@8.0.0: resolution: {integrity: sha512-3KKrV5ZVI8if87DVSi1vDeByYrkGzg4mEfeu4alwgmmIeARiBLKCZS2uw5Gb6nU9x9Yufyj3iudm6i7nl52PFw==} - dependencies: - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - devlop: 1.1.0 - property-information: 6.5.0 - space-separated-tokens: 2.0.2 - web-namespaces: 2.0.1 - zwitch: 2.0.4 - dev: false - /hast-util-to-text@4.0.2: + hast-util-to-text@4.0.2: resolution: {integrity: sha512-KK6y/BN8lbaq654j7JgBydev7wuNMcID54lkRav1P0CaE1e47P72AWWPiGKXTJU271ooYzcvTAn/Zt0REnvc7A==} - dependencies: - '@types/hast': 3.0.4 - '@types/unist': 3.0.3 - hast-util-is-element: 3.0.0 - unist-util-find-after: 5.0.0 - dev: false - /hast-util-whitespace@3.0.0: + hast-util-whitespace@3.0.0: resolution: {integrity: sha512-88JUN06ipLwsnv+dVn+OIYOvAuvBMy/Qoi6O7mQHxdPXpjy+Cd6xRkWwux7DKO+4sYILtLBRIKgsdpS2gQc7qw==} - dependencies: - '@types/hast': 3.0.4 - dev: false - /hastscript@9.0.1: + hastscript@9.0.1: resolution: {integrity: sha512-g7df9rMFX/SPi34tyGCyUBREQoKkapwdY/T04Qn9TDWfHhAYt4/I0gMVirzK5wEzeUqIjEB+LXC/ypb7Aqno5w==} - dependencies: - '@types/hast': 3.0.4 - comma-separated-tokens: 2.0.3 - hast-util-parse-selector: 4.0.0 - property-information: 7.1.0 - space-separated-tokens: 2.0.2 - dev: false - /highlight.js@11.11.1: + highlight.js@11.11.1: resolution: {integrity: sha512-Xwwo44whKBVCYoliBQwaPvtd/2tYFkRQtXDWj1nackaV2JPXx3L0+Jvd8/qCJ2p+ML0/XVkJ2q+Mr+UVdpJK5w==} engines: {node: '>=12.0.0'} - dev: false - /hono@4.10.6: + hono@4.10.6: resolution: {integrity: sha512-BIdolzGpDO9MQ4nu3AUuDwHZZ+KViNm+EZ75Ae55eMXMqLVhDFqEMXxtUe9Qh8hjL+pIna/frs2j6Y2yD5Ua/g==} engines: {node: '>=16.9.0'} - dev: false - /html-url-attributes@3.0.1: + html-escaper@2.0.2: + resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + + html-url-attributes@3.0.1: resolution: {integrity: sha512-ol6UPyBWqsrO6EJySPz2O7ZSr856WDrEzM5zMqp+FJJLGMW35cLYmmZnl0vztAZxRUoNZJFTCohfjuIJ8I4QBQ==} - dev: false - /html-void-elements@3.0.0: + html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} - dev: false - /https-proxy-agent@7.0.6(supports-color@10.2.2): + https-proxy-agent@7.0.6: resolution: {integrity: sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==} engines: {node: '>= 14'} - dependencies: - agent-base: 7.1.4 - debug: 4.4.3(supports-color@10.2.2) - transitivePeerDependencies: - - supports-color - dev: true - /ignore@5.3.2: + ignore@5.3.2: resolution: {integrity: sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==} engines: {node: '>= 4'} - dev: true - /ignore@7.0.5: + ignore@7.0.5: resolution: {integrity: sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg==} engines: {node: '>= 4'} - dev: true - /import-fresh@3.3.1: + import-fresh@3.3.1: resolution: {integrity: sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==} engines: {node: '>=6'} - dependencies: - parent-module: 1.0.1 - resolve-from: 4.0.0 - dev: true - /imurmurhash@0.1.4: + imurmurhash@0.1.4: resolution: {integrity: sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==} engines: {node: '>=0.8.19'} - dev: true - /index-to-position@1.2.0: + index-to-position@1.2.0: resolution: {integrity: sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==} engines: {node: '>=18'} - dev: true - /inline-style-parser@0.2.7: + inline-style-parser@0.2.7: resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} - dev: false - /is-alphabetical@2.0.1: + is-alphabetical@2.0.1: resolution: {integrity: sha512-FWyyY60MeTNyeSRpkM2Iry0G9hpr7/9kD40mD/cGQEuilcZYS4okz8SN2Q6rLCJ8gbCt6fN+rC+6tMGS99LaxQ==} - dev: false - /is-alphanumerical@2.0.1: + is-alphanumerical@2.0.1: resolution: {integrity: sha512-hmbYhX/9MUMF5uh7tOXyK/n0ZvWpad5caBA17GsC6vyuCqaWliRG5K1qS9inmUhEMaOBIW7/whAnSwveW/LtZw==} - dependencies: - is-alphabetical: 2.0.1 - is-decimal: 2.0.1 - dev: false - /is-decimal@2.0.1: + is-decimal@2.0.1: resolution: {integrity: sha512-AAB9hiomQs5DXWcRB1rqsxGUstbRroFOPPVAomNk/3XHR5JyEZChOyTWe2oayKnsSsr/kcGqF+z6yuH6HHpN0A==} - dev: false - /is-extglob@2.1.1: + is-extglob@2.1.1: resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} engines: {node: '>=0.10.0'} - dev: true - /is-fullwidth-code-point@3.0.0: + is-fullwidth-code-point@3.0.0: resolution: {integrity: sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==} engines: {node: '>=8'} - dev: true - /is-glob@4.0.3: + is-glob@4.0.3: resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} engines: {node: '>=0.10.0'} - dependencies: - is-extglob: 2.1.1 - dev: true - /is-hexadecimal@2.0.1: + is-hexadecimal@2.0.1: resolution: {integrity: sha512-DgZQp241c8oO6cA1SbTEWiXeoxV42vlcJxgH+B3hi1AiqqKruZR3ZGF8In3fj4+/y/7rHvlOZLZtgJ/4ttYGZg==} - dev: false - /is-plain-obj@4.1.0: + is-plain-obj@4.1.0: resolution: {integrity: sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==} engines: {node: '>=12'} - dev: false - /isexe@2.0.0: + isexe@2.0.0: resolution: {integrity: sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==} - dev: true - /jiti@2.6.1: + istanbul-lib-coverage@3.2.2: + resolution: {integrity: sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==} + engines: {node: '>=8'} + + istanbul-lib-report@3.0.1: + resolution: {integrity: sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==} + engines: {node: '>=10'} + + istanbul-lib-source-maps@5.0.6: + resolution: {integrity: sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==} + engines: {node: '>=10'} + + istanbul-reports@3.2.0: + resolution: {integrity: sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==} + engines: {node: '>=8'} + + jackspeak@3.4.3: + resolution: {integrity: sha512-OGlZQpz2yfahA/Rd1Y8Cd9SIEsqvXkLVoSw/cgwhnhFMDbsQFeZYoJJ7bIZBS9BcamUW96asq/npPWugM+RQBw==} + + jiti@2.6.1: resolution: {integrity: sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==} hasBin: true - dev: false - /js-levenshtein@1.1.6: + js-levenshtein@1.1.6: resolution: {integrity: sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==} engines: {node: '>=0.10.0'} - dev: true - /js-tokens@4.0.0: + js-tokens@10.0.0: + resolution: {integrity: sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==} + + js-tokens@4.0.0: resolution: {integrity: sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==} - dev: true - /js-tokens@9.0.1: + js-tokens@9.0.1: resolution: {integrity: sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ==} - dev: true - /js-yaml@4.1.1: + js-yaml@4.1.1: resolution: {integrity: sha512-qQKT4zQxXl8lLwBtHMWwaTcGfFOZviOJet3Oy/xmGk2gZH677CJM9EvtfdSkgWcATZhj/55JZ0rmy3myCT5lsA==} hasBin: true - dependencies: - argparse: 2.0.1 - dev: true - /jsesc@3.1.0: + jsesc@3.1.0: resolution: {integrity: sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==} engines: {node: '>=6'} hasBin: true - dev: true - /json-buffer@3.0.1: + json-buffer@3.0.1: resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==} - dev: true - /json-schema-traverse@0.4.1: + json-schema-traverse@0.4.1: resolution: {integrity: sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==} - dev: true - /json-schema-traverse@1.0.0: + json-schema-traverse@1.0.0: resolution: {integrity: sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==} - dev: true - /json-stable-stringify-without-jsonify@1.0.1: + json-stable-stringify-without-jsonify@1.0.1: resolution: {integrity: sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==} - dev: true - /json5@2.2.3: + json5@2.2.3: resolution: {integrity: sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==} engines: {node: '>=6'} hasBin: true - dev: true - /keyv@4.5.4: + keyv@4.5.4: resolution: {integrity: sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==} - dependencies: - json-buffer: 3.0.1 - dev: true - /levn@0.4.1: + levn@0.4.1: resolution: {integrity: sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==} engines: {node: '>= 0.8.0'} - dependencies: - prelude-ls: 1.2.1 - type-check: 0.4.0 - dev: true - /lightningcss-android-arm64@1.30.2: + lightningcss-android-arm64@1.30.2: resolution: {integrity: sha512-BH9sEdOCahSgmkVhBLeU7Hc9DWeZ1Eb6wNS6Da8igvUwAe0sqROHddIlvU06q3WyXVEOYDZ6ykBZQnjTbmo4+A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [android] - requiresBuild: true - dev: false - optional: true - /lightningcss-darwin-arm64@1.30.2: + lightningcss-darwin-arm64@1.30.2: resolution: {integrity: sha512-ylTcDJBN3Hp21TdhRT5zBOIi73P6/W0qwvlFEk22fkdXchtNTOU4Qc37SkzV+EKYxLouZ6M4LG9NfZ1qkhhBWA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [darwin] - requiresBuild: true - dev: false - optional: true - /lightningcss-darwin-x64@1.30.2: + lightningcss-darwin-x64@1.30.2: resolution: {integrity: sha512-oBZgKchomuDYxr7ilwLcyms6BCyLn0z8J0+ZZmfpjwg9fRVZIR5/GMXd7r9RH94iDhld3UmSjBM6nXWM2TfZTQ==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [darwin] - requiresBuild: true - dev: false - optional: true - /lightningcss-freebsd-x64@1.30.2: + lightningcss-freebsd-x64@1.30.2: resolution: {integrity: sha512-c2bH6xTrf4BDpK8MoGG4Bd6zAMZDAXS569UxCAGcA7IKbHNMlhGQ89eRmvpIUGfKWNVdbhSbkQaWhEoMGmGslA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [freebsd] - requiresBuild: true - dev: false - optional: true - /lightningcss-linux-arm-gnueabihf@1.30.2: + lightningcss-linux-arm-gnueabihf@1.30.2: resolution: {integrity: sha512-eVdpxh4wYcm0PofJIZVuYuLiqBIakQ9uFZmipf6LF/HRj5Bgm0eb3qL/mr1smyXIS1twwOxNWndd8z0E374hiA==} engines: {node: '>= 12.0.0'} cpu: [arm] os: [linux] - requiresBuild: true - dev: false - optional: true - /lightningcss-linux-arm64-gnu@1.30.2: + lightningcss-linux-arm64-gnu@1.30.2: resolution: {integrity: sha512-UK65WJAbwIJbiBFXpxrbTNArtfuznvxAJw4Q2ZGlU8kPeDIWEX1dg3rn2veBVUylA2Ezg89ktszWbaQnxD/e3A==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: false - optional: true - /lightningcss-linux-arm64-musl@1.30.2: + lightningcss-linux-arm64-musl@1.30.2: resolution: {integrity: sha512-5Vh9dGeblpTxWHpOx8iauV02popZDsCYMPIgiuw97OJ5uaDsL86cnqSFs5LZkG3ghHoX5isLgWzMs+eD1YzrnA==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [linux] - requiresBuild: true - dev: false - optional: true - /lightningcss-linux-x64-gnu@1.30.2: + lightningcss-linux-x64-gnu@1.30.2: resolution: {integrity: sha512-Cfd46gdmj1vQ+lR6VRTTadNHu6ALuw2pKR9lYq4FnhvgBc4zWY1EtZcAc6EffShbb1MFrIPfLDXD6Xprbnni4w==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - requiresBuild: true - dev: false - optional: true - /lightningcss-linux-x64-musl@1.30.2: + lightningcss-linux-x64-musl@1.30.2: resolution: {integrity: sha512-XJaLUUFXb6/QG2lGIW6aIk6jKdtjtcffUT0NKvIqhSBY3hh9Ch+1LCeH80dR9q9LBjG3ewbDjnumefsLsP6aiA==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [linux] - requiresBuild: true - dev: false - optional: true - /lightningcss-win32-arm64-msvc@1.30.2: + lightningcss-win32-arm64-msvc@1.30.2: resolution: {integrity: sha512-FZn+vaj7zLv//D/192WFFVA0RgHawIcHqLX9xuWiQt7P0PtdFEVaxgF9rjM/IRYHQXNnk61/H/gb2Ei+kUQ4xQ==} engines: {node: '>= 12.0.0'} cpu: [arm64] os: [win32] - requiresBuild: true - dev: false - optional: true - /lightningcss-win32-x64-msvc@1.30.2: + lightningcss-win32-x64-msvc@1.30.2: resolution: {integrity: sha512-5g1yc73p+iAkid5phb4oVFMB45417DkRevRbt/El/gKXJk4jid+vPFF/AXbxn05Aky8PapwzZrdJShv5C0avjw==} engines: {node: '>= 12.0.0'} cpu: [x64] os: [win32] - requiresBuild: true - dev: false - optional: true - /lightningcss@1.30.2: + lightningcss@1.30.2: resolution: {integrity: sha512-utfs7Pr5uJyyvDETitgsaqSyjCb2qNRAtuqUeWIAKztsOYdcACf2KtARYXg2pSvhkt+9NfoaNY7fxjl6nuMjIQ==} engines: {node: '>= 12.0.0'} - dependencies: - detect-libc: 2.1.2 - optionalDependencies: - lightningcss-android-arm64: 1.30.2 - lightningcss-darwin-arm64: 1.30.2 - lightningcss-darwin-x64: 1.30.2 - lightningcss-freebsd-x64: 1.30.2 - lightningcss-linux-arm-gnueabihf: 1.30.2 - lightningcss-linux-arm64-gnu: 1.30.2 - lightningcss-linux-arm64-musl: 1.30.2 - lightningcss-linux-x64-gnu: 1.30.2 - lightningcss-linux-x64-musl: 1.30.2 - lightningcss-win32-arm64-msvc: 1.30.2 - lightningcss-win32-x64-msvc: 1.30.2 - dev: false - /locate-path@6.0.0: + locate-path@6.0.0: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} - dependencies: - p-locate: 5.0.0 - dev: true - /lodash.merge@4.6.2: + lodash.merge@4.6.2: resolution: {integrity: sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==} - dev: true - /longest-streak@3.1.0: + longest-streak@3.1.0: resolution: {integrity: sha512-9Ri+o0JYgehTaVBBDoMqIl8GXtbWg711O3srftcHhZ0dqnETqLaoIK0x17fUw9rFSlK/0NlsKe0Ahhyl5pXE2g==} - dev: false - /loupe@3.2.1: + loupe@3.2.1: resolution: {integrity: sha512-CdzqowRJCeLU72bHvWqwRBBlLcMEtIvGrlvef74kMnV2AolS9Y8xUv1I0U/MNAWMhBlKIoyuEgoJ0t/bbwHbLQ==} - dev: true - /lowlight@3.3.0: + lowlight@3.3.0: resolution: {integrity: sha512-0JNhgFoPvP6U6lE/UdVsSq99tn6DhjjpAj5MxG49ewd2mOBVtwWYIT8ClyABhq198aXXODMU6Ox8DrGy/CpTZQ==} - dependencies: - '@types/hast': 3.0.4 - devlop: 1.1.0 - highlight.js: 11.11.1 - dev: false - /lru-cache@5.1.1: + lru-cache@10.4.3: + resolution: {integrity: sha512-JNAzZcXrCt42VGLuYz0zfAzDfAvJWW6AfYlDBQyDV5DClI2m5sAmK+OIO7s59XfsRsWHp02jAJrRadPRGTt6SQ==} + + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} - dependencies: - yallist: 3.1.1 - dev: true - /lucide-react@0.546.0(react@19.2.0): + lucide-react@0.546.0: resolution: {integrity: sha512-Z94u6fKT43lKeYHiVyvyR8fT7pwCzDu7RyMPpTvh054+xahSgj4HFQ+NmflvzdXsoAjYGdCguGaFKYuvq0ThCQ==} peerDependencies: react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 - dependencies: - react: 19.2.0 - dev: false - /magic-string@0.30.21: + magic-string@0.30.21: resolution: {integrity: sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==} - dependencies: - '@jridgewell/sourcemap-codec': 1.5.5 - /markdown-table@3.0.4: + magicast@0.3.5: + resolution: {integrity: sha512-L0WhttDl+2BOsybvEOLK7fW3UA0OQ0IQ2d6Zl2x/a6vVRs3bAY0ECOSHHeL5jD+SbOpOCUEi0y1DgHEn9Qn1AQ==} + + make-dir@4.0.0: + resolution: {integrity: sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==} + engines: {node: '>=10'} + + markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} - dev: false - /marked@14.0.0: + marked@14.0.0: resolution: {integrity: sha512-uIj4+faQ+MgHgwUW1l2PsPglZLOLOT1uErt06dAPtx2kjteLAkbsd/0FiYg/MGS+i7ZKLb7w2WClxHkzOOuryQ==} engines: {node: '>= 18'} hasBin: true - dev: false - /math-intrinsics@1.1.0: + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} - dev: false - /mdast-util-find-and-replace@3.0.2: + mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} - dependencies: - '@types/mdast': 4.0.4 - escape-string-regexp: 5.0.0 - unist-util-is: 6.0.1 - unist-util-visit-parents: 6.0.2 - dev: false - /mdast-util-from-markdown@2.0.2: + mdast-util-from-markdown@2.0.2: resolution: {integrity: sha512-uZhTV/8NBuw0WHkPTrCqDOl0zVe1BIng5ZtHoDk49ME1qqcjYmmLmOf0gELgcRMxN4w2iuIeVso5/6QymSrgmA==} - dependencies: - '@types/mdast': 4.0.4 - '@types/unist': 3.0.3 - decode-named-character-reference: 1.2.0 - devlop: 1.1.0 - mdast-util-to-string: 4.0.0 - micromark: 4.0.2 - micromark-util-decode-numeric-character-reference: 2.0.2 + + mdast-util-gfm-autolink-literal@2.0.1: + resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + + mdast-util-gfm-footnote@2.1.0: + resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + + mdast-util-gfm-strikethrough@2.0.0: + resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + + mdast-util-gfm-table@2.0.0: + resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + + mdast-util-gfm-task-list-item@2.0.0: + resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + + mdast-util-gfm@3.1.0: + resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + + mdast-util-mdx-expression@2.0.1: + resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + + mdast-util-mdx-jsx@3.2.0: + resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + + mdast-util-mdxjs-esm@2.0.1: + resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + + mdast-util-phrasing@4.1.0: + resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + + mdast-util-to-hast@13.2.1: + resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + + mdast-util-to-markdown@2.1.2: + resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + + mdast-util-to-string@4.0.0: + resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + + micromark-core-commonmark@2.0.3: + resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + + micromark-extension-gfm-autolink-literal@2.1.0: + resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + + micromark-extension-gfm-footnote@2.1.0: + resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + + micromark-extension-gfm-strikethrough@2.1.0: + resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + + micromark-extension-gfm-table@2.1.1: + resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + + micromark-extension-gfm-tagfilter@2.0.0: + resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + + micromark-extension-gfm-task-list-item@2.1.0: + resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + + micromark-extension-gfm@3.0.0: + resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + + micromark-factory-destination@2.0.1: + resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + + micromark-factory-label@2.0.1: + resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + + micromark-factory-space@2.0.1: + resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + + micromark-factory-title@2.0.1: + resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + + micromark-factory-whitespace@2.0.1: + resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + + micromark-util-character@2.1.1: + resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + + micromark-util-chunked@2.0.1: + resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + + micromark-util-classify-character@2.0.1: + resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + + micromark-util-combine-extensions@2.0.1: + resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + + micromark-util-decode-numeric-character-reference@2.0.2: + resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + + micromark-util-decode-string@2.0.1: + resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + + micromark-util-encode@2.0.1: + resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} + + micromark-util-html-tag-name@2.0.1: + resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} + + micromark-util-normalize-identifier@2.0.1: + resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + + micromark-util-resolve-all@2.0.1: + resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + + micromark-util-sanitize-uri@2.0.1: + resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + + micromark-util-subtokenize@2.1.0: + resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + + micromark-util-symbol@2.0.1: + resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} + + micromark-util-types@2.0.2: + resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} + + micromark@4.0.2: + resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + + minimatch@10.2.4: + resolution: {integrity: sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg==} + engines: {node: 18 || 20 || >=22} + + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + + minimatch@5.1.6: + resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} + engines: {node: '>=10'} + + minimatch@9.0.5: + resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} + engines: {node: '>=16 || 14 >=14.17'} + + minipass@7.1.3: + resolution: {integrity: sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==} + engines: {node: '>=16 || 14 >=14.17'} + + monaco-editor@0.55.1: + resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + + mrmime@2.0.1: + resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} + engines: {node: '>=10'} + + ms@2.1.3: + resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + + nanoid@3.3.11: + resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} + engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} + hasBin: true + + natural-compare@1.4.0: + resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} + + node-releases@2.0.27: + resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} + + normalize-range@0.1.2: + resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} + engines: {node: '>=0.10.0'} + + openapi-typescript@7.10.1: + resolution: {integrity: sha512-rBcU8bjKGGZQT4K2ekSTY2Q5veOQbVG/lTKZ49DeCyT9z62hM2Vj/LLHjDHC9W7LJG8YMHcdXpRZDqC1ojB/lw==} + hasBin: true + peerDependencies: + typescript: ^5.x + + optionator@0.9.4: + resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} + engines: {node: '>= 0.8.0'} + + p-limit@3.1.0: + resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} + engines: {node: '>=10'} + + p-locate@5.0.0: + resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} + engines: {node: '>=10'} + + package-json-from-dist@1.0.1: + resolution: {integrity: sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==} + + parent-module@1.0.1: + resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} + engines: {node: '>=6'} + + parse-entities@4.0.2: + resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + + parse-json@8.3.0: + resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} + engines: {node: '>=18'} + + parse5@7.3.0: + resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + + path-exists@4.0.0: + resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} + engines: {node: '>=8'} + + path-key@3.1.1: + resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} + engines: {node: '>=8'} + + path-scurry@1.11.1: + resolution: {integrity: sha512-Xa4Nw17FS9ApQFJ9umLiJS4orGjm7ZzwUrwamcGQuHSzDyth9boKDaycYdDcZDuqYATXw4HFXgaqWTctW/v1HA==} + engines: {node: '>=16 || 14 >=14.18'} + + pathe@2.0.3: + resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} + + pathval@2.0.1: + resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} + engines: {node: '>= 14.16'} + + picocolors@1.1.1: + resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + + picomatch@4.0.3: + resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} + engines: {node: '>=12'} + + pluralize@8.0.0: + resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} + engines: {node: '>=4'} + + postcss-value-parser@4.2.0: + resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} + + postcss@8.5.6: + resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} + engines: {node: ^10 || ^12 || >=14} + + prelude-ls@1.2.1: + resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} + engines: {node: '>= 0.8.0'} + + property-information@6.5.0: + resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} + + property-information@7.1.0: + resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} + + proxy-from-env@1.1.0: + resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + + punycode@2.3.1: + resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} + engines: {node: '>=6'} + + react-dom@19.2.0: + resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} + peerDependencies: + react: ^19.2.0 + + react-hook-form@7.66.1: + resolution: {integrity: sha512-2KnjpgG2Rhbi+CIiIBQQ9Df6sMGH5ExNyFl4Hw9qO7pIqMBR8Bvu9RQyjl3JM4vehzCh9soiNUM/xYMswb2EiA==} + engines: {node: '>=18.0.0'} + peerDependencies: + react: ^16.8.0 || ^17 || ^18 || ^19 + + react-markdown@10.1.0: + resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} + peerDependencies: + '@types/react': '>=18' + react: '>=18' + + react-refresh@0.18.0: + resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} + engines: {node: '>=0.10.0'} + + react-remove-scroll-bar@2.3.8: + resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + peerDependenciesMeta: + '@types/react': + optional: true + + react-remove-scroll@2.7.1: + resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react-router-dom@7.9.6: + resolution: {integrity: sha512-2MkC2XSXq6HjGcihnx1s0DBWQETI4mlis4Ux7YTLvP67xnGxCvq+BcCQSO81qQHVUTM1V53tl4iVVaY5sReCOA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + + react-router@7.9.6: + resolution: {integrity: sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==} + engines: {node: '>=20.0.0'} + peerDependencies: + react: '>=18' + react-dom: '>=18' + peerDependenciesMeta: + react-dom: + optional: true + + react-style-singleton@2.2.3: + resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + react@19.2.0: + resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} + engines: {node: '>=0.10.0'} + + rehype-highlight@7.0.2: + resolution: {integrity: sha512-k158pK7wdC2qL3M5NcZROZ2tR/l7zOzjxXd5VGdcfIyoijjQqpHd3JKtYSBDpDZ38UI2WJWuFAtkMDxmx5kstA==} + + rehype-raw@7.0.0: + resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + + remark-gfm@4.0.1: + resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + + remark-parse@11.0.0: + resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + + remark-rehype@11.1.2: + resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + + remark-stringify@11.0.0: + resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + + require-directory@2.1.1: + resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} + engines: {node: '>=0.10.0'} + + require-from-string@2.0.2: + resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} + engines: {node: '>=0.10.0'} + + resolve-from@4.0.0: + resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} + engines: {node: '>=4'} + + rollup@4.53.3: + resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} + engines: {node: '>=18.0.0', npm: '>=8.0.0'} + hasBin: true + + rxjs@7.8.2: + resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + + scheduler@0.27.0: + resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} + + semver@6.3.1: + resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} + hasBin: true + + semver@7.7.3: + resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} + engines: {node: '>=10'} + hasBin: true + + set-cookie-parser@2.7.2: + resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} + + shebang-command@2.0.0: + resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} + engines: {node: '>=8'} + + shebang-regex@3.0.0: + resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} + engines: {node: '>=8'} + + shell-quote@1.8.3: + resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} + engines: {node: '>= 0.4'} + + siginfo@2.0.0: + resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} + + signal-exit@4.1.0: + resolution: {integrity: sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==} + engines: {node: '>=14'} + + sirv@3.0.2: + resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} + engines: {node: '>=18'} + + sonner@2.0.7: + resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} + peerDependencies: + react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + + source-map-js@1.2.1: + resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} + engines: {node: '>=0.10.0'} + + space-separated-tokens@2.0.2: + resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} + + stackback@0.0.2: + resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} + + state-local@1.0.7: + resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} + + std-env@3.10.0: + resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} + + string-width@4.2.3: + resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} + engines: {node: '>=8'} + + string-width@5.1.2: + resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} + engines: {node: '>=12'} + + stringify-entities@4.0.4: + resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + + strip-ansi@6.0.1: + resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} + engines: {node: '>=8'} + + strip-ansi@7.2.0: + resolution: {integrity: sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==} + engines: {node: '>=12'} + + strip-json-comments@3.1.1: + resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} + engines: {node: '>=8'} + + strip-literal@3.1.0: + resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + + style-to-js@1.1.21: + resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + + supports-color@10.2.2: + resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} + engines: {node: '>=18'} + + supports-color@7.2.0: + resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} + engines: {node: '>=8'} + + supports-color@8.1.1: + resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} + engines: {node: '>=10'} + + tailwind-merge@3.4.0: + resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + + tailwindcss@4.1.17: + resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} + + tapable@2.3.0: + resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} + engines: {node: '>=6'} + + test-exclude@7.0.2: + resolution: {integrity: sha512-u9E6A+ZDYdp7a4WnarkXPZOx8Ilz46+kby6p1yZ8zsGTz9gYa6FIS7lj2oezzNKmtdyyJNNmmXDppga5GB7kSw==} + engines: {node: '>=18'} + + tinybench@2.9.0: + resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} + + tinyexec@0.3.2: + resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} + + tinyglobby@0.2.15: + resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} + engines: {node: '>=12.0.0'} + + tinypool@1.1.1: + resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} + engines: {node: ^18.0.0 || >=20.0.0} + + tinyrainbow@2.0.0: + resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} + engines: {node: '>=14.0.0'} + + tinyspy@4.0.4: + resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} + engines: {node: '>=14.0.0'} + + totalist@3.0.1: + resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} + engines: {node: '>=6'} + + tree-kill@1.2.2: + resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} + hasBin: true + + trim-lines@3.0.1: + resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} + + trough@2.2.0: + resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} + + ts-api-utils@2.1.0: + resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} + engines: {node: '>=18.12'} + peerDependencies: + typescript: '>=4.8.4' + + tslib@2.8.1: + resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + + type-check@0.4.0: + resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} + engines: {node: '>= 0.8.0'} + + type-fest@4.41.0: + resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} + engines: {node: '>=16'} + + typescript-eslint@8.48.0: + resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} + engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + typescript: '>=4.8.4 <6.0.0' + + typescript@5.9.3: + resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} + engines: {node: '>=14.17'} + hasBin: true + + undici-types@7.16.0: + resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + + unified@11.0.5: + resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + + unist-util-find-after@5.0.0: + resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + + unist-util-is@6.0.1: + resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + + unist-util-position@5.0.0: + resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + + unist-util-stringify-position@4.0.0: + resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + + unist-util-visit-parents@6.0.2: + resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + + unist-util-visit@5.0.0: + resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + + update-browserslist-db@1.1.4: + resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} + hasBin: true + peerDependencies: + browserslist: '>= 4.21.0' + + uri-js@4.4.1: + resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + + use-callback-ref@1.3.3: + resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + use-sidecar@1.1.3: + resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} + engines: {node: '>=10'} + peerDependencies: + '@types/react': '*' + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + vfile-location@5.0.3: + resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + + vfile-message@4.0.3: + resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + + vfile@6.0.3: + resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + + vite-node@3.2.4: + resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + + vite@7.2.4: + resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} + engines: {node: ^20.19.0 || >=22.12.0} + hasBin: true + peerDependencies: + '@types/node': ^20.19.0 || >=22.12.0 + jiti: '>=1.21.0' + less: ^4.0.0 + lightningcss: ^1.21.0 + sass: ^1.70.0 + sass-embedded: ^1.70.0 + stylus: '>=0.54.8' + sugarss: ^5.0.0 + terser: ^5.16.0 + tsx: ^4.8.1 + yaml: ^2.4.2 + peerDependenciesMeta: + '@types/node': + optional: true + jiti: + optional: true + less: + optional: true + lightningcss: + optional: true + sass: + optional: true + sass-embedded: + optional: true + stylus: + optional: true + sugarss: + optional: true + terser: + optional: true + tsx: + optional: true + yaml: + optional: true + + vitest@3.2.4: + resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} + engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} + hasBin: true + peerDependencies: + '@edge-runtime/vm': '*' + '@types/debug': ^4.1.12 + '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 + '@vitest/browser': 3.2.4 + '@vitest/ui': 3.2.4 + happy-dom: '*' + jsdom: '*' + peerDependenciesMeta: + '@edge-runtime/vm': + optional: true + '@types/debug': + optional: true + '@types/node': + optional: true + '@vitest/browser': + optional: true + '@vitest/ui': + optional: true + happy-dom: + optional: true + jsdom: + optional: true + + web-namespaces@2.0.1: + resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} + + which@2.0.2: + resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} + engines: {node: '>= 8'} + hasBin: true + + why-is-node-running@2.3.0: + resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} + engines: {node: '>=8'} + hasBin: true + + word-wrap@1.2.5: + resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} + engines: {node: '>=0.10.0'} + + wrap-ansi@7.0.0: + resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} + engines: {node: '>=10'} + + wrap-ansi@8.1.0: + resolution: {integrity: sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==} + engines: {node: '>=12'} + + y18n@5.0.8: + resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} + engines: {node: '>=10'} + + yallist@3.1.1: + resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} + + yaml-ast-parser@0.0.43: + resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} + + yargs-parser@21.1.1: + resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} + engines: {node: '>=12'} + + yargs@17.7.2: + resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} + engines: {node: '>=12'} + + yocto-queue@0.1.0: + resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} + engines: {node: '>=10'} + + zod@4.1.13: + resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} + + zustand@5.0.8: + resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} + engines: {node: '>=12.20.0'} + peerDependencies: + '@types/react': '>=18.0.0' + immer: '>=9.0.6' + react: '>=18.0.0' + use-sync-external-store: '>=1.2.0' + peerDependenciesMeta: + '@types/react': + optional: true + immer: + optional: true + react: + optional: true + use-sync-external-store: + optional: true + + zwitch@2.0.4: + resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} + +snapshots: + + '@ampproject/remapping@2.3.0': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@babel/code-frame@7.27.1': + dependencies: + '@babel/helper-validator-identifier': 7.28.5 + js-tokens: 4.0.0 + picocolors: 1.1.1 + + '@babel/compat-data@7.28.5': {} + + '@babel/core@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-compilation-targets': 7.27.2 + '@babel/helper-module-transforms': 7.28.3(@babel/core@7.28.5) + '@babel/helpers': 7.28.4 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/remapping': 2.3.5 + convert-source-map: 2.0.0 + debug: 4.4.3(supports-color@10.2.2) + gensync: 1.0.0-beta.2 + json5: 2.2.3 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + + '@babel/generator@7.28.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + jsesc: 3.1.0 + + '@babel/helper-compilation-targets@7.27.2': + dependencies: + '@babel/compat-data': 7.28.5 + '@babel/helper-validator-option': 7.27.1 + browserslist: 4.28.0 + lru-cache: 5.1.1 + semver: 6.3.1 + + '@babel/helper-globals@7.28.0': {} + + '@babel/helper-module-imports@7.27.1': + dependencies: + '@babel/traverse': 7.28.5 + '@babel/types': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-module-transforms@7.28.3(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-module-imports': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + '@babel/traverse': 7.28.5 + transitivePeerDependencies: + - supports-color + + '@babel/helper-plugin-utils@7.27.1': {} + + '@babel/helper-string-parser@7.27.1': {} + + '@babel/helper-validator-identifier@7.28.5': {} + + '@babel/helper-validator-option@7.27.1': {} + + '@babel/helpers@7.28.4': + dependencies: + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + + '@babel/parser@7.28.5': + dependencies: + '@babel/types': 7.28.5 + + '@babel/plugin-transform-react-jsx-self@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/plugin-transform-react-jsx-source@7.27.1(@babel/core@7.28.5)': + dependencies: + '@babel/core': 7.28.5 + '@babel/helper-plugin-utils': 7.27.1 + + '@babel/template@7.27.2': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@babel/traverse@7.28.5': + dependencies: + '@babel/code-frame': 7.27.1 + '@babel/generator': 7.28.5 + '@babel/helper-globals': 7.28.0 + '@babel/parser': 7.28.5 + '@babel/template': 7.27.2 + '@babel/types': 7.28.5 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + '@babel/types@7.28.5': + dependencies: + '@babel/helper-string-parser': 7.27.1 + '@babel/helper-validator-identifier': 7.28.5 + + '@bcoe/v8-coverage@1.0.2': {} + + '@esbuild/aix-ppc64@0.25.12': + optional: true + + '@esbuild/android-arm64@0.25.12': + optional: true + + '@esbuild/android-arm@0.25.12': + optional: true + + '@esbuild/android-x64@0.25.12': + optional: true + + '@esbuild/darwin-arm64@0.25.12': + optional: true + + '@esbuild/darwin-x64@0.25.12': + optional: true + + '@esbuild/freebsd-arm64@0.25.12': + optional: true + + '@esbuild/freebsd-x64@0.25.12': + optional: true + + '@esbuild/linux-arm64@0.25.12': + optional: true + + '@esbuild/linux-arm@0.25.12': + optional: true + + '@esbuild/linux-ia32@0.25.12': + optional: true + + '@esbuild/linux-loong64@0.25.12': + optional: true + + '@esbuild/linux-mips64el@0.25.12': + optional: true + + '@esbuild/linux-ppc64@0.25.12': + optional: true + + '@esbuild/linux-riscv64@0.25.12': + optional: true + + '@esbuild/linux-s390x@0.25.12': + optional: true + + '@esbuild/linux-x64@0.25.12': + optional: true + + '@esbuild/netbsd-arm64@0.25.12': + optional: true + + '@esbuild/netbsd-x64@0.25.12': + optional: true + + '@esbuild/openbsd-arm64@0.25.12': + optional: true + + '@esbuild/openbsd-x64@0.25.12': + optional: true + + '@esbuild/openharmony-arm64@0.25.12': + optional: true + + '@esbuild/sunos-x64@0.25.12': + optional: true + + '@esbuild/win32-arm64@0.25.12': + optional: true + + '@esbuild/win32-ia32@0.25.12': + optional: true + + '@esbuild/win32-x64@0.25.12': + optional: true + + '@eslint-community/eslint-utils@4.9.0(eslint@9.39.1(jiti@2.6.1))': + dependencies: + eslint: 9.39.1(jiti@2.6.1) + eslint-visitor-keys: 3.4.3 + + '@eslint-community/regexpp@4.12.2': {} + + '@eslint/config-array@0.21.1': + dependencies: + '@eslint/object-schema': 2.1.7 + debug: 4.4.3(supports-color@10.2.2) + minimatch: 3.1.2 + transitivePeerDependencies: + - supports-color + + '@eslint/config-helpers@0.4.2': + dependencies: + '@eslint/core': 0.17.0 + + '@eslint/core@0.17.0': + dependencies: + '@types/json-schema': 7.0.15 + + '@eslint/eslintrc@3.3.1': + dependencies: + ajv: 6.12.6 + debug: 4.4.3(supports-color@10.2.2) + espree: 10.4.0 + globals: 14.0.0 + ignore: 5.3.2 + import-fresh: 3.3.1 + js-yaml: 4.1.1 + minimatch: 3.1.2 + strip-json-comments: 3.1.1 + transitivePeerDependencies: + - supports-color + + '@eslint/js@9.39.1': {} + + '@eslint/object-schema@2.1.7': {} + + '@eslint/plugin-kit@0.4.1': + dependencies: + '@eslint/core': 0.17.0 + levn: 0.4.1 + + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/react-dom@2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/dom': 1.7.4 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@floating-ui/utils@0.2.10': {} + + '@hono/node-server@1.19.6(hono@4.10.6)': + dependencies: + hono: 4.10.6 + + '@hookform/resolvers@5.2.2(react-hook-form@7.66.1(react@19.2.0))': + dependencies: + '@standard-schema/utils': 0.3.0 + react-hook-form: 7.66.1(react@19.2.0) + + '@humanfs/core@0.19.1': {} + + '@humanfs/node@0.16.7': + dependencies: + '@humanfs/core': 0.19.1 + '@humanwhocodes/retry': 0.4.3 + + '@humanwhocodes/module-importer@1.0.1': {} + + '@humanwhocodes/retry@0.4.3': {} + + '@isaacs/cliui@8.0.2': + dependencies: + string-width: 5.1.2 + string-width-cjs: string-width@4.2.3 + strip-ansi: 7.2.0 + strip-ansi-cjs: strip-ansi@6.0.1 + wrap-ansi: 8.1.0 + wrap-ansi-cjs: wrap-ansi@7.0.0 + + '@istanbuljs/schema@0.1.3': {} + + '@jridgewell/gen-mapping@0.3.13': + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/remapping@2.3.5': + dependencies: + '@jridgewell/gen-mapping': 0.3.13 + '@jridgewell/trace-mapping': 0.3.31 + + '@jridgewell/resolve-uri@3.1.2': {} + + '@jridgewell/sourcemap-codec@1.5.5': {} + + '@jridgewell/trace-mapping@0.3.31': + dependencies: + '@jridgewell/resolve-uri': 3.1.2 + '@jridgewell/sourcemap-codec': 1.5.5 + + '@monaco-editor/loader@1.7.0': + dependencies: + state-local: 1.0.7 + + '@monaco-editor/react@4.7.0(monaco-editor@0.55.1)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@monaco-editor/loader': 1.7.0 + monaco-editor: 0.55.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + + '@pkgjs/parseargs@0.11.0': + optional: true + + '@polka/url@1.0.0-next.29': {} + + '@radix-ui/number@1.1.1': {} + + '@radix-ui/primitive@1.1.3': {} + + '@radix-ui/react-arrow@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-checkbox@1.3.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-collection@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-compose-refs@1.1.2(@types/react@19.2.7)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-context@1.1.2(@types/react@19.2.7)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-dialog@1.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-direction@1.1.1(@types/react@19.2.7)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-dismissable-layer@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-escape-keydown': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-dropdown-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-menu': 2.1.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-focus-guards@1.1.3(@types/react@19.2.7)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-focus-scope@1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-id@1.1.1(@types/react@19.2.7)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-label@2.1.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-menu@2.1.16(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-popper@1.2.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@floating-ui/react-dom': 2.1.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-arrow': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-rect': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/rect': 1.1.1 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-portal@1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-presence@1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-primitive@2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-primitive@2.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-slot': 1.2.4(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-roving-focus@1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-select@2.2.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-dismissable-layer': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-focus-guards': 1.1.3(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-focus-scope': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-popper': 1.2.8(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-portal': 1.1.9(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-slot': 1.2.3(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-visually-hidden': 1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + aria-hidden: 1.2.6 + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + react-remove-scroll: 2.7.1(@types/react@19.2.7)(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-slider@1.3.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/number': 1.1.1 + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-collection': 1.1.7(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-slot@1.2.3(@types/react@19.2.7)(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-slot@1.2.4(@types/react@19.2.7)(react@19.2.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-switch@1.2.6(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-previous': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-size': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-tabs@1.1.13(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/primitive': 1.1.3 + '@radix-ui/react-context': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-direction': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-presence': 1.1.5(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-roving-focus': 1.1.11(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-use-controllable-state': 1.2.2(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/react-use-callback-ref@1.1.1(@types/react@19.2.7)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-use-controllable-state@1.2.2(@types/react@19.2.7)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-effect-event': 0.0.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-use-effect-event@0.0.2(@types/react@19.2.7)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-use-escape-keydown@1.1.1(@types/react@19.2.7)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-callback-ref': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-use-layout-effect@1.1.1(@types/react@19.2.7)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-use-previous@1.1.1(@types/react@19.2.7)(react@19.2.0)': + dependencies: + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-use-rect@1.1.1(@types/react@19.2.7)(react@19.2.0)': + dependencies: + '@radix-ui/rect': 1.1.1 + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-use-size@1.1.1(@types/react@19.2.7)(react@19.2.0)': + dependencies: + '@radix-ui/react-use-layout-effect': 1.1.1(@types/react@19.2.7)(react@19.2.0) + react: 19.2.0 + optionalDependencies: + '@types/react': 19.2.7 + + '@radix-ui/react-visually-hidden@1.2.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0)': + dependencies: + '@radix-ui/react-primitive': 2.1.3(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + optionalDependencies: + '@types/react': 19.2.7 + '@types/react-dom': 19.2.3(@types/react@19.2.7) + + '@radix-ui/rect@1.1.1': {} + + '@redocly/ajv@8.17.1': + dependencies: + fast-deep-equal: 3.1.3 + fast-uri: 3.1.0 + json-schema-traverse: 1.0.0 + require-from-string: 2.0.2 + + '@redocly/config@0.22.2': {} + + '@redocly/openapi-core@1.34.5(supports-color@10.2.2)': + dependencies: + '@redocly/ajv': 8.17.1 + '@redocly/config': 0.22.2 + colorette: 1.4.0 + https-proxy-agent: 7.0.6(supports-color@10.2.2) + js-levenshtein: 1.1.6 + js-yaml: 4.1.1 + minimatch: 5.1.6 + pluralize: 8.0.0 + yaml-ast-parser: 0.0.43 + transitivePeerDependencies: + - supports-color + + '@rolldown/pluginutils@1.0.0-beta.47': {} + + '@rollup/rollup-android-arm-eabi@4.53.3': + optional: true + + '@rollup/rollup-android-arm64@4.53.3': + optional: true + + '@rollup/rollup-darwin-arm64@4.53.3': + optional: true + + '@rollup/rollup-darwin-x64@4.53.3': + optional: true + + '@rollup/rollup-freebsd-arm64@4.53.3': + optional: true + + '@rollup/rollup-freebsd-x64@4.53.3': + optional: true + + '@rollup/rollup-linux-arm-gnueabihf@4.53.3': + optional: true + + '@rollup/rollup-linux-arm-musleabihf@4.53.3': + optional: true + + '@rollup/rollup-linux-arm64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-arm64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-loong64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-ppc64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-riscv64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-riscv64-musl@4.53.3': + optional: true + + '@rollup/rollup-linux-s390x-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-x64-gnu@4.53.3': + optional: true + + '@rollup/rollup-linux-x64-musl@4.53.3': + optional: true + + '@rollup/rollup-openharmony-arm64@4.53.3': + optional: true + + '@rollup/rollup-win32-arm64-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-ia32-msvc@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-gnu@4.53.3': + optional: true + + '@rollup/rollup-win32-x64-msvc@4.53.3': + optional: true + + '@standard-schema/utils@0.3.0': {} + + '@tailwindcss/node@4.1.17': + dependencies: + '@jridgewell/remapping': 2.3.5 + enhanced-resolve: 5.18.3 + jiti: 2.6.1 + lightningcss: 1.30.2 + magic-string: 0.30.21 + source-map-js: 1.2.1 + tailwindcss: 4.1.17 + + '@tailwindcss/oxide-android-arm64@4.1.17': + optional: true + + '@tailwindcss/oxide-darwin-arm64@4.1.17': + optional: true + + '@tailwindcss/oxide-darwin-x64@4.1.17': + optional: true + + '@tailwindcss/oxide-freebsd-x64@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm-gnueabihf@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm64-gnu@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-arm64-musl@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-x64-gnu@4.1.17': + optional: true + + '@tailwindcss/oxide-linux-x64-musl@4.1.17': + optional: true + + '@tailwindcss/oxide-wasm32-wasi@4.1.17': + optional: true + + '@tailwindcss/oxide-win32-arm64-msvc@4.1.17': + optional: true + + '@tailwindcss/oxide-win32-x64-msvc@4.1.17': + optional: true + + '@tailwindcss/oxide@4.1.17': + optionalDependencies: + '@tailwindcss/oxide-android-arm64': 4.1.17 + '@tailwindcss/oxide-darwin-arm64': 4.1.17 + '@tailwindcss/oxide-darwin-x64': 4.1.17 + '@tailwindcss/oxide-freebsd-x64': 4.1.17 + '@tailwindcss/oxide-linux-arm-gnueabihf': 4.1.17 + '@tailwindcss/oxide-linux-arm64-gnu': 4.1.17 + '@tailwindcss/oxide-linux-arm64-musl': 4.1.17 + '@tailwindcss/oxide-linux-x64-gnu': 4.1.17 + '@tailwindcss/oxide-linux-x64-musl': 4.1.17 + '@tailwindcss/oxide-wasm32-wasi': 4.1.17 + '@tailwindcss/oxide-win32-arm64-msvc': 4.1.17 + '@tailwindcss/oxide-win32-x64-msvc': 4.1.17 + + '@tailwindcss/vite@4.1.17(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@tailwindcss/node': 4.1.17 + '@tailwindcss/oxide': 4.1.17 + tailwindcss: 4.1.17 + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2) + + '@tanstack/query-core@5.90.11': {} + + '@tanstack/react-query@5.90.11(react@19.2.0)': + dependencies: + '@tanstack/query-core': 5.90.11 + react: 19.2.0 + + '@types/babel__core@7.20.5': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + '@types/babel__generator': 7.27.0 + '@types/babel__template': 7.4.4 + '@types/babel__traverse': 7.28.0 + + '@types/babel__generator@7.27.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/babel__template@7.4.4': + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + + '@types/babel__traverse@7.28.0': + dependencies: + '@babel/types': 7.28.5 + + '@types/better-sqlite3@7.6.13': + dependencies: + '@types/node': 24.10.1 + + '@types/bun@1.3.11': + dependencies: + bun-types: 1.3.11 + + '@types/chai@5.2.3': + dependencies: + '@types/deep-eql': 4.0.2 + assertion-error: 2.0.1 + + '@types/debug@4.1.12': + dependencies: + '@types/ms': 2.1.0 + + '@types/deep-eql@4.0.2': {} + + '@types/estree-jsx@1.0.5': + dependencies: + '@types/estree': 1.0.8 + + '@types/estree@1.0.8': {} + + '@types/hast@3.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/json-schema@7.0.15': {} + + '@types/mdast@4.0.4': + dependencies: + '@types/unist': 3.0.3 + + '@types/ms@2.1.0': {} + + '@types/node@24.10.1': + dependencies: + undici-types: 7.16.0 + + '@types/react-dom@19.2.3(@types/react@19.2.7)': + dependencies: + '@types/react': 19.2.7 + + '@types/react@19.2.7': + dependencies: + csstype: 3.2.3 + + '@types/trusted-types@2.0.7': + optional: true + + '@types/unist@2.0.11': {} + + '@types/unist@3.0.3': {} + + '@typescript-eslint/eslint-plugin@8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/regexpp': 4.12.2 + '@typescript-eslint/parser': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/type-utils': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.48.0 + eslint: 9.39.1(jiti@2.6.1) + graphemer: 1.4.0 + ignore: 7.0.5 + natural-compare: 1.4.0 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + '@typescript-eslint/visitor-keys': 8.48.0 + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/project-service@8.48.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 + debug: 4.4.3(supports-color@10.2.2) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/scope-manager@8.48.0': + dependencies: + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/visitor-keys': 8.48.0 + + '@typescript-eslint/tsconfig-utils@8.48.0(typescript@5.9.3)': + dependencies: + typescript: 5.9.3 + + '@typescript-eslint/type-utils@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + debug: 4.4.3(supports-color@10.2.2) + eslint: 9.39.1(jiti@2.6.1) + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/types@8.48.0': {} + + '@typescript-eslint/typescript-estree@8.48.0(typescript@5.9.3)': + dependencies: + '@typescript-eslint/project-service': 8.48.0(typescript@5.9.3) + '@typescript-eslint/tsconfig-utils': 8.48.0(typescript@5.9.3) + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/visitor-keys': 8.48.0 + debug: 4.4.3(supports-color@10.2.2) + minimatch: 9.0.5 + semver: 7.7.3 + tinyglobby: 0.2.15 + ts-api-utils: 2.1.0(typescript@5.9.3) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/utils@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3)': + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@typescript-eslint/scope-manager': 8.48.0 + '@typescript-eslint/types': 8.48.0 + '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) + typescript: 5.9.3 + transitivePeerDependencies: + - supports-color + + '@typescript-eslint/visitor-keys@8.48.0': + dependencies: + '@typescript-eslint/types': 8.48.0 + eslint-visitor-keys: 4.2.1 + + '@ungap/structured-clone@1.3.0': {} + + '@vitejs/plugin-react@5.1.1(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@babel/core': 7.28.5 + '@babel/plugin-transform-react-jsx-self': 7.27.1(@babel/core@7.28.5) + '@babel/plugin-transform-react-jsx-source': 7.27.1(@babel/core@7.28.5) + '@rolldown/pluginutils': 1.0.0-beta.47 + '@types/babel__core': 7.20.5 + react-refresh: 0.18.0 + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2) + transitivePeerDependencies: + - supports-color + + '@vitest/coverage-v8@3.2.4(vitest@3.2.4)': + dependencies: + '@ampproject/remapping': 2.3.0 + '@bcoe/v8-coverage': 1.0.2 + ast-v8-to-istanbul: 0.3.12 + debug: 4.4.3(supports-color@10.2.2) + istanbul-lib-coverage: 3.2.2 + istanbul-lib-report: 3.0.1 + istanbul-lib-source-maps: 5.0.6 + istanbul-reports: 3.2.0 + magic-string: 0.30.21 + magicast: 0.3.5 + std-env: 3.10.0 + test-exclude: 7.0.2 + tinyrainbow: 2.0.0 + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/ui@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2) + transitivePeerDependencies: + - supports-color + + '@vitest/expect@3.2.4': + dependencies: + '@types/chai': 5.2.3 + '@vitest/spy': 3.2.4 + '@vitest/utils': 3.2.4 + chai: 5.3.3 + tinyrainbow: 2.0.0 + + '@vitest/mocker@3.2.4(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2))': + dependencies: + '@vitest/spy': 3.2.4 + estree-walker: 3.0.3 + magic-string: 0.30.21 + optionalDependencies: + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2) + + '@vitest/pretty-format@3.2.4': + dependencies: + tinyrainbow: 2.0.0 + + '@vitest/runner@3.2.4': + dependencies: + '@vitest/utils': 3.2.4 + pathe: 2.0.3 + strip-literal: 3.1.0 + + '@vitest/snapshot@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + magic-string: 0.30.21 + pathe: 2.0.3 + + '@vitest/spy@3.2.4': + dependencies: + tinyspy: 4.0.4 + + '@vitest/ui@3.2.4(vitest@3.2.4)': + dependencies: + '@vitest/utils': 3.2.4 + fflate: 0.8.2 + flatted: 3.3.3 + pathe: 2.0.3 + sirv: 3.0.2 + tinyglobby: 0.2.15 + tinyrainbow: 2.0.0 + vitest: 3.2.4(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/ui@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2) + + '@vitest/utils@3.2.4': + dependencies: + '@vitest/pretty-format': 3.2.4 + loupe: 3.2.1 + tinyrainbow: 2.0.0 + + acorn-jsx@5.3.2(acorn@8.15.0): + dependencies: + acorn: 8.15.0 + + acorn@8.15.0: {} + + agent-base@7.1.4: {} + + ajv@6.12.6: + dependencies: + fast-deep-equal: 3.1.3 + fast-json-stable-stringify: 2.1.0 + json-schema-traverse: 0.4.1 + uri-js: 4.4.1 + + ansi-colors@4.1.3: {} + + ansi-regex@5.0.1: {} + + ansi-regex@6.2.2: {} + + ansi-styles@4.3.0: + dependencies: + color-convert: 2.0.1 + + ansi-styles@6.2.3: {} + + argparse@2.0.1: {} + + aria-hidden@1.2.6: + dependencies: + tslib: 2.8.1 + + assertion-error@2.0.1: {} + + ast-v8-to-istanbul@0.3.12: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + estree-walker: 3.0.3 + js-tokens: 10.0.0 + + asynckit@0.4.0: {} + + autoprefixer@10.4.22(postcss@8.5.6): + dependencies: + browserslist: 4.28.0 + caniuse-lite: 1.0.30001757 + fraction.js: 5.3.4 + normalize-range: 0.1.2 + picocolors: 1.1.1 + postcss: 8.5.6 + postcss-value-parser: 4.2.0 + + axios@1.13.2: + dependencies: + follow-redirects: 1.15.11 + form-data: 4.0.5 + proxy-from-env: 1.1.0 + transitivePeerDependencies: + - debug + + bail@2.0.2: {} + + balanced-match@1.0.2: {} + + balanced-match@4.0.4: {} + + baseline-browser-mapping@2.8.31: {} + + brace-expansion@1.1.12: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + brace-expansion@2.0.2: + dependencies: + balanced-match: 1.0.2 + + brace-expansion@5.0.5: + dependencies: + balanced-match: 4.0.4 + + browserslist@4.28.0: + dependencies: + baseline-browser-mapping: 2.8.31 + caniuse-lite: 1.0.30001757 + electron-to-chromium: 1.5.260 + node-releases: 2.0.27 + update-browserslist-db: 1.1.4(browserslist@4.28.0) + + bun-types@1.3.11: + dependencies: + '@types/node': 24.10.1 + + cac@6.7.14: {} + + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + + callsites@3.1.0: {} + + caniuse-lite@1.0.30001757: {} + + ccount@2.0.1: {} + + chai@5.3.3: + dependencies: + assertion-error: 2.0.1 + check-error: 2.1.1 + deep-eql: 5.0.2 + loupe: 3.2.1 + pathval: 2.0.1 + + chalk@4.1.2: + dependencies: + ansi-styles: 4.3.0 + supports-color: 7.2.0 + + change-case@5.4.4: {} + + character-entities-html4@2.1.0: {} + + character-entities-legacy@3.0.0: {} + + character-entities@2.0.2: {} + + character-reference-invalid@2.0.1: {} + + check-error@2.1.1: {} + + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + + cliui@8.0.1: + dependencies: + string-width: 4.2.3 + strip-ansi: 6.0.1 + wrap-ansi: 7.0.0 + + clsx@2.1.1: {} + + cmdk@1.1.1(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0): + dependencies: + '@radix-ui/react-compose-refs': 1.1.2(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-dialog': 1.1.15(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + '@radix-ui/react-id': 1.1.1(@types/react@19.2.7)(react@19.2.0) + '@radix-ui/react-primitive': 2.1.4(@types/react-dom@19.2.3(@types/react@19.2.7))(@types/react@19.2.7)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + react: 19.2.0 + react-dom: 19.2.0(react@19.2.0) + transitivePeerDependencies: + - '@types/react' + - '@types/react-dom' + + color-convert@2.0.1: + dependencies: + color-name: 1.1.4 + + color-name@1.1.4: {} + + colorette@1.4.0: {} + + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + + comma-separated-tokens@2.0.3: {} + + concat-map@0.0.1: {} + + concurrently@9.2.1: + dependencies: + chalk: 4.1.2 + rxjs: 7.8.2 + shell-quote: 1.8.3 + supports-color: 8.1.1 + tree-kill: 1.2.2 + yargs: 17.7.2 + + convert-source-map@2.0.0: {} + + cookie@1.0.2: {} + + cross-spawn@7.0.6: + dependencies: + path-key: 3.1.1 + shebang-command: 2.0.0 + which: 2.0.2 + + csstype@3.2.3: {} + + date-fns@4.1.0: {} + + debug@4.4.3(supports-color@10.2.2): + dependencies: + ms: 2.1.3 + optionalDependencies: + supports-color: 10.2.2 + + decode-named-character-reference@1.2.0: + dependencies: + character-entities: 2.0.2 + + deep-eql@5.0.2: {} + + deep-is@0.1.4: {} + + delayed-stream@1.0.0: {} + + dequal@2.0.3: {} + + detect-libc@2.1.2: {} + + detect-node-es@1.1.0: {} + + devlop@1.1.0: + dependencies: + dequal: 2.0.3 + + diff@8.0.2: {} + + dompurify@3.2.7: + optionalDependencies: + '@types/trusted-types': 2.0.7 + + dotenv@17.2.3: {} + + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + + eastasianwidth@0.2.0: {} + + electron-to-chromium@1.5.260: {} + + emoji-regex@8.0.0: {} + + emoji-regex@9.2.2: {} + + enhanced-resolve@5.18.3: + dependencies: + graceful-fs: 4.2.11 + tapable: 2.3.0 + + entities@6.0.1: {} + + es-define-property@1.0.1: {} + + es-errors@1.3.0: {} + + es-module-lexer@1.7.0: {} + + es-object-atoms@1.1.1: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.2 + + esbuild@0.25.12: + optionalDependencies: + '@esbuild/aix-ppc64': 0.25.12 + '@esbuild/android-arm': 0.25.12 + '@esbuild/android-arm64': 0.25.12 + '@esbuild/android-x64': 0.25.12 + '@esbuild/darwin-arm64': 0.25.12 + '@esbuild/darwin-x64': 0.25.12 + '@esbuild/freebsd-arm64': 0.25.12 + '@esbuild/freebsd-x64': 0.25.12 + '@esbuild/linux-arm': 0.25.12 + '@esbuild/linux-arm64': 0.25.12 + '@esbuild/linux-ia32': 0.25.12 + '@esbuild/linux-loong64': 0.25.12 + '@esbuild/linux-mips64el': 0.25.12 + '@esbuild/linux-ppc64': 0.25.12 + '@esbuild/linux-riscv64': 0.25.12 + '@esbuild/linux-s390x': 0.25.12 + '@esbuild/linux-x64': 0.25.12 + '@esbuild/netbsd-arm64': 0.25.12 + '@esbuild/netbsd-x64': 0.25.12 + '@esbuild/openbsd-arm64': 0.25.12 + '@esbuild/openbsd-x64': 0.25.12 + '@esbuild/openharmony-arm64': 0.25.12 + '@esbuild/sunos-x64': 0.25.12 + '@esbuild/win32-arm64': 0.25.12 + '@esbuild/win32-ia32': 0.25.12 + '@esbuild/win32-x64': 0.25.12 + + escalade@3.2.0: {} + + escape-string-regexp@4.0.0: {} + + escape-string-regexp@5.0.0: {} + + eslint-plugin-react-hooks@5.2.0(eslint@9.39.1(jiti@2.6.1)): + dependencies: + eslint: 9.39.1(jiti@2.6.1) + + eslint-plugin-react-refresh@0.4.24(eslint@9.39.1(jiti@2.6.1)): + dependencies: + eslint: 9.39.1(jiti@2.6.1) + + eslint-scope@8.4.0: + dependencies: + esrecurse: 4.3.0 + estraverse: 5.3.0 + + eslint-visitor-keys@3.4.3: {} + + eslint-visitor-keys@4.2.1: {} + + eslint@9.39.1(jiti@2.6.1): + dependencies: + '@eslint-community/eslint-utils': 4.9.0(eslint@9.39.1(jiti@2.6.1)) + '@eslint-community/regexpp': 4.12.2 + '@eslint/config-array': 0.21.1 + '@eslint/config-helpers': 0.4.2 + '@eslint/core': 0.17.0 + '@eslint/eslintrc': 3.3.1 + '@eslint/js': 9.39.1 + '@eslint/plugin-kit': 0.4.1 + '@humanfs/node': 0.16.7 + '@humanwhocodes/module-importer': 1.0.1 + '@humanwhocodes/retry': 0.4.3 + '@types/estree': 1.0.8 + ajv: 6.12.6 + chalk: 4.1.2 + cross-spawn: 7.0.6 + debug: 4.4.3(supports-color@10.2.2) + escape-string-regexp: 4.0.0 + eslint-scope: 8.4.0 + eslint-visitor-keys: 4.2.1 + espree: 10.4.0 + esquery: 1.6.0 + esutils: 2.0.3 + fast-deep-equal: 3.1.3 + file-entry-cache: 8.0.0 + find-up: 5.0.0 + glob-parent: 6.0.2 + ignore: 5.3.2 + imurmurhash: 0.1.4 + is-glob: 4.0.3 + json-stable-stringify-without-jsonify: 1.0.1 + lodash.merge: 4.6.2 + minimatch: 3.1.2 + natural-compare: 1.4.0 + optionator: 0.9.4 + optionalDependencies: + jiti: 2.6.1 + transitivePeerDependencies: + - supports-color + + espree@10.4.0: + dependencies: + acorn: 8.15.0 + acorn-jsx: 5.3.2(acorn@8.15.0) + eslint-visitor-keys: 4.2.1 + + esquery@1.6.0: + dependencies: + estraverse: 5.3.0 + + esrecurse@4.3.0: + dependencies: + estraverse: 5.3.0 + + estraverse@5.3.0: {} + + estree-util-is-identifier-name@3.0.0: {} + + estree-walker@3.0.3: + dependencies: + '@types/estree': 1.0.8 + + esutils@2.0.3: {} + + expect-type@1.2.2: {} + + extend@3.0.2: {} + + fast-deep-equal@3.1.3: {} + + fast-json-stable-stringify@2.1.0: {} + + fast-levenshtein@2.0.6: {} + + fast-uri@3.1.0: {} + + fdir@6.5.0(picomatch@4.0.3): + optionalDependencies: + picomatch: 4.0.3 + + fflate@0.8.2: {} + + file-entry-cache@8.0.0: + dependencies: + flat-cache: 4.0.1 + + find-up@5.0.0: + dependencies: + locate-path: 6.0.0 + path-exists: 4.0.0 + + flat-cache@4.0.1: + dependencies: + flatted: 3.3.3 + keyv: 4.5.4 + + flatted@3.3.3: {} + + follow-redirects@1.15.11: {} + + foreground-child@3.3.1: + dependencies: + cross-spawn: 7.0.6 + signal-exit: 4.1.0 + + form-data@4.0.5: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.2 + mime-types: 2.1.35 + + fraction.js@5.3.4: {} + + fsevents@2.3.3: + optional: true + + function-bind@1.1.2: {} + + gensync@1.0.0-beta.2: {} + + get-caller-file@2.0.5: {} + + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.1 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.2 + math-intrinsics: 1.1.0 + + get-nonce@1.0.1: {} + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.1 + + glob-parent@6.0.2: + dependencies: + is-glob: 4.0.3 + + glob@10.5.0: + dependencies: + foreground-child: 3.3.1 + jackspeak: 3.4.3 + minimatch: 9.0.5 + minipass: 7.1.3 + package-json-from-dist: 1.0.1 + path-scurry: 1.11.1 + + globals@14.0.0: {} + + globals@16.5.0: {} + + gopd@1.2.0: {} + + graceful-fs@4.2.11: {} + + graphemer@1.4.0: {} + + has-flag@4.0.0: {} + + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + + hasown@2.0.2: + dependencies: + function-bind: 1.1.2 + + hast-util-from-parse5@8.0.3: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + devlop: 1.1.0 + hastscript: 9.0.1 + property-information: 7.1.0 + vfile: 6.0.3 + vfile-location: 5.0.3 + web-namespaces: 2.0.1 + + hast-util-is-element@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-parse-selector@4.0.0: + dependencies: + '@types/hast': 3.0.4 + + hast-util-raw@9.1.0: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + '@ungap/structured-clone': 1.3.0 + hast-util-from-parse5: 8.0.3 + hast-util-to-parse5: 8.0.0 + html-void-elements: 3.0.0 + mdast-util-to-hast: 13.2.1 + parse5: 7.3.0 + unist-util-position: 5.0.0 + unist-util-visit: 5.0.0 + vfile: 6.0.3 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-jsx-runtime@2.3.6: + dependencies: + '@types/estree': 1.0.8 + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + estree-util-is-identifier-name: 3.0.0 + hast-util-whitespace: 3.0.0 + mdast-util-mdx-expression: 2.0.1 + mdast-util-mdx-jsx: 3.2.0 + mdast-util-mdxjs-esm: 2.0.1 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + style-to-js: 1.1.21 + unist-util-position: 5.0.0 + vfile-message: 4.0.3 + transitivePeerDependencies: + - supports-color + + hast-util-to-parse5@8.0.0: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + devlop: 1.1.0 + property-information: 6.5.0 + space-separated-tokens: 2.0.2 + web-namespaces: 2.0.1 + zwitch: 2.0.4 + + hast-util-to-text@4.0.2: + dependencies: + '@types/hast': 3.0.4 + '@types/unist': 3.0.3 + hast-util-is-element: 3.0.0 + unist-util-find-after: 5.0.0 + + hast-util-whitespace@3.0.0: + dependencies: + '@types/hast': 3.0.4 + + hastscript@9.0.1: + dependencies: + '@types/hast': 3.0.4 + comma-separated-tokens: 2.0.3 + hast-util-parse-selector: 4.0.0 + property-information: 7.1.0 + space-separated-tokens: 2.0.2 + + highlight.js@11.11.1: {} + + hono@4.10.6: {} + + html-escaper@2.0.2: {} + + html-url-attributes@3.0.1: {} + + html-void-elements@3.0.0: {} + + https-proxy-agent@7.0.6(supports-color@10.2.2): + dependencies: + agent-base: 7.1.4 + debug: 4.4.3(supports-color@10.2.2) + transitivePeerDependencies: + - supports-color + + ignore@5.3.2: {} + + ignore@7.0.5: {} + + import-fresh@3.3.1: + dependencies: + parent-module: 1.0.1 + resolve-from: 4.0.0 + + imurmurhash@0.1.4: {} + + index-to-position@1.2.0: {} + + inline-style-parser@0.2.7: {} + + is-alphabetical@2.0.1: {} + + is-alphanumerical@2.0.1: + dependencies: + is-alphabetical: 2.0.1 + is-decimal: 2.0.1 + + is-decimal@2.0.1: {} + + is-extglob@2.1.1: {} + + is-fullwidth-code-point@3.0.0: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-hexadecimal@2.0.1: {} + + is-plain-obj@4.1.0: {} + + isexe@2.0.0: {} + + istanbul-lib-coverage@3.2.2: {} + + istanbul-lib-report@3.0.1: + dependencies: + istanbul-lib-coverage: 3.2.2 + make-dir: 4.0.0 + supports-color: 7.2.0 + + istanbul-lib-source-maps@5.0.6: + dependencies: + '@jridgewell/trace-mapping': 0.3.31 + debug: 4.4.3(supports-color@10.2.2) + istanbul-lib-coverage: 3.2.2 + transitivePeerDependencies: + - supports-color + + istanbul-reports@3.2.0: + dependencies: + html-escaper: 2.0.2 + istanbul-lib-report: 3.0.1 + + jackspeak@3.4.3: + dependencies: + '@isaacs/cliui': 8.0.2 + optionalDependencies: + '@pkgjs/parseargs': 0.11.0 + + jiti@2.6.1: {} + + js-levenshtein@1.1.6: {} + + js-tokens@10.0.0: {} + + js-tokens@4.0.0: {} + + js-tokens@9.0.1: {} + + js-yaml@4.1.1: + dependencies: + argparse: 2.0.1 + + jsesc@3.1.0: {} + + json-buffer@3.0.1: {} + + json-schema-traverse@0.4.1: {} + + json-schema-traverse@1.0.0: {} + + json-stable-stringify-without-jsonify@1.0.1: {} + + json5@2.2.3: {} + + keyv@4.5.4: + dependencies: + json-buffer: 3.0.1 + + levn@0.4.1: + dependencies: + prelude-ls: 1.2.1 + type-check: 0.4.0 + + lightningcss-android-arm64@1.30.2: + optional: true + + lightningcss-darwin-arm64@1.30.2: + optional: true + + lightningcss-darwin-x64@1.30.2: + optional: true + + lightningcss-freebsd-x64@1.30.2: + optional: true + + lightningcss-linux-arm-gnueabihf@1.30.2: + optional: true + + lightningcss-linux-arm64-gnu@1.30.2: + optional: true + + lightningcss-linux-arm64-musl@1.30.2: + optional: true + + lightningcss-linux-x64-gnu@1.30.2: + optional: true + + lightningcss-linux-x64-musl@1.30.2: + optional: true + + lightningcss-win32-arm64-msvc@1.30.2: + optional: true + + lightningcss-win32-x64-msvc@1.30.2: + optional: true + + lightningcss@1.30.2: + dependencies: + detect-libc: 2.1.2 + optionalDependencies: + lightningcss-android-arm64: 1.30.2 + lightningcss-darwin-arm64: 1.30.2 + lightningcss-darwin-x64: 1.30.2 + lightningcss-freebsd-x64: 1.30.2 + lightningcss-linux-arm-gnueabihf: 1.30.2 + lightningcss-linux-arm64-gnu: 1.30.2 + lightningcss-linux-arm64-musl: 1.30.2 + lightningcss-linux-x64-gnu: 1.30.2 + lightningcss-linux-x64-musl: 1.30.2 + lightningcss-win32-arm64-msvc: 1.30.2 + lightningcss-win32-x64-msvc: 1.30.2 + + locate-path@6.0.0: + dependencies: + p-locate: 5.0.0 + + lodash.merge@4.6.2: {} + + longest-streak@3.1.0: {} + + loupe@3.2.1: {} + + lowlight@3.3.0: + dependencies: + '@types/hast': 3.0.4 + devlop: 1.1.0 + highlight.js: 11.11.1 + + lru-cache@10.4.3: {} + + lru-cache@5.1.1: + dependencies: + yallist: 3.1.1 + + lucide-react@0.546.0(react@19.2.0): + dependencies: + react: 19.2.0 + + magic-string@0.30.21: + dependencies: + '@jridgewell/sourcemap-codec': 1.5.5 + + magicast@0.3.5: + dependencies: + '@babel/parser': 7.28.5 + '@babel/types': 7.28.5 + source-map-js: 1.2.1 + + make-dir@4.0.0: + dependencies: + semver: 7.7.3 + + markdown-table@3.0.4: {} + + marked@14.0.0: {} + + math-intrinsics@1.1.0: {} + + mdast-util-find-and-replace@3.0.2: + dependencies: + '@types/mdast': 4.0.4 + escape-string-regexp: 5.0.0 + unist-util-is: 6.0.1 + unist-util-visit-parents: 6.0.2 + + mdast-util-from-markdown@2.0.2: + dependencies: + '@types/mdast': 4.0.4 + '@types/unist': 3.0.3 + decode-named-character-reference: 1.2.0 + devlop: 1.1.0 + mdast-util-to-string: 4.0.0 + micromark: 4.0.2 + micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-decode-string: 2.0.1 micromark-util-normalize-identifier: 2.0.1 micromark-util-symbol: 2.0.1 @@ -3532,20 +4926,16 @@ packages: unist-util-stringify-position: 4.0.0 transitivePeerDependencies: - supports-color - dev: false - /mdast-util-gfm-autolink-literal@2.0.1: - resolution: {integrity: sha512-5HVP2MKaP6L+G6YaxPNjuL0BPrq9orG3TsrZ9YXbA3vDw/ACI4MEsnoDpn6ZNm7GnZgtAcONJyPhOP8tNJQavQ==} + mdast-util-gfm-autolink-literal@2.0.1: dependencies: '@types/mdast': 4.0.4 ccount: 2.0.1 devlop: 1.1.0 mdast-util-find-and-replace: 3.0.2 micromark-util-character: 2.1.1 - dev: false - /mdast-util-gfm-footnote@2.1.0: - resolution: {integrity: sha512-sqpDWlsHn7Ac9GNZQMeUzPQSMzR6Wv0WKRNvQRg0KqHh02fpTz69Qc1QSseNX29bhz1ROIyNyxExfawVKTm1GQ==} + mdast-util-gfm-footnote@2.1.0: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 @@ -3554,20 +4944,16 @@ packages: micromark-util-normalize-identifier: 2.0.1 transitivePeerDependencies: - supports-color - dev: false - /mdast-util-gfm-strikethrough@2.0.0: - resolution: {integrity: sha512-mKKb915TF+OC5ptj5bJ7WFRPdYtuHv0yTRxK2tJvi+BDqbkiG7h7u/9SI89nRAYcmap2xHQL9D+QG/6wSrTtXg==} + mdast-util-gfm-strikethrough@2.0.0: dependencies: '@types/mdast': 4.0.4 mdast-util-from-markdown: 2.0.2 mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - dev: false - /mdast-util-gfm-table@2.0.0: - resolution: {integrity: sha512-78UEvebzz/rJIxLvE7ZtDd/vIQ0RHv+3Mh5DR96p7cS7HsBhYIICDBCu8csTNWNO6tBWfqXPWekRuj2FNOGOZg==} + mdast-util-gfm-table@2.0.0: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 @@ -3576,10 +4962,8 @@ packages: mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - dev: false - /mdast-util-gfm-task-list-item@2.0.0: - resolution: {integrity: sha512-IrtvNvjxC1o06taBAVJznEnkiHxLFTzgonUdy8hzFVeDun0uTjxxrRGVaNFqkU1wJR3RBPEfsxmU6jDWPofrTQ==} + mdast-util-gfm-task-list-item@2.0.0: dependencies: '@types/mdast': 4.0.4 devlop: 1.1.0 @@ -3587,10 +4971,8 @@ packages: mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - dev: false - /mdast-util-gfm@3.1.0: - resolution: {integrity: sha512-0ulfdQOM3ysHhCJ1p06l0b0VKlhU0wuQs3thxZQagjcjPrlFRqY215uZGHHJan9GEAXd9MbfPjFJz+qMkVR6zQ==} + mdast-util-gfm@3.1.0: dependencies: mdast-util-from-markdown: 2.0.2 mdast-util-gfm-autolink-literal: 2.0.1 @@ -3601,10 +4983,8 @@ packages: mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - dev: false - /mdast-util-mdx-expression@2.0.1: - resolution: {integrity: sha512-J6f+9hUp+ldTZqKRSg7Vw5V6MqjATc+3E4gf3CFNcuZNWD8XdyI6zQ8GqH7f8169MM6P7hMBRDVGnn7oHB9kXQ==} + mdast-util-mdx-expression@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 @@ -3614,10 +4994,8 @@ packages: mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - dev: false - /mdast-util-mdx-jsx@3.2.0: - resolution: {integrity: sha512-lj/z8v0r6ZtsN/cGNNtemmmfoLAFZnjMbNyLzBafjzikOM+glrjNHPlf6lQDOTccj9n5b0PPihEBbhneMyGs1Q==} + mdast-util-mdx-jsx@3.2.0: dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 @@ -3633,10 +5011,8 @@ packages: vfile-message: 4.0.3 transitivePeerDependencies: - supports-color - dev: false - /mdast-util-mdxjs-esm@2.0.1: - resolution: {integrity: sha512-EcmOpxsZ96CvlP03NghtH1EsLtr0n9Tm4lPUJUBccV9RwUOneqSycg19n5HGzCf+10LozMRSObtVr3ee1WoHtg==} + mdast-util-mdxjs-esm@2.0.1: dependencies: '@types/estree-jsx': 1.0.5 '@types/hast': 3.0.4 @@ -3646,17 +5022,13 @@ packages: mdast-util-to-markdown: 2.1.2 transitivePeerDependencies: - supports-color - dev: false - /mdast-util-phrasing@4.1.0: - resolution: {integrity: sha512-TqICwyvJJpBwvGAMZjj4J2n0X8QWp21b9l0o7eXyVJ25YNWYbJDVIyD1bZXE6WtV6RmKJVYmQAKWa0zWOABz2w==} + mdast-util-phrasing@4.1.0: dependencies: '@types/mdast': 4.0.4 unist-util-is: 6.0.1 - dev: false - /mdast-util-to-hast@13.2.1: - resolution: {integrity: sha512-cctsq2wp5vTsLIcaymblUriiTcZd0CwWtCbLvrOzYCDZoWyMNV8sZ7krj09FSnsiJi3WVsHLM4k6Dq/yaPyCXA==} + mdast-util-to-hast@13.2.1: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 @@ -3667,10 +5039,8 @@ packages: unist-util-position: 5.0.0 unist-util-visit: 5.0.0 vfile: 6.0.3 - dev: false - /mdast-util-to-markdown@2.1.2: - resolution: {integrity: sha512-xj68wMTvGXVOKonmog6LwyJKrYXZPvlwabaryTjLh9LuvovB/KAH+kvi8Gjj+7rJjsFi23nkUxRQv1KqSroMqA==} + mdast-util-to-markdown@2.1.2: dependencies: '@types/mdast': 4.0.4 '@types/unist': 3.0.3 @@ -3681,16 +5051,12 @@ packages: micromark-util-decode-string: 2.0.1 unist-util-visit: 5.0.0 zwitch: 2.0.4 - dev: false - /mdast-util-to-string@4.0.0: - resolution: {integrity: sha512-0H44vDimn51F0YwvxSJSm0eCDOJTRlmN0R1yBh4HLj9wiV1Dn0QoXGbvFAWj2hSItVTlCmBF1hqKlIyUBVFLPg==} + mdast-util-to-string@4.0.0: dependencies: '@types/mdast': 4.0.4 - dev: false - /micromark-core-commonmark@2.0.3: - resolution: {integrity: sha512-RDBrHEMSxVFLg6xvnXmb1Ayr2WzLAWjeSATAoxwKYJV94TeNavgoIdA0a9ytzDSVzBy2YKFK+emCPOEibLeCrg==} + micromark-core-commonmark@2.0.3: dependencies: decode-named-character-reference: 1.2.0 devlop: 1.1.0 @@ -3708,19 +5074,15 @@ packages: micromark-util-subtokenize: 2.1.0 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-extension-gfm-autolink-literal@2.1.0: - resolution: {integrity: sha512-oOg7knzhicgQ3t4QCjCWgTmfNhvQbDDnJeVu9v81r7NltNCVmhPy1fJRX27pISafdjL+SVc4d3l48Gb6pbRypw==} + micromark-extension-gfm-autolink-literal@2.1.0: dependencies: micromark-util-character: 2.1.1 micromark-util-sanitize-uri: 2.0.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-extension-gfm-footnote@2.1.0: - resolution: {integrity: sha512-/yPhxI1ntnDNsiHtzLKYnE3vf9JZ6cAisqVDauhp4CEHxlb4uoOTxOCJ+9s51bIB8U1N1FJ1RXOKTIlD5B/gqw==} + micromark-extension-gfm-footnote@2.1.0: dependencies: devlop: 1.1.0 micromark-core-commonmark: 2.0.3 @@ -3730,10 +5092,8 @@ packages: micromark-util-sanitize-uri: 2.0.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-extension-gfm-strikethrough@2.1.0: - resolution: {integrity: sha512-ADVjpOOkjz1hhkZLlBiYA9cR2Anf8F4HqZUO6e5eDcPQd0Txw5fxLzzxnEkSkfnD0wziSGiv7sYhk/ktvbf1uw==} + micromark-extension-gfm-strikethrough@2.1.0: dependencies: devlop: 1.1.0 micromark-util-chunked: 2.0.1 @@ -3741,36 +5101,28 @@ packages: micromark-util-resolve-all: 2.0.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-extension-gfm-table@2.1.1: - resolution: {integrity: sha512-t2OU/dXXioARrC6yWfJ4hqB7rct14e8f7m0cbI5hUmDyyIlwv5vEtooptH8INkbLzOatzKuVbQmAYcbWoyz6Dg==} + micromark-extension-gfm-table@2.1.1: dependencies: devlop: 1.1.0 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-extension-gfm-tagfilter@2.0.0: - resolution: {integrity: sha512-xHlTOmuCSotIA8TW1mDIM6X2O1SiX5P9IuDtqGonFhEK0qgRI4yeC6vMxEV2dgyr2TiD+2PQ10o+cOhdVAcwfg==} + micromark-extension-gfm-tagfilter@2.0.0: dependencies: micromark-util-types: 2.0.2 - dev: false - /micromark-extension-gfm-task-list-item@2.1.0: - resolution: {integrity: sha512-qIBZhqxqI6fjLDYFTBIa4eivDMnP+OZqsNwmQ3xNLE4Cxwc+zfQEfbs6tzAo2Hjq+bh6q5F+Z8/cksrLFYWQQw==} + micromark-extension-gfm-task-list-item@2.1.0: dependencies: devlop: 1.1.0 micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-extension-gfm@3.0.0: - resolution: {integrity: sha512-vsKArQsicm7t0z2GugkCKtZehqUm31oeGBV/KVSorWSy8ZlNAv7ytjFhvaryUiCUJYqs+NoE6AFhpQvBTM6Q4w==} + micromark-extension-gfm@3.0.0: dependencies: micromark-extension-gfm-autolink-literal: 2.1.0 micromark-extension-gfm-footnote: 2.1.0 @@ -3780,140 +5132,100 @@ packages: micromark-extension-gfm-task-list-item: 2.1.0 micromark-util-combine-extensions: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-factory-destination@2.0.1: - resolution: {integrity: sha512-Xe6rDdJlkmbFRExpTOmRj9N3MaWmbAgdpSrBQvCFqhezUn4AHqJHbaEnfbVYYiexVSs//tqOdY/DxhjdCiJnIA==} + micromark-factory-destination@2.0.1: dependencies: micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-factory-label@2.0.1: - resolution: {integrity: sha512-VFMekyQExqIW7xIChcXn4ok29YE3rnuyveW3wZQWWqF4Nv9Wk5rgJ99KzPvHjkmPXF93FXIbBp6YdW3t71/7Vg==} + micromark-factory-label@2.0.1: dependencies: devlop: 1.1.0 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-factory-space@2.0.1: - resolution: {integrity: sha512-zRkxjtBxxLd2Sc0d+fbnEunsTj46SWXgXciZmHq0kDYGnck/ZSGj9/wULTV95uoeYiK5hRXP2mJ98Uo4cq/LQg==} + micromark-factory-space@2.0.1: dependencies: micromark-util-character: 2.1.1 micromark-util-types: 2.0.2 - dev: false - /micromark-factory-title@2.0.1: - resolution: {integrity: sha512-5bZ+3CjhAd9eChYTHsjy6TGxpOFSKgKKJPJxr293jTbfry2KDoWkhBb6TcPVB4NmzaPhMs1Frm9AZH7OD4Cjzw==} + micromark-factory-title@2.0.1: dependencies: micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-factory-whitespace@2.0.1: - resolution: {integrity: sha512-Ob0nuZ3PKt/n0hORHyvoD9uZhr+Za8sFoP+OnMcnWK5lngSzALgQYKMr9RJVOWLqQYuyn6ulqGWSXdwf6F80lQ==} + micromark-factory-whitespace@2.0.1: dependencies: micromark-factory-space: 2.0.1 micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-util-character@2.1.1: - resolution: {integrity: sha512-wv8tdUTJ3thSFFFJKtpYKOYiGP2+v96Hvk4Tu8KpCAsTMs6yi+nVmGh1syvSCsaxz45J6Jbw+9DD6g97+NV67Q==} + micromark-util-character@2.1.1: dependencies: micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-util-chunked@2.0.1: - resolution: {integrity: sha512-QUNFEOPELfmvv+4xiNg2sRYeS/P84pTW0TCgP5zc9FpXetHY0ab7SxKyAQCNCc1eK0459uoLI1y5oO5Vc1dbhA==} + micromark-util-chunked@2.0.1: dependencies: micromark-util-symbol: 2.0.1 - dev: false - /micromark-util-classify-character@2.0.1: - resolution: {integrity: sha512-K0kHzM6afW/MbeWYWLjoHQv1sgg2Q9EccHEDzSkxiP/EaagNzCm7T/WMKZ3rjMbvIpvBiZgwR3dKMygtA4mG1Q==} + micromark-util-classify-character@2.0.1: dependencies: micromark-util-character: 2.1.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-util-combine-extensions@2.0.1: - resolution: {integrity: sha512-OnAnH8Ujmy59JcyZw8JSbK9cGpdVY44NKgSM7E9Eh7DiLS2E9RNQf0dONaGDzEG9yjEl5hcqeIsj4hfRkLH/Bg==} + micromark-util-combine-extensions@2.0.1: dependencies: micromark-util-chunked: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-util-decode-numeric-character-reference@2.0.2: - resolution: {integrity: sha512-ccUbYk6CwVdkmCQMyr64dXz42EfHGkPQlBj5p7YVGzq8I7CtjXZJrubAYezf7Rp+bjPseiROqe7G6foFd+lEuw==} + micromark-util-decode-numeric-character-reference@2.0.2: dependencies: micromark-util-symbol: 2.0.1 - dev: false - /micromark-util-decode-string@2.0.1: - resolution: {integrity: sha512-nDV/77Fj6eH1ynwscYTOsbK7rR//Uj0bZXBwJZRfaLEJ1iGBR6kIfNmlNqaqJf649EP0F3NWNdeJi03elllNUQ==} + micromark-util-decode-string@2.0.1: dependencies: decode-named-character-reference: 1.2.0 micromark-util-character: 2.1.1 micromark-util-decode-numeric-character-reference: 2.0.2 micromark-util-symbol: 2.0.1 - dev: false - /micromark-util-encode@2.0.1: - resolution: {integrity: sha512-c3cVx2y4KqUnwopcO9b/SCdo2O67LwJJ/UyqGfbigahfegL9myoEFoDYZgkT7f36T0bLrM9hZTAaAyH+PCAXjw==} - dev: false + micromark-util-encode@2.0.1: {} - /micromark-util-html-tag-name@2.0.1: - resolution: {integrity: sha512-2cNEiYDhCWKI+Gs9T0Tiysk136SnR13hhO8yW6BGNyhOC4qYFnwF1nKfD3HFAIXA5c45RrIG1ub11GiXeYd1xA==} - dev: false + micromark-util-html-tag-name@2.0.1: {} - /micromark-util-normalize-identifier@2.0.1: - resolution: {integrity: sha512-sxPqmo70LyARJs0w2UclACPUUEqltCkJ6PhKdMIDuJ3gSf/Q+/GIe3WKl0Ijb/GyH9lOpUkRAO2wp0GVkLvS9Q==} + micromark-util-normalize-identifier@2.0.1: dependencies: micromark-util-symbol: 2.0.1 - dev: false - /micromark-util-resolve-all@2.0.1: - resolution: {integrity: sha512-VdQyxFWFT2/FGJgwQnJYbe1jjQoNTS4RjglmSjTUlpUMa95Htx9NHeYW4rGDJzbjvCsl9eLjMQwGeElsqmzcHg==} + micromark-util-resolve-all@2.0.1: dependencies: micromark-util-types: 2.0.2 - dev: false - /micromark-util-sanitize-uri@2.0.1: - resolution: {integrity: sha512-9N9IomZ/YuGGZZmQec1MbgxtlgougxTodVwDzzEouPKo3qFWvymFHWcnDi2vzV1ff6kas9ucW+o3yzJK9YB1AQ==} + micromark-util-sanitize-uri@2.0.1: dependencies: micromark-util-character: 2.1.1 micromark-util-encode: 2.0.1 micromark-util-symbol: 2.0.1 - dev: false - /micromark-util-subtokenize@2.1.0: - resolution: {integrity: sha512-XQLu552iSctvnEcgXw6+Sx75GflAPNED1qx7eBJ+wydBb2KCbRZe+NwvIEEMM83uml1+2WSXpBAcp9IUCgCYWA==} + micromark-util-subtokenize@2.1.0: dependencies: devlop: 1.1.0 micromark-util-chunked: 2.0.1 micromark-util-symbol: 2.0.1 micromark-util-types: 2.0.2 - dev: false - /micromark-util-symbol@2.0.1: - resolution: {integrity: sha512-vs5t8Apaud9N28kgCrRUdEed4UJ+wWNvicHLPxCa9ENlYuAY31M0ETy5y1vA33YoNPDFTghEbnh6efaE8h4x0Q==} - dev: false + micromark-util-symbol@2.0.1: {} - /micromark-util-types@2.0.2: - resolution: {integrity: sha512-Yw0ECSpJoViF1qTU4DC6NwtC4aWGt1EkzaQB8KPPyCRR8z9TWeV0HbEFGTO+ZY1wB22zmxnJqhPyTpOVCpeHTA==} - dev: false + micromark-util-types@2.0.2: {} - /micromark@4.0.2: - resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + micromark@4.0.2: dependencies: '@types/debug': 4.1.12 debug: 4.4.3(supports-color@10.2.2) @@ -3934,78 +5246,49 @@ packages: micromark-util-types: 2.0.2 transitivePeerDependencies: - supports-color - dev: false - /mime-db@1.52.0: - resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} - engines: {node: '>= 0.6'} - dev: false + mime-db@1.52.0: {} - /mime-types@2.1.35: - resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} - engines: {node: '>= 0.6'} + mime-types@2.1.35: dependencies: mime-db: 1.52.0 - dev: false - /minimatch@3.1.2: - resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + minimatch@10.2.4: + dependencies: + brace-expansion: 5.0.5 + + minimatch@3.1.2: dependencies: brace-expansion: 1.1.12 - dev: true - /minimatch@5.1.6: - resolution: {integrity: sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==} - engines: {node: '>=10'} + minimatch@5.1.6: dependencies: brace-expansion: 2.0.2 - dev: true - /minimatch@9.0.5: - resolution: {integrity: sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==} - engines: {node: '>=16 || 14 >=14.17'} + minimatch@9.0.5: dependencies: brace-expansion: 2.0.2 - dev: true - /monaco-editor@0.55.1: - resolution: {integrity: sha512-jz4x+TJNFHwHtwuV9vA9rMujcZRb0CEilTEwG2rRSpe/A7Jdkuj8xPKttCgOh+v/lkHy7HsZ64oj+q3xoAFl9A==} + minipass@7.1.3: {} + + monaco-editor@0.55.1: dependencies: dompurify: 3.2.7 marked: 14.0.0 - dev: false - /mrmime@2.0.1: - resolution: {integrity: sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==} - engines: {node: '>=10'} - dev: true + mrmime@2.0.1: {} - /ms@2.1.3: - resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} + ms@2.1.3: {} - /nanoid@3.3.11: - resolution: {integrity: sha512-N8SpfPUnUp1bK+PMYW8qSWdl9U+wwNWI4QKxOYDy9JAro3WMX7p2OeVRF9v+347pnakNevPmiHhNmZ2HbFA76w==} - engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} - hasBin: true + nanoid@3.3.11: {} - /natural-compare@1.4.0: - resolution: {integrity: sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==} - dev: true + natural-compare@1.4.0: {} - /node-releases@2.0.27: - resolution: {integrity: sha512-nmh3lCkYZ3grZvqcCH+fjmQ7X+H0OeZgP40OierEaAptX4XofMh5kwNbWh7lBduUzCcV/8kZ+NDLCwm2iorIlA==} - dev: true + node-releases@2.0.27: {} - /normalize-range@0.1.2: - resolution: {integrity: sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==} - engines: {node: '>=0.10.0'} - dev: true + normalize-range@0.1.2: {} - /openapi-typescript@7.10.1(typescript@5.9.3): - resolution: {integrity: sha512-rBcU8bjKGGZQT4K2ekSTY2Q5veOQbVG/lTKZ49DeCyT9z62hM2Vj/LLHjDHC9W7LJG8YMHcdXpRZDqC1ojB/lw==} - hasBin: true - peerDependencies: - typescript: ^5.x + openapi-typescript@7.10.1(typescript@5.9.3): dependencies: '@redocly/openapi-core': 1.34.5(supports-color@10.2.2) ansi-colors: 4.1.3 @@ -4014,11 +5297,8 @@ packages: supports-color: 10.2.2 typescript: 5.9.3 yargs-parser: 21.1.1 - dev: true - /optionator@0.9.4: - resolution: {integrity: sha512-6IpQ7mKUxRcZNLIObR0hz7lxsapSSIYNZJwXPGeF0mTVqGKFIXj1DQcMoT22S3ROcLyY/rz0PWaWZ9ayWmad9g==} - engines: {node: '>= 0.8.0'} + optionator@0.9.4: dependencies: deep-is: 0.1.4 fast-levenshtein: 2.0.6 @@ -4026,31 +5306,22 @@ packages: prelude-ls: 1.2.1 type-check: 0.4.0 word-wrap: 1.2.5 - dev: true - /p-limit@3.1.0: - resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} - engines: {node: '>=10'} + p-limit@3.1.0: dependencies: yocto-queue: 0.1.0 - dev: true - /p-locate@5.0.0: - resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} - engines: {node: '>=10'} + p-locate@5.0.0: dependencies: p-limit: 3.1.0 - dev: true - /parent-module@1.0.1: - resolution: {integrity: sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==} - engines: {node: '>=6'} + package-json-from-dist@1.0.1: {} + + parent-module@1.0.1: dependencies: callsites: 3.1.0 - dev: true - /parse-entities@4.0.2: - resolution: {integrity: sha512-GG2AQYWoLgL877gQIKeRPGO1xF9+eG1ujIb5soS5gPvLQ1y2o8FL90w2QWNdf9I361Mpp7726c+lj3U0qK1uGw==} + parse-entities@4.0.2: dependencies: '@types/unist': 2.0.11 character-entities-legacy: 3.0.0 @@ -4059,111 +5330,64 @@ packages: is-alphanumerical: 2.0.1 is-decimal: 2.0.1 is-hexadecimal: 2.0.1 - dev: false - /parse-json@8.3.0: - resolution: {integrity: sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==} - engines: {node: '>=18'} + parse-json@8.3.0: dependencies: '@babel/code-frame': 7.27.1 index-to-position: 1.2.0 type-fest: 4.41.0 - dev: true - /parse5@7.3.0: - resolution: {integrity: sha512-IInvU7fabl34qmi9gY8XOVxhYyMyuH2xUNpb2q8/Y+7552KlejkRvqvD19nMoUW/uQGGbqNpA6Tufu5FL5BZgw==} + parse5@7.3.0: dependencies: entities: 6.0.1 - dev: false - /path-exists@4.0.0: - resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} - engines: {node: '>=8'} - dev: true + path-exists@4.0.0: {} - /path-key@3.1.1: - resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} - engines: {node: '>=8'} - dev: true + path-key@3.1.1: {} - /pathe@2.0.3: - resolution: {integrity: sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==} - dev: true + path-scurry@1.11.1: + dependencies: + lru-cache: 10.4.3 + minipass: 7.1.3 - /pathval@2.0.1: - resolution: {integrity: sha512-//nshmD55c46FuFw26xV/xFAaB5HF9Xdap7HJBBnrKdAd6/GxDBaNA1870O79+9ueg61cZLSVc+OaFlfmObYVQ==} - engines: {node: '>= 14.16'} - dev: true + pathe@2.0.3: {} - /picocolors@1.1.1: - resolution: {integrity: sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==} + pathval@2.0.1: {} - /picomatch@4.0.3: - resolution: {integrity: sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q==} - engines: {node: '>=12'} + picocolors@1.1.1: {} - /pluralize@8.0.0: - resolution: {integrity: sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==} - engines: {node: '>=4'} - dev: true + picomatch@4.0.3: {} - /postcss-value-parser@4.2.0: - resolution: {integrity: sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==} - dev: true + pluralize@8.0.0: {} - /postcss@8.5.6: - resolution: {integrity: sha512-3Ybi1tAuwAP9s0r1UQ2J4n5Y0G05bJkpUIO0/bI9MhwmD70S5aTWbXGBwxHrelT+XM1k6dM0pk+SwNkpTRN7Pg==} - engines: {node: ^10 || ^12 || >=14} + postcss-value-parser@4.2.0: {} + + postcss@8.5.6: dependencies: nanoid: 3.3.11 picocolors: 1.1.1 source-map-js: 1.2.1 - /prelude-ls@1.2.1: - resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==} - engines: {node: '>= 0.8.0'} - dev: true + prelude-ls@1.2.1: {} - /property-information@6.5.0: - resolution: {integrity: sha512-PgTgs/BlvHxOu8QuEN7wi5A0OmXaBcHpmCSTehcs6Uuu9IkDIEo13Hy7n898RHfrQ49vKCoGeWZSaAK01nwVig==} - dev: false + property-information@6.5.0: {} - /property-information@7.1.0: - resolution: {integrity: sha512-TwEZ+X+yCJmYfL7TPUOcvBZ4QfoT5YenQiJuX//0th53DE6w0xxLEtfK3iyryQFddXuvkIk51EEgrJQ0WJkOmQ==} - dev: false + property-information@7.1.0: {} - /proxy-from-env@1.1.0: - resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} - dev: false + proxy-from-env@1.1.0: {} - /punycode@2.3.1: - resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} - engines: {node: '>=6'} - dev: true + punycode@2.3.1: {} - /react-dom@19.2.0(react@19.2.0): - resolution: {integrity: sha512-UlbRu4cAiGaIewkPyiRGJk0imDN2T3JjieT6spoL2UeSf5od4n5LB/mQ4ejmxhCFT1tYe8IvaFulzynWovsEFQ==} - peerDependencies: - react: ^19.2.0 + react-dom@19.2.0(react@19.2.0): dependencies: react: 19.2.0 scheduler: 0.27.0 - dev: false - /react-hook-form@7.66.1(react@19.2.0): - resolution: {integrity: sha512-2KnjpgG2Rhbi+CIiIBQQ9Df6sMGH5ExNyFl4Hw9qO7pIqMBR8Bvu9RQyjl3JM4vehzCh9soiNUM/xYMswb2EiA==} - engines: {node: '>=18.0.0'} - peerDependencies: - react: ^16.8.0 || ^17 || ^18 || ^19 + react-hook-form@7.66.1(react@19.2.0): dependencies: react: 19.2.0 - dev: false - /react-markdown@10.1.0(@types/react@19.2.7)(react@19.2.0): - resolution: {integrity: sha512-qKxVopLT/TyA6BX3Ue5NwabOsAzm0Q7kAPwq6L+wWDwisYs7R8vZ0nRXqq6rkueboxpkjvLGU9fWifiX/ZZFxQ==} - peerDependencies: - '@types/react': '>=18' - react: '>=18' + react-markdown@10.1.0(@types/react@19.2.7)(react@19.2.0): dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 @@ -4180,117 +5404,67 @@ packages: vfile: 6.0.3 transitivePeerDependencies: - supports-color - dev: false - /react-refresh@0.18.0: - resolution: {integrity: sha512-QgT5//D3jfjJb6Gsjxv0Slpj23ip+HtOpnNgnb2S5zU3CB26G/IDPGoy4RJB42wzFE46DRsstbW6tKHoKbhAxw==} - engines: {node: '>=0.10.0'} - dev: true + react-refresh@0.18.0: {} - /react-remove-scroll-bar@2.3.8(@types/react@19.2.7)(react@19.2.0): - resolution: {integrity: sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 - peerDependenciesMeta: - '@types/react': - optional: true + react-remove-scroll-bar@2.3.8(@types/react@19.2.7)(react@19.2.0): dependencies: - '@types/react': 19.2.7 react: 19.2.0 react-style-singleton: 2.2.3(@types/react@19.2.7)(react@19.2.0) tslib: 2.8.1 - dev: false + optionalDependencies: + '@types/react': 19.2.7 - /react-remove-scroll@2.7.1(@types/react@19.2.7)(react@19.2.0): - resolution: {integrity: sha512-HpMh8+oahmIdOuS5aFKKY6Pyog+FNaZV/XyJOq7b4YFwsFHe5yYfdbIalI4k3vU2nSDql7YskmUseHsRrJqIPA==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + react-remove-scroll@2.7.1(@types/react@19.2.7)(react@19.2.0): dependencies: - '@types/react': 19.2.7 react: 19.2.0 react-remove-scroll-bar: 2.3.8(@types/react@19.2.7)(react@19.2.0) react-style-singleton: 2.2.3(@types/react@19.2.7)(react@19.2.0) tslib: 2.8.1 use-callback-ref: 1.3.3(@types/react@19.2.7)(react@19.2.0) use-sidecar: 1.1.3(@types/react@19.2.7)(react@19.2.0) - dev: false + optionalDependencies: + '@types/react': 19.2.7 - /react-router-dom@7.9.6(react-dom@19.2.0)(react@19.2.0): - resolution: {integrity: sha512-2MkC2XSXq6HjGcihnx1s0DBWQETI4mlis4Ux7YTLvP67xnGxCvq+BcCQSO81qQHVUTM1V53tl4iVVaY5sReCOA==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: '>=18' - react-dom: '>=18' + react-router-dom@7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - react-router: 7.9.6(react-dom@19.2.0)(react@19.2.0) - dev: false + react-router: 7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0) - /react-router@7.9.6(react-dom@19.2.0)(react@19.2.0): - resolution: {integrity: sha512-Y1tUp8clYRXpfPITyuifmSoE2vncSME18uVLgaqyxh9H35JWpIfzHo+9y3Fzh5odk/jxPW29IgLgzcdwxGqyNA==} - engines: {node: '>=20.0.0'} - peerDependencies: - react: '>=18' - react-dom: '>=18' - peerDependenciesMeta: - react-dom: - optional: true + react-router@7.9.6(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: cookie: 1.0.2 react: 19.2.0 - react-dom: 19.2.0(react@19.2.0) set-cookie-parser: 2.7.2 - dev: false + optionalDependencies: + react-dom: 19.2.0(react@19.2.0) - /react-style-singleton@2.2.3(@types/react@19.2.7)(react@19.2.0): - resolution: {integrity: sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + react-style-singleton@2.2.3(@types/react@19.2.7)(react@19.2.0): dependencies: - '@types/react': 19.2.7 get-nonce: 1.0.1 react: 19.2.0 tslib: 2.8.1 - dev: false + optionalDependencies: + '@types/react': 19.2.7 - /react@19.2.0: - resolution: {integrity: sha512-tmbWg6W31tQLeB5cdIBOicJDJRR2KzXsV7uSK9iNfLWQ5bIZfxuPEHp7M8wiHyHnn0DD1i7w3Zmin0FtkrwoCQ==} - engines: {node: '>=0.10.0'} - dev: false + react@19.2.0: {} - /rehype-highlight@7.0.2: - resolution: {integrity: sha512-k158pK7wdC2qL3M5NcZROZ2tR/l7zOzjxXd5VGdcfIyoijjQqpHd3JKtYSBDpDZ38UI2WJWuFAtkMDxmx5kstA==} + rehype-highlight@7.0.2: dependencies: '@types/hast': 3.0.4 hast-util-to-text: 4.0.2 lowlight: 3.3.0 unist-util-visit: 5.0.0 vfile: 6.0.3 - dev: false - /rehype-raw@7.0.0: - resolution: {integrity: sha512-/aE8hCfKlQeA8LmyeyQvQF3eBiLRGNlfBJEvWH7ivp9sBqs7TNqBL5X3v157rM4IFETqDnIOO+z5M/biZbo9Ww==} + rehype-raw@7.0.0: dependencies: '@types/hast': 3.0.4 hast-util-raw: 9.1.0 vfile: 6.0.3 - dev: false - /remark-gfm@4.0.1: - resolution: {integrity: sha512-1quofZ2RQ9EWdeN34S79+KExV1764+wCUGop5CPL1WGdD0ocPpu91lzPGbwWMECpEpd42kJGQwzRfyov9j4yNg==} + remark-gfm@4.0.1: dependencies: '@types/mdast': 4.0.4 mdast-util-gfm: 3.1.0 @@ -4300,10 +5474,8 @@ packages: unified: 11.0.5 transitivePeerDependencies: - supports-color - dev: false - /remark-parse@11.0.0: - resolution: {integrity: sha512-FCxlKLNGknS5ba/1lmpYijMUzX2esxW5xQqjWxw2eHFfS2MSdaHVINFmhjo+qN1WhZhNimq0dZATN9pH0IDrpA==} + remark-parse@11.0.0: dependencies: '@types/mdast': 4.0.4 mdast-util-from-markdown: 2.0.2 @@ -4311,45 +5483,28 @@ packages: unified: 11.0.5 transitivePeerDependencies: - supports-color - dev: false - /remark-rehype@11.1.2: - resolution: {integrity: sha512-Dh7l57ianaEoIpzbp0PC9UKAdCSVklD8E5Rpw7ETfbTl3FqcOOgq5q2LVDhgGCkaBv7p24JXikPdvhhmHvKMsw==} + remark-rehype@11.1.2: dependencies: '@types/hast': 3.0.4 '@types/mdast': 4.0.4 mdast-util-to-hast: 13.2.1 unified: 11.0.5 vfile: 6.0.3 - dev: false - /remark-stringify@11.0.0: - resolution: {integrity: sha512-1OSmLd3awB/t8qdoEOMazZkNsfVTeY4fTsgzcQFdXNq8ToTN4ZGwrMnlda4K6smTFKD+GRV6O48i6Z4iKgPPpw==} + remark-stringify@11.0.0: dependencies: '@types/mdast': 4.0.4 mdast-util-to-markdown: 2.1.2 unified: 11.0.5 - dev: false - /require-directory@2.1.1: - resolution: {integrity: sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==} - engines: {node: '>=0.10.0'} - dev: true + require-directory@2.1.1: {} - /require-from-string@2.0.2: - resolution: {integrity: sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==} - engines: {node: '>=0.10.0'} - dev: true + require-from-string@2.0.2: {} - /resolve-from@4.0.0: - resolution: {integrity: sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==} - engines: {node: '>=4'} - dev: true + resolve-from@4.0.0: {} - /rollup@4.53.3: - resolution: {integrity: sha512-w8GmOxZfBmKknvdXU1sdM9NHcoQejwF/4mNgj2JuEEdRaHwwF12K7e9eXn1nLZ07ad+du76mkVsyeb2rKGllsA==} - engines: {node: '>=18.0.0', npm: '>=8.0.0'} - hasBin: true + rollup@4.53.3: dependencies: '@types/estree': 1.0.8 optionalDependencies: @@ -4377,266 +5532,163 @@ packages: '@rollup/rollup-win32-x64-msvc': 4.53.3 fsevents: 2.3.3 - /rxjs@7.8.2: - resolution: {integrity: sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==} + rxjs@7.8.2: dependencies: tslib: 2.8.1 - dev: true - /scheduler@0.27.0: - resolution: {integrity: sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==} - dev: false + scheduler@0.27.0: {} - /semver@6.3.1: - resolution: {integrity: sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==} - hasBin: true - dev: true + semver@6.3.1: {} - /semver@7.7.3: - resolution: {integrity: sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q==} - engines: {node: '>=10'} - hasBin: true - dev: true + semver@7.7.3: {} - /set-cookie-parser@2.7.2: - resolution: {integrity: sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==} - dev: false + set-cookie-parser@2.7.2: {} - /shebang-command@2.0.0: - resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==} - engines: {node: '>=8'} + shebang-command@2.0.0: dependencies: shebang-regex: 3.0.0 - dev: true - /shebang-regex@3.0.0: - resolution: {integrity: sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==} - engines: {node: '>=8'} - dev: true + shebang-regex@3.0.0: {} - /shell-quote@1.8.3: - resolution: {integrity: sha512-ObmnIF4hXNg1BqhnHmgbDETF8dLPCggZWBjkQfhZpbszZnYur5DUljTcCHii5LC3J5E0yeO/1LIMyH+UvHQgyw==} - engines: {node: '>= 0.4'} - dev: true + shell-quote@1.8.3: {} - /siginfo@2.0.0: - resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} - dev: true + siginfo@2.0.0: {} - /sirv@3.0.2: - resolution: {integrity: sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==} - engines: {node: '>=18'} + signal-exit@4.1.0: {} + + sirv@3.0.2: dependencies: '@polka/url': 1.0.0-next.29 mrmime: 2.0.1 totalist: 3.0.1 - dev: true - /sonner@2.0.7(react-dom@19.2.0)(react@19.2.0): - resolution: {integrity: sha512-W6ZN4p58k8aDKA4XPcx2hpIQXBRAgyiWVkYhT7CvK6D3iAu7xjvVyhQHg2/iaKJZ1XVJ4r7XuwGL+WGEK37i9w==} - peerDependencies: - react: ^18.0.0 || ^19.0.0 || ^19.0.0-rc - react-dom: ^18.0.0 || ^19.0.0 || ^19.0.0-rc + sonner@2.0.7(react-dom@19.2.0(react@19.2.0))(react@19.2.0): dependencies: react: 19.2.0 react-dom: 19.2.0(react@19.2.0) - dev: false - /source-map-js@1.2.1: - resolution: {integrity: sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==} - engines: {node: '>=0.10.0'} + source-map-js@1.2.1: {} - /space-separated-tokens@2.0.2: - resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} - dev: false + space-separated-tokens@2.0.2: {} - /stackback@0.0.2: - resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} - dev: true + stackback@0.0.2: {} - /state-local@1.0.7: - resolution: {integrity: sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==} - dev: false + state-local@1.0.7: {} - /std-env@3.10.0: - resolution: {integrity: sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==} - dev: true + std-env@3.10.0: {} - /string-width@4.2.3: - resolution: {integrity: sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==} - engines: {node: '>=8'} + string-width@4.2.3: dependencies: emoji-regex: 8.0.0 is-fullwidth-code-point: 3.0.0 strip-ansi: 6.0.1 - dev: true - /stringify-entities@4.0.4: - resolution: {integrity: sha512-IwfBptatlO+QCJUo19AqvrPNqlVMpW9YEL2LIVY+Rpv2qsjCGxaDLNRgeGsQWJhfItebuJhsGSLjaBbNSQ+ieg==} + string-width@5.1.2: + dependencies: + eastasianwidth: 0.2.0 + emoji-regex: 9.2.2 + strip-ansi: 7.2.0 + + stringify-entities@4.0.4: dependencies: character-entities-html4: 2.1.0 character-entities-legacy: 3.0.0 - dev: false - /strip-ansi@6.0.1: - resolution: {integrity: sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==} - engines: {node: '>=8'} + strip-ansi@6.0.1: dependencies: ansi-regex: 5.0.1 - dev: true - /strip-json-comments@3.1.1: - resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==} - engines: {node: '>=8'} - dev: true + strip-ansi@7.2.0: + dependencies: + ansi-regex: 6.2.2 - /strip-literal@3.1.0: - resolution: {integrity: sha512-8r3mkIM/2+PpjHoOtiAW8Rg3jJLHaV7xPwG+YRGrv6FP0wwk/toTpATxWYOW0BKdWwl82VT2tFYi5DlROa0Mxg==} + strip-json-comments@3.1.1: {} + + strip-literal@3.1.0: dependencies: js-tokens: 9.0.1 - dev: true - /style-to-js@1.1.21: - resolution: {integrity: sha512-RjQetxJrrUJLQPHbLku6U/ocGtzyjbJMP9lCNK7Ag0CNh690nSH8woqWH9u16nMjYBAok+i7JO1NP2pOy8IsPQ==} + style-to-js@1.1.21: dependencies: style-to-object: 1.0.14 - dev: false - /style-to-object@1.0.14: - resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + style-to-object@1.0.14: dependencies: inline-style-parser: 0.2.7 - dev: false - /supports-color@10.2.2: - resolution: {integrity: sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==} - engines: {node: '>=18'} + supports-color@10.2.2: {} - /supports-color@7.2.0: - resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} - engines: {node: '>=8'} + supports-color@7.2.0: dependencies: has-flag: 4.0.0 - dev: true - /supports-color@8.1.1: - resolution: {integrity: sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==} - engines: {node: '>=10'} + supports-color@8.1.1: dependencies: has-flag: 4.0.0 - dev: true - /tailwind-merge@3.4.0: - resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} - dev: false + tailwind-merge@3.4.0: {} - /tailwindcss@4.1.17: - resolution: {integrity: sha512-j9Ee2YjuQqYT9bbRTfTZht9W/ytp5H+jJpZKiYdP/bpnXARAuELt9ofP0lPnmHjbga7SNQIxdTAXCmtKVYjN+Q==} + tailwindcss@4.1.17: {} - /tapable@2.3.0: - resolution: {integrity: sha512-g9ljZiwki/LfxmQADO3dEY1CbpmXT5Hm2fJ+QaGKwSXUylMybePR7/67YW7jOrrvjEgL1Fmz5kzyAjWVWLlucg==} - engines: {node: '>=6'} - dev: false + tapable@2.3.0: {} - /tinybench@2.9.0: - resolution: {integrity: sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==} - dev: true + test-exclude@7.0.2: + dependencies: + '@istanbuljs/schema': 0.1.3 + glob: 10.5.0 + minimatch: 10.2.4 - /tinyexec@0.3.2: - resolution: {integrity: sha512-KQQR9yN7R5+OSwaK0XQoj22pwHoTlgYqmUscPYoknOoWCWfj/5/ABTMRi69FrKU5ffPVh5QcFikpWJI/P1ocHA==} - dev: true + tinybench@2.9.0: {} - /tinyglobby@0.2.15: - resolution: {integrity: sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ==} - engines: {node: '>=12.0.0'} + tinyexec@0.3.2: {} + + tinyglobby@0.2.15: dependencies: fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 - /tinypool@1.1.1: - resolution: {integrity: sha512-Zba82s87IFq9A9XmjiX5uZA/ARWDrB03OHlq+Vw1fSdt0I+4/Kutwy8BP4Y/y/aORMo61FQ0vIb5j44vSo5Pkg==} - engines: {node: ^18.0.0 || >=20.0.0} - dev: true + tinypool@1.1.1: {} - /tinyrainbow@2.0.0: - resolution: {integrity: sha512-op4nsTR47R6p0vMUUoYl/a+ljLFVtlfaXkLQmqfLR1qHma1h/ysYk4hEXZ880bf2CYgTskvTa/e196Vd5dDQXw==} - engines: {node: '>=14.0.0'} - dev: true + tinyrainbow@2.0.0: {} - /tinyspy@4.0.4: - resolution: {integrity: sha512-azl+t0z7pw/z958Gy9svOTuzqIk6xq+NSheJzn5MMWtWTFywIacg2wUlzKFGtt3cthx0r2SxMK0yzJOR0IES7Q==} - engines: {node: '>=14.0.0'} - dev: true + tinyspy@4.0.4: {} - /totalist@3.0.1: - resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} - engines: {node: '>=6'} - dev: true + totalist@3.0.1: {} - /tree-kill@1.2.2: - resolution: {integrity: sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==} - hasBin: true - dev: true + tree-kill@1.2.2: {} - /trim-lines@3.0.1: - resolution: {integrity: sha512-kRj8B+YHZCc9kQYdWfJB2/oUl9rA99qbowYYBtr4ui4mZyAQ2JpvVBd/6U2YloATfqBhBTSMhTpgBHtU0Mf3Rg==} - dev: false + trim-lines@3.0.1: {} - /trough@2.2.0: - resolution: {integrity: sha512-tmMpK00BjZiUyVyvrBK7knerNgmgvcV/KLVyuma/SC+TQN167GrMRciANTz09+k3zW8L8t60jWO1GpfkZdjTaw==} - dev: false + trough@2.2.0: {} - /ts-api-utils@2.1.0(typescript@5.9.3): - resolution: {integrity: sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ==} - engines: {node: '>=18.12'} - peerDependencies: - typescript: '>=4.8.4' + ts-api-utils@2.1.0(typescript@5.9.3): dependencies: typescript: 5.9.3 - dev: true - /tslib@2.8.1: - resolution: {integrity: sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==} + tslib@2.8.1: {} - /type-check@0.4.0: - resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} - engines: {node: '>= 0.8.0'} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 - dev: true - /type-fest@4.41.0: - resolution: {integrity: sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==} - engines: {node: '>=16'} - dev: true + type-fest@4.41.0: {} - /typescript-eslint@8.48.0(eslint@9.39.1)(typescript@5.9.3): - resolution: {integrity: sha512-fcKOvQD9GUn3Xw63EgiDqhvWJ5jsyZUaekl3KVpGsDJnN46WJTe3jWxtQP9lMZm1LJNkFLlTaWAxK2vUQR+cqw==} - engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} - peerDependencies: - eslint: ^8.57.0 || ^9.0.0 - typescript: '>=4.8.4 <6.0.0' + typescript-eslint@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3): dependencies: - '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0)(eslint@9.39.1)(typescript@5.9.3) - '@typescript-eslint/parser': 8.48.0(eslint@9.39.1)(typescript@5.9.3) + '@typescript-eslint/eslint-plugin': 8.48.0(@typescript-eslint/parser@8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3))(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + '@typescript-eslint/parser': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) '@typescript-eslint/typescript-estree': 8.48.0(typescript@5.9.3) - '@typescript-eslint/utils': 8.48.0(eslint@9.39.1)(typescript@5.9.3) - eslint: 9.39.1 + '@typescript-eslint/utils': 8.48.0(eslint@9.39.1(jiti@2.6.1))(typescript@5.9.3) + eslint: 9.39.1(jiti@2.6.1) typescript: 5.9.3 transitivePeerDependencies: - supports-color - dev: true - /typescript@5.9.3: - resolution: {integrity: sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==} - engines: {node: '>=14.17'} - hasBin: true + typescript@5.9.3: {} - /undici-types@7.16.0: - resolution: {integrity: sha512-Zz+aZWSj8LE6zoxD+xrjh4VfkIG8Ya6LvYkZqtUQGJPZjYl53ypCaUwWqo7eI0x66KBGeRo+mlBEkMSeSZ38Nw==} + undici-types@7.16.0: {} - /unified@11.0.5: - resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} + unified@11.0.5: dependencies: '@types/unist': 3.0.3 bail: 2.0.2 @@ -4645,127 +5697,82 @@ packages: is-plain-obj: 4.1.0 trough: 2.2.0 vfile: 6.0.3 - dev: false - /unist-util-find-after@5.0.0: - resolution: {integrity: sha512-amQa0Ep2m6hE2g72AugUItjbuM8X8cGQnFoHk0pGfrFeT9GZhzN5SW8nRsiGKK7Aif4CrACPENkA6P/Lw6fHGQ==} + unist-util-find-after@5.0.0: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 - dev: false - /unist-util-is@6.0.1: - resolution: {integrity: sha512-LsiILbtBETkDz8I9p1dQ0uyRUWuaQzd/cuEeS1hoRSyW5E5XGmTzlwY1OrNzzakGowI9Dr/I8HVaw4hTtnxy8g==} + unist-util-is@6.0.1: dependencies: '@types/unist': 3.0.3 - dev: false - /unist-util-position@5.0.0: - resolution: {integrity: sha512-fucsC7HjXvkB5R3kTCO7kUjRdrS0BJt3M/FPxmHMBOm8JQi2BsHAHFsy27E0EolP8rp0NzXsJ+jNPyDWvOJZPA==} + unist-util-position@5.0.0: dependencies: '@types/unist': 3.0.3 - dev: false - /unist-util-stringify-position@4.0.0: - resolution: {integrity: sha512-0ASV06AAoKCDkS2+xw5RXJywruurpbC4JZSm7nr7MOt1ojAzvyyaO+UxZf18j8FCF6kmzCZKcAgN/yu2gm2XgQ==} + unist-util-stringify-position@4.0.0: dependencies: '@types/unist': 3.0.3 - dev: false - /unist-util-visit-parents@6.0.2: - resolution: {integrity: sha512-goh1s1TBrqSqukSc8wrjwWhL0hiJxgA8m4kFxGlQ+8FYQ3C/m11FcTs4YYem7V664AhHVvgoQLk890Ssdsr2IQ==} + unist-util-visit-parents@6.0.2: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 - dev: false - /unist-util-visit@5.0.0: - resolution: {integrity: sha512-MR04uvD+07cwl/yhVuVWAtw+3GOR/knlL55Nd/wAdblk27GCVt3lqpTivy/tkJcZoNPzTwS1Y+KMojlLDhoTzg==} + unist-util-visit@5.0.0: dependencies: '@types/unist': 3.0.3 unist-util-is: 6.0.1 unist-util-visit-parents: 6.0.2 - dev: false - /update-browserslist-db@1.1.4(browserslist@4.28.0): - resolution: {integrity: sha512-q0SPT4xyU84saUX+tomz1WLkxUbuaJnR1xWt17M7fJtEJigJeWUNGUqrauFXsHnqev9y9JTRGwk13tFBuKby4A==} - hasBin: true - peerDependencies: - browserslist: '>= 4.21.0' + update-browserslist-db@1.1.4(browserslist@4.28.0): dependencies: browserslist: 4.28.0 escalade: 3.2.0 picocolors: 1.1.1 - dev: true - /uri-js@4.4.1: - resolution: {integrity: sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==} + uri-js@4.4.1: dependencies: punycode: 2.3.1 - dev: true - /use-callback-ref@1.3.3(@types/react@19.2.7)(react@19.2.0): - resolution: {integrity: sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + use-callback-ref@1.3.3(@types/react@19.2.7)(react@19.2.0): dependencies: - '@types/react': 19.2.7 react: 19.2.0 tslib: 2.8.1 - dev: false + optionalDependencies: + '@types/react': 19.2.7 - /use-sidecar@1.1.3(@types/react@19.2.7)(react@19.2.0): - resolution: {integrity: sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==} - engines: {node: '>=10'} - peerDependencies: - '@types/react': '*' - react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc - peerDependenciesMeta: - '@types/react': - optional: true + use-sidecar@1.1.3(@types/react@19.2.7)(react@19.2.0): dependencies: - '@types/react': 19.2.7 detect-node-es: 1.1.0 react: 19.2.0 tslib: 2.8.1 - dev: false + optionalDependencies: + '@types/react': 19.2.7 - /vfile-location@5.0.3: - resolution: {integrity: sha512-5yXvWDEgqeiYiBe1lbxYF7UMAIm/IcopxMHrMQDq3nvKcjPKIhZklUKL+AE7J7uApI4kwe2snsK+eI6UTj9EHg==} + vfile-location@5.0.3: dependencies: '@types/unist': 3.0.3 vfile: 6.0.3 - dev: false - /vfile-message@4.0.3: - resolution: {integrity: sha512-QTHzsGd1EhbZs4AsQ20JX1rC3cOlt/IWJruk893DfLRr57lcnOeMaWG4K0JrRta4mIJZKth2Au3mM3u03/JWKw==} + vfile-message@4.0.3: dependencies: '@types/unist': 3.0.3 unist-util-stringify-position: 4.0.0 - dev: false - /vfile@6.0.3: - resolution: {integrity: sha512-KzIbH/9tXat2u30jf+smMwFCsno4wHVdNmzFyL+T/L3UGqqk6JKfVqOFOZEpZSHADH1k40ab6NUIXZq422ov3Q==} + vfile@6.0.3: dependencies: '@types/unist': 3.0.3 vfile-message: 4.0.3 - dev: false - /vite-node@3.2.4: - resolution: {integrity: sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true + vite-node@3.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2): dependencies: cac: 6.7.14 debug: 4.4.3(supports-color@10.2.2) es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.2.4(@types/node@24.10.1) + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2) transitivePeerDependencies: - '@types/node' - jiti @@ -4779,49 +5786,9 @@ packages: - terser - tsx - yaml - dev: true - /vite@7.2.4(@types/node@24.10.1): - resolution: {integrity: sha512-NL8jTlbo0Tn4dUEXEsUg8KeyG/Lkmc4Fnzb8JXN/Ykm9G4HNImjtABMJgkQoVjOBN/j2WAwDTRytdqJbZsah7w==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - peerDependencies: - '@types/node': ^20.19.0 || >=22.12.0 - jiti: '>=1.21.0' - less: ^4.0.0 - lightningcss: ^1.21.0 - sass: ^1.70.0 - sass-embedded: ^1.70.0 - stylus: '>=0.54.8' - sugarss: ^5.0.0 - terser: ^5.16.0 - tsx: ^4.8.1 - yaml: ^2.4.2 - peerDependenciesMeta: - '@types/node': - optional: true - jiti: - optional: true - less: - optional: true - lightningcss: - optional: true - sass: - optional: true - sass-embedded: - optional: true - stylus: - optional: true - sugarss: - optional: true - terser: - optional: true - tsx: - optional: true - yaml: - optional: true + vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2): dependencies: - '@types/node': 24.10.1 esbuild: 0.25.12 fdir: 6.5.0(picomatch@4.0.3) picomatch: 4.0.3 @@ -4829,44 +5796,20 @@ packages: rollup: 4.53.3 tinyglobby: 0.2.15 optionalDependencies: + '@types/node': 24.10.1 fsevents: 2.3.3 + jiti: 2.6.1 + lightningcss: 1.30.2 - /vitest@3.2.4(@vitest/ui@3.2.4): - resolution: {integrity: sha512-LUCP5ev3GURDysTWiP47wRRUpLKMOfPh+yKTx3kVIEiu5KOMeqzpnYNsKyOoVrULivR8tLcks4+lga33Whn90A==} - engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} - hasBin: true - peerDependencies: - '@edge-runtime/vm': '*' - '@types/debug': ^4.1.12 - '@types/node': ^18.0.0 || ^20.0.0 || >=22.0.0 - '@vitest/browser': 3.2.4 - '@vitest/ui': 3.2.4 - happy-dom: '*' - jsdom: '*' - peerDependenciesMeta: - '@edge-runtime/vm': - optional: true - '@types/debug': - optional: true - '@types/node': - optional: true - '@vitest/browser': - optional: true - '@vitest/ui': - optional: true - happy-dom: - optional: true - jsdom: - optional: true + vitest@3.2.4(@types/debug@4.1.12)(@types/node@24.10.1)(@vitest/ui@3.2.4)(jiti@2.6.1)(lightningcss@1.30.2): dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.4 - '@vitest/mocker': 3.2.4(vite@7.2.4) + '@vitest/mocker': 3.2.4(vite@7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2)) '@vitest/pretty-format': 3.2.4 '@vitest/runner': 3.2.4 '@vitest/snapshot': 3.2.4 '@vitest/spy': 3.2.4 - '@vitest/ui': 3.2.4(vitest@3.2.4) '@vitest/utils': 3.2.4 chai: 5.3.3 debug: 4.4.3(supports-color@10.2.2) @@ -4880,9 +5823,13 @@ packages: tinyglobby: 0.2.15 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.2.4(@types/node@24.10.1) - vite-node: 3.2.4 + vite: 7.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2) + vite-node: 3.2.4(@types/node@24.10.1)(jiti@2.6.1)(lightningcss@1.30.2) why-is-node-running: 2.3.0 + optionalDependencies: + '@types/debug': 4.1.12 + '@types/node': 24.10.1 + '@vitest/ui': 3.2.4(vitest@3.2.4) transitivePeerDependencies: - jiti - less @@ -4896,64 +5843,41 @@ packages: - terser - tsx - yaml - dev: true - /web-namespaces@2.0.1: - resolution: {integrity: sha512-bKr1DkiNa2krS7qxNtdrtHAmzuYGFQLiQ13TsorsdT6ULTkPLKuu5+GsFpDlg6JFjUTwX2DyhMPG2be8uPrqsQ==} - dev: false + web-namespaces@2.0.1: {} - /which@2.0.2: - resolution: {integrity: sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==} - engines: {node: '>= 8'} - hasBin: true + which@2.0.2: dependencies: isexe: 2.0.0 - dev: true - /why-is-node-running@2.3.0: - resolution: {integrity: sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==} - engines: {node: '>=8'} - hasBin: true + why-is-node-running@2.3.0: dependencies: siginfo: 2.0.0 stackback: 0.0.2 - dev: true - /word-wrap@1.2.5: - resolution: {integrity: sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==} - engines: {node: '>=0.10.0'} - dev: true + word-wrap@1.2.5: {} - /wrap-ansi@7.0.0: - resolution: {integrity: sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==} - engines: {node: '>=10'} + wrap-ansi@7.0.0: dependencies: ansi-styles: 4.3.0 string-width: 4.2.3 strip-ansi: 6.0.1 - dev: true - /y18n@5.0.8: - resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} - engines: {node: '>=10'} - dev: true + wrap-ansi@8.1.0: + dependencies: + ansi-styles: 6.2.3 + string-width: 5.1.2 + strip-ansi: 7.2.0 - /yallist@3.1.1: - resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} - dev: true + y18n@5.0.8: {} - /yaml-ast-parser@0.0.43: - resolution: {integrity: sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==} - dev: true + yallist@3.1.1: {} - /yargs-parser@21.1.1: - resolution: {integrity: sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==} - engines: {node: '>=12'} - dev: true + yaml-ast-parser@0.0.43: {} - /yargs@17.7.2: - resolution: {integrity: sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==} - engines: {node: '>=12'} + yargs-parser@21.1.1: {} + + yargs@17.7.2: dependencies: cliui: 8.0.1 escalade: 3.2.0 @@ -4962,39 +5886,14 @@ packages: string-width: 4.2.3 y18n: 5.0.8 yargs-parser: 21.1.1 - dev: true - /yocto-queue@0.1.0: - resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} - engines: {node: '>=10'} - dev: true + yocto-queue@0.1.0: {} - /zod@4.1.13: - resolution: {integrity: sha512-AvvthqfqrAhNH9dnfmrfKzX5upOdjUVJYFqNSlkmGf64gRaTzlPwz99IHYnVs28qYAybvAlBV+H7pn0saFY4Ig==} - dev: false + zod@4.1.13: {} - /zustand@5.0.8(@types/react@19.2.7)(react@19.2.0): - resolution: {integrity: sha512-gyPKpIaxY9XcO2vSMrLbiER7QMAMGOQZVRdJ6Zi782jkbzZygq5GI9nG8g+sMgitRtndwaBSl7uiqC49o1SSiw==} - engines: {node: '>=12.20.0'} - peerDependencies: - '@types/react': '>=18.0.0' - immer: '>=9.0.6' - react: '>=18.0.0' - use-sync-external-store: '>=1.2.0' - peerDependenciesMeta: - '@types/react': - optional: true - immer: - optional: true - react: - optional: true - use-sync-external-store: - optional: true - dependencies: + zustand@5.0.8(@types/react@19.2.7)(react@19.2.0): + optionalDependencies: '@types/react': 19.2.7 react: 19.2.0 - dev: false - /zwitch@2.0.4: - resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} - dev: false + zwitch@2.0.4: {} diff --git a/scripts/docker-entrypoint.sh b/scripts/docker-entrypoint.sh index 1ca8786d..b2b59109 100644 --- a/scripts/docker-entrypoint.sh +++ b/scripts/docker-entrypoint.sh @@ -1,14 +1,19 @@ #!/bin/bash -set -e +set -euo pipefail export BUN_INSTALL="$HOME/.bun" export PATH="$BUN_INSTALL/bin:$HOME/.opencode/bin:$HOME/.local/bin:$PATH" +if [[ "${NODE_ENV:-development}" == "production" && -z "${AUTH_TOKEN:-}" ]]; then + echo "❌ AUTH_TOKEN must be set when NODE_ENV=production" + exit 1 +fi + echo "🔍 Checking Bun installation..." if ! command -v bun >/dev/null 2>&1; then echo "❌ Bun not found. Installing..." - curl -fsSL https://bun.sh/install | bash + curl -fsSL https://bun.com/install | bash -s -- "bun-v${BUN_VERSION:-1.2.21}" if ! command -v bun >/dev/null 2>&1; then echo "❌ Failed to install Bun. Exiting." @@ -30,6 +35,12 @@ else echo "✅ OpenCode is installed (version: $OPENCODE_VERSION)" fi +if [[ -n "${CORS_ORIGIN:-}" ]]; then + echo "🌐 Allowed browser origins: ${CORS_ORIGIN}" +else + echo "🌐 Allowed browser origins: same-origin only" +fi + echo "🚀 Starting OpenCode WebUI Backend..." exec "$@" diff --git a/scripts/setup-dev.sh b/scripts/setup-dev.sh index f4fac5b4..863069fb 100755 --- a/scripts/setup-dev.sh +++ b/scripts/setup-dev.sh @@ -4,15 +4,29 @@ set -e echo "🔍 Checking prerequisites..." -# Check if Node.js/Bun is installed +# Check if Node.js is installed +if command -v node &> /dev/null; then + echo "✅ Node.js is installed" +else + echo "❌ Node.js is not installed. Please install it and try again." + exit 1 +fi + +# Check if pnpm is installed +if command -v pnpm &> /dev/null; then + echo "✅ pnpm is installed" +else + echo "❌ pnpm is not installed. Enable Corepack or install pnpm before continuing." + echo " corepack enable" + echo " corepack prepare pnpm@9.15.0 --activate" + exit 1 +fi + +# Check if Bun is installed if command -v bun &> /dev/null; then echo "✅ Bun is installed" - NODE_CMD="bun" -elif command -v node &> /dev/null; then - echo "✅ Node.js is installed" - NODE_CMD="node" else - echo "❌ Neither Bun nor Node.js is installed. Please install one of them." + echo "❌ Bun is not installed. Please install Bun before continuing." exit 1 fi @@ -48,11 +62,7 @@ fi # Install dependencies echo "📦 Installing dependencies..." -if [ "$NODE_CMD" = "bun" ]; then - bun install -else - npm install -fi +pnpm install echo "✅ Dependencies installed" @@ -68,6 +78,6 @@ fi echo "✅ Dev environment ready!" echo "" echo "🚀 To start development:" -echo " npm run dev # Start both backend and frontend" -echo " npm run dev:backend # Start backend only" -echo " npm run dev:frontend # Start frontend only" +echo " pnpm dev # Start both backend and frontend" +echo " pnpm dev:backend # Start backend only" +echo " pnpm dev:frontend # Start frontend only" diff --git a/shared/src/config/defaults.ts b/shared/src/config/defaults.ts index e77e401b..8885791c 100644 --- a/shared/src/config/defaults.ts +++ b/shared/src/config/defaults.ts @@ -1,8 +1,8 @@ export const DEFAULTS = { SERVER: { PORT: 5003, - HOST: '0.0.0.0', - CORS_ORIGIN: 'http://localhost:5173', + HOST: '127.0.0.1', + CORS_ORIGIN: '', AUTH_TOKEN: '', }, diff --git a/shared/src/config/env.ts b/shared/src/config/env.ts index 55ecb17e..4c4798c7 100644 --- a/shared/src/config/env.ts +++ b/shared/src/config/env.ts @@ -36,14 +36,16 @@ const resolveWorkspacePath = (): string => { } const workspaceBasePath = resolveWorkspacePath() +const nodeEnv = getEnvString('NODE_ENV', 'development') +const defaultServerHost = nodeEnv === 'production' ? DEFAULTS.SERVER.HOST : '0.0.0.0' export const ENV = { SERVER: { PORT: getEnvNumber('PORT', DEFAULTS.SERVER.PORT), - HOST: getEnvString('HOST', DEFAULTS.SERVER.HOST), + HOST: getEnvString('HOST', defaultServerHost), CORS_ORIGIN: getEnvString('CORS_ORIGIN', DEFAULTS.SERVER.CORS_ORIGIN), AUTH_TOKEN: getEnvString('AUTH_TOKEN', DEFAULTS.SERVER.AUTH_TOKEN), - NODE_ENV: getEnvString('NODE_ENV', 'development'), + NODE_ENV: nodeEnv, }, OPENCODE: { @@ -90,7 +92,7 @@ export const getDatabasePath = () => ENV.DATABASE.PATH export const getApiUrl = (port: number = ENV.SERVER.PORT): string => { const host = ENV.SERVER.HOST - if (host === '0.0.0.0') { + if (host === '0.0.0.0' || host === '::') { const interfaces = os.networkInterfaces() const ips = Object.values(interfaces) .flat() diff --git a/shared/src/schemas/repo.ts b/shared/src/schemas/repo.ts index f54fe666..b8d5b56f 100644 --- a/shared/src/schemas/repo.ts +++ b/shared/src/schemas/repo.ts @@ -4,7 +4,7 @@ export const RepoStatusSchema = z.enum(['cloning', 'ready', 'error']) export const RepoSchema = z.object({ id: z.number(), - repoUrl: z.string().url().optional(), + repoUrl: z.string().optional(), localPath: z.string(), fullPath: z.string(), branch: z.string().optional(), @@ -18,7 +18,7 @@ export const RepoSchema = z.object({ }) export const CreateRepoRequestSchema = z.object({ - repoUrl: z.string().url().optional(), + repoUrl: z.string().min(1).optional(), localPath: z.string().optional(), branch: z.string().optional(), openCodeConfigName: z.string().optional(),