From ab6b8e38bcfafe9c65960b41b19f88918a438081 Mon Sep 17 00:00:00 2001 From: kohta ito Date: Tue, 15 Sep 2026 16:00:37 +0900 Subject: [PATCH 01/21] feat: add packages/spa as React Router v7 + Vite SPA sample MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - separate workspace alongside Next.js client - ssr:false, Node built-in HTTP static server - server-side /api/user proxy (API_URI + API_TOKEN never exposed to browser) - loopback-only, exact Host/Origin validation, raw path parsing, O_NOFOLLOW symlink protection - 5s absolute deadline, decoded body ≤1MiB (with genuine gzip streamed test at limit boundaries + immediate abort) - redirect rejection, client-disconnect/shutdown cancellation, runtime validation + sanitized errors - deterministic dark dashboard UI (connection status, cards, meter-like user list, 4 states, responsive) - full CI (ci-spa.yml + updated ci-client.yml), lint/tsc/build/test pass - Vite dependency split (root vite-plus override + scoped @react-router/dev / vite-node) - spec + 6 rounds qualified code review (Blocking/Major=0, all prior M-00x closed) Closes limit-monitor reference SPA sample request. Base: 8987d1920289ee26a6228e25dfac680dd948fe14 --- .github/workflows/ci-client.yml | 2 + .github/workflows/ci-spa.yml | 44 + .../spa-sample-code-review-round2.json | 19 + .../spa-sample-code-review-round3.json | 16 + .../spa-sample-code-review-round4.json | 15 + .../spa-sample-code-review-round5.json | 14 + docs/spec/spa-sample.md | 347 + package-lock.json | 17747 +++++++++------- package.json | 8 +- packages/spa/.gitignore | 2 + .../spa/app/components/DashboardView.test.tsx | 70 + packages/spa/app/components/DashboardView.tsx | 113 + packages/spa/app/entry.client.tsx | 12 + packages/spa/app/entry.server.tsx | 27 + packages/spa/app/lib/api-client.test.ts | 51 + packages/spa/app/lib/api-client.ts | 27 + packages/spa/app/lib/format.ts | 19 + packages/spa/app/root.tsx | 55 + packages/spa/app/routes.ts | 3 + packages/spa/app/routes/dashboard.tsx | 11 + packages/spa/app/styles.css | 265 + packages/spa/app/styles.test.ts | 14 + packages/spa/package.json | 36 + packages/spa/react-router.config.ts | 9 + packages/spa/src/api-contract.test.ts | 43 + packages/spa/src/api-contract.ts | 53 + packages/spa/src/server/authority.test.ts | 46 + packages/spa/src/server/authority.ts | 41 + packages/spa/src/server/config.test.ts | 47 + packages/spa/src/server/config.ts | 111 + packages/spa/src/server/http-response.ts | 56 + packages/spa/src/server/index.ts | 25 + packages/spa/src/server/proxy.test.ts | 442 + packages/spa/src/server/proxy.ts | 188 + .../spa/src/server/request-target.test.ts | 28 + packages/spa/src/server/request-target.ts | 54 + packages/spa/src/server/static-server.test.ts | 355 + packages/spa/src/server/static-server.ts | 384 + packages/spa/tsconfig.json | 29 + packages/spa/tsconfig.server.json | 18 + packages/spa/vite.config.ts | 66 + 41 files changed, 13573 insertions(+), 7339 deletions(-) create mode 100644 .github/workflows/ci-spa.yml create mode 100644 docs/spec/reviews/spa-sample-code-review-round2.json create mode 100644 docs/spec/reviews/spa-sample-code-review-round3.json create mode 100644 docs/spec/reviews/spa-sample-code-review-round4.json create mode 100644 docs/spec/reviews/spa-sample-code-review-round5.json create mode 100644 docs/spec/spa-sample.md create mode 100644 packages/spa/.gitignore create mode 100644 packages/spa/app/components/DashboardView.test.tsx create mode 100644 packages/spa/app/components/DashboardView.tsx create mode 100644 packages/spa/app/entry.client.tsx create mode 100644 packages/spa/app/entry.server.tsx create mode 100644 packages/spa/app/lib/api-client.test.ts create mode 100644 packages/spa/app/lib/api-client.ts create mode 100644 packages/spa/app/lib/format.ts create mode 100644 packages/spa/app/root.tsx create mode 100644 packages/spa/app/routes.ts create mode 100644 packages/spa/app/routes/dashboard.tsx create mode 100644 packages/spa/app/styles.css create mode 100644 packages/spa/app/styles.test.ts create mode 100644 packages/spa/package.json create mode 100644 packages/spa/react-router.config.ts create mode 100644 packages/spa/src/api-contract.test.ts create mode 100644 packages/spa/src/api-contract.ts create mode 100644 packages/spa/src/server/authority.test.ts create mode 100644 packages/spa/src/server/authority.ts create mode 100644 packages/spa/src/server/config.test.ts create mode 100644 packages/spa/src/server/config.ts create mode 100644 packages/spa/src/server/http-response.ts create mode 100644 packages/spa/src/server/index.ts create mode 100644 packages/spa/src/server/proxy.test.ts create mode 100644 packages/spa/src/server/proxy.ts create mode 100644 packages/spa/src/server/request-target.test.ts create mode 100644 packages/spa/src/server/request-target.ts create mode 100644 packages/spa/src/server/static-server.test.ts create mode 100644 packages/spa/src/server/static-server.ts create mode 100644 packages/spa/tsconfig.json create mode 100644 packages/spa/tsconfig.server.json create mode 100644 packages/spa/vite.config.ts diff --git a/.github/workflows/ci-client.yml b/.github/workflows/ci-client.yml index 5fcbd2d..d59aefd 100644 --- a/.github/workflows/ci-client.yml +++ b/.github/workflows/ci-client.yml @@ -5,6 +5,7 @@ on: paths: - 'packages/client/**' - 'package.json' + - 'package-lock.json' - 'vite.config.ts' - 'lint-rules/**' branches: [ main ] @@ -14,6 +15,7 @@ on: - 'packages/shared/**' - 'packages/client/**' - 'package.json' + - 'package-lock.json' - 'vite.config.ts' - 'lint-rules/**' diff --git a/.github/workflows/ci-spa.yml b/.github/workflows/ci-spa.yml new file mode 100644 index 0000000..0fd83bb --- /dev/null +++ b/.github/workflows/ci-spa.yml @@ -0,0 +1,44 @@ +name: CI SPA + +on: + push: + paths: + - '.github/workflows/ci-spa.yml' + - 'packages/spa/**' + - 'packages/shared/**' + - 'package.json' + - 'package-lock.json' + - 'vite.config.ts' + - 'lint-rules/**' + branches: [ main ] + pull_request: + paths: + - '.github/workflows/ci-spa.yml' + - 'packages/spa/**' + - 'packages/shared/**' + - 'package.json' + - 'package-lock.json' + - 'vite.config.ts' + - 'lint-rules/**' + +env: + WORKSPACE_NAME: spa + +jobs: + test: + runs-on: ubuntu-latest + strategy: + matrix: + node-version: [24.x] + steps: + - uses: actions/checkout@11d5960a326750d5838078e36cf38b85af677262 # v4.4.0 + - name: Use Node.js ${{ matrix.node-version }} + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 # v4.4.0 + with: + node-version: ${{ matrix.node-version }} + - run: npm ci + - run: npm run lint -w ${{ env.WORKSPACE_NAME }} + - run: npm run build -w shared + - run: npm run tsc -w ${{ env.WORKSPACE_NAME }} + - run: npm run build -w ${{ env.WORKSPACE_NAME }} + - run: npm run test -w ${{ env.WORKSPACE_NAME }} diff --git a/docs/spec/reviews/spa-sample-code-review-round2.json b/docs/spec/reviews/spa-sample-code-review-round2.json new file mode 100644 index 0000000..8e75858 --- /dev/null +++ b/docs/spec/reviews/spa-sample-code-review-round2.json @@ -0,0 +1,19 @@ +{ + "review_stage": "initial implementation review", + "base": "8987d1920289ee26a6228e25dfac680dd948fe14", + "scope": "packages/spa, SPA CI/spec/lockfile changes; diagnostic generated files excluded", + "reviewer_model": "gpt-5.6-sol", + "capability_tier": "frontier", + "passed": false, + "blocking_findings": [], + "major_findings": [ + "M-001 | Major | packages/spa/vite.config.ts:40-43 | If the development server cannot expose its effective port, /api/user falls through to Vite instead of returning the required fail-closed 503 and may produce an unsanitized or SPA response. | Send the fixed 503 response when getDevelopmentConfig() returns null; never call next() for a reserved API target.", + "M-002 | Major | packages/spa/src/server/proxy.test.ts and packages/spa/src/server/static-server.test.ts | CI can pass despite regressions in redirect rejection, the absolute deadline, disconnect/shutdown cancellation, inclusive 1 MiB boundaries, compressed decoded-size enforcement, encoded API dispatch, HEAD/POST behavior, or preexisting symlink rejection because these required cases are untested. | Add deterministic tests covering the proxy deadline and cancellation lifecycle, redirects, limit-1/limit/limit+1 decoded bodies including compression, and the complete security-relevant endpoint/symlink matrix." + ], + "minor_findings": [ + "m-001 | Minor | packages/spa/src/server/config.ts:78 | String.trim() removes Unicode whitespace as well as ASCII whitespace, so a token with a non-ASCII whitespace code point at either edge is silently changed contrary to the canonical token-normalization contract. | Replace trim() with explicit leading/trailing ASCII-whitespace removal and add boundary tests." + ], + "invalid_findings": [], + "suggestions": [], + "summary": "Fresh read-only review did not pass. M-001, M-002, and m-001 were subsequently addressed and sent through fresh closure reviews." +} diff --git a/docs/spec/reviews/spa-sample-code-review-round3.json b/docs/spec/reviews/spa-sample-code-review-round3.json new file mode 100644 index 0000000..8efec3d --- /dev/null +++ b/docs/spec/reviews/spa-sample-code-review-round3.json @@ -0,0 +1,16 @@ +{ + "review_stage": "closure review after M-001/M-002/m-001 fixes", + "base": "8987d1920289ee26a6228e25dfac680dd948fe14", + "scope": "packages/spa, SPA CI/spec/lockfile changes; diagnostic generated files excluded", + "reviewer_model": "GPT-5 Codex", + "capability_tier": "frontier", + "passed": false, + "blocking_findings": [], + "major_findings": [ + "M-002 | Major | packages/spa/src/server/proxy.ts:46 and proxy.test.ts:187 | An oversized decoded response only cancels the reader, while the test labels plain JSON bytes as gzip and therefore exercises no decompression; a compressed oversized response can regress without detection and the required fetch abort is not verified. | Abort the request controller immediately on overflow and test a genuinely gzip-compressed streamed upstream at the limit-1, limit, and limit+1 decoded boundaries, asserting cancellation." + ], + "minor_findings": [], + "invalid_findings": [], + "suggestions": [], + "summary": "Closure did not pass because the compressed decoded-size and overflow-cancellation coverage was not meaningful. M-001, deadline checks, cancellation, encoded dispatch, HEAD/POST, symlink handling, ASCII token trimming, and O_NOFOLLOW were otherwise accepted." +} diff --git a/docs/spec/reviews/spa-sample-code-review-round4.json b/docs/spec/reviews/spa-sample-code-review-round4.json new file mode 100644 index 0000000..fe228ca --- /dev/null +++ b/docs/spec/reviews/spa-sample-code-review-round4.json @@ -0,0 +1,15 @@ +{ + "review_stage": "final closure review", + "base": "8987d1920289ee26a6228e25dfac680dd948fe14", + "scope": "packages/spa, SPA CI/spec/lockfile changes; diagnostic generated files excluded", + "reviewer_model": "GPT-5 Codex", + "capability_tier": "primary", + "closed_findings": ["M-001", "M-002", "m-001"], + "passed": true, + "blocking_findings": [], + "major_findings": [], + "minor_findings": [], + "invalid_findings": [], + "suggestions": [], + "summary": "Fresh read-only closure review passed against base 8987d1920289ee26a6228e25dfac680dd948fe14. The scoped implementation and tests satisfy the canonical SPA, proxy, authority, cancellation, decoded-size, static-file safety, UI, and CI requirements. Prior findings M-001, M-002, and m-001 are closed, with no regressions found." +} diff --git a/docs/spec/reviews/spa-sample-code-review-round5.json b/docs/spec/reviews/spa-sample-code-review-round5.json new file mode 100644 index 0000000..0aeb78b --- /dev/null +++ b/docs/spec/reviews/spa-sample-code-review-round5.json @@ -0,0 +1,14 @@ +{ + "review_stage": "final documentation closure review", + "base": "8987d1920289ee26a6228e25dfac680dd948fe14", + "scope": "packages/spa, SPA CI/spec/lockfile changes; diagnostic generated files excluded", + "reviewer_model": "GPT-5 Codex", + "capability_tier": "primary", + "passed": true, + "blocking_findings": [], + "major_findings": [], + "minor_findings": [], + "invalid_findings": [], + "suggestions": [], + "summary": "Fresh read-only closure review passed against the final documentation revision. Acceptance checkmarks, the Vite Plus/vite-cli alias note, and the implementation-review reference are consistent with the implementation, lockfile, CI, review artifacts, and validation evidence. Prior findings M-001, M-002, and m-001 remain closed." +} diff --git a/docs/spec/spa-sample.md b/docs/spec/spa-sample.md new file mode 100644 index 0000000..a661c92 --- /dev/null +++ b/docs/spec/spa-sample.md @@ -0,0 +1,347 @@ +# SPA サンプルパッケージ仕様書 + +## Status + +- 対象ブランチ: `feature/spa-sample` +- 基準revision: `8987d1920289ee26a6228e25dfac680dd948fe14` +- Round 1 / Round 2 / Round 3の敵対的レビュー指摘を反映した改訂版。 +- 最終closure review(Round 4)は同等モデルのfresh独立fallbackで実施し、Blocking/Major 0件で合格した。 +- ユーザーの選択と、追加確認がタイムアウトした2点に対する安全側の仮定を含む。 + +## Overview + +`service-template` に、既存のNext.js `packages/client`と併設できるReact SPAのサンプルとして`packages/spa`を追加する。 + +単一画面の目的は、`service-template`の既存APIからユーザー一覧を取得し、`limit-monitor` dashboardの視覚的方向性(暗色背景、接続状態、中央の状態パネル、カード型の情報表示、淡い境界線、状態色)で状態を確認できるようにすることである。 + +`limit-monitor`のaccount/bucket/meterは、`service-template`の既存APIがそのデータを返さないため実装しない。APIが返した値から残量などを推測・捏造しない。 + +既存の`packages/client`(Next.js)は変更せず、別workspaceとして追加する。 + +## Inputs & Outputs + +### Runtime configuration + +値はSPAのブラウザbundleへ埋め込まず、SPAを配信するNode server(およびVite dev serverのproxy)だけが読む。 + +- `API_URI`: 既存APIのbase URL。既定値は`http://localhost:8000`。`http`/`https`のorigin形式だけを受理し、userinfo、path、query、fragmentを拒否する。 +- `API_TOKEN`: 既存APIへ渡すBearer tokenの値。前後のASCII whitespaceをtrimし、trim後が空文字の場合、proxyは固定の503を返す。tokenをログ・client bundle・レスポンスへ出さない。token内部のwhitespaceは変更せず、Authorization headerへそのまま渡す。 +- `HOST`: SPA配信serverのbind address。既定値は`127.0.0.1`。外部公開によるcredentialed proxyの無認証利用を防ぐため、`127.0.0.1`、`localhost`、`::1`以外は起動時に拒否する。 +- `PORT`: SPA配信serverのport。既定値は`8789`。1以上65535以下の整数だけを受理する。 +- `SPA_DIST_DIR`: 静的配信root。未設定時はserver build出力から`dist/public`を解決する。`start`時に存在するdirectoryであることを確認し、欠落・非directoryなら起動を失敗させる。 +- proxy timeout: 固定`5_000ms`。環境変数で緩和しない。 +- upstream response最大サイズ: 固定`1_048_576 bytes`。Fetch response bodyをcontent decoding後のstream bytesとして数え、超過直後にabortして502にする。`Content-Length`だけに依存しない。 + +### Trust boundary and request authority + +このサンプルのcredentialed proxyにはbrowser caller向けの認証機能がないため、production配信serverはloopback bindだけを許可する。さらに、routingより前に次を検証する。 + +- `Host` headerは、設定した`HOST`と`PORT`から作ったauthority(IPv6は角括弧を含む)との完全一致だけを受理する。別名、別port、欠落Hostは400固定bodyで拒否する。既定値へ暗黙に寄せない。 +- `Origin` headerが存在する場合、`http://`との完全一致だけを受理し、不一致は403固定bodyで拒否する。`Origin`がない非browser clientはHost検証を通れば受理する。 +- `Access-Control-Allow-Origin`などCORS許可headerは一切返さない。 +- `HOST`をloopback以外へ変更する設定は起動時に拒否する。DNS rebindingで攻撃者originからloopbackへ到達しても、Host/Origin検証でcredentialed proxyを呼び出せないようにする。 +- HTTP/1 requestの`rawHeaders`で`Host` fieldがちょうど1個、`Origin` fieldが0個または1個であることを確認する。重複field、comma-joined value、欠落Hostは固定bodyで拒否し、`req.headers`の結合済みvalueだけをtrustしない。 + +Vite dev serverも`127.0.0.1` bind、`port: 0`、`127.0.0.1`/`localhost`のhost allowlistを設定し、同じAPI proxyのsanitizationを使う。dev proxyのeffective authorityは、listen後の`server.httpServer.address().port`と固定host名から都度導出する(例: `127.0.0.1:5173`)。dev proxyもHostをそのportとの完全一致で検証し、Originがある場合は`http://<そのHost>`との完全一致で検証する。portを取得できない間はAPI proxyを503にする。dev serverはCORSを有効にしない。 + +### Browser request + +ブラウザは同一originの次のendpointだけを呼ぶ。 + +```http +GET /api/user +``` + +本番ではSPA Node serverが`API_URI`の`/api/user`へserver-side fetchし、次のheaderを付ける。 + +```http +Authorization: Bearer +Accept: application/json +``` + +fetchは`redirect: 'error'`を明示し、redirect先へAuthorizationを送らない。Vite dev serverではproductionと同じproxy fetch関数を使って既存APIへ転送する。ブラウザから既存APIへ直接tokenを送らない。 + +### URL parsing and API dispatch + +serverはHTTP request targetを次の順で1回だけ処理し、`new URL()`のpath正規化や複数回decodeへ依存しない。 + +1. raw targetが`/`で始まり`//`で始まらないことを確認する。不正なら400。 +2. queryとfragmentをraw pathnameから分離する。static assetではquery/fragmentを無視する。API endpointはquery/fragment付きの`/api/user`を400とする。 +3. `decodeURIComponent`を一度だけ適用し、malformed percent、NUL、backslash、`..` segmentがあれば400。 +4. decoded pathnameの先頭segmentが大文字小文字を問わず`api`で始まる場合(`api`そのものだけでなく`apiary`も含む)はreserved API namespaceとする。raw targetが正確に`/api/user`で、decoded pathnameも正確に`/api/user`のときだけproxyへdispatchする。それ以外(`/api%2Fuser`、`/%61pi/user`、`/api%252Fuser`、`/api/unknown`、`/apiary`など)は404とし、SPA fallbackしない。malformed percentなどstep 3の400が先に適用される。 +5. reserved namespaceでないpathだけをstatic file解決へ渡す。 + +### Upstream success example + +既存TypeSpecの`GET /api/user`契約に従い、成功応答は次の形である。 + +```json +{ + "count": 2, + "user": [ + { + "id": 1, + "name": "Alice", + "created_at": 1710000000, + "updated_at": 1710003600 + }, + { + "id": 2, + "name": "Bob", + "created_at": 1710007200, + "updated_at": 1710010800 + } + ] +} +``` + +proxy側でruntime validationを完了し、validな200応答だけを同じschemaのJSONへ再serializeしてbrowserへ返す。契約に合わない200応答は固定の502応答へ置き換え、raw bodyをbrowserへ渡さない。コンパイル時の型は`shared/src/schema`の生成型から導出し、同じobject shapeを手書きで再宣言しない。 + +`count`は`user.length`と一致しなければinvalidとする。current API実装がcountを取得件数として返すため、pagination等の別意味は導入しない。 + +### UI outputs + +1. **Loading**: `Hub 問い合わせ中`相当の控えめな状態と、`--`を表示する。mainへ`aria-busy="true"`を設定する。 +2. **Success / non-empty**: + - headerに`Service Template`と`API ONLINE`を表示する。 + - summary cardにAPIから取得した`count`を大きく表示し、ラベルは`登録ユーザー`とする。 + - user cardに`user`の各行(名前、ID、作成日時、更新日時)を表示する。 +3. **Success / empty**: `count === 0`かつ`user.length === 0`の場合、空状態カードに`--`と「ユーザーがありません」を表示する。 +4. **Failure**: + - headerに`API OFFLINE`を表示する。 + - 中央の状態カードに`OFFLINE`と「Service APIへ接続できません」を表示する。 + - token未設定、upstream非2xx、network failure、timeout、response size超過、redirect、JSON parse失敗、JSON shape不正を、tokenやupstream bodyを漏らさず同一の利用者向けエラー表示へ集約する。 + +status表示は`role="status" aria-live="polite"`、failure表示は`role="alert"`を使い、色だけに依存しない。 + +このサンプルはReact Routerの初回`clientLoader`から1回だけ取得する。手動refresh、定期refresh、編集、ページ遷移、chart、account/bucket/meterは実装しない。React StrictMode下でもfetchをcomponent effectに置かないため、初回navigationのloader requestは1回である。明示的なrevalidate操作も行わない。 + +### Timestamp display + +`created_at`と`updated_at`はTypeSpecのdocに従うUnix timestamp secondsとする。0以上のsafe integerで、`Date`が表現できる範囲だけをvalidとする。表示は`Intl.DateTimeFormat('ja-JP', { timeZone: 'Asia/Tokyo', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false })`で行い、末尾に`JST`を付ける。invalid valueに対するformat関数の`--`はproxyを迂回して関数を直接呼ぶ場合のdefensive fallbackであり、proxy経由のinvalid responseは画面へ到達せずfailureになる。 + +## Data Model + +永続化は行わない。ブラウザで扱う型は、既存API契約から次のように導出する。 + +```typescript +schema.paths['/api/user']['get']['responses']['200']['content']['application/json'] +``` + +runtime validationには`zod/mini`を使う。`id`、`count`、timestampの数値範囲、`name`のstring、`user`の配列、および`count === user.length`を検証する。 + +- `count`と`id`は0以上のsafe integer。 +- timestampsは0以上のsafe integerで、`new Date(seconds * 1000)`がvalidとなる範囲。 +- `name`は空文字も既存API契約上は受理する。表示時は文字列をそのままtext nodeへ渡し、HTMLとして解釈しない。 + +## Tech Stack + +- React 19 +- React Router v7 Framework Mode +- Vite Plus(既存rootの`vite-plus`およびVite overrideを利用)。rootの`vite` overrideはVite Plus coreへ解決されるため、SPAの標準Vite CLIは`vite-cli: npm:vite@^8.2.2` aliasで分離し、`npm run dev`の`vite` binへ接続する。`@react-router/dev`のVite peerは8.2.2、`vite-node`のVite dependencyは7.3.6へrootのscoped overrideで固定し、npm依存木をvalidに保つ。 +- TypeScript +- Node.js組み込み`node:http`による静的asset配信server +- `zod/mini`による外部API応答validation +- npm workspaces + +### Technical investigation + +方式は次の既存実装・契約を確認して決定した。 + +- `limit-monitor/packages/client/package.json`: React Router v7、React 19、`ssr: false` SPA、Node配信serverの構成。 +- `limit-monitor/packages/client/react-router.config.ts`: `ssr: false`と`buildDirectory: 'dist/spa'`の設定。 +- `limit-monitor/packages/client/src/server/static-server.ts`: static asset、SPA fallback、path traversal拒否、GET/HEAD制限、cache controlの実装。 +- `service-template/packages/shared/typespec/user.tsp`: 既存API`GET /api/user`の認証header、200/401/500応答、`count`/`user` response shape、Unix timestamp secondsのdoc。 +- `service-template/packages/api/src/lib/middleware.ts`: `Authorization` headerが必須で、Bearer tokenの検証を行う実装。 +- `service-template/packages/client/src/app/proxy/api/[...path]/route.ts`: 現行Next.jsがserver-sideでsession cookieを読み、APIへAuthorizationを注入する実装。SPAではこのhttpOnly cookieをbrowserから直接利用できないため、同じ安全境界をNode server-side proxyで維持する。 + +上記から、browser bundleへ`VITE_API_TOKEN`を埋め込む方式や、API responseに存在しないmeter値の生成は採用しない。 + +## Interface + +### Repository/package + +- 新規workspace: `packages/spa` +- 既存`packages/client`は併存させる。 +- package script: + - `dev`: React Router/Vite dev server。`/api/user`はproductionと同じsanitize済みdev proxyを使う。 + - `pretsc`: `shared` build(fresh checkoutでも生成schema型を用意する) + - `tsc`: React Router typegen + TypeScript noEmit + - `build`: SPA client buildとNode配信server buildを`dist/public` / `dist/server`へ出力 + - `start`: `dist/server/index.js`を起動 + - `test`: Vite Plus test + - `format` / `format-check` + - `lint` / `lint-fix` + +### Routes and server behavior + +- React Routerのapplication routeは`/`の1画面だけ。static serverが`/dashboard`などのextensionless pathへindex.htmlを返すのはtransport fallbackのテスト対象であり、サポートするapplication routeとは扱わない。 +- 静的serverは`GET` / `HEAD`だけを受理する。authority検証はrouting前に行う。 +- `/api/user`はGET専用のserver-side proxy endpointとする。`HEAD /api/user`はupstreamへ接続せず405と`Allow: GET`を返す。その他の`/api` namespaceは404とし、SPA fallbackしない。 +- Vite dev middlewareでeffective authorityを取得できない間、static targetはViteへ継続するが、malformed targetは400、reserved API targetは固定503(`Development server is not ready\n`)として`next()`へ流さない。 +- proxy successはvalidなupstream JSONだけを200で返す。missing tokenは503、upstream非2xx・network failure・timeout・redirect・response size超過・malformed/invalid shapeはすべて固定bodyの502とする。upstreamのstatus/bodyはbrowserへ転送しない。 +- proxy fetchは`redirect: 'error'`を使い、monotonic clock(`performance.now()`)によるabsolute deadlineをfetch直前に開始する。response headers受領、decoded body全量読込、size check、JSON parse、schema validation、serializeの各段階の前後でdeadlineを確認し、完了時刻がdeadlineを超えていれば200にせず502とする。deadline超過時はabortして502とする。browser requestのaborted/response closeおよびserver shutdown時はupstream fetchをAbortする。 +- body上限はFetch response bodyがcontent decodingされた後にstreamから受け取るbytesへ適用し、`Content-Length`の有無に関係なくchunk単位で数える。許容境界は`1_048_576` bytes以下(limit-1、limitはvalid)とし、累計がlimit+1になるchunkは一切bufferへ追加せず直ちにabortして502とする。chunkがlimitを超えても超過部分を保持・browser転送しない。 +- 拡張子のないpathは`index.html`へSPA fallbackする。ただし`/api` namespaceはURL parse後に除外する。 +- 拡張子付きで存在しないassetは404とし、SPA fallbackしない。 +- `..`、encoded traversal、backslash、NUL、protocol-relative URL、malformed percent encodingは400で拒否する。 +- 静的distributionは起動後に外部writerが変更しないimmutableなtrusted release treeを前提とする。設定された`SPA_DIST_DIR`自身もsymlinkであってはならず、起動時に`lstat`で拒否する。serverは実行中のpath置換競合へのportableな保証を提供しない。起動時・request時にsymlinkを配信対象から除外し、canonical root/fileがroot配下であることを確認し、最終file openでは`O_NOFOLLOW`相当を使う。事前に作られた中間directory/file symlinkは400/404とし、root外の実体を返さない。 +- authority不一致は400固定body、API requestのOrigin不一致は403固定bodyとし、どちらもproxy/static処理へ進まない。 +- 拡張子とContent-Typeの対応は次のとおりとする: `.html`=`text/html; charset=utf-8`、`.js`/`.mjs`=`text/javascript; charset=utf-8`、`.css`=`text/css; charset=utf-8`、`.json`/`.map`=`application/json; charset=utf-8`、`.svg`=`image/svg+xml`、`.png`=`image/png`、`.jpg`/`.jpeg`=`image/jpeg`、`.gif`=`image/gif`、`.webp`=`image/webp`、`.ico`=`image/x-icon`、`.woff`=`font/woff`、`.woff2`=`font/woff2`、`.ttf`=`font/ttf`、`.wasm`=`application/wasm`、`.webmanifest`=`application/manifest+json`、未知拡張子=`application/octet-stream`。 +- hashed asset(`assets/`配下)は`public, max-age=31536000, immutable`、`index.html`とAPI応答は`no-store`とする。全レスポンスに`X-Content-Type-Options: nosniff`を付ける。 + +### Endpoint/method/status/header matrix + +| Precedence/request | Condition | Status | Required headers/body | +| --- | --- | --- | --- | +| any request | Host missing, duplicated, comma-joined, or not the exact configured authority | 400 | `content-type: text/plain; charset=utf-8`, `cache-control: no-store`, `x-content-type-options: nosniff`, body `Bad Request\n` | +| any request with Origin | Origin duplicated, comma-joined, or not the exact `http://` | 403 | same headers, body `Forbidden\n` | +| any request | malformed target, protocol-relative target, malformed percent, NUL, backslash, or `..` segment | 400 | same fixed-error headers, body `Bad Request\n` | +| dev reserved API target | effective Vite dev authority is unavailable | 503 | same fixed-error headers, body `Development server is not ready\n`, no `next()` | +| `GET /` | valid authority, index exists | 200 | HTML MIME, `cache-control: no-store`, `nosniff`, index body | +| `GET /dashboard` | valid authority, extensionless transport fallback | 200 | index HTML, `no-store`; application route support is out of scope | +| `GET /assets/app-abcdef.js` | existing asset | 200 | JS MIME, immutable cache, `nosniff`, asset body | +| `GET /assets/missing.js` | missing asset | 404 | same headers, body `Not Found\n` | +| `GET /api/user` | valid authority, no Origin or matching Origin, token + valid upstream | 200 | `content-type: application/json; charset=utf-8`, `cache-control: no-store`, `nosniff`, reserialized JSON | +| `GET /api/user` | missing or whitespace-only token | 503 | same fixed-error headers, body `API token is not configured\n` | +| `GET /api/user` | any upstream/proxy validation failure | 502 | same fixed-error headers, body `Bad Gateway\n` | +| `GET /api/user?x=1` | query is not part of endpoint | 400 | same fixed-error headers, body `Bad Request\n`, no upstream call | +| `GET /api/unknown`, `/api%2Fuser`, `/%61pi/user`, `/api%252Fuser`, `/apiary` | reserved namespace but not exact endpoint | 404 | same fixed-error headers, body `Not Found\n`, no SPA fallback | +| `HEAD /api/user` | valid authority/origin | 405 | `allow: GET`, fixed-error headers, empty body, no upstream call | +| `POST /api/user` | valid authority/origin | 405 | `allow: GET`, fixed-error headers, body `Method Not Allowed\n`, no upstream call | +| `POST /` | valid authority/origin, unsupported method | 405 | `allow: GET, HEAD`, fixed-error headers, body `Method Not Allowed\n` | +| static `HEAD` | same lookup as corresponding static GET | corresponding GET status | same headers, empty body | +| any path | preexisting symlink in root or traversed component | 400 | same fixed-error headers, body `Bad Request\n` | + +`cache-control: no-store` and `x-content-type-options: nosniff` are required on every fixed error. Fixed bodies include the trailing newline and are never derived from upstream errors. `Origin` mismatch is checked for static and API requests alike. + +### Deterministic UI test fixtures + +`DashboardView`はloaderの実データとは独立して、次のfixtureをpropsとして直接受け取れる純粋な表示単位に分ける。 + +- loading: `HydrateFallback`を直接renderする。 +- success: `ok: true`、`count: 2`、Alice/Bobのexample response。 +- empty: `ok: true`、`count: 0`、`user: []`。 +- failure: `ok: false`、`status: 502`、bodyは`Bad Gateway`(表示では固定offline文言のみ)。 + +Vite Plus test + Testing Libraryで、4 fixtureそれぞれの必須文言、`role="status"`/`role="alert"`、`aria-busy`、count/user rowの有無をassertする。`clientLoader`はfetch spyを1回だけ呼び、React componentのuseEffectは使用しない。styles testでhex値、breakpoint、必須class/レイアウト宣言を確認する。live browserのviewport計測は成功fixtureを返す一時upstream serverを`API_URI`に指定して実行し、390px/1280px時の`scrollWidth <= clientWidth`、content width `<= 960px`、required header/status/summary/user-card arrangementをCSS computed valuesとselectorで確認する。loading/empty/failureの状態選択はTesting Library fixtureで決定的に行う。live browser検証で使用する一時upstreamはloopback bind・固定JSON・固定portまたは動的portを使い、既存APIや外部networkへ接続しない。 + +## Error Handling + +- fetch例外、timeout、redirect拒否、response size超過: server proxyは502固定body、browserはoffline表示。 +- `API_TOKEN`未設定: production/dev proxyとも503固定body。token値はレスポンスへ含めない。 +- upstream非2xx: server proxyは502固定body。upstream status/bodyはbrowserへ転送しない。 +- upstream 200のJSON parse失敗、schema validation失敗、count/user length mismatch、invalid number/date: server proxyは502固定body。 +- static path不正・traversal・拒否symlink: 400または404。dist外のfileを返さない。 +- unsupported method: 405と`Allow` headerを返す。 +- invalid `API_URI`、invalid `PORT`、non-loopback `HOST`、missing/non-directory `SPA_DIST_DIR`: 起動時に失敗する。 +- index.html欠落: 起動時に失敗。runtime request時のfixture serverでは404。 + +## Non-functional Requirements + +- API tokenはclient bundle、HTML、console log、access log、error bodyへ出さない。 +- Node serverはloopback bind、Host exact allowlist、optional Origin exact allowlistだけを使い、外部公開やCORSを設定で有効化できない。 +- 外部APIのデータ件数に比例するnetwork callを行わず、初回navigationの`GET /api/user`を1回だけ呼ぶ。 +- upstream fetchはfetch開始からvalidation完了まで5秒でabortし、content-decoded bodyを1MiBを超えて保持しない(1MiBちょうどは許容)。client disconnectとSIGTERMでもactive fetchをabortする。 +- UIは既存API応答が長くなっても横方向へはみ出さず、small viewportで1列へ縮退する。 +- static path解決はraw path / decoded path / canonical pathを検証し、immutable tree内のsymlinkを配信しない。 +- 新規packageのCIでlint、typecheck、shared build、spa build、testを実行する。 + +## Visual acceptance tokens + +- background: `#101418` +- panel: `#1a2027` +- panel border: `#2a323c` +- primary text: `#e6ebf0` +- muted text: `#8b98a5` +- online: `#34c176` +- offline/error: `#e5534b` +- page max width: `960px` +- page padding: `16px` +- panel radius: `12px` +- card gap: `16px` +- mobile-to-grid breakpoint: `640px` + +At viewport width 390pxはheader・summary・user rowsが横overflowせず1列、1280pxではcontent widthが960pxを超えないことをlive browserの`document.documentElement.scrollWidth <= document.documentElement.clientWidth`とcontent elementの`getBoundingClientRect().width <= 960`で確認する。loading、success、empty、offlineの4状態ではdeterministic fixtureによる必須文言・ARIA属性と上記token値を確認する。 + +## Out of Scope + +- Next.js `packages/client`の置換・削除・リファクタリング。 +- 新しいTypeSpec endpoint、API schema、DB schema、migration。 +- service-templateの認証provider変更。 +- browserへtokenを露出する方式。 +- LAN/public bind、proxy caller認証、CORS、production deploy。 +- 本物のlimit-monitor Hub、account、bucket、remaining percentage、reset time、chart。 +- refresh操作、ユーザー編集、ページ遷移、永続化。 +- 実行中distributionを外部writerが置き換えた場合のrace-free filesystem保証。 + +## Acceptance Criteria + +- [x] `packages/spa`がnpm workspaceとして認識され、`packages/client`と併存する。 +- [x] `packages/spa`にNext.js依存、Next.js設定、Next.js API routeが存在しない。 +- [x] React Router v7 + Viteの`ssr: false` SPAとして`npm run build -w spa`が成功し、`dist/public/index.html`と`dist/server/index.js`が生成される。 +- [x] `npm run dev -w spa`でSPAを起動でき、loopback Vite dev proxy経由で`GET /api/user`を呼べる。missing token/upstream errorのdev responseはproductionと同じsanitize contractを使い、effective authority未取得時のreserved API targetは固定503でfail-closedになる。 +- [x] production serverが`/api/user`だけをserver-side proxyし、`API_TOKEN`をbrowserへ渡さない。non-loopback HOST、Host authority不一致、Origin不一致を拒否する。 +- [x] proxyがredirectを拒否し、fetch開始からvalidation完了まで5秒deadline、decoded streamed body 1MiB上限、client disconnect/shutdown cancellationを適用する。 +- [x] valid success responseだけがbrowserへ再serializeされ、non-2xx/raw invalid responseが漏れない。`count !== user.length`は502になる。 +- [x] success responseの`count`/`user`、empty response、upstream failure、network failure、invalid response shapeがdeterministic fixture/API testに対応するUI状態として表示される。 +- [x] `limit-monitor`由来のdark dashboard方向性を、Visual acceptance tokens、4状態、390px/1280pxのlive browser計測で確認できる。 +- [x] static serverのSPA fallback、asset 404、path traversal拒否、unknown/encoded `/api`拒否、preexisting symlink拒否、method制限、content type/cache control、Host/Origin制限をendpoint matrixどおりテストで確認できる。 +- [x] `npm run lint -w spa`、`npm run tsc -w spa`、`npm run build -w shared`、`npm run build -w spa`、`npm run test -w spa`が成功する。 +- [x] `ci-spa.yml`が次のpathを監視する: `.github/workflows/ci-spa.yml`、`packages/spa/**`、`packages/shared/**`、`package.json`、`package-lock.json`、root `vite.config.ts`、`lint-rules/**`。workflowは`npm ci`、spa lint、shared build、spa tsc、spa build、spa testを順に実行する。spaの`pretsc`も単体実行時のfresh checkoutを成立させるためshared buildを行う。 +- [x] root workspace/lockfile変更が既存clientへ影響するため、`ci-client.yml`も`package-lock.json`をtrigger pathへ含め、既存のclient lint、shared build、client build、client testを実行する。spa追加だけでclientの既存contractを黙って省略しない。 +- [x] 変更前から存在する`packages/client`のlint/build/test契約を壊さない。 + +## Assumptions + +- package名`spa`、既存Next.js packageとの併設、React Router + Vite、Node static serverはユーザー選択に基づく。 +- ユーザーは「service-templateの既存APIへ接続」を選択したため、表示データは既存`/api/user`の`count`/`user`に限定する。limit-monitorのmeterを再現するためのAPI拡張は要求されていない。 +- Authorization方式とデータ対応付けの追加確認は2回タイムアウトしたため、安全側の実装としてloopback-only、Host/Origin allowlist、server-side `API_URI` + `API_TOKEN` proxyを採用する。browser bundleへtokenを埋め込まない。 +- 「見た目だけの静的1画面」は、画面を1ページに限定し、refreshや編集などの操作を追加しない意味で解釈する。ただし、初回表示時の既存API GETとloading/success/empty/error状態の描画は、先に選択されたAPI接続要件を満たすため実装する。 +- distributionの実行中変更は運用上禁止されたimmutable release treeを前提にする。`SPA_DIST_DIR`自身もsymlink不可で、起動時にnon-symlink directoryとして固定する。serverは外部writerとの同時変更を保護するfilesystem primitiveを提供しない。request時のsymlink拒否は起動後に事前配置されたtreeに対して保証し、同時置換競合はsupportしない。 + +## Adversarial Review + +### Round 1 + +- artifact: `docs/spec/reviews/spa-sample-round1.json` +- reviewer: GPT-5 Codex(CLI指定`gpt-5.6-sol`、runtime capability tier非公開) +- model relationship: unknown +- qualified gate: Pending(identity/tierの十分な証明なし) +- result: Blocking 1、Major 11。全指摘を改訂版へ反映した。 + +### Round 2 + +- artifact: `docs/spec/reviews/spa-sample-round2.json` +- reviewer: `gpt-5.6-sol`(runtime report) +- capability tier: not exposed +- model relationship: unknown +- qualified gate: Pending(author modelとの能力関係がruntimeで証明されていない) +- result: Blocking 2、Major 4。全指摘を本改訂版へ反映した。 + +### Round 3 + +- artifact: `docs/spec/reviews/spa-sample-round3.json` +- reviewer: `gpt-5.6-sol`(runtime report) +- capability tier: not exposed +- model relationship: unknown +- qualified gate: Pending(能力関係の証明なし) +- result: Blocking 2、Major 7。指摘を本改訂版へ反映した。原文verdictは修正前revisionの証跡として保存している。 + +### Round 4 / final closure + +- artifact: `docs/spec/reviews/spa-sample-round4.json` +- reviewer: `gpt-5.6-luna` +- capability tier: runtime (not exposed) +- model relationship: `Fallback: equivalent reviewer`(author modelと同一モデルをfresh独立contextで実施) +- 対象: CI順序修正後の本仕様書 +- 判定: **Passed** +- Blocking: 0、Major: 0、Minor: 0、Invalid: 0 +- transcript: `/home/koh110/.hermes/cache/delegation/live/deleg_bc68c7f6/task-0.log` + +## Implementation Review + +- final closure artifact: `docs/spec/reviews/spa-sample-code-review-round4.json` +- reviewer: GPT-5 Codex(capability tier: primary) +- result: **Passed**(Blocking 0、Major 0、Minor 0、Invalid 0) +- closed findings: M-001(dev proxy fail-closed)、M-002(security boundary/limit/cancellation test coverage)、m-001(ASCII-only token trim) diff --git a/package-lock.json b/package-lock.json index 25aab48..7ef4425 100644 --- a/package-lock.json +++ b/package-lock.json @@ -71,2046 +71,2174 @@ "node": ">=6.9.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.28.5", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.28.5.tgz", - "integrity": "sha512-qSs4ifwzKJSV39ucNjsvc6WVHs6b7S03sOh2OcHF9UHfVPqWWALUsNUVzhSBiItjRZoLHx7nIarVjqKVusUZ1Q==", + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" } }, - "node_modules/@babel/runtime": { + "node_modules/@babel/core": { "version": "7.29.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", - "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, "engines": { "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@blazediff/core": { - "version": "1.9.1", - "resolved": "https://registry.npmjs.org/@blazediff/core/-/core-1.9.1.tgz", - "integrity": "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==", - "license": "MIT" - }, - "node_modules/@bramus/specificity": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", - "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", - "devOptional": true, + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, "license": "MIT", "dependencies": { - "css-tree": "^3.0.0" + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", "bin": { - "specificity": "bin/cli.js" + "semver": "bin/semver.js" } }, - "node_modules/@csstools/color-helpers": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", - "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, "engines": { - "node": ">=20.19.0" + "node": ">=6.9.0" } }, - "node_modules/@csstools/css-calc": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.3.0.tgz", - "integrity": "sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz", + "integrity": "sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw==", + "dev": true, "license": "MIT", - "engines": { - "node": ">=20.19.0" + "dependencies": { + "@babel/types": "^7.29.7" }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@csstools/css-color-parser": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.10.tgz", - "integrity": "sha512-UZhQLIUyJaaMepqehrCODwCg2KW25vFvLWBmqYFaPclYvvxzj/sG8LBOhBFCp11i9uE7t1EyS+RAoV9tztPFyw==", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, "license": "MIT", "dependencies": { - "@csstools/color-helpers": "^6.1.0", - "@csstools/css-calc": "^3.3.0" + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, "engines": { - "node": ">=20.19.0" - }, - "peerDependencies": { - "@csstools/css-parser-algorithms": "^4.0.0", - "@csstools/css-tokenizer": "^4.0.0" + "node": ">=6.9.0" } }, - "node_modules/@csstools/css-parser-algorithms": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", - "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz", + "integrity": "sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/helper-replace-supers": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/traverse": "^7.29.7", + "semver": "^6.3.1" + }, "engines": { - "node": ">=20.19.0" + "node": ">=6.9.0" }, "peerDependencies": { - "@csstools/css-tokenizer": "^4.0.0" + "@babel/core": "^7.0.0" } }, - "node_modules/@csstools/css-syntax-patches-for-csstree": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.7.tgz", - "integrity": "sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], - "license": "MIT-0", - "peerDependencies": { - "css-tree": "^3.2.1" - }, - "peerDependenciesMeta": { - "css-tree": { - "optional": true - } + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@csstools/css-tokenizer": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", - "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", - "devOptional": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/csstools" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/csstools" - } - ], + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=20.19.0" + "node": ">=6.9.0" } }, - "node_modules/@electric-sql/pglite": { - "version": "0.4.3", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.4.3.tgz", - "integrity": "sha512-ichuWTgtd4mOM1G4SpyGJa5trT03lWbMypDV0fUXUCXg5hiHqVAz/bZyV68NqmkLB7WcYmj1RMJVSp8HV/v/ZQ==", - "license": "Apache-2.0" - }, - "node_modules/@electric-sql/pglite-socket": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.1.3.tgz", - "integrity": "sha512-LAciWM0M1dCL8hlsxu2venbVZcdxema0BtDfpWYVqr+Y468UADw0pFWidhKw1M8sfJ8rdLT71tjMmnirf/IZRQ==", - "license": "Apache-2.0", - "bin": { - "pglite-server": "dist/scripts/server.js" + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz", + "integrity": "sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" }, - "peerDependencies": { - "@electric-sql/pglite": "0.4.3" - } - }, - "node_modules/@electric-sql/pglite-tools": { - "version": "0.3.3", - "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.3.3.tgz", - "integrity": "sha512-AlzLJTRJ8+UFgK8CmxIpyIpJ0+YaFw02IiOSdYrqxwPXdSyeIShz8aa9Tq+tYFXdPwcaMp/Fc80mQZ1dkOQ/wg==", - "license": "Apache-2.0", - "peerDependencies": { - "@electric-sql/pglite": "0.4.3" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@emnapi/runtime": { - "version": "1.11.3", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", - "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, "license": "MIT", - "optional": true, "dependencies": { - "tslib": "^2.4.0" + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@exodus/bytes": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", - "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", - "devOptional": true, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": ">=6.9.0" }, "peerDependencies": { - "@noble/hashes": "^1.8.0 || ^2.0.0" - }, - "peerDependenciesMeta": { - "@noble/hashes": { - "optional": true - } + "@babel/core": "^7.0.0" } }, - "node_modules/@floating-ui/core": { - "version": "1.7.5", - "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", - "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz", + "integrity": "sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong==", + "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/utils": "^0.2.11" + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@floating-ui/dom": { - "version": "1.7.6", - "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", - "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, "license": "MIT", - "dependencies": { - "@floating-ui/core": "^1.7.5", - "@floating-ui/utils": "^0.2.11" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@floating-ui/react-dom": { - "version": "2.1.8", - "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", - "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", + "node_modules/@babel/helper-replace-supers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz", + "integrity": "sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ==", + "dev": true, "license": "MIT", "dependencies": { - "@floating-ui/dom": "^1.7.6" + "@babel/helper-member-expression-to-functions": "^7.29.7", + "@babel/helper-optimise-call-expression": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "react": ">=16.8.0", - "react-dom": ">=16.8.0" + "@babel/core": "^7.0.0" } }, - "node_modules/@floating-ui/utils": { - "version": "0.2.11", - "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", - "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", - "license": "MIT" + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz", + "integrity": "sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } }, - "node_modules/@hono/node-server": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.0.tgz", - "integrity": "sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg==", + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, "license": "MIT", "engines": { - "node": ">=20" - }, - "peerDependencies": { - "hono": "^4" + "node": ">=6.9.0" } }, - "node_modules/@img/colour": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", - "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", "license": "MIT", - "optional": true, "engines": { - "node": ">=18" + "node": ">=6.9.0" } }, - "node_modules/@img/sharp-darwin-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", - "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", - "cpu": [ - "arm64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-arm64": "1.3.2" + "node": ">=6.9.0" } }, - "node_modules/@img/sharp-darwin-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", - "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", - "cpu": [ - "x64" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, "engines": { - "node": ">=20.9.0" + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.8.tgz", + "integrity": "sha512-E8lTAYNB1KW+FH+VGJuZM1ioAx2E6oVlvQFRrf5P8ZZmsiJXYAD9vTFV7yyEURNzgh1dFqMZuO6tUwcARbqFCA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" }, - "funding": { - "url": "https://opencollective.com/libvips" + "bin": { + "parser": "bin/babel-parser.js" }, - "optionalDependencies": { - "@img/sharp-libvips-darwin-x64": "1.3.2" + "engines": { + "node": ">=6.0.0" } }, - "node_modules/@img/sharp-freebsd-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", - "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", - "license": "Apache-2.0", - "optional": true, - "os": [ - "freebsd" - ], + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz", + "integrity": "sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A==", + "dev": true, + "license": "MIT", "dependencies": { - "@img/sharp-wasm32": "0.35.3" + "@babel/helper-plugin-utils": "^7.29.7" }, "engines": { - "node": ">=20.9.0" + "node": ">=6.9.0" }, - "funding": { - "url": "https://opencollective.com/libvips" + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@img/sharp-libvips-darwin-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", - "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", - "cpu": [ - "arm64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz", + "integrity": "sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@img/sharp-libvips-darwin-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", - "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", - "cpu": [ - "x64" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "darwin" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz", + "integrity": "sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@img/sharp-libvips-linux-arm": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", - "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", - "cpu": [ - "arm" - ], - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babel/plugin-transform-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz", + "integrity": "sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.29.7", + "@babel/helper-create-class-features-plugin": "^7.29.7", + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-skip-transparent-expression-wrappers": "^7.29.7", + "@babel/plugin-syntax-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@img/sharp-libvips-linux-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", - "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babel/preset-typescript": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/preset-typescript/-/preset-typescript-7.29.7.tgz", + "integrity": "sha512-/Foi8vKY2EVbed/1eZx0gJEEwHAIxogrySI7rULcRIvhZzbvoE/b5qG5Ghc0WKAFKOHA9SD1x7RsFlOYdutIiQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-plugin-utils": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "@babel/plugin-syntax-jsx": "^7.29.7", + "@babel/plugin-transform-modules-commonjs": "^7.29.7", + "@babel/plugin-transform-typescript": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" } }, - "node_modules/@img/sharp-libvips-linux-ppc64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", - "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", - "cpu": [ - "ppc64" - ], - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@img/sharp-libvips-linux-riscv64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", - "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", - "cpu": [ - "riscv64" - ], - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@img/sharp-libvips-linux-s390x": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", - "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", - "cpu": [ - "s390x" - ], - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@img/sharp-libvips-linux-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", - "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@img/sharp-libvips-linuxmusl-arm64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", - "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@img/sharp-libvips-linuxmusl-x64": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", - "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], - "license": "LGPL-3.0-or-later", - "optional": true, - "os": [ - "linux" - ], - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@img/sharp-linux-arm": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", - "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", - "cpu": [ - "arm" - ], - "libc": [ - "glibc" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node_modules/@blazediff/core": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@blazediff/core/-/core-1.9.1.tgz", + "integrity": "sha512-ehg3jIkYKulZh+8om/O25vkvSsXXwC+skXmyA87FFx6A/45eqOkZsBltMw/TVteb0mloiGT8oGRTcjRAz66zaA==", + "license": "MIT" + }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm": "1.3.2" + "bin": { + "specificity": "bin/cli.js" } }, - "node_modules/@img/sharp-linux-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", - "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" + "node_modules/@csstools/color-helpers": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.0.tgz", + "integrity": "sha512-064IFJdjTfUqnjpCVpMOdbr8FLQBhinbZj6yRv2An2E41O/pLEXqfFRWqGq/SxlE5PEUYTlvWsG2r8MswAVvkg==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT-0", "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-arm64": "1.3.2" + "node": ">=20.19.0" } }, - "node_modules/@img/sharp-linux-ppc64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", - "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", - "cpu": [ - "ppc64" - ], - "libc": [ - "glibc" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" + "node_modules/@csstools/css-calc": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.3.0.tgz", + "integrity": "sha512-c5ihYsPkdG6JCkU2zTMm4+k6r7RXuGxtWYhu5DHMIiF1FHzrfmHL5so11AoFpUv/tu61xfcmT4AmKoFfMPoqdQ==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT", "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=20.19.0" }, - "optionalDependencies": { - "@img/sharp-libvips-linux-ppc64": "1.3.2" + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" } }, - "node_modules/@img/sharp-linux-riscv64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", - "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", - "cpu": [ - "riscv64" - ], - "libc": [ - "glibc" - ], - "license": "Apache-2.0", - "optional": true, - "os": [ - "linux" + "node_modules/@csstools/css-color-parser": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.1.10.tgz", + "integrity": "sha512-UZhQLIUyJaaMepqehrCODwCg2KW25vFvLWBmqYFaPclYvvxzj/sG8LBOhBFCp11i9uE7t1EyS+RAoV9tztPFyw==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.0", + "@csstools/css-calc": "^3.3.0" + }, "engines": { - "node": ">=20.9.0" + "node": ">=20.19.0" }, - "funding": { - "url": "https://opencollective.com/libvips" + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" }, - "optionalDependencies": { - "@img/sharp-libvips-linux-riscv64": "1.3.2" + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" } }, - "node_modules/@img/sharp-linux-s390x": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", - "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", - "cpu": [ - "s390x" + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.7.tgz", + "integrity": "sha512-fQ+05118eQS1cofO3aJpB5efgpBZMvIzwr/sbC8kDLVA5XLG8q1kJV5yzrUAI1f7lvhPnm8fgIjzFB8/O/5Dig==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], - "libc": [ - "glibc" + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.0.tgz", + "integrity": "sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==", + "devOptional": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@electric-sql/pglite": { + "version": "0.4.3", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite/-/pglite-0.4.3.tgz", + "integrity": "sha512-ichuWTgtd4mOM1G4SpyGJa5trT03lWbMypDV0fUXUCXg5hiHqVAz/bZyV68NqmkLB7WcYmj1RMJVSp8HV/v/ZQ==", + "license": "Apache-2.0" + }, + "node_modules/@electric-sql/pglite-socket": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-socket/-/pglite-socket-0.1.3.tgz", + "integrity": "sha512-LAciWM0M1dCL8hlsxu2venbVZcdxema0BtDfpWYVqr+Y468UADw0pFWidhKw1M8sfJ8rdLT71tjMmnirf/IZRQ==", + "license": "Apache-2.0", + "bin": { + "pglite-server": "dist/scripts/server.js" + }, + "peerDependencies": { + "@electric-sql/pglite": "0.4.3" + } + }, + "node_modules/@electric-sql/pglite-tools": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/@electric-sql/pglite-tools/-/pglite-tools-0.3.3.tgz", + "integrity": "sha512-AlzLJTRJ8+UFgK8CmxIpyIpJ0+YaFw02IiOSdYrqxwPXdSyeIShz8aa9Tq+tYFXdPwcaMp/Fc80mQZ1dkOQ/wg==", "license": "Apache-2.0", + "peerDependencies": { + "@electric-sql/pglite": "0.4.3" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.28.2.tgz", + "integrity": "sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==", + "cpu": [ + "ppc64" + ], + "license": "MIT", "optional": true, "os": [ - "linux" + "aix" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-s390x": "1.3.2" + "node": ">=18" } }, - "node_modules/@img/sharp-linux-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", - "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", + "node_modules/@esbuild/android-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.28.2.tgz", + "integrity": "sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==", "cpu": [ - "x64" - ], - "libc": [ - "glibc" + "arm" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linux-x64": "1.3.2" + "node": ">=18" } }, - "node_modules/@img/sharp-linuxmusl-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", - "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", + "node_modules/@esbuild/android-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.28.2.tgz", + "integrity": "sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==", "cpu": [ "arm64" ], - "libc": [ - "musl" - ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" + "node": ">=18" } }, - "node_modules/@img/sharp-linuxmusl-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", - "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", + "node_modules/@esbuild/android-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.28.2.tgz", + "integrity": "sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==", "cpu": [ "x64" ], - "libc": [ - "musl" - ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "android" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-libvips-linuxmusl-x64": "1.3.2" + "node": ">=18" } }, - "node_modules/@img/sharp-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", - "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", - "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", + "node_modules/@esbuild/darwin-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.28.2.tgz", + "integrity": "sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==", + "cpu": [ + "arm64" + ], + "license": "MIT", "optional": true, - "dependencies": { - "@emnapi/runtime": "^1.11.1" - }, + "os": [ + "darwin" + ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=18" } }, - "node_modules/@img/sharp-webcontainers-wasm32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", - "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", + "node_modules/@esbuild/darwin-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.28.2.tgz", + "integrity": "sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==", "cpu": [ - "wasm32" + "x64" ], - "license": "Apache-2.0", + "license": "MIT", "optional": true, - "dependencies": { - "@img/sharp-wasm32": "0.35.3" - }, + "os": [ + "darwin" + ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=18" } }, - "node_modules/@img/sharp-win32-arm64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", - "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.28.2.tgz", + "integrity": "sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==", "cpu": [ "arm64" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "win32" + "freebsd" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=18" } }, - "node_modules/@img/sharp-win32-ia32": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", - "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", + "node_modules/@esbuild/freebsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.28.2.tgz", + "integrity": "sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==", "cpu": [ - "ia32" + "x64" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "win32" + "freebsd" ], "engines": { - "node": "^20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=18" } }, - "node_modules/@img/sharp-win32-x64": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", - "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", + "node_modules/@esbuild/linux-arm": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.28.2.tgz", + "integrity": "sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==", "cpu": [ - "x64" + "arm" ], - "license": "Apache-2.0 AND LGPL-3.0-or-later", + "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": ">=20.9.0" - }, - "funding": { - "url": "https://opencollective.com/libvips" + "node": ">=18" } }, - "node_modules/@inquirer/ansi": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz", - "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==", - "dev": true, + "node_modules/@esbuild/linux-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.28.2.tgz", + "integrity": "sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==", + "cpu": [ + "arm64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": ">=18" } }, - "node_modules/@inquirer/checkbox": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.1.tgz", - "integrity": "sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw==", - "dev": true, + "node_modules/@esbuild/linux-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.28.2.tgz", + "integrity": "sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^2.0.7", - "@inquirer/core": "^11.2.1", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/confirm": { - "version": "6.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.1.1.tgz", - "integrity": "sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==", - "dev": true, + "node_modules/@esbuild/linux-loong64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.28.2.tgz", + "integrity": "sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==", + "cpu": [ + "loong64" + ], "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/core": { - "version": "11.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz", - "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==", - "dev": true, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.28.2.tgz", + "integrity": "sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==", + "cpu": [ + "mips64el" + ], "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^2.0.7", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7", - "cli-width": "^4.1.0", - "fast-wrap-ansi": "^0.2.0", - "mute-stream": "^3.0.0", - "signal-exit": "^4.1.0" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/editor": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.2.2.tgz", - "integrity": "sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg==", - "dev": true, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.28.2.tgz", + "integrity": "sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==", + "cpu": [ + "ppc64" + ], "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/external-editor": "^3.0.3", - "@inquirer/type": "^4.0.7" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/expand": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.1.tgz", - "integrity": "sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g==", - "dev": true, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.28.2.tgz", + "integrity": "sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==", + "cpu": [ + "riscv64" + ], "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/external-editor": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.3.tgz", - "integrity": "sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA==", - "dev": true, + "node_modules/@esbuild/linux-s390x": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.28.2.tgz", + "integrity": "sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==", + "cpu": [ + "s390x" + ], "license": "MIT", - "dependencies": { - "chardet": "^2.1.1", - "iconv-lite": "^0.7.2" - }, + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/figures": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz", - "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==", - "dev": true, + "node_modules/@esbuild/linux-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.28.2.tgz", + "integrity": "sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==", + "cpu": [ + "x64" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": ">=18" } }, - "node_modules/@inquirer/input": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.2.tgz", - "integrity": "sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg==", - "dev": true, + "node_modules/@esbuild/netbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-arm64/-/netbsd-arm64-0.28.2.tgz", + "integrity": "sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/number": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.1.1.tgz", - "integrity": "sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA==", - "dev": true, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.28.2.tgz", + "integrity": "sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" - }, + "optional": true, + "os": [ + "netbsd" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/password": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.1.1.tgz", - "integrity": "sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg==", - "dev": true, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.28.2.tgz", + "integrity": "sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^2.0.7", - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/prompts": { - "version": "8.5.2", - "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.5.2.tgz", - "integrity": "sha512-IYR/3C/paEVVQYQvdDlFZVjRCJVYHHON0XXMH91KO9GSxs0TdKYWlUdvfQl2EfAHDxUaN3IBffkE/BDTh5nJ6g==", - "dev": true, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.28.2.tgz", + "integrity": "sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@inquirer/checkbox": "^5.2.1", - "@inquirer/confirm": "^6.1.1", - "@inquirer/editor": "^5.2.2", - "@inquirer/expand": "^5.1.1", - "@inquirer/input": "^5.1.2", - "@inquirer/number": "^4.1.1", - "@inquirer/password": "^5.1.1", - "@inquirer/rawlist": "^5.3.1", - "@inquirer/search": "^4.2.1", - "@inquirer/select": "^5.2.1" - }, + "optional": true, + "os": [ + "openbsd" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/rawlist": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.1.tgz", - "integrity": "sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og==", - "dev": true, + "node_modules/@esbuild/openharmony-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/openharmony-arm64/-/openharmony-arm64-0.28.2.tgz", + "integrity": "sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/type": "^4.0.7" - }, + "optional": true, + "os": [ + "openharmony" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/search": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.2.1.tgz", - "integrity": "sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g==", - "dev": true, + "node_modules/@esbuild/sunos-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.28.2.tgz", + "integrity": "sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@inquirer/core": "^11.2.1", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7" - }, + "optional": true, + "os": [ + "sunos" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/select": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.1.tgz", - "integrity": "sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw==", - "dev": true, + "node_modules/@esbuild/win32-arm64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.28.2.tgz", + "integrity": "sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@inquirer/ansi": "^2.0.7", - "@inquirer/core": "^11.2.1", - "@inquirer/figures": "^2.0.7", - "@inquirer/type": "^4.0.7" - }, + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" - }, - "peerDependencies": { - "@types/node": ">=18" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "node": ">=18" } }, - "node_modules/@inquirer/type": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", - "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", - "dev": true, + "node_modules/@esbuild/win32-ia32": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.28.2.tgz", + "integrity": "sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==", + "cpu": [ + "ia32" + ], "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.28.2.tgz", + "integrity": "sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.1.tgz", + "integrity": "sha512-S6mL0yNB/Abt9Ei4tq8gDhcczc4S3+vQ4ra7vxnAf+YHC02srtqxKKZghx2Dq6p0e66THKwR6r8N6P95wEty7Q==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" }, "peerDependencies": { - "@types/node": ">=18" + "@noble/hashes": "^1.8.0 || ^2.0.0" }, "peerDependenciesMeta": { - "@types/node": { + "@noble/hashes": { "optional": true } } }, - "node_modules/@isaacs/fs-minipass": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", - "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", - "dev": true, - "license": "ISC", - "dependencies": { - "minipass": "^7.0.4" - }, - "engines": { - "node": ">=18.0.0" - } - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.13", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", - "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", - "dev": true, + "node_modules/@floating-ui/core": { + "version": "1.7.5", + "resolved": "https://registry.npmjs.org/@floating-ui/core/-/core-1.7.5.tgz", + "integrity": "sha512-1Ih4WTWyw0+lKyFMcBHGbb5U5FtuHJuujoyyr5zTaWS5EYMeT6Jb2AuDeftsCsEuchO+mM2ij5+q9crhydzLhQ==", "license": "MIT", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.0", - "@jridgewell/trace-mapping": "^0.3.24" + "@floating-ui/utils": "^0.2.11" } }, - "node_modules/@jridgewell/remapping": { - "version": "2.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", - "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", - "dev": true, + "node_modules/@floating-ui/dom": { + "version": "1.7.6", + "resolved": "https://registry.npmjs.org/@floating-ui/dom/-/dom-1.7.6.tgz", + "integrity": "sha512-9gZSAI5XM36880PPMm//9dfiEngYoC6Am2izES1FF406YFsjvyBMmeJ2g4SAju3xWwtuynNRFL2s9hgxpLI5SQ==", "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.24" + "@floating-ui/core": "^1.7.5", + "@floating-ui/utils": "^0.2.11" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, + "node_modules/@floating-ui/react-dom": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@floating-ui/react-dom/-/react-dom-2.1.8.tgz", + "integrity": "sha512-cC52bHwM/n/CxS87FH0yWdngEZrjdtLW/qVruo68qg+prK7ZQ4YGdut2GyDVpoGeAYe/h899rVeOVm6Oi40k2A==", "license": "MIT", - "engines": { - "node": ">=6.0.0" + "dependencies": { + "@floating-ui/dom": "^1.7.6" + }, + "peerDependencies": { + "react": ">=16.8.0", + "react-dom": ">=16.8.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.5.5", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", - "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "node_modules/@floating-ui/utils": { + "version": "0.2.11", + "resolved": "https://registry.npmjs.org/@floating-ui/utils/-/utils-0.2.11.tgz", + "integrity": "sha512-RiB/yIh78pcIxl6lLMG0CgBXAZ2Y0eVHqMPYugu+9U0AeT6YBeiJpf7lbdJNIugFP5SIjwNRgo4DhR1Qxi26Gg==", "license": "MIT" }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.31", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", - "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", - "dev": true, + "node_modules/@hono/node-server": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@hono/node-server/-/node-server-2.1.0.tgz", + "integrity": "sha512-XovyyCCnBzW+zKu+z/zq8hwNs4KOR5rEMAOxo2f40Q5xoOI37IMm6MIg2COOUtUApo0i6850MTBKH2u4QLGIqg==", "license": "MIT", - "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "engines": { + "node": ">=20" + }, + "peerDependencies": { + "hono": "^4" } }, - "node_modules/@next/env": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@next/env/-/env-16.3.0.tgz", - "integrity": "sha512-o9r1S0BNiNreHP9Vs+Qnqd9kviDkJh8xIACY7UFZSmiGbbQRzPBBosvHzAU4TULHOIuOj/18RSsyz2qrREmIFw==", - "license": "MIT" + "node_modules/@img/colour": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@img/colour/-/colour-1.1.0.tgz", + "integrity": "sha512-Td76q7j57o/tLVdgS746cYARfSyxk8iEfRxewL9h4OMzYhbW4TAcppl0mT4eyqXddh6L/jwoM75mo7ixa/pCeQ==", + "license": "MIT", + "optional": true, + "engines": { + "node": ">=18" + } }, - "node_modules/@next/swc-darwin-arm64": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.3.0.tgz", - "integrity": "sha512-55hpqq18bEVAlxedlTt3tFqZmKg2nUXT1kn1G/BGEy0R13h3LwtwHPVzzjG6P4LLeOHE32PFDQUVaJEWvBEZBw==", + "node_modules/@img/sharp-darwin-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-arm64/-/sharp-darwin-arm64-0.35.3.tgz", + "integrity": "sha512-RMnFX7YQsMoh7lWfcM4NEHHymBX/rLuKNPVM84XE9ONPcaSCDgE7CHIHpSgPcO2xcRthgBy1HfNO319mwhIAkg==", "cpu": [ "arm64" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">= 10" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-arm64": "1.3.2" } }, - "node_modules/@next/swc-darwin-x64": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.3.0.tgz", - "integrity": "sha512-SOi96kSaF5T+0wW4koiM1bWzSPwjzTesC1p3df+FjdOi5LIQkBK/blxh7HdoKnNuI4PURF1OO7TZqtfnbWDSgw==", + "node_modules/@img/sharp-darwin-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-darwin-x64/-/sharp-darwin-x64-0.35.3.tgz", + "integrity": "sha512-Xo+5uFBtLN0BKqieTxiFzFPQAUlBbbH5iBKyRX/z1JrbnYsHTfKJnUfL8+p2TPXr1pXqao4eeL4Rl144uDpK9w==", "cpu": [ "x64" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">= 10" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-darwin-x64": "1.3.2" } }, - "node_modules/@next/swc-linux-arm64-gnu": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.3.0.tgz", - "integrity": "sha512-P0gZAoPMF4dyTRzhmkV4PrqVzSOB6t4mC1oI3c4dqijJ+OVEVx5clIXAKR4/uQpsqw2KKM/0D5tVumcR2r5blg==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", + "node_modules/@img/sharp-freebsd-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-freebsd-wasm32/-/sharp-freebsd-wasm32-0.35.3.tgz", + "integrity": "sha512-lUxcqWIj2wMQ9BrwNjngcr1gWUr5xgaGThBRqPPalIC2n67Cqj1uPh8NnA/ZhAg8hUbKl+kVHKwgUIwe6ZYPrg==", + "license": "Apache-2.0", "optional": true, "os": [ - "linux" + "freebsd" ], + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, "engines": { - "node": ">= 10" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@next/swc-linux-arm64-musl": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.3.0.tgz", - "integrity": "sha512-tXXGKJw0m37O0eKJARVTX/TheKPhz0QFVtVVZXmOig+9YKLQOSP6hvf2pxv5DO7CLEJyTHx3Pg043CDQkv1G4Q==", + "node_modules/@img/sharp-libvips-darwin-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-arm64/-/sharp-libvips-darwin-arm64-1.3.2.tgz", + "integrity": "sha512-9J6ypZFpQBj4YnePGoq/S38w6nz+vqg5WZLrLGY4YuSemdMq47GMLBPO42MzwdGwpg/agZ7xzZcFHa48xlywfg==", "cpu": [ "arm64" ], - "libc": [ - "musl" - ], - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "linux" + "darwin" ], - "engines": { - "node": ">= 10" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@next/swc-linux-x64-gnu": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.3.0.tgz", - "integrity": "sha512-pjGxK5EY7yWml78ALejFkWmgHsU7wbFQrISiugpH6FbUJhgEvw3xFZ/EBAtLl7QtL0WdQKiG9eWJ3mOKGTukHw==", + "node_modules/@img/sharp-libvips-darwin-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-darwin-x64/-/sharp-libvips-darwin-x64-1.3.2.tgz", + "integrity": "sha512-m2pW1n6cns9VaubNwsZ+c3CRYjxNQWgJ5gPlnL1nbBcpkBvFm6SCFN5o0psFHI8w9n11NKhFkeEDns98tiqbEw==", "cpu": [ "x64" ], - "libc": [ - "glibc" - ], - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "linux" + "darwin" ], - "engines": { - "node": ">= 10" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@next/swc-linux-x64-musl": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.3.0.tgz", - "integrity": "sha512-sjo++Xx+lomlPs3HRsHWhVDyGG6ms1kGW5EtHLERdII8AyG1i+f6aq68xHREO6AEMlhjTNEWBSmfJfqm9orf7g==", + "node_modules/@img/sharp-libvips-linux-arm": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm/-/sharp-libvips-linux-arm-1.3.2.tgz", + "integrity": "sha512-1eMLzy92I4J6rmi4mAT8yC3HxOtniyGELlzGbNMLLeqe052ahFQ0h6LFq+lh5DsDIdYViIDst08abvSbcEdLXQ==", "cpu": [ - "x64" + "arm" ], "libc": [ - "musl" + "glibc" ], - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" ], - "engines": { - "node": ">= 10" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@next/swc-win32-arm64-msvc": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.3.0.tgz", - "integrity": "sha512-C5JSgiO54wURdaxdEUIXqkz04uMqC9UmPX1gtDrV/5Tf1UowdWYI8uA5hfFbPolTlp0q4KZ60xlHePNibf0VIw==", + "node_modules/@img/sharp-libvips-linux-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-arm64/-/sharp-libvips-linux-arm64-1.3.2.tgz", + "integrity": "sha512-dqVSFynCox4C/J8kT16V7SIFAns0IjgLwkvYT7p8LQVmJ5OS5b6tI9IGflxTeuBS//zXeFIUbwt5dwxyZ17cnA==", "cpu": [ "arm64" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "win32" + "linux" ], - "engines": { - "node": ">= 10" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@next/swc-win32-x64-msvc": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.3.0.tgz", - "integrity": "sha512-fDOggsweNb5SSw0ZKVk6U+gxSyGFFlIBY/LBc1r8GUj4u/6t6oArL+Pmkg0MBnsgR+KkdsURilVH4F3GXUGepA==", + "node_modules/@img/sharp-libvips-linux-ppc64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-ppc64/-/sharp-libvips-linux-ppc64-1.3.2.tgz", + "integrity": "sha512-3z0NHDxD6n5I9gc05U1eW1AyRm+Gznzq3naMrthPNqE6oYykcogW0l/jfpJdjYnuNl8R7yI9pNbE1XiUeyq0Aw==", "cpu": [ - "x64" + "ppc64" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "win32" + "linux" ], - "engines": { - "node": ">= 10" - } - }, - "node_modules/@oxc-project/runtime": { - "version": "0.143.0", - "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.143.0.tgz", - "integrity": "sha512-zIuXUf+YGIgsPk0xlQmzTY8NCSc8jE/pSfDodlQ9H3EGZABmr+AtIjXRrnpQAXuXzhDSNqZz9cuhud8hDDLvpg==", - "license": "MIT", - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxc-project/types": { - "version": "0.143.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.143.0.tgz", - "integrity": "sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==", - "license": "MIT", "funding": { - "url": "https://github.com/sponsors/Boshen" + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxfmt/binding-android-arm-eabi": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.62.0.tgz", - "integrity": "sha512-pdsv0C4gPjJ8H1+sd8u0BDx+yLACTL+rgeMIOL1ln4ihSnhw8CWXtYWgvcSkyTfgGBIzFKab+d8rx9Xl4en/Kw==", + "node_modules/@img/sharp-libvips-linux-riscv64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-riscv64/-/sharp-libvips-linux-riscv64-1.3.2.tgz", + "integrity": "sha512-bsb4rI+NldGOsXuej2r8OdSS8+zXDVaCWxyWrcv6kneTOlgAHtZABRzBBCwdsPiD90J4myNJuHpg6kA20ImW/w==", "cpu": [ - "arm" + "riscv64" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "android" + "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxfmt/binding-android-arm64": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.62.0.tgz", - "integrity": "sha512-WC3YQ7uS/KtDrjmqwBviwFKe9qeoi+eXx8aX1z/ffG23Md75myjrJaQqTuJvdOLPoa4EYTjDWH0dHXfwulCVog==", + "node_modules/@img/sharp-libvips-linux-s390x": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-s390x/-/sharp-libvips-linux-s390x-1.3.2.tgz", + "integrity": "sha512-/ABshyj8gCpyIrNXnHn4LorDJ0HHm1VhXPBlxZ8zAtfVPAaSafXPGn+sUSIRiwaSBy0mmFjSjiXI5mkcwdChKQ==", "cpu": [ - "arm64" + "s390x" ], - "license": "MIT", + "libc": [ + "glibc" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "android" + "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxfmt/binding-darwin-arm64": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.62.0.tgz", - "integrity": "sha512-GM8Yf3LjjaR1I8PD0SfeoIlwhsh9GvSF+cQ8sf624Yxnjsyumn95aFzYfKJVefblfDIiOAnZ7QVm2sa21Er/0Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxfmt/binding-darwin-x64": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.62.0.tgz", - "integrity": "sha512-d5THp7F8bCxLqNogEXDORRsQD6dosf3EyFtnXfBer6v+8tGdcWIjoDX9WaXrrF/26zOmL8qHpPTKCEvpBDmZkQ==", + "node_modules/@img/sharp-libvips-linux-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linux-x64/-/sharp-libvips-linux-x64-1.3.2.tgz", + "integrity": "sha512-ITPEtgffGJ0S6G9dRyw/366tJQqFRcHWPHhC+Stpg3Z8AEMrDrTr2lhdz4f/Y/HMbRh//7Z5mBzEpVdi62Oc3w==", "cpu": [ "x64" ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" - } - }, - "node_modules/@oxfmt/binding-freebsd-x64": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.62.0.tgz", - "integrity": "sha512-1DnrtXGZooOZ0fHgAXZUaDQzBVh1CM2MNW4oBXyQ2aWKvCHjyljvT9fgBkOM0fEOb96X5eqtcfJ0YUVt9jj66g==", - "cpu": [ - "x64" + "libc": [ + "glibc" ], - "license": "MIT", + "license": "LGPL-3.0-or-later", "optional": true, "os": [ - "freebsd" + "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxfmt/binding-linux-arm-gnueabihf": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.62.0.tgz", - "integrity": "sha512-4pQDHOYRH+Huqe0StIaWyvk2CVl/aTaqSrbZpA3/pLS2xH24ME7lBgYprhQF2fRkHBzhGGGKliwxFsDdHwx59g==", + "node_modules/@img/sharp-libvips-linuxmusl-arm64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-arm64/-/sharp-libvips-linuxmusl-arm64-1.3.2.tgz", + "integrity": "sha512-zE9EdiUzUmg5mDT5a1rk5fYJ6GWPloTwWBYDS14naqHsL+EaMpDj1AWnpLgh3u0YCORv2Tt50wrcrpYqkP97Kw==", "cpu": [ - "arm" + "arm64" ], - "license": "MIT", + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxfmt/binding-linux-arm-musleabihf": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.62.0.tgz", - "integrity": "sha512-X0jAaZJFMCVKhB6YyWVTQ/wN2DLsBcZKSMqTS76bF6riT+XZdtg2FPEdjDvdVbunO9cG+tWiVaEs4Zs38lxYog==", + "node_modules/@img/sharp-libvips-linuxmusl-x64": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@img/sharp-libvips-linuxmusl-x64/-/sharp-libvips-linuxmusl-x64-1.3.2.tgz", + "integrity": "sha512-m0lrLiUt+lBYnCFr8qV/65yMR4E/c7/wf78I5eKTdkEakFAlZ9QlzEM3QIhhAwVeUhLAHLcCq7a7Vszq/oFNZQ==", "cpu": [ - "arm" + "x64" ], - "license": "MIT", + "libc": [ + "musl" + ], + "license": "LGPL-3.0-or-later", "optional": true, "os": [ "linux" ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxfmt/binding-linux-arm64-gnu": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.62.0.tgz", - "integrity": "sha512-682Z8T5s8T5ATArYtsejKvbIfd8LEAXyyDkKkoZVq8HND7Vx8TYLlrDjDSeYfodMeVwHOgkj13lJYR8cj6vUSg==", + "node_modules/@img/sharp-linux-arm": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm/-/sharp-linux-arm-0.35.3.tgz", + "integrity": "sha512-affVWCTLooy8TSxbDx2qkzuDeaWLNVBA+P//FNBirHsXpP2fuBhk5AuboYUnrDnzoXes8GFjpTx0SBFOCRg+FA==", "cpu": [ - "arm64" + "arm" ], "libc": [ "glibc" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm": "1.3.2" } }, - "node_modules/@oxfmt/binding-linux-arm64-musl": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.62.0.tgz", - "integrity": "sha512-lk25fAl7KWaLWVJcW0CHEXB7QlQZtx5eDkjpaGMK0hzXTjUe0Wmlu8IKuFHoviSOcEJedRTs4VE/506VqGxGew==", + "node_modules/@img/sharp-linux-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-arm64/-/sharp-linux-arm64-0.35.3.tgz", + "integrity": "sha512-QgKDspHPnrU+GQ55XPhGwyhC8acLVOOSyAvo1oVfFmrIXLkDNmGWzAfDZ4xK8oSA1qBQrALcHX0G5UZni/SuFQ==", "cpu": [ "arm64" ], "libc": [ - "musl" + "glibc" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-arm64": "1.3.2" } }, - "node_modules/@oxfmt/binding-linux-ppc64-gnu": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.62.0.tgz", - "integrity": "sha512-SFyNqHQLwySceWNLhiSldx7wPXRAzP0L0WcW9GegP3uWrpZGJiZlQO85NbHAFPEfxR9PhZ9qSnZryEh7+v+4Gw==", + "node_modules/@img/sharp-linux-ppc64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-ppc64/-/sharp-linux-ppc64-0.35.3.tgz", + "integrity": "sha512-sMd8rDxmpLOwv/7N44klFjOD5DUO7FLdjiXDI0hoxYaf7Ar262dQIEkosE98bps+5HPLtp/EvNqeqQtOycP/IA==", "cpu": [ "ppc64" ], "libc": [ "glibc" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-ppc64": "1.3.2" } }, - "node_modules/@oxfmt/binding-linux-riscv64-gnu": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.62.0.tgz", - "integrity": "sha512-KYj55C1ywJfHo6+aKDuEmUtVEdJALsC5GwayDGsI6FGz2GxFqNr/mA8nxVsNbJzm7sE5MRqTQ9ziImSzhYXysA==", + "node_modules/@img/sharp-linux-riscv64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-riscv64/-/sharp-linux-riscv64-0.35.3.tgz", + "integrity": "sha512-0Eob78yjlYPfL5vMNWAW55l3R9Y6BQS/gOfe0ZcP9mEz9ohhKSt4im1hayiknXgf8AWrFqMvJcKIdmLmEe7yeQ==", "cpu": [ "riscv64" ], "libc": [ "glibc" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-riscv64": "1.3.2" } }, - "node_modules/@oxfmt/binding-linux-riscv64-musl": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.62.0.tgz", - "integrity": "sha512-BhZDNo5GOU5nC378RhD0/XpvaEBHsH3HLgJp8YZX3A0InC7oivzA63HsRmiXFLtLSHAstEVrDf6fbC7Rs8Jh/A==", + "node_modules/@img/sharp-linux-s390x": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-s390x/-/sharp-linux-s390x-0.35.3.tgz", + "integrity": "sha512-KgAxQ0DxpNOq1rG2t5cgTgShJFGSuU7XO45cqC+1NVOuZnP6tlgZRuSYOfNupGkHID0o3cJOsw4DVeJpMovcGw==", "cpu": [ - "riscv64" + "s390x" ], "libc": [ - "musl" + "glibc" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-s390x": "1.3.2" } }, - "node_modules/@oxfmt/binding-linux-s390x-gnu": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.62.0.tgz", - "integrity": "sha512-UyAFmyHkgSgUJ/wOM4p3U8AC2yAFvRH5PNBs7TnK0fObTT/XSWcdr/lAzPSWaekHaZFaMeFZyk9n93Joq3J93A==", + "node_modules/@img/sharp-linux-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linux-x64/-/sharp-linux-x64-0.35.3.tgz", + "integrity": "sha512-8pqvxubL2PGdhlPy6GLqzDYMUjyRmKAwKHYKixpdJYBUK7PJ0C029XdsnpFIdgRZG68fZiGdHVWcKPvtiPB4cA==", "cpu": [ - "s390x" + "x64" ], "libc": [ "glibc" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linux-x64": "1.3.2" } }, - "node_modules/@oxfmt/binding-linux-x64-gnu": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.62.0.tgz", - "integrity": "sha512-1iYMP0leytWazFubD/WnINJuIrzRPuoL1aWEJdlGezEzDbTxcd29R4r8IUzP2oWeKst5V02uMJgR2NILlPlG6w==", + "node_modules/@img/sharp-linuxmusl-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-arm64/-/sharp-linuxmusl-arm64-0.35.3.tgz", + "integrity": "sha512-Vz0iQjzzcSX3HCbfwFfCSG/9SCIqyO0mH2sXyiHaAYfBk0cRsCWXRyQYX0ovCK/PAQBbTzQ0dsPQHh5MAFL59w==", "cpu": [ - "x64" + "arm64" ], "libc": [ - "glibc" + "musl" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2" } }, - "node_modules/@oxfmt/binding-linux-x64-musl": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.62.0.tgz", - "integrity": "sha512-4rA/URtJSTVNVAQz6Q8wf7SaRvOXVy+TizriT9hs/Y1XhLR/R+92uWKRQG8yFWRAIEBbFHJ6WevQcl/G9SXEfw==", + "node_modules/@img/sharp-linuxmusl-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-linuxmusl-x64/-/sharp-linuxmusl-x64-0.35.3.tgz", + "integrity": "sha512-6O1NPKcDVj9QEdg7Hx549EX8U0rp6yXQERqru6yRN7fGBn32UvIRJUlWnk+8xDCiG76hXVBbX82NZ/ZKr0euIg==", "cpu": [ "x64" ], "libc": [ "musl" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, "os": [ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-libvips-linuxmusl-x64": "1.3.2" } }, - "node_modules/@oxfmt/binding-openharmony-arm64": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.62.0.tgz", - "integrity": "sha512-mSZuFHU2ar1KLUjXpI2QBQcJ1VsOB3mOCgQXuXCpKs19dgh4u+OaovNfrWDfiJb+ihJ2+f7YFcaO9bS2dlTCXA==", - "cpu": [ - "arm64" - ], - "license": "MIT", + "node_modules/@img/sharp-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-wasm32/-/sharp-wasm32-0.35.3.tgz", + "integrity": "sha512-cZ0XkcYGpHZkqW6iCkqTcmUC0CD9DhD5d/qeZlZkfRBn6GnHniZXLUo5+9xw8Iv76YE6LQFN9YNBlKREcCG76w==", + "license": "Apache-2.0 AND LGPL-3.0-or-later AND MIT", "optional": true, - "os": [ - "openharmony" - ], + "dependencies": { + "@emnapi/runtime": "^1.11.1" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxfmt/binding-win32-arm64-msvc": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.62.0.tgz", - "integrity": "sha512-OfwuhkcjDlqC4EgDojtiV9mzpLqeB9KqTOWPOjLEYBVdDCVSxqW3qzp/xcIxsbtI0UgGCnKvAqYKyY25kf5JZw==", + "node_modules/@img/sharp-webcontainers-wasm32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-webcontainers-wasm32/-/sharp-webcontainers-wasm32-0.35.3.tgz", + "integrity": "sha512-2rnq7bX3NzeR2T4YWgz8qiG4h3TSdMe+vN1iQXpJleSJ3SM5zQ8Fy2SyyXAWlbxpEZ2Y+Z4u1BePgJEYbSy80Q==", "cpu": [ - "arm64" + "wasm32" ], - "license": "MIT", + "license": "Apache-2.0", "optional": true, - "os": [ - "win32" - ], + "dependencies": { + "@img/sharp-wasm32": "0.35.3" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxfmt/binding-win32-ia32-msvc": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.62.0.tgz", - "integrity": "sha512-P9uDDNFRzghO3X8QAzhkjKhK7JvtABsVn8UYtFX7uor12IAnwNt8nNIctvfWj1JkQU/kE+fmLRPiw7XlrIHsZw==", + "node_modules/@img/sharp-win32-arm64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-arm64/-/sharp-win32-arm64-0.35.3.tgz", + "integrity": "sha512-4bPwFdMbeC4JQ8L8LOyWp6nsHcboP5fxkp6iPOXz2Vg49R42TuMs2whkJ5OAP4/Ul035qOzy0AecOF9VOscn4w==", "cpu": [ - "ia32" + "arm64" ], - "license": "MIT", + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxfmt/binding-win32-x64-msvc": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.62.0.tgz", - "integrity": "sha512-dlI5SY7XYQCiCBafntWagCR6HcAJB/NpsLtdlPx8x08+Osz8Ok1HHz1GZuusegCe/VoJ6pAnF5a4pd5OZAq7qQ==", + "node_modules/@img/sharp-win32-ia32": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-ia32/-/sharp-win32-ia32-0.35.3.tgz", + "integrity": "sha512-r53mXsBN6lFUDiST764SvgwUdHAqM4rPAiDzAmf4fLoB6X/rkfyTrLCg6+g17wJJiCmB3JYgHuUldCWUIRFSXw==", "cpu": [ - "x64" + "ia32" ], - "license": "MIT", + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxlint-tsgolint/darwin-arm64": { - "version": "7.0.2001", - "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/darwin-arm64/-/darwin-arm64-7.0.2001.tgz", - "integrity": "sha512-CUJEdbSZ54+Xy9OXqOhWLTKZKV0BBiV7C2i/ygyVmXtkUNXx5YCzN8DpSSshTAKktoL7S+tnQ/ftFG/i7X896w==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@oxlint-tsgolint/darwin-x64": { - "version": "7.0.2001", - "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/darwin-x64/-/darwin-x64-7.0.2001.tgz", - "integrity": "sha512-pXfBb5BqONCcgrXQNUZWXgiYmRSWJzd97S8i41VVOh6ut0tyo+cJ5FKFpczDHxiVNfj/3e7c9B4MtztNdpIVCw==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@oxlint-tsgolint/linux-arm64": { - "version": "7.0.2001", - "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/linux-arm64/-/linux-arm64-7.0.2001.tgz", - "integrity": "sha512-roP7zujb/QDPzDwEKsFFpzNHHy91/Y7oX9vQXk78ekyZtcQj1QXDIMH33gjDdHBfRl4K9pZ36xhRgrP4Zr+R8A==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxlint-tsgolint/linux-x64": { - "version": "7.0.2001", - "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/linux-x64/-/linux-x64-7.0.2001.tgz", - "integrity": "sha512-UDezNqdECVmngu2TPnjaS1YoAmcTaBoI5lV9vk3VahBxoi+I5r9k3iJTT7qZoYWOXTD/7T7bNcwRgrocR6BscQ==", - "cpu": [ - "x64" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@oxlint-tsgolint/win32-arm64": { - "version": "7.0.2001", - "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/win32-arm64/-/win32-arm64-7.0.2001.tgz", - "integrity": "sha512-uJZhqB6pdXLuN+AD1F5082byyQti/NPmJA77GtcFlmT2HzRelqbNls3SaIqxpjdFgvSBF9g0yOKGBkGFg7kX8Q==", - "cpu": [ - "arm64" - ], - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@oxlint-tsgolint/win32-x64": { - "version": "7.0.2001", - "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/win32-x64/-/win32-x64-7.0.2001.tgz", - "integrity": "sha512-FkDRm8hx9OwzGQqyWG1tO5QrTLRApff9DzSgpz9QZau37BR8d1VYKOxMLGf6shPZntJFoTwIIJYT68VndYDCog==", + "node_modules/@img/sharp-win32-x64": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/@img/sharp-win32-x64/-/sharp-win32-x64-0.35.3.tgz", + "integrity": "sha512-D4y1vNeZrIIJCN+uHaWVtH86B+aCrdMYYjicy9pXHvbGZeGYLLSd3wdVuC37FxVXlU1ARsk84eKWfWMXGYEqvA==", "cpu": [ "x64" ], - "license": "MIT", + "license": "Apache-2.0 AND LGPL-3.0-or-later", "optional": true, "os": [ "win32" - ] - }, - "node_modules/@oxlint/binding-android-arm-eabi": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.77.0.tgz", - "integrity": "sha512-E06sKWS6PiI6HRxS1wyQg22HvApt01hI7fV+T3wUk3OSbaaP4a3hYGY/MIQDmASqCiRjBdpRQYkgMkqH82cWmQ==", - "cpu": [ - "arm" - ], - "license": "MIT", - "optional": true, - "os": [ - "android" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=20.9.0" + }, + "funding": { + "url": "https://opencollective.com/libvips" } }, - "node_modules/@oxlint/binding-android-arm64": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.77.0.tgz", - "integrity": "sha512-NvsKz0KZxTp9cYWPLf+FXaSZwB3oO3peAjtukpOMBgse2vhQSoIIVqeO1yR0lEo/UcdZIDL18uq+kL0LzQ0ytA==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/ansi": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/ansi/-/ansi-2.0.7.tgz", + "integrity": "sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "android" - ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" } }, - "node_modules/@oxlint/binding-darwin-arm64": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.77.0.tgz", - "integrity": "sha512-bgjTn6nW4bQCFBvSvuHCpDD+sONvmpo4lGI4PxzMt1quBA+xYxhczk6RiCn3GZ9gY8uhaBbwhj9MdKGfu6T9DA==", - "cpu": [ - "arm64" - ], + "node_modules/@inquirer/checkbox": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/checkbox/-/checkbox-5.2.1.tgz", + "integrity": "sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@oxlint/binding-darwin-x64": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.77.0.tgz", - "integrity": "sha512-aotaIttH1R6j1Rwhx0M0htgeZyGtVQqYNTVEYMN/UcgHPquGA6kmk9OyuDc3a2GKUQBC+3C3GVQCcrRPMYqAFA==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/confirm": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/confirm/-/confirm-6.1.1.tgz", + "integrity": "sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@oxlint/binding-freebsd-x64": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.77.0.tgz", - "integrity": "sha512-nNx/wta7ksRAdYvq+l4AWjXkLxEXHALhENxjj2cYbQAIR4ybaA5L+hCbE63HOmft5czQ6ks+hb8vmEAnn7YGPg==", - "cpu": [ - "x64" - ], + "node_modules/@inquirer/core": { + "version": "11.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/core/-/core-11.2.1.tgz", + "integrity": "sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7", + "cli-width": "^4.1.0", + "fast-wrap-ansi": "^0.2.0", + "mute-stream": "^3.0.0", + "signal-exit": "^4.1.0" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@oxlint/binding-linux-arm-gnueabihf": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.77.0.tgz", - "integrity": "sha512-tMLLjM7xXtzXisVCzkOTXNCy9bZVId2wteNwjohlFDR/jY6WagpEDA1c1wu4xRc20Hojaxj+V6DSR7gbKxijWA==", - "cpu": [ - "arm" - ], + "node_modules/@inquirer/editor": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/@inquirer/editor/-/editor-5.2.2.tgz", + "integrity": "sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/external-editor": "^3.0.3", + "@inquirer/type": "^4.0.7" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@oxlint/binding-linux-arm-musleabihf": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.77.0.tgz", - "integrity": "sha512-MiAFDFaqR0tmHTAyo0YDcZ5hyLREdYw/RQhc2R3cbT+8O3tB+zqPM2th9TTQ+Uo3jn/embS+DO+HyX9ztCPkOQ==", - "cpu": [ - "arm" - ], + "node_modules/@inquirer/expand": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/expand/-/expand-5.1.1.tgz", + "integrity": "sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@oxlint/binding-linux-arm64-gnu": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.77.0.tgz", - "integrity": "sha512-/xqQ3B16i1T4cyt/9Mn+4CpzhUXoBXp7kVpIwzOXNFLj5JmK1bIjsbSnX296Gg8A/o7oDtKWikFgBx0SLwztkw==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], + "node_modules/@inquirer/external-editor": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@inquirer/external-editor/-/external-editor-3.0.3.tgz", + "integrity": "sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "chardet": "^2.1.1", + "iconv-lite": "^0.7.2" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@oxlint/binding-linux-arm64-musl": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.77.0.tgz", - "integrity": "sha512-LSbwuRKiNCenPDcbARqAZ5RfBy7gmj7vOvfJRLeCDU3gFtSxWbhv/+VTlaUqzUhNj1gFLHB8h7ALnxa/Az6z6g==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], + "node_modules/@inquirer/figures": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/figures/-/figures-2.0.7.tgz", + "integrity": "sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" } }, - "node_modules/@oxlint/binding-linux-ppc64-gnu": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.77.0.tgz", - "integrity": "sha512-QWdcH31mXEUe5Nq1s0CfCpceaKjIo9uZtwDjAuL681g1axf+5x8xrg/eXWaw//4NCxYZ4V4e5Hu5tvdR+pTBlg==", - "cpu": [ - "ppc64" - ], - "libc": [ - "glibc" - ], + "node_modules/@inquirer/input": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@inquirer/input/-/input-5.1.2.tgz", + "integrity": "sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@oxlint/binding-linux-riscv64-gnu": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.77.0.tgz", - "integrity": "sha512-GnOfYgJxbcElOiPZaDFDl406ONddwvOWk2jvAAAEjwAl4GofNoHF+/HHUIBYa6bFCArlcGPi0XjC4cU1pkgF/Q==", - "cpu": [ - "riscv64" - ], - "libc": [ - "glibc" - ], + "node_modules/@inquirer/number": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/number/-/number-4.1.1.tgz", + "integrity": "sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@oxlint/binding-linux-riscv64-musl": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.77.0.tgz", - "integrity": "sha512-AyEMTUCf0xY+hHF+IxqXFQIX0yQOIR8ykpY0lJNOw9xYqOzUX8dyZfRvlG0RfXwuQn2eonf/8NrMmDSZJjdqsA==", - "cpu": [ - "riscv64" - ], - "libc": [ - "musl" - ], + "node_modules/@inquirer/password": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@inquirer/password/-/password-5.1.1.tgz", + "integrity": "sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@oxlint/binding-linux-s390x-gnu": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.77.0.tgz", - "integrity": "sha512-sPLzEcNvxd/oyVQ5oZo92CiHkFkpBeRop13E/P3TPY+hZfXHKCOWKI70TE2RYwMKFJDc20EMjH16L7NZICtKTw==", - "cpu": [ - "s390x" - ], - "libc": [ - "glibc" - ], + "node_modules/@inquirer/prompts": { + "version": "8.5.2", + "resolved": "https://registry.npmjs.org/@inquirer/prompts/-/prompts-8.5.2.tgz", + "integrity": "sha512-IYR/3C/paEVVQYQvdDlFZVjRCJVYHHON0XXMH91KO9GSxs0TdKYWlUdvfQl2EfAHDxUaN3IBffkE/BDTh5nJ6g==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": "^20.19.0 || >=22.12.0" + "dependencies": { + "@inquirer/checkbox": "^5.2.1", + "@inquirer/confirm": "^6.1.1", + "@inquirer/editor": "^5.2.2", + "@inquirer/expand": "^5.1.1", + "@inquirer/input": "^5.1.2", + "@inquirer/number": "^4.1.1", + "@inquirer/password": "^5.1.1", + "@inquirer/rawlist": "^5.3.1", + "@inquirer/search": "^4.2.1", + "@inquirer/select": "^5.2.1" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/@oxlint/binding-linux-x64-gnu": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.77.0.tgz", - "integrity": "sha512-1Oh2ssH2L7lwyvkdSqaMUfsGfwU2Wfvew+obBUYjRVqhpBcUpwnsPSEr1IzVi9XqkuY10geiLsNKecqaZC34Dw==", + "node_modules/@inquirer/rawlist": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/@inquirer/rawlist/-/rawlist-5.3.1.tgz", + "integrity": "sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/search": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/search/-/search-4.2.1.tgz", + "integrity": "sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/select": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/@inquirer/select/-/select-5.2.1.tgz", + "integrity": "sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@inquirer/ansi": "^2.0.7", + "@inquirer/core": "^11.2.1", + "@inquirer/figures": "^2.0.7", + "@inquirer/type": "^4.0.7" + }, + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@inquirer/type": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/@inquirer/type/-/type-4.0.7.tgz", + "integrity": "sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=23.5.0 || ^22.13.0 || ^20.17.0" + }, + "peerDependencies": { + "@types/node": ">=18" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } + } + }, + "node_modules/@isaacs/fs-minipass": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@isaacs/fs-minipass/-/fs-minipass-4.0.1.tgz", + "integrity": "sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "minipass": "^7.0.4" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.5", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz", + "integrity": "sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og==", + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@mjackson/node-fetch-server": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@mjackson/node-fetch-server/-/node-fetch-server-0.2.0.tgz", + "integrity": "sha512-EMlH1e30yzmTpGLQjlFmaDAjyOeZhng1/XCd7DExR8PNAnG/G1tyruZxEoUe11ClnwGhGrtsdnyyUx1frSzjng==", + "dev": true, + "license": "MIT" + }, + "node_modules/@napi-rs/lzma-linux-x64-gnu": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/@napi-rs/lzma-linux-x64-gnu/-/lzma-linux-x64-gnu-1.5.1.tgz", + "integrity": "sha512-oTXEIha4SsuXdTA4Iyskj0kpdx2yVXdhd75c2v3xGrHFfVMsbhTPZU/nMPL4sWKo4pBHm3aucLaqGlF696dTyQ==", "cpu": [ "x64" ], + "dev": true, "libc": [ "glibc" ], @@ -2120,1291 +2248,1175 @@ "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": "^22.20 || ^24.12 || >=25" } }, - "node_modules/@oxlint/binding-linux-x64-musl": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.77.0.tgz", - "integrity": "sha512-0j/2wRgNGO+Qj/M1uu/p57h/hFTTWWcfie0ufkbabeus2s5+/QqkCflnMOwLLN5m2GsNeWp4xdl4cPa4n7QCOQ==", + "node_modules/@next/env": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@next/env/-/env-16.3.0.tgz", + "integrity": "sha512-o9r1S0BNiNreHP9Vs+Qnqd9kviDkJh8xIACY7UFZSmiGbbQRzPBBosvHzAU4TULHOIuOj/18RSsyz2qrREmIFw==", + "license": "MIT" + }, + "node_modules/@next/swc-darwin-arm64": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-arm64/-/swc-darwin-arm64-16.3.0.tgz", + "integrity": "sha512-55hpqq18bEVAlxedlTt3tFqZmKg2nUXT1kn1G/BGEy0R13h3LwtwHPVzzjG6P4LLeOHE32PFDQUVaJEWvBEZBw==", "cpu": [ - "x64" - ], - "libc": [ - "musl" + "arm64" ], "license": "MIT", "optional": true, "os": [ - "linux" + "darwin" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10" } }, - "node_modules/@oxlint/binding-openharmony-arm64": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.77.0.tgz", - "integrity": "sha512-BJ/j54qS0usEnyDkLYURMj2iiD9h5Cyy+ppzeMSXBGRXaGRNWnj1Mw14NqWMR5E/PzdgB30OOCCzLzbRoduafw==", + "node_modules/@next/swc-darwin-x64": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-darwin-x64/-/swc-darwin-x64-16.3.0.tgz", + "integrity": "sha512-SOi96kSaF5T+0wW4koiM1bWzSPwjzTesC1p3df+FjdOi5LIQkBK/blxh7HdoKnNuI4PURF1OO7TZqtfnbWDSgw==", "cpu": [ - "arm64" + "x64" ], "license": "MIT", "optional": true, "os": [ - "openharmony" + "darwin" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10" } }, - "node_modules/@oxlint/binding-win32-arm64-msvc": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.77.0.tgz", - "integrity": "sha512-Yh8w+g2Lpx7StrvtYkoz9JJvXjB9wxgFChFNb85nrXm/wj/XTwGWS1hve9+900HL7llrntYB3YP+y32E3tRqzA==", + "node_modules/@next/swc-linux-arm64-gnu": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-gnu/-/swc-linux-arm64-gnu-16.3.0.tgz", + "integrity": "sha512-P0gZAoPMF4dyTRzhmkV4PrqVzSOB6t4mC1oI3c4dqijJ+OVEVx5clIXAKR4/uQpsqw2KKM/0D5tVumcR2r5blg==", "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10" } }, - "node_modules/@oxlint/binding-win32-ia32-msvc": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.77.0.tgz", - "integrity": "sha512-zja5b7+6a7UsRFgAQSrnax5vrzliEyNPLCjfXONu/vTWswaIVZGFajJZptaeRvPE4LghtFdAzVFlexTm7MVTGA==", + "node_modules/@next/swc-linux-arm64-musl": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-arm64-musl/-/swc-linux-arm64-musl-16.3.0.tgz", + "integrity": "sha512-tXXGKJw0m37O0eKJARVTX/TheKPhz0QFVtVVZXmOig+9YKLQOSP6hvf2pxv5DO7CLEJyTHx3Pg043CDQkv1G4Q==", "cpu": [ - "ia32" + "arm64" + ], + "libc": [ + "musl" ], "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10" } }, - "node_modules/@oxlint/binding-win32-x64-msvc": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.77.0.tgz", - "integrity": "sha512-+teyvPDZ2RjUvo+SuCqS/UhaJl1QtdW5fWT5NJTV61V5MIuIS90Db9LixmtEGvXixyttiK62P96MSu3UlpviBw==", - "cpu": [ - "x64" - ], + "node_modules/@next/swc-linux-x64-gnu": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-gnu/-/swc-linux-x64-gnu-16.3.0.tgz", + "integrity": "sha512-pjGxK5EY7yWml78ALejFkWmgHsU7wbFQrISiugpH6FbUJhgEvw3xFZ/EBAtLl7QtL0WdQKiG9eWJ3mOKGTukHw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ - "win32" + "linux" ], "engines": { - "node": "^20.19.0 || >=22.12.0" + "node": ">= 10" } }, - "node_modules/@oxlint/plugins": { - "version": "1.73.0", - "resolved": "https://registry.npmjs.org/@oxlint/plugins/-/plugins-1.73.0.tgz", - "integrity": "sha512-OhgMQeMmZA0dcFcX4/priaJZWdFECxiClgq6mRX6aatZEcV9PbKC3P3/v8U1hVjviT1i5U+vR8lAtBV6m4FXAA==", + "node_modules/@next/swc-linux-x64-musl": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-linux-x64-musl/-/swc-linux-x64-musl-16.3.0.tgz", + "integrity": "sha512-sjo++Xx+lomlPs3HRsHWhVDyGG6ms1kGW5EtHLERdII8AyG1i+f6aq68xHREO6AEMlhjTNEWBSmfJfqm9orf7g==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/Boshen" + "node": ">= 10" } }, - "node_modules/@polka/url": { - "version": "1.0.0-next.29", - "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", - "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", - "license": "MIT" - }, - "node_modules/@prisma/adapter-pg": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.9.1.tgz", - "integrity": "sha512-Ho2RK1KanQxLNSC0sR5bpiiVep10sWPLXCcxK+KXfI/Q69TMRbiafSvLPv3V9snimX72rMCqGlyJ4sBO4lKTAw==", - "license": "Apache-2.0", - "dependencies": { - "@prisma/driver-adapter-utils": "7.9.1", - "@types/pg": "^8.16.0", - "pg": "^8.16.3", - "postgres-array": "3.0.4" + "node_modules/@next/swc-win32-arm64-msvc": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-arm64-msvc/-/swc-win32-arm64-msvc-16.3.0.tgz", + "integrity": "sha512-C5JSgiO54wURdaxdEUIXqkz04uMqC9UmPX1gtDrV/5Tf1UowdWYI8uA5hfFbPolTlp0q4KZ60xlHePNibf0VIw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 10" } }, - "node_modules/@prisma/client": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.9.1.tgz", - "integrity": "sha512-+xgrh2EhJVF79wC0yX5G4PI1Rdcm7Qn/nekNQ+t/O153wtNggruHal+fXHSa0QE+Tp/Cw5wvxeCEhZZ59xGm8Q==", - "license": "Apache-2.0", - "dependencies": { - "@prisma/client-runtime-utils": "7.9.1" - }, + "node_modules/@next/swc-win32-x64-msvc": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/@next/swc-win32-x64-msvc/-/swc-win32-x64-msvc-16.3.0.tgz", + "integrity": "sha512-fDOggsweNb5SSw0ZKVk6U+gxSyGFFlIBY/LBc1r8GUj4u/6t6oArL+Pmkg0MBnsgR+KkdsURilVH4F3GXUGepA==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": "^20.19 || ^22.12 || >=24.0" - }, - "peerDependencies": { - "prisma": "*", - "typescript": ">=5.4.0" - }, - "peerDependenciesMeta": { - "prisma": { - "optional": true - }, - "typescript": { - "optional": true - } + "node": ">= 10" } }, - "node_modules/@prisma/client-runtime-utils": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.9.1.tgz", - "integrity": "sha512-mVIBGYdO5CFmK0HvjxrtfIyQQcPdb88pSCeVQriVQPVZyDovIWblpHfOgcS8QO187j3QF0ePArH8qPhp0AU2vg==", - "license": "Apache-2.0" - }, - "node_modules/@prisma/config": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.9.1.tgz", - "integrity": "sha512-4znKhxTmXmuPye9Z6pbIyYb5VZlkZ05qG1L6Dr4g+7oTwc6V50Bs9XirFBDdjWt+H/AabMn9aUnxBcvj8z05aA==", - "license": "Apache-2.0", - "dependencies": { - "c12": "3.3.4", - "deepmerge-ts": "7.1.5", - "effect": "3.20.0", - "empathic": "2.0.0" + "node_modules/@oxc-project/runtime": { + "version": "0.143.0", + "resolved": "https://registry.npmjs.org/@oxc-project/runtime/-/runtime-0.143.0.tgz", + "integrity": "sha512-zIuXUf+YGIgsPk0xlQmzTY8NCSc8jE/pSfDodlQ9H3EGZABmr+AtIjXRrnpQAXuXzhDSNqZz9cuhud8hDDLvpg==", + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@prisma/debug": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.9.1.tgz", - "integrity": "sha512-/cpVZ4itxtcgB8GHBvZtcmuEjq+lWsLrRJxFMbwZrT1RIdtuKmUm7PPGo/wzfbYpBrk+9WmmBE8CHJw2rybKDQ==", - "license": "Apache-2.0" - }, - "node_modules/@prisma/dev": { - "version": "0.24.17", - "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.24.17.tgz", - "integrity": "sha512-UvdZzmpFwknnfreh6Jije84ekkYGPYEJhXG1tFzCsCfQyzJifrOo38eZc0qajzvaC6OLUOrN9ML5XfCnEZL9DA==", - "license": "ISC", - "dependencies": { - "@electric-sql/pglite": "0.4.3", - "@electric-sql/pglite-socket": "0.1.3", - "@electric-sql/pglite-tools": "0.3.3", - "@prisma/get-platform": "7.2.0", - "@prisma/query-plan-executor": "7.2.0", - "@prisma/streams-local": "0.1.11", - "find-my-way": "9.7.0", - "foreground-child": "3.3.1", - "get-port-please": "3.2.0", - "pathe": "2.0.3", - "proper-lockfile": "4.1.2", - "remeda": "2.33.4", - "std-env": "3.10.0", - "valibot": "1.4.2", - "zeptomatch": "2.1.0" + "node_modules/@oxc-project/types": { + "version": "0.143.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.143.0.tgz", + "integrity": "sha512-u6JZdLBTLotrNC9Vd6vPssINdzcCzleKAH6EJKImQb7GtYvX5keN2dxkoK44stCc4tffE6QQRtZTXVSzsLUlWA==", + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@prisma/dev/node_modules/std-env": { - "version": "3.10.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", - "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", - "license": "MIT" - }, - "node_modules/@prisma/driver-adapter-utils": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.9.1.tgz", - "integrity": "sha512-vmHehG7nn/heW32DXXpp13DxxAxVVe6n250oEt3dOL2E/4bt3olktKZN0mzSuxMMronyMSkbeW2uCOn3F4g8RQ==", - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "7.9.1" + "node_modules/@oxfmt/binding-android-arm-eabi": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm-eabi/-/binding-android-arm-eabi-0.62.0.tgz", + "integrity": "sha512-pdsv0C4gPjJ8H1+sd8u0BDx+yLACTL+rgeMIOL1ln4ihSnhw8CWXtYWgvcSkyTfgGBIzFKab+d8rx9Xl4en/Kw==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@prisma/engines": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.9.1.tgz", - "integrity": "sha512-UprXSMNXx2NF5ow4pqaQtE8OuBz6K78B0wc0tn2L28G5r933iWp1DR9Do2qWrsNvvFIP3x6mpEWnQtckMO0Uhg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "7.9.1", - "@prisma/engines-version": "7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad", - "@prisma/fetch-engine": "7.9.1", - "@prisma/get-platform": "7.9.1" + "node_modules/@oxfmt/binding-android-arm64": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-android-arm64/-/binding-android-arm64-0.62.0.tgz", + "integrity": "sha512-WC3YQ7uS/KtDrjmqwBviwFKe9qeoi+eXx8aX1z/ffG23Md75myjrJaQqTuJvdOLPoa4EYTjDWH0dHXfwulCVog==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@prisma/engines-version": { - "version": "7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad", - "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad.tgz", - "integrity": "sha512-2BsPPFksz3CQUXG6af3rVCtJKg6+JJGJTtfgu2fU8DdXhOfkBjulCq8mwybCd6ge0/jhZq2kOtLAbmUDMyI1nA==", - "license": "Apache-2.0" + "node_modules/@oxfmt/binding-darwin-arm64": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-arm64/-/binding-darwin-arm64-0.62.0.tgz", + "integrity": "sha512-GM8Yf3LjjaR1I8PD0SfeoIlwhsh9GvSF+cQ8sf624Yxnjsyumn95aFzYfKJVefblfDIiOAnZ7QVm2sa21Er/0Q==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@prisma/engines/node_modules/@prisma/get-platform": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.9.1.tgz", - "integrity": "sha512-PK8R60YZRQvYxBrGG9i7l2/rFyzy+2MuI1dKtmtrCqPH8YpiJx/MfiC7LRzX5786rZDEv7BngcjfIJW4/9ADuw==", - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "7.9.1" + "node_modules/@oxfmt/binding-darwin-x64": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-darwin-x64/-/binding-darwin-x64-0.62.0.tgz", + "integrity": "sha512-d5THp7F8bCxLqNogEXDORRsQD6dosf3EyFtnXfBer6v+8tGdcWIjoDX9WaXrrF/26zOmL8qHpPTKCEvpBDmZkQ==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@prisma/fetch-engine": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.9.1.tgz", - "integrity": "sha512-9DwxrNTeT25Orbu9CWh0CZvVlyY1lmscpbaeLZcOnuR7zcuFrt91YSmmOfIm7zJ08YOZ6mVzURKwLoMwEBcK8w==", - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "7.9.1", - "@prisma/engines-version": "7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad", - "@prisma/get-platform": "7.9.1" + "node_modules/@oxfmt/binding-freebsd-x64": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-freebsd-x64/-/binding-freebsd-x64-0.62.0.tgz", + "integrity": "sha512-1DnrtXGZooOZ0fHgAXZUaDQzBVh1CM2MNW4oBXyQ2aWKvCHjyljvT9fgBkOM0fEOb96X5eqtcfJ0YUVt9jj66g==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@prisma/fetch-engine/node_modules/@prisma/get-platform": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.9.1.tgz", - "integrity": "sha512-PK8R60YZRQvYxBrGG9i7l2/rFyzy+2MuI1dKtmtrCqPH8YpiJx/MfiC7LRzX5786rZDEv7BngcjfIJW4/9ADuw==", - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "7.9.1" + "node_modules/@oxfmt/binding-linux-arm-gnueabihf": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-0.62.0.tgz", + "integrity": "sha512-4pQDHOYRH+Huqe0StIaWyvk2CVl/aTaqSrbZpA3/pLS2xH24ME7lBgYprhQF2fRkHBzhGGGKliwxFsDdHwx59g==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@prisma/get-platform": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.2.0.tgz", - "integrity": "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==", - "license": "Apache-2.0", - "dependencies": { - "@prisma/debug": "7.2.0" + "node_modules/@oxfmt/binding-linux-arm-musleabihf": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-0.62.0.tgz", + "integrity": "sha512-X0jAaZJFMCVKhB6YyWVTQ/wN2DLsBcZKSMqTS76bF6riT+XZdtg2FPEdjDvdVbunO9cG+tWiVaEs4Zs38lxYog==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@prisma/get-platform/node_modules/@prisma/debug": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.2.0.tgz", - "integrity": "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==", - "license": "Apache-2.0" - }, - "node_modules/@prisma/query-plan-executor": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/@prisma/query-plan-executor/-/query-plan-executor-7.2.0.tgz", - "integrity": "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==", - "license": "Apache-2.0" - }, - "node_modules/@prisma/streams-local": { - "version": "0.1.11", - "resolved": "https://registry.npmjs.org/@prisma/streams-local/-/streams-local-0.1.11.tgz", - "integrity": "sha512-0TcebL559MByKqTJ+SsrFIEg228iw8UCVRFckzgfRSiJqczhs+MuAgWOF9lnOIV/IVqvu+KMnFTH0eDeTQMpUg==", - "license": "Apache-2.0", - "dependencies": { - "ajv": "^8.12.0", - "better-result": "^2.7.0", - "env-paths": "^3.0.0", - "proper-lockfile": "^4.1.2" - }, + "node_modules/@oxfmt/binding-linux-arm64-gnu": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.62.0.tgz", + "integrity": "sha512-682Z8T5s8T5ATArYtsejKvbIfd8LEAXyyDkKkoZVq8HND7Vx8TYLlrDjDSeYfodMeVwHOgkj13lJYR8cj6vUSg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "bun": ">=1.2.0", - "node": ">=22.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@prisma/streams-local/node_modules/env-paths": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", - "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "node_modules/@oxfmt/binding-linux-arm64-musl": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.62.0.tgz", + "integrity": "sha512-lk25fAl7KWaLWVJcW0CHEXB7QlQZtx5eDkjpaGMK0hzXTjUe0Wmlu8IKuFHoviSOcEJedRTs4VE/506VqGxGew==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@prisma/studio-core": { - "version": "0.33.0", - "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.33.0.tgz", - "integrity": "sha512-V2fX/nKEymNTrHXwfP26PGjoLStO35Ogu+ex7CFJbLrMYEcZxxZpiSNOs7px23Hk5mzLWvM5RsqG6Ka+rha+wg==", - "license": "Apache-2.0", - "dependencies": { - "@radix-ui/react-toggle": "1.1.10", - "@visx/curve": "4.0.1-alpha.0", - "@visx/event": "4.0.1-alpha.0", - "@visx/grid": "4.0.1-alpha.0", - "@visx/group": "4.0.1-alpha.0", - "@visx/responsive": "4.0.1-alpha.0", - "@visx/scale": "4.0.1-alpha.0", - "@visx/shape": "4.0.1-alpha.0", - "d3-array": "3.2.4", - "d3-shape": "3.2.0", - "elkjs": "0.11.1" - }, + "node_modules/@oxfmt/binding-linux-ppc64-gnu": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-0.62.0.tgz", + "integrity": "sha512-SFyNqHQLwySceWNLhiSldx7wPXRAzP0L0WcW9GegP3uWrpZGJiZlQO85NbHAFPEfxR9PhZ9qSnZryEh7+v+4Gw==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "^20.19 || ^22.12 || >=24.0", - "pnpm": "8" - }, - "peerDependencies": { - "@types/react": "^18.0.0 || ^19.0.0", - "react": "^18.0.0 || ^19.0.0", - "react-dom": "^18.0.0 || ^19.0.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/colors": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-3.0.0.tgz", - "integrity": "sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==", - "license": "MIT" - }, - "node_modules/@radix-ui/number": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", - "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", - "license": "MIT" - }, - "node_modules/@radix-ui/primitive": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", - "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", - "license": "MIT" + "node_modules/@oxfmt/binding-linux-riscv64-gnu": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-0.62.0.tgz", + "integrity": "sha512-KYj55C1ywJfHo6+aKDuEmUtVEdJALsC5GwayDGsI6FGz2GxFqNr/mA8nxVsNbJzm7sE5MRqTQ9ziImSzhYXysA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" + } }, - "node_modules/@radix-ui/react-accessible-icon": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz", - "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==", + "node_modules/@oxfmt/binding-linux-riscv64-musl": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-0.62.0.tgz", + "integrity": "sha512-BhZDNo5GOU5nC378RhD0/XpvaEBHsH3HLgJp8YZX3A0InC7oivzA63HsRmiXFLtLSHAstEVrDf6fbC7Rs8Jh/A==", + "cpu": [ + "riscv64" + ], + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@radix-ui/react-visually-hidden": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-accordion": { - "version": "1.2.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", - "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", + "node_modules/@oxfmt/binding-linux-s390x-gnu": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-0.62.0.tgz", + "integrity": "sha512-UyAFmyHkgSgUJ/wOM4p3U8AC2yAFvRH5PNBs7TnK0fObTT/XSWcdr/lAzPSWaekHaZFaMeFZyk9n93Joq3J93A==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collapsible": "1.1.12", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-alert-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", - "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", + "node_modules/@oxfmt/binding-linux-x64-gnu": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.62.0.tgz", + "integrity": "sha512-1iYMP0leytWazFubD/WnINJuIrzRPuoL1aWEJdlGezEzDbTxcd29R4r8IUzP2oWeKst5V02uMJgR2NILlPlG6w==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dialog": "1.1.15", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-arrow": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", - "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", + "node_modules/@oxfmt/binding-linux-x64-musl": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-linux-x64-musl/-/binding-linux-x64-musl-0.62.0.tgz", + "integrity": "sha512-4rA/URtJSTVNVAQz6Q8wf7SaRvOXVy+TizriT9hs/Y1XhLR/R+92uWKRQG8yFWRAIEBbFHJ6WevQcl/G9SXEfw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-aspect-ratio": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz", - "integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==", + "node_modules/@oxfmt/binding-openharmony-arm64": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-openharmony-arm64/-/binding-openharmony-arm64-0.62.0.tgz", + "integrity": "sha512-mSZuFHU2ar1KLUjXpI2QBQcJ1VsOB3mOCgQXuXCpKs19dgh4u+OaovNfrWDfiJb+ihJ2+f7YFcaO9bS2dlTCXA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-avatar": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", - "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", + "node_modules/@oxfmt/binding-win32-arm64-msvc": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-0.62.0.tgz", + "integrity": "sha512-OfwuhkcjDlqC4EgDojtiV9mzpLqeB9KqTOWPOjLEYBVdDCVSxqW3qzp/xcIxsbtI0UgGCnKvAqYKyY25kf5JZw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-checkbox": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", - "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", + "node_modules/@oxfmt/binding-win32-ia32-msvc": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-0.62.0.tgz", + "integrity": "sha512-P9uDDNFRzghO3X8QAzhkjKhK7JvtABsVn8UYtFX7uor12IAnwNt8nNIctvfWj1JkQU/kE+fmLRPiw7XlrIHsZw==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-collapsible": { - "version": "1.1.12", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", - "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", + "node_modules/@oxfmt/binding-win32-x64-msvc": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/@oxfmt/binding-win32-x64-msvc/-/binding-win32-x64-msvc-0.62.0.tgz", + "integrity": "sha512-dlI5SY7XYQCiCBafntWagCR6HcAJB/NpsLtdlPx8x08+Osz8Ok1HHz1GZuusegCe/VoJ6pAnF5a4pd5OZAq7qQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-collection": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", - "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", - "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } + "node_modules/@oxlint-tsgolint/darwin-arm64": { + "version": "7.0.2001", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/darwin-arm64/-/darwin-arm64-7.0.2001.tgz", + "integrity": "sha512-CUJEdbSZ54+Xy9OXqOhWLTKZKV0BBiV7C2i/ygyVmXtkUNXx5YCzN8DpSSshTAKktoL7S+tnQ/ftFG/i7X896w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@radix-ui/react-compose-refs": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", - "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", + "node_modules/@oxlint-tsgolint/darwin-x64": { + "version": "7.0.2001", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/darwin-x64/-/darwin-x64-7.0.2001.tgz", + "integrity": "sha512-pXfBb5BqONCcgrXQNUZWXgiYmRSWJzd97S8i41VVOh6ut0tyo+cJ5FKFpczDHxiVNfj/3e7c9B4MtztNdpIVCw==", + "cpu": [ + "x64" + ], "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@radix-ui/react-context": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", - "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", + "node_modules/@oxlint-tsgolint/linux-arm64": { + "version": "7.0.2001", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/linux-arm64/-/linux-arm64-7.0.2001.tgz", + "integrity": "sha512-roP7zujb/QDPzDwEKsFFpzNHHy91/Y7oX9vQXk78ekyZtcQj1QXDIMH33gjDdHBfRl4K9pZ36xhRgrP4Zr+R8A==", + "cpu": [ + "arm64" + ], "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@radix-ui/react-context-menu": { - "version": "2.2.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", - "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", + "node_modules/@oxlint-tsgolint/linux-x64": { + "version": "7.0.2001", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/linux-x64/-/linux-x64-7.0.2001.tgz", + "integrity": "sha512-UDezNqdECVmngu2TPnjaS1YoAmcTaBoI5lV9vk3VahBxoi+I5r9k3iJTT7qZoYWOXTD/7T7bNcwRgrocR6BscQ==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@radix-ui/react-dialog": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", - "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", + "node_modules/@oxlint-tsgolint/win32-arm64": { + "version": "7.0.2001", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/win32-arm64/-/win32-arm64-7.0.2001.tgz", + "integrity": "sha512-uJZhqB6pdXLuN+AD1F5082byyQti/NPmJA77GtcFlmT2HzRelqbNls3SaIqxpjdFgvSBF9g0yOKGBkGFg7kX8Q==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } + "optional": true, + "os": [ + "win32" + ] }, - "node_modules/@radix-ui/react-direction": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", - "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", + "node_modules/@oxlint-tsgolint/win32-x64": { + "version": "7.0.2001", + "resolved": "https://registry.npmjs.org/@oxlint-tsgolint/win32-x64/-/win32-x64-7.0.2001.tgz", + "integrity": "sha512-FkDRm8hx9OwzGQqyWG1tO5QrTLRApff9DzSgpz9QZau37BR8d1VYKOxMLGf6shPZntJFoTwIIJYT68VndYDCog==", + "cpu": [ + "x64" + ], "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@oxlint/binding-android-arm-eabi": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm-eabi/-/binding-android-arm-eabi-1.77.0.tgz", + "integrity": "sha512-E06sKWS6PiI6HRxS1wyQg22HvApt01hI7fV+T3wUk3OSbaaP4a3hYGY/MIQDmASqCiRjBdpRQYkgMkqH82cWmQ==", + "cpu": [ + "arm" + ], + "license": "MIT", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-dismissable-layer": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", - "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", + "node_modules/@oxlint/binding-android-arm64": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-android-arm64/-/binding-android-arm64-1.77.0.tgz", + "integrity": "sha512-NvsKz0KZxTp9cYWPLf+FXaSZwB3oO3peAjtukpOMBgse2vhQSoIIVqeO1yR0lEo/UcdZIDL18uq+kL0LzQ0ytA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-escape-keydown": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-dropdown-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", - "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", + "node_modules/@oxlint/binding-darwin-arm64": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-arm64/-/binding-darwin-arm64-1.77.0.tgz", + "integrity": "sha512-bgjTn6nW4bQCFBvSvuHCpDD+sONvmpo4lGI4PxzMt1quBA+xYxhczk6RiCn3GZ9gY8uhaBbwhj9MdKGfu6T9DA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-focus-guards": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", - "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", + "node_modules/@oxlint/binding-darwin-x64": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-darwin-x64/-/binding-darwin-x64-1.77.0.tgz", + "integrity": "sha512-aotaIttH1R6j1Rwhx0M0htgeZyGtVQqYNTVEYMN/UcgHPquGA6kmk9OyuDc3a2GKUQBC+3C3GVQCcrRPMYqAFA==", + "cpu": [ + "x64" + ], "license": "MIT", - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-focus-scope": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", - "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", + "node_modules/@oxlint/binding-freebsd-x64": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-freebsd-x64/-/binding-freebsd-x64-1.77.0.tgz", + "integrity": "sha512-nNx/wta7ksRAdYvq+l4AWjXkLxEXHALhENxjj2cYbQAIR4ybaA5L+hCbE63HOmft5czQ6ks+hb8vmEAnn7YGPg==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-form": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz", - "integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==", + "node_modules/@oxlint/binding-linux-arm-gnueabihf": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.77.0.tgz", + "integrity": "sha512-tMLLjM7xXtzXisVCzkOTXNCy9bZVId2wteNwjohlFDR/jY6WagpEDA1c1wu4xRc20Hojaxj+V6DSR7gbKxijWA==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-label": "2.1.7", - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-hover-card": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", - "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", + "node_modules/@oxlint/binding-linux-arm-musleabihf": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm-musleabihf/-/binding-linux-arm-musleabihf-1.77.0.tgz", + "integrity": "sha512-MiAFDFaqR0tmHTAyo0YDcZ5hyLREdYw/RQhc2R3cbT+8O3tB+zqPM2th9TTQ+Uo3jn/embS+DO+HyX9ztCPkOQ==", + "cpu": [ + "arm" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-icons": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz", - "integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==", + "node_modules/@oxlint/binding-linux-arm64-gnu": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.77.0.tgz", + "integrity": "sha512-/xqQ3B16i1T4cyt/9Mn+4CpzhUXoBXp7kVpIwzOXNFLj5JmK1bIjsbSnX296Gg8A/o7oDtKWikFgBx0SLwztkw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "peerDependencies": { - "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-id": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", - "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", + "node_modules/@oxlint/binding-linux-arm64-musl": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.77.0.tgz", + "integrity": "sha512-LSbwuRKiNCenPDcbARqAZ5RfBy7gmj7vOvfJRLeCDU3gFtSxWbhv/+VTlaUqzUhNj1gFLHB8h7ALnxa/Az6z6g==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-label": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", - "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", + "node_modules/@oxlint/binding-linux-ppc64-gnu": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.77.0.tgz", + "integrity": "sha512-QWdcH31mXEUe5Nq1s0CfCpceaKjIo9uZtwDjAuL681g1axf+5x8xrg/eXWaw//4NCxYZ4V4e5Hu5tvdR+pTBlg==", + "cpu": [ + "ppc64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-menu": { - "version": "2.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", - "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "node_modules/@oxlint/binding-linux-riscv64-gnu": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-1.77.0.tgz", + "integrity": "sha512-GnOfYgJxbcElOiPZaDFDl406ONddwvOWk2jvAAAEjwAl4GofNoHF+/HHUIBYa6bFCArlcGPi0XjC4cU1pkgF/Q==", + "cpu": [ + "riscv64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-menubar": { - "version": "1.1.16", - "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", - "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", + "node_modules/@oxlint/binding-linux-riscv64-musl": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-1.77.0.tgz", + "integrity": "sha512-AyEMTUCf0xY+hHF+IxqXFQIX0yQOIR8ykpY0lJNOw9xYqOzUX8dyZfRvlG0RfXwuQn2eonf/8NrMmDSZJjdqsA==", + "cpu": [ + "riscv64" + ], + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-navigation-menu": { - "version": "1.2.14", - "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", - "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", + "node_modules/@oxlint/binding-linux-s390x-gnu": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.77.0.tgz", + "integrity": "sha512-sPLzEcNvxd/oyVQ5oZo92CiHkFkpBeRop13E/P3TPY+hZfXHKCOWKI70TE2RYwMKFJDc20EMjH16L7NZICtKTw==", + "cpu": [ + "s390x" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-one-time-password-field": { - "version": "0.1.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.8.tgz", - "integrity": "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==", + "node_modules/@oxlint/binding-linux-x64-gnu": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.77.0.tgz", + "integrity": "sha512-1Oh2ssH2L7lwyvkdSqaMUfsGfwU2Wfvew+obBUYjRVqhpBcUpwnsPSEr1IzVi9XqkuY10geiLsNKecqaZC34Dw==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-password-toggle-field": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.3.tgz", - "integrity": "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==", + "node_modules/@oxlint/binding-linux-x64-musl": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-linux-x64-musl/-/binding-linux-x64-musl-1.77.0.tgz", + "integrity": "sha512-0j/2wRgNGO+Qj/M1uu/p57h/hFTTWWcfie0ufkbabeus2s5+/QqkCflnMOwLLN5m2GsNeWp4xdl4cPa4n7QCOQ==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-is-hydrated": "0.1.0" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-popover": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", - "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", + "node_modules/@oxlint/binding-openharmony-arm64": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-openharmony-arm64/-/binding-openharmony-arm64-1.77.0.tgz", + "integrity": "sha512-BJ/j54qS0usEnyDkLYURMj2iiD9h5Cyy+ppzeMSXBGRXaGRNWnj1Mw14NqWMR5E/PzdgB30OOCCzLzbRoduafw==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "openharmony" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-popper": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", - "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", + "node_modules/@oxlint/binding-win32-arm64-msvc": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.77.0.tgz", + "integrity": "sha512-Yh8w+g2Lpx7StrvtYkoz9JJvXjB9wxgFChFNb85nrXm/wj/XTwGWS1hve9+900HL7llrntYB3YP+y32E3tRqzA==", + "cpu": [ + "arm64" + ], "license": "MIT", - "dependencies": { - "@floating-ui/react-dom": "^2.0.0", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-rect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/rect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-portal": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", - "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", + "node_modules/@oxlint/binding-win32-ia32-msvc": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.77.0.tgz", + "integrity": "sha512-zja5b7+6a7UsRFgAQSrnax5vrzliEyNPLCjfXONu/vTWswaIVZGFajJZptaeRvPE4LghtFdAzVFlexTm7MVTGA==", + "cpu": [ + "ia32" + ], "license": "MIT", - "dependencies": { - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-presence": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", - "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "node_modules/@oxlint/binding-win32-x64-msvc": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/@oxlint/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.77.0.tgz", + "integrity": "sha512-+teyvPDZ2RjUvo+SuCqS/UhaJl1QtdW5fWT5NJTV61V5MIuIS90Db9LixmtEGvXixyttiK62P96MSu3UlpviBw==", + "cpu": [ + "x64" + ], "license": "MIT", - "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-use-layout-effect": "1.1.1" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@radix-ui/react-primitive": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", - "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", + "node_modules/@oxlint/plugins": { + "version": "1.73.0", + "resolved": "https://registry.npmjs.org/@oxlint/plugins/-/plugins-1.73.0.tgz", + "integrity": "sha512-OhgMQeMmZA0dcFcX4/priaJZWdFECxiClgq6mRX6aatZEcV9PbKC3P3/v8U1hVjviT1i5U+vR8lAtBV6m4FXAA==", "license": "MIT", - "dependencies": { - "@radix-ui/react-slot": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/Boshen" } }, - "node_modules/@radix-ui/react-progress": { - "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", - "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", - "license": "MIT", + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "license": "MIT" + }, + "node_modules/@prisma/adapter-pg": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/adapter-pg/-/adapter-pg-7.9.1.tgz", + "integrity": "sha512-Ho2RK1KanQxLNSC0sR5bpiiVep10sWPLXCcxK+KXfI/Q69TMRbiafSvLPv3V9snimX72rMCqGlyJ4sBO4lKTAw==", + "license": "Apache-2.0", "dependencies": { - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-primitive": "2.1.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } + "@prisma/driver-adapter-utils": "7.9.1", + "@types/pg": "^8.16.0", + "pg": "^8.16.3", + "postgres-array": "3.0.4" } }, - "node_modules/@radix-ui/react-radio-group": { - "version": "1.3.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", - "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", - "license": "MIT", + "node_modules/@prisma/client": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/client/-/client-7.9.1.tgz", + "integrity": "sha512-+xgrh2EhJVF79wC0yX5G4PI1Rdcm7Qn/nekNQ+t/O153wtNggruHal+fXHSa0QE+Tp/Cw5wvxeCEhZZ59xGm8Q==", + "license": "Apache-2.0", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" + "@prisma/client-runtime-utils": "7.9.1" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24.0" }, "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "prisma": "*", + "typescript": ">=5.4.0" }, "peerDependenciesMeta": { - "@types/react": { + "prisma": { "optional": true }, - "@types/react-dom": { + "typescript": { "optional": true } } }, - "node_modules/@radix-ui/react-roving-focus": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", - "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", - "license": "MIT", + "node_modules/@prisma/client-runtime-utils": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/client-runtime-utils/-/client-runtime-utils-7.9.1.tgz", + "integrity": "sha512-mVIBGYdO5CFmK0HvjxrtfIyQQcPdb88pSCeVQriVQPVZyDovIWblpHfOgcS8QO187j3QF0ePArH8qPhp0AU2vg==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/config": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/config/-/config-7.9.1.tgz", + "integrity": "sha512-4znKhxTmXmuPye9Z6pbIyYb5VZlkZ05qG1L6Dr4g+7oTwc6V50Bs9XirFBDdjWt+H/AabMn9aUnxBcvj8z05aA==", + "license": "Apache-2.0", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, - "peerDependencies": { + "c12": "3.3.4", + "deepmerge-ts": "7.1.5", + "effect": "3.20.0", + "empathic": "2.0.0" + } + }, + "node_modules/@prisma/debug": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.9.1.tgz", + "integrity": "sha512-/cpVZ4itxtcgB8GHBvZtcmuEjq+lWsLrRJxFMbwZrT1RIdtuKmUm7PPGo/wzfbYpBrk+9WmmBE8CHJw2rybKDQ==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/dev": { + "version": "0.24.17", + "resolved": "https://registry.npmjs.org/@prisma/dev/-/dev-0.24.17.tgz", + "integrity": "sha512-UvdZzmpFwknnfreh6Jije84ekkYGPYEJhXG1tFzCsCfQyzJifrOo38eZc0qajzvaC6OLUOrN9ML5XfCnEZL9DA==", + "license": "ISC", + "dependencies": { + "@electric-sql/pglite": "0.4.3", + "@electric-sql/pglite-socket": "0.1.3", + "@electric-sql/pglite-tools": "0.3.3", + "@prisma/get-platform": "7.2.0", + "@prisma/query-plan-executor": "7.2.0", + "@prisma/streams-local": "0.1.11", + "find-my-way": "9.7.0", + "foreground-child": "3.3.1", + "get-port-please": "3.2.0", + "pathe": "2.0.3", + "proper-lockfile": "4.1.2", + "remeda": "2.33.4", + "std-env": "3.10.0", + "valibot": "1.4.2", + "zeptomatch": "2.1.0" + } + }, + "node_modules/@prisma/dev/node_modules/std-env": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-3.10.0.tgz", + "integrity": "sha512-5GS12FdOZNliM5mAOxFRg7Ir0pWz8MdpYm6AY6VPkGpbA7ZzmbzNcBJQ0GPvvyWgcY7QAhCgf9Uy89I03faLkg==", + "license": "MIT" + }, + "node_modules/@prisma/driver-adapter-utils": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/driver-adapter-utils/-/driver-adapter-utils-7.9.1.tgz", + "integrity": "sha512-vmHehG7nn/heW32DXXpp13DxxAxVVe6n250oEt3dOL2E/4bt3olktKZN0mzSuxMMronyMSkbeW2uCOn3F4g8RQ==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.9.1" + } + }, + "node_modules/@prisma/engines": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/engines/-/engines-7.9.1.tgz", + "integrity": "sha512-UprXSMNXx2NF5ow4pqaQtE8OuBz6K78B0wc0tn2L28G5r933iWp1DR9Do2qWrsNvvFIP3x6mpEWnQtckMO0Uhg==", + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.9.1", + "@prisma/engines-version": "7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad", + "@prisma/fetch-engine": "7.9.1", + "@prisma/get-platform": "7.9.1" + } + }, + "node_modules/@prisma/engines-version": { + "version": "7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad", + "resolved": "https://registry.npmjs.org/@prisma/engines-version/-/engines-version-7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad.tgz", + "integrity": "sha512-2BsPPFksz3CQUXG6af3rVCtJKg6+JJGJTtfgu2fU8DdXhOfkBjulCq8mwybCd6ge0/jhZq2kOtLAbmUDMyI1nA==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/engines/node_modules/@prisma/get-platform": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.9.1.tgz", + "integrity": "sha512-PK8R60YZRQvYxBrGG9i7l2/rFyzy+2MuI1dKtmtrCqPH8YpiJx/MfiC7LRzX5786rZDEv7BngcjfIJW4/9ADuw==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.9.1" + } + }, + "node_modules/@prisma/fetch-engine": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/fetch-engine/-/fetch-engine-7.9.1.tgz", + "integrity": "sha512-9DwxrNTeT25Orbu9CWh0CZvVlyY1lmscpbaeLZcOnuR7zcuFrt91YSmmOfIm7zJ08YOZ6mVzURKwLoMwEBcK8w==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.9.1", + "@prisma/engines-version": "7.9.0-1.e922089b7d7502aff4249d5da3420f6fa55fc6ad", + "@prisma/get-platform": "7.9.1" + } + }, + "node_modules/@prisma/fetch-engine/node_modules/@prisma/get-platform": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.9.1.tgz", + "integrity": "sha512-PK8R60YZRQvYxBrGG9i7l2/rFyzy+2MuI1dKtmtrCqPH8YpiJx/MfiC7LRzX5786rZDEv7BngcjfIJW4/9ADuw==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.9.1" + } + }, + "node_modules/@prisma/get-platform": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/get-platform/-/get-platform-7.2.0.tgz", + "integrity": "sha512-k1V0l0Td1732EHpAfi2eySTezyllok9dXb6UQanajkJQzPUGi3vO2z7jdkz67SypFTdmbnyGYxvEvYZdZsMAVA==", + "license": "Apache-2.0", + "dependencies": { + "@prisma/debug": "7.2.0" + } + }, + "node_modules/@prisma/get-platform/node_modules/@prisma/debug": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/debug/-/debug-7.2.0.tgz", + "integrity": "sha512-YSGTiSlBAVJPzX4ONZmMotL+ozJwQjRmZweQNIq/ER0tQJKJynNkRB3kyvt37eOfsbMCXk3gnLF6J9OJ4QWftw==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/query-plan-executor": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@prisma/query-plan-executor/-/query-plan-executor-7.2.0.tgz", + "integrity": "sha512-EOZmNzcV8uJ0mae3DhTsiHgoNCuu1J9mULQpGCh62zN3PxPTd+qI9tJvk5jOst8WHKQNwJWR3b39t0XvfBB0WQ==", + "license": "Apache-2.0" + }, + "node_modules/@prisma/streams-local": { + "version": "0.1.11", + "resolved": "https://registry.npmjs.org/@prisma/streams-local/-/streams-local-0.1.11.tgz", + "integrity": "sha512-0TcebL559MByKqTJ+SsrFIEg228iw8UCVRFckzgfRSiJqczhs+MuAgWOF9lnOIV/IVqvu+KMnFTH0eDeTQMpUg==", + "license": "Apache-2.0", + "dependencies": { + "ajv": "^8.12.0", + "better-result": "^2.7.0", + "env-paths": "^3.0.0", + "proper-lockfile": "^4.1.2" + }, + "engines": { + "bun": ">=1.2.0", + "node": ">=22.0.0" + } + }, + "node_modules/@prisma/streams-local/node_modules/env-paths": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-3.0.0.tgz", + "integrity": "sha512-dtJUTepzMW3Lm/NPxRf3wP4642UWhjL2sQxc+ym2YMj1m/H2zDNQOlezafzkHwn6sMstjHTwG6iQQsctDW/b1A==", + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@prisma/studio-core": { + "version": "0.33.0", + "resolved": "https://registry.npmjs.org/@prisma/studio-core/-/studio-core-0.33.0.tgz", + "integrity": "sha512-V2fX/nKEymNTrHXwfP26PGjoLStO35Ogu+ex7CFJbLrMYEcZxxZpiSNOs7px23Hk5mzLWvM5RsqG6Ka+rha+wg==", + "license": "Apache-2.0", + "dependencies": { + "@radix-ui/react-toggle": "1.1.10", + "@visx/curve": "4.0.1-alpha.0", + "@visx/event": "4.0.1-alpha.0", + "@visx/grid": "4.0.1-alpha.0", + "@visx/group": "4.0.1-alpha.0", + "@visx/responsive": "4.0.1-alpha.0", + "@visx/scale": "4.0.1-alpha.0", + "@visx/shape": "4.0.1-alpha.0", + "d3-array": "3.2.4", + "d3-shape": "3.2.0", + "elkjs": "0.11.1" + }, + "engines": { + "node": "^20.19 || ^22.12 || >=24.0", + "pnpm": "8" + }, + "peerDependencies": { + "@types/react": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@radix-ui/colors": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@radix-ui/colors/-/colors-3.0.0.tgz", + "integrity": "sha512-FUOsGBkHrYJwCSEtWRCIfQbZG7q1e6DgxCIOe1SUQzDe/7rXXeA47s8yCn6fuTNQAj1Zq4oTFi9Yjp3wzElcxg==", + "license": "MIT" + }, + "node_modules/@radix-ui/number": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/number/-/number-1.1.1.tgz", + "integrity": "sha512-MkKCwxlXTgz6CFoJx3pCwn07GKp36+aZyu/u2Ln2VrA5DcdyCZkASEDBTd8x5whTQQL5CiYf4prXKLcgQdv29g==", + "license": "MIT" + }, + "node_modules/@radix-ui/primitive": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz", + "integrity": "sha512-JTF99U/6XIjCBo0wqkU5sK10glYe27MRRsfwoiq5zzOEZLHU3A3KCMa5X/azekYRCJ0HlwI0crAXS/5dEHTzDg==", + "license": "MIT" + }, + "node_modules/@radix-ui/react-accessible-icon": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accessible-icon/-/react-accessible-icon-1.1.7.tgz", + "integrity": "sha512-XM+E4WXl0OqUJFovy6GjmxxFyx9opfCAIUku4dlKRd5YEPqt4kALOkQOp0Of6reHuUkJuiPBEc5k0o4z4lTC8A==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", @@ -3419,21 +3431,21 @@ } } }, - "node_modules/@radix-ui/react-scroll-area": { - "version": "1.2.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", - "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", + "node_modules/@radix-ui/react-accordion": { + "version": "1.2.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-accordion/-/react-accordion-1.2.12.tgz", + "integrity": "sha512-T4nygeh9YE9dLRPhAHSeOZi7HBXo+0kYIPJXayZfvWOWA0+n3dESrZbjfDPUABkUNym6Hd+f2IR113To8D2GPA==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-id": "1.1.1", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", @@ -3450,33 +3462,18 @@ } } }, - "node_modules/@radix-ui/react-select": { - "version": "2.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", - "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", + "node_modules/@radix-ui/react-alert-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-alert-dialog/-/react-alert-dialog-1.1.15.tgz", + "integrity": "sha512-oTVLkEw5GpdRe29BqJ0LSDFWI3qu0vR1M0mUkOQWDIUnY/QIkLpgDMWuKxP94c2NAC2LGcgVhG1ImF3jkZ5wXw==", "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.1", "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-dialog": "1.1.15", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3", - "aria-hidden": "^1.2.4", - "react-remove-scroll": "^2.6.3" + "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -3493,10 +3490,10 @@ } } }, - "node_modules/@radix-ui/react-separator": { + "node_modules/@radix-ui/react-arrow": { "version": "1.1.7", - "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", - "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-arrow/-/react-arrow-1.1.7.tgz", + "integrity": "sha512-F+M1tLhO+mlQaOWspE8Wstg+z6PwxwRd8oQ8IXceWz92kfAmalTRf0EjrouQeo7QssEPfCn05B4Ihs1K9WQ/7w==", "license": "MIT", "dependencies": { "@radix-ui/react-primitive": "2.1.3" @@ -3516,23 +3513,13 @@ } } }, - "node_modules/@radix-ui/react-slider": { - "version": "1.3.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", - "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", - "license": "MIT", + "node_modules/@radix-ui/react-aspect-ratio": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-aspect-ratio/-/react-aspect-ratio-1.1.7.tgz", + "integrity": "sha512-Yq6lvO9HQyPwev1onK1daHCHqXVLzPhSVjmsNjCa2Zcxy2f7uJD2itDtxknv6FzAKCwD1qQkeVDmX/cev13n/g==", + "license": "MIT", "dependencies": { - "@radix-ui/number": "1.1.1", - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-previous": "1.1.1", - "@radix-ui/react-use-size": "1.1.1" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", @@ -3549,33 +3536,43 @@ } } }, - "node_modules/@radix-ui/react-slot": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", - "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", + "node_modules/@radix-ui/react-avatar": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-avatar/-/react-avatar-1.1.10.tgz", + "integrity": "sha512-V8piFfWapM5OmNCXTzVQY+E1rDa53zY+MQ4Y7356v4fFz6vqCyUtIz2rUD44ZEdwg78/jKmMJHj07+C/Z/rcog==", "license": "MIT", "dependencies": { - "@radix-ui/react-compose-refs": "1.1.2" + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-switch": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", - "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", + "node_modules/@radix-ui/react-checkbox": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-checkbox/-/react-checkbox-1.3.3.tgz", + "integrity": "sha512-wBbpv+NQftHDdG86Qc0pIyXk5IR3tM8Vd0nWLKDcX8nNn4nXFOFwsKuqw2okA/1D/mpaAkmuyndrPJTYDNZtFw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-use-controllable-state": "1.2.2", "@radix-ui/react-use-previous": "1.1.1", @@ -3596,20 +3593,20 @@ } } }, - "node_modules/@radix-ui/react-tabs": { - "version": "1.1.13", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", - "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", + "node_modules/@radix-ui/react-collapsible": { + "version": "1.1.12", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collapsible/-/react-collapsible-1.1.12.tgz", + "integrity": "sha512-Uu+mSh4agx2ib1uIGPP4/CKNULyajb3p92LsVXmH2EHVMTfZWpll88XJ0j4W0z3f8NK1eYl1+Mf/szHPmcHzyA==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", "@radix-ui/react-id": "1.1.1", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-use-controllable-state": "1.2.2" + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -3626,24 +3623,16 @@ } } }, - "node_modules/@radix-ui/react-toast": { - "version": "1.2.15", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", - "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", + "node_modules/@radix-ui/react-collection": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-collection/-/react-collection-1.1.7.tgz", + "integrity": "sha512-Fh9rGN0MoI4ZFUNyfFVNU4y9LUz93u9/0K+yLgA2bwRojxM8JU1DyvvMBabnZPBgMWREAJvU2jjVzq+LrFUglw==", "license": "MIT", "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-collection": "1.1.7", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3" + "@radix-ui/react-slot": "1.2.3" }, "peerDependencies": { "@types/react": "*", @@ -3660,73 +3649,48 @@ } } }, - "node_modules/@radix-ui/react-toggle": { - "version": "1.1.10", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", - "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", + "node_modules/@radix-ui/react-compose-refs": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-compose-refs/-/react-compose-refs-1.1.2.tgz", + "integrity": "sha512-z4eqJvfiNnFMHIIvXP3CY57y2WJs5g2v3X0zm9mEJkrkNv4rDxu+sg9Jh8EkXyeqBkB7SOcboo9dMVqhyrACIg==", "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-toggle-group": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", - "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", + "node_modules/@radix-ui/react-context": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context/-/react-context-1.1.2.tgz", + "integrity": "sha512-jCi/QKUM2r1Ju5a3J64TH2A5SpKAgh0LpknyqdQ4m6DCV0xJ2HG1xARRwNGPQfi1SLdLWZ1OJz6F4OMBBNiGJA==", "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-toggle": "1.1.10", - "@radix-ui/react-use-controllable-state": "1.2.2" - }, "peerDependencies": { "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true - }, - "@types/react-dom": { - "optional": true } } }, - "node_modules/@radix-ui/react-toolbar": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz", - "integrity": "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==", + "node_modules/@radix-ui/react-context-menu": { + "version": "2.2.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-context-menu/-/react-context-menu-2.2.16.tgz", + "integrity": "sha512-O8morBEW+HsVG28gYDZPTrT9UUovQUlJue5YO836tiTJhuIWBm/zQHc7j388sHWtdH/xUZurK9olD2+pcqx5ww==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-menu": "2.1.16", "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-separator": "1.1.7", - "@radix-ui/react-toggle-group": "1.1.11" + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", @@ -3743,24 +3707,26 @@ } } }, - "node_modules/@radix-ui/react-tooltip": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", - "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", + "node_modules/@radix-ui/react-dialog": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dialog/-/react-dialog-1.1.15.tgz", + "integrity": "sha512-TCglVRtzlffRNxRMEyR36DGBLJpeusFcgMVD9PZEzAKnUs1lKCgX5u9BmC2Yg+LL9MgZDugFFs1Vl+Jp4t/PGw==", "license": "MIT", "dependencies": { "@radix-ui/primitive": "1.1.3", "@radix-ui/react-compose-refs": "1.1.2", "@radix-ui/react-context": "1.1.2", "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", "@radix-ui/react-id": "1.1.1", - "@radix-ui/react-popper": "1.2.8", "@radix-ui/react-portal": "1.1.9", "@radix-ui/react-presence": "1.1.5", "@radix-ui/react-primitive": "2.1.3", "@radix-ui/react-slot": "1.2.3", "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-visually-hidden": "1.2.3" + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", @@ -3777,10 +3743,10 @@ } } }, - "node_modules/@radix-ui/react-use-callback-ref": { + "node_modules/@radix-ui/react-direction": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", - "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-direction/-/react-direction-1.1.1.tgz", + "integrity": "sha512-1UEWRX6jnOA2y4H5WczZ44gOOjTEmlqv1uNW4GAJEO5+bauCBhv8snY65Iw5/VOS/ghKN9gr2KjnLKxrsvoMVw==", "license": "MIT", "peerDependencies": { "@types/react": "*", @@ -3792,51 +3758,67 @@ } } }, - "node_modules/@radix-ui/react-use-controllable-state": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", - "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", + "node_modules/@radix-ui/react-dismissable-layer": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dismissable-layer/-/react-dismissable-layer-1.1.11.tgz", + "integrity": "sha512-Nqcp+t5cTB8BinFkZgXiMJniQH0PsUt2k51FUhbdfeKvc4ACcG2uQniY/8+h1Yv6Kza4Q7lD7PQV0z0oicE0Mg==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-escape-keydown": "1.1.1" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-use-effect-event": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", - "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", + "node_modules/@radix-ui/react-dropdown-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-dropdown-menu/-/react-dropdown-menu-2.1.16.tgz", + "integrity": "sha512-1PLGQEynI/3OX/ftV54COn+3Sud/Mn8vALg2rWnBLnRaGtJDduNW/22XjlGgPdpcIbiQxjKtb7BkcjP00nqfJw==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-use-escape-keydown": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", - "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", + "node_modules/@radix-ui/react-focus-guards": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-guards/-/react-focus-guards-1.1.3.tgz", + "integrity": "sha512-0rFg/Rj2Q62NCm62jZw0QX7a3sz6QCQU0LpZdNrJX8byRGaGVTqbrW9jAoIAHyMQqsNpeZ81YgSizOt5WXq0Pw==", "license": "MIT", - "dependencies": { - "@radix-ui/react-use-callback-ref": "1.1.1" - }, "peerDependencies": { "@types/react": "*", "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" @@ -3847,61 +3829,106 @@ } } }, - "node_modules/@radix-ui/react-use-is-hydrated": { - "version": "0.1.0", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", - "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", + "node_modules/@radix-ui/react-focus-scope": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-focus-scope/-/react-focus-scope-1.1.7.tgz", + "integrity": "sha512-t2ODlkXBQyn7jkl6TNaw/MtVEVvIGelJDCG41Okq/KwUsJBwQ4XVZsHAVUkK4mBv3ewiAS3PGuUWuY2BoK4ZUw==", "license": "MIT", "dependencies": { - "use-sync-external-store": "^1.5.0" + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-use-layout-effect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", - "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", + "node_modules/@radix-ui/react-form": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-form/-/react-form-0.1.8.tgz", + "integrity": "sha512-QM70k4Zwjttifr5a4sZFts9fn8FzHYvQ5PiB19O2HsYibaHSVt9fH9rzB0XZo/YcM+b7t/p7lYCT/F5eOeF5yQ==", "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-primitive": "2.1.3" + }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-use-previous": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", - "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "node_modules/@radix-ui/react-hover-card": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-hover-card/-/react-hover-card-1.1.15.tgz", + "integrity": "sha512-qgTkjNT1CfKMoP0rcasmlH2r1DAiYicWsDsufxl940sT2wHNEWWv6FMWIQXWhVdmC1d/HYfbhQx60KYyAtKxjg==", "license": "MIT", + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-use-rect": { + "node_modules/@radix-ui/react-icons": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-icons/-/react-icons-1.3.2.tgz", + "integrity": "sha512-fyQIhGDhzfc9pK2kH6Pl9c4BDJGfMkPqkyIgYDthyNYoNg3wVhoJMMh19WS4Up/1KMPFVpNsT2q3WmXn2N1m6g==", + "license": "MIT", + "peerDependencies": { + "react": "^16.x || ^17.x || ^18.x || ^19.0.0 || ^19.0.0-rc" + } + }, + "node_modules/@radix-ui/react-id": { "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", - "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "resolved": "https://registry.npmjs.org/@radix-ui/react-id/-/react-id-1.1.1.tgz", + "integrity": "sha512-kGkGegYIdQsOb4XjsfM97rXsiHaBwco+hFI66oO4s9LU+PLAC5oJ7khdOVFxkhsmlbpUqDAvXw11CluXP+jkHg==", "license": "MIT", "dependencies": { - "@radix-ui/rect": "1.1.1" + "@radix-ui/react-use-layout-effect": "1.1.1" }, "peerDependencies": { "@types/react": "*", @@ -3913,31 +3940,53 @@ } } }, - "node_modules/@radix-ui/react-use-size": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", - "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "node_modules/@radix-ui/react-label": { + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-label/-/react-label-2.1.7.tgz", + "integrity": "sha512-YT1GqPSL8kJn20djelMX7/cTRp/Y9w5IZHvfxQTVHrOqa2yMl7i/UfMqKRU5V7mEyKTrUVgJXhNQPVCG8PBLoQ==", "license": "MIT", "dependencies": { - "@radix-ui/react-use-layout-effect": "1.1.1" + "@radix-ui/react-primitive": "2.1.3" }, "peerDependencies": { "@types/react": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { "optional": true + }, + "@types/react-dom": { + "optional": true } } }, - "node_modules/@radix-ui/react-visually-hidden": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", - "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "node_modules/@radix-ui/react-menu": { + "version": "2.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menu/-/react-menu-2.1.16.tgz", + "integrity": "sha512-72F2T+PLlphrqLcAotYPp0uJMr5SjP5SL01wfEspJbru5Zs5vQaSHb4VB3ZMJPimgHHCHG7gMOeOB9H3Hdmtxg==", "license": "MIT", "dependencies": { - "@radix-ui/react-primitive": "2.1.3" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" }, "peerDependencies": { "@types/react": "*", @@ -3954,28 +4003,28 @@ } } }, - "node_modules/@radix-ui/rect": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", - "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", - "license": "MIT" - }, - "node_modules/@radix-ui/themes": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@radix-ui/themes/-/themes-3.3.0.tgz", - "integrity": "sha512-I0/h2CRNTpYNB7Mi3xFIvSsQq5a108d7kK8dTO5zp5b9HR5QJXKag6B8tjpz2ITkVYkFdkGk45doNkSr7OxwNw==", + "node_modules/@radix-ui/react-menubar": { + "version": "1.1.16", + "resolved": "https://registry.npmjs.org/@radix-ui/react-menubar/-/react-menubar-1.1.16.tgz", + "integrity": "sha512-EB1FktTz5xRRi2Er974AUQZWg2yVBb1yjip38/lgwtCVRd3a+maUoGHN/xs9Yv8SY8QwbSEb+YrxGadVWbEutA==", "license": "MIT", "dependencies": { - "@radix-ui/colors": "^3.0.0", - "classnames": "^2.3.2", - "radix-ui": "^1.1.3", - "react-remove-scroll-bar": "^2.3.8" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { "@types/react": "*", "@types/react-dom": "*", - "react": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { "@types/react": { @@ -3986,5698 +4035,8218 @@ } } }, - "node_modules/@redocly/ajv": { - "version": "8.11.2", - "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz", - "integrity": "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==", - "dev": true, + "node_modules/@radix-ui/react-navigation-menu": { + "version": "1.2.14", + "resolved": "https://registry.npmjs.org/@radix-ui/react-navigation-menu/-/react-navigation-menu-1.2.14.tgz", + "integrity": "sha512-YB9mTFQvCOAQMHU+C/jVl96WmuWeltyUEpRJJky51huhds5W2FQr1J8D/16sQlf0ozxkPK8uF3niQMdUwZPv5w==", "license": "MIT", "dependencies": { - "fast-deep-equal": "^3.1.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2", - "uri-js-replace": "^1.0.1" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@redocly/config": { - "version": "0.22.0", - "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.0.tgz", - "integrity": "sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/@redocly/openapi-core": { - "version": "1.34.19", - "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.19.tgz", - "integrity": "sha512-o/0VgsBXgwcY1lyeqcVtSGdTQAPnVggo0fbFVPlxl5XVDKUcVH0OLRqt3CbkwByT5FU305E0iE0O7MzThjDblw==", - "dev": true, + "node_modules/@radix-ui/react-one-time-password-field": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-one-time-password-field/-/react-one-time-password-field-0.1.8.tgz", + "integrity": "sha512-ycS4rbwURavDPVjCb5iS3aG4lURFDILi6sKI/WITUMZ13gMmn/xGjpLoqBAalhJaDk8I3UbCM5GzKHrnzwHbvg==", "license": "MIT", "dependencies": { - "@redocly/ajv": "8.11.2", - "@redocly/config": "0.22.0", - "colorette": "1.4.0", - "https-proxy-agent": "7.0.6", - "js-levenshtein": "1.1.6", - "js-yaml": "4.3.1", - "minimatch": "5.1.9", - "pluralize": "8.0.0", - "yaml-ast-parser": "0.0.43" + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1" }, - "engines": { - "node": ">=18.17.0", - "npm": ">=9.5.0" - } - }, - "node_modules/@rolldown/pluginutils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", - "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.62.4", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.62.4.tgz", - "integrity": "sha512-W69hukhZ3KKNRCaMIEzKvcFye42hh0FE1+YoYaf5+Ikacuftoco6yO/xouz0hc5d5W/s3yBro5jRiuEE/Q5vUw==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@scalar/helpers": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.10.0.tgz", - "integrity": "sha512-IAfnpIZnXY6ni+zyFMwWHBa5b/7yr4mCSvoTGR84oS9q4Quy2wjgafnr7CyfL65ney3iilBZHigZYLYqdqCu3Q==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=22" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@scalar/json-magic": { - "version": "0.12.20", - "resolved": "https://registry.npmjs.org/@scalar/json-magic/-/json-magic-0.12.20.tgz", - "integrity": "sha512-5JawJ1L3+ddDoKefkXsklKs6CmmTIcPDmkJPpAkbRi9QQiU9MUONQ4VSi2z3ij+8Ka4neNhsXBNG4itPjurBLg==", - "dev": true, + "node_modules/@radix-ui/react-password-toggle-field": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-password-toggle-field/-/react-password-toggle-field-0.1.3.tgz", + "integrity": "sha512-/UuCrDBWravcaMix4TdT+qlNdVwOM1Nck9kWx/vafXsdfj1ChfhOdfi3cy9SGBpWgTXwYCuboT/oYpJy3clqfw==", "license": "MIT", "dependencies": { - "@scalar/helpers": "0.10.0", - "pathe": "^2.0.3", - "yaml": "^2.9.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-is-hydrated": "0.1.0" }, - "engines": { - "node": ">=22" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@scalar/openapi-parser": { - "version": "0.28.12", - "resolved": "https://registry.npmjs.org/@scalar/openapi-parser/-/openapi-parser-0.28.12.tgz", - "integrity": "sha512-s9XgyuWOJ2hQuojulgVm86upBF6vG8IQ8XSCpZxemm6Z2qVncNw2qsZKZ3+6eJOqCQEgJLmvgHSlXpRKq1si9Q==", - "dev": true, + "node_modules/@radix-ui/react-popover": { + "version": "1.1.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popover/-/react-popover-1.1.15.tgz", + "integrity": "sha512-kr0X2+6Yy/vJzLYJUPCZEc8SfQcf+1COFoAqauJm74umQhta9M7lNJHP7QQS3vkvcGLQUbWpMzwrXYwrYztHKA==", "license": "MIT", "dependencies": { - "@scalar/helpers": "0.10.0", - "@scalar/json-magic": "0.12.20", - "@scalar/openapi-types": "0.9.4", - "@scalar/openapi-upgrader": "0.2.13", - "ajv": "^8.17.1", - "ajv-draft-04": "^1.0.0", - "ajv-formats": "^3.0.1", - "jsonpointer": "^5.0.1", - "leven": "^4.0.0", - "yaml": "^2.9.0" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" }, - "engines": { - "node": ">=22" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@scalar/openapi-types": { - "version": "0.9.4", - "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.9.4.tgz", - "integrity": "sha512-eUSIjZEBLEF2i2pvcNdzXhzlKx6qt+hZsNklLmCyzPBoXWxHcQaEClgMFavXDRRvJDdi6LkyjqGUqqf0XgRgFg==", - "dev": true, + "node_modules/@radix-ui/react-popper": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-popper/-/react-popper-1.2.8.tgz", + "integrity": "sha512-0NJQ4LFFUuWkE7Oxf0htBKS6zLkkjBH+hM1uk7Ng705ReR8m/uelduy1DBo0PyBXPKVnBA6YBlU94MBGXrSBCw==", "license": "MIT", - "engines": { - "node": ">=22" + "dependencies": { + "@floating-ui/react-dom": "^2.0.0", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-rect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@scalar/openapi-upgrader": { - "version": "0.2.13", - "resolved": "https://registry.npmjs.org/@scalar/openapi-upgrader/-/openapi-upgrader-0.2.13.tgz", - "integrity": "sha512-bPTkDsthDXj/3bgO7RDmRra1OfwxG/uQio6LP0h9Z8NCCgoZQ4E+V7S6bwF/9TWxbMRlb9djRNpbXCTh/L3C5g==", - "dev": true, + "node_modules/@radix-ui/react-portal": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@radix-ui/react-portal/-/react-portal-1.1.9.tgz", + "integrity": "sha512-bpIxvq03if6UNwXZ+HTK71JLh4APvnXntDc6XOX8UVq4XQOVl7lwok0AvIl+b8zgCw3fSaVTZMpAPPagXbKmHQ==", "license": "MIT", "dependencies": { - "@scalar/openapi-types": "0.9.4" + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-layout-effect": "1.1.1" }, - "engines": { - "node": ">=22" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@standard-schema/spec": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", - "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", - "license": "MIT" - }, - "node_modules/@swc/helpers": { - "version": "0.5.15", - "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", - "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", - "license": "Apache-2.0", + "node_modules/@radix-ui/react-presence": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/@radix-ui/react-presence/-/react-presence-1.1.5.tgz", + "integrity": "sha512-/jfEwNDdQVBCNvjkGit4h6pMOzq8bHkopq458dPt2lMjx+eBQUohZNG9A7DtO/O5ukSbxuaNGXMjHicgwy6rQQ==", + "license": "MIT", "dependencies": { - "tslib": "^2.8.0" + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@tailwindcss/node": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", - "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", - "dev": true, + "node_modules/@radix-ui/react-primitive": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-primitive/-/react-primitive-2.1.3.tgz", + "integrity": "sha512-m9gTwRkhy2lvCPe6QJp4d3G1TYEUHn/FzJUtq9MjH46an1wJU+GdoGC5VLof8RX8Ft/DlpshApkhswDLZzHIcQ==", "license": "MIT", "dependencies": { - "@jridgewell/remapping": "^2.3.5", - "enhanced-resolve": "^5.24.1", - "jiti": "^2.7.0", - "lightningcss": "1.32.0", - "magic-string": "^0.30.21", - "source-map-js": "^1.2.1", - "tailwindcss": "4.3.3" + "@radix-ui/react-slot": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@tailwindcss/oxide": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", - "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", - "dev": true, + "node_modules/@radix-ui/react-progress": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-progress/-/react-progress-1.1.7.tgz", + "integrity": "sha512-vPdg/tF6YC/ynuBIJlk1mm7Le0VgW6ub6J2UWnTQ7/D23KXcPI1qy+0vBkgKgd38RCMJavBXpB83HPNFMTb0Fg==", "license": "MIT", - "engines": { - "node": ">= 20" + "dependencies": { + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3" }, - "optionalDependencies": { - "@tailwindcss/oxide-android-arm64": "4.3.3", - "@tailwindcss/oxide-darwin-arm64": "4.3.3", - "@tailwindcss/oxide-darwin-x64": "4.3.3", - "@tailwindcss/oxide-freebsd-x64": "4.3.3", - "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", - "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", - "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", - "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", - "@tailwindcss/oxide-linux-x64-musl": "4.3.3", - "@tailwindcss/oxide-wasm32-wasi": "4.3.3", - "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", - "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@tailwindcss/oxide-android-arm64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", - "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@radix-ui/react-radio-group": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-radio-group/-/react-radio-group-1.3.8.tgz", + "integrity": "sha512-VBKYIYImA5zsxACdisNQ3BjCBfmbGH3kQlnFVqlWU4tXwjy7cGX8ta80BcrO+WJXIn5iBylEH3K6ZTlee//lgQ==", "license": "MIT", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 20" + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@tailwindcss/oxide-darwin-arm64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", - "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@radix-ui/react-roving-focus": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-roving-focus/-/react-roving-focus-1.1.11.tgz", + "integrity": "sha512-7A6S9jSgm/S+7MdtNDSb+IU859vQqJ/QAtcYQcfFC6W8RS4IxIZDldLR0xqCFZ6DCyrQLjLPsxtTNch5jVA4lA==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@tailwindcss/oxide-darwin-x64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", - "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@radix-ui/react-scroll-area": { + "version": "1.2.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-scroll-area/-/react-scroll-area-1.2.10.tgz", + "integrity": "sha512-tAXIa1g3sM5CGpVT0uIbUx/U3Gs5N8T52IICuCtObaos1S8fzsrPXG5WObkQN3S6NVl6wKgPhAIiBGbWnvc97A==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 20" + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@tailwindcss/oxide-freebsd-x64": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", - "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@radix-ui/react-select": { + "version": "2.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-select/-/react-select-2.2.6.tgz", + "integrity": "sha512-I30RydO+bnn2PQztvo25tswPH+wFBjehVGtmagkU78yMdwTwVf12wnAOF+AeP8S2N8xD+5UPbGhkUfPyvT+mwQ==", "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 20" + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3", + "aria-hidden": "^1.2.4", + "react-remove-scroll": "^2.6.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", - "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@radix-ui/react-separator": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/@radix-ui/react-separator/-/react-separator-1.1.7.tgz", + "integrity": "sha512-0HEb8R9E8A+jZjvmFCy/J4xhbXy3TV+9XSnGJ3KvTtjlIUy/YQ/p6UYZvi7YbeoeXdyU9+Y3scizK6hkY37baA==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", - "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], + "node_modules/@radix-ui/react-slider": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slider/-/react-slider-1.3.6.tgz", + "integrity": "sha512-JPYb1GuM1bxfjMRlNLE+BcmBC8onfCi60Blk7OBqi2MLTFdS+8401U4uFjnwkOr49BLmXxLC6JHkvAsx5OJvHw==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" + "dependencies": { + "@radix-ui/number": "1.1.1", + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@tailwindcss/oxide-linux-arm64-musl": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", - "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-gnu": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", - "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-linux-x64-musl": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", - "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 20" - } - }, - "node_modules/@tailwindcss/oxide-wasm32-wasi": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", - "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", - "bundleDependencies": [ - "@napi-rs/wasm-runtime", - "@emnapi/core", - "@emnapi/runtime", - "@tybys/wasm-util", - "@emnapi/wasi-threads", - "tslib" - ], - "cpu": [ - "wasm32" - ], - "dev": true, + "node_modules/@radix-ui/react-slot": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-slot/-/react-slot-1.2.3.tgz", + "integrity": "sha512-aeNmHnBxbi2St0au6VBVC7JXFlhLlOnvIIlePNniyUNAClzmtAUEY8/pBiK3iHjufOlwA+c20/8jngo7xcrg8A==", "license": "MIT", - "optional": true, "dependencies": { - "@emnapi/core": "^1.11.1", - "@emnapi/runtime": "^1.11.1", - "@emnapi/wasi-threads": "^1.2.2", - "@napi-rs/wasm-runtime": "^1.1.4", - "@tybys/wasm-util": "^0.10.2", - "tslib": "^2.8.1" + "@radix-ui/react-compose-refs": "1.1.2" }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", - "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@tailwindcss/oxide-win32-x64-msvc": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", - "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@radix-ui/react-switch": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@radix-ui/react-switch/-/react-switch-1.2.6.tgz", + "integrity": "sha512-bByzr1+ep1zk4VubeEVViV592vu2lHE2BZY5OnzehZqOOgogN80+mNtCqPkhn2gklJqOpxWgPoYTSnhBCqpOXQ==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 20" + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-previous": "1.1.1", + "@radix-ui/react-use-size": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@tailwindcss/postcss": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.3.tgz", - "integrity": "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==", - "dev": true, + "node_modules/@radix-ui/react-tabs": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tabs/-/react-tabs-1.1.13.tgz", + "integrity": "sha512-7xdcatg7/U+7+Udyoj2zodtI9H/IIopqo+YOIcZOq1nJwXWBZ9p8xiu5llXlekDbZkca79a/fozEYQXIA4sW6A==", "license": "MIT", "dependencies": { - "@alloc/quick-lru": "^5.2.0", - "@tailwindcss/node": "4.3.3", - "@tailwindcss/oxide": "4.3.3", - "postcss": "^8.5.16", - "tailwindcss": "4.3.3" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@testing-library/dom": { - "version": "10.4.1", - "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", - "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", + "node_modules/@radix-ui/react-toast": { + "version": "1.2.15", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toast/-/react-toast-1.2.15.tgz", + "integrity": "sha512-3OSz3TacUWy4WtOXV38DggwxoqJK4+eDkNMl5Z/MJZaoUPaP4/9lf81xXMe1I2ReTAptverZUpbPY4wWwWyL5g==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.10.4", - "@babel/runtime": "^7.12.5", - "@types/aria-query": "^5.0.1", - "aria-query": "5.3.0", - "dom-accessibility-api": "^0.5.9", - "lz-string": "^1.5.0", - "picocolors": "1.1.1", - "pretty-format": "^27.0.2" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" }, - "engines": { - "node": ">=18" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@testing-library/user-event": { - "version": "14.6.4", - "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.4.tgz", - "integrity": "sha512-QCGwP6QrjypBLwyj5cuyfVamkaIEy/XGY+1VDehbtbQqOggYmTFpFOdWR5mPz14vX8vXLMVjDHlRNBcClyO9ew==", + "node_modules/@radix-ui/react-toggle": { + "version": "1.1.10", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle/-/react-toggle-1.1.10.tgz", + "integrity": "sha512-lS1odchhFTeZv3xwHH31YPObmJn8gOg7Lq12inrr0+BH/l3Tsq32VfjqH1oh80ARM3mlkfMic15n0kg4sD1poQ==", "license": "MIT", - "engines": { - "node": ">=12", - "npm": ">=6" + "dependencies": { + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-use-controllable-state": "1.2.2" }, "peerDependencies": { - "@testing-library/dom": ">=7.21.4" + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@types/aria-query": { - "version": "5.0.4", - "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", - "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", - "license": "MIT" - }, - "node_modules/@types/chai": { - "version": "5.2.3", - "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", - "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "node_modules/@radix-ui/react-toggle-group": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toggle-group/-/react-toggle-group-1.1.11.tgz", + "integrity": "sha512-5umnS0T8JQzQT6HbPyO7Hh9dgd82NmS36DQr+X/YJ9ctFNCiiQd6IJAYYZ33LUwm8M+taCz5t2ui29fHZc4Y6Q==", "license": "MIT", "dependencies": { - "@types/deep-eql": "*", - "assertion-error": "^2.0.1" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-use-controllable-state": "1.2.2" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@types/d3-array": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.3.tgz", - "integrity": "sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==", - "license": "MIT" - }, - "node_modules/@types/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==", - "license": "MIT" - }, - "node_modules/@types/d3-delaunay": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", - "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==", - "license": "MIT" - }, - "node_modules/@types/d3-format": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", - "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==", - "license": "MIT" - }, - "node_modules/@types/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "node_modules/@radix-ui/react-toolbar": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/@radix-ui/react-toolbar/-/react-toolbar-1.1.11.tgz", + "integrity": "sha512-4ol06/1bLoFu1nwUqzdD4Y5RZ9oDdKeiHIsntug54Hcr1pgaHiPqHFEaXI1IFP/EsOfROQZ8Mig9VTIRza6Tjg==", "license": "MIT", "dependencies": { - "@types/geojson": "*" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-toggle-group": "1.1.11" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@types/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "node_modules/@radix-ui/react-tooltip": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@radix-ui/react-tooltip/-/react-tooltip-1.2.8.tgz", + "integrity": "sha512-tY7sVt1yL9ozIxvmbtN5qtmH2krXcBCfjEiCgKGLqunJHvgvZG2Pcl2oQ3kbcZARb1BGEHdkLzcYGO8ynVlieg==", "license": "MIT", "dependencies": { - "@types/d3-color": "*" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-id": "1.1.1", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-visually-hidden": "1.2.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@types/d3-path": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", - "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", - "license": "MIT" - }, - "node_modules/@types/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==", + "node_modules/@radix-ui/react-use-callback-ref": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-callback-ref/-/react-use-callback-ref-1.1.1.tgz", + "integrity": "sha512-FkBMwD+qbGQeMu1cOHnuGB6x4yzPjho8ap5WtbEJ26umhgqVXbhekKUQO+hZEL1vU92a3wHwdp0HAcqAUF5iDg==", "license": "MIT", - "dependencies": { - "@types/d3-time": "*" + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@types/d3-shape": { - "version": "3.1.7", - "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", - "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "node_modules/@radix-ui/react-use-controllable-state": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-controllable-state/-/react-use-controllable-state-1.2.2.tgz", + "integrity": "sha512-BjasUjixPFdS+NKkypcyyN5Pmg83Olst0+c6vGov0diwTEo6mgdqVR6hxcEgFuh4QrAs7Rc+9KuGJ9TVCj0Zzg==", "license": "MIT", "dependencies": { - "@types/d3-path": "*" + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@types/d3-time": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", - "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==", - "license": "MIT" - }, - "node_modules/@types/d3-time-format": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", - "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==", - "license": "MIT" - }, - "node_modules/@types/deep-eql": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", - "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", - "license": "MIT" - }, - "node_modules/@types/estree": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", - "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", - "license": "MIT" - }, - "node_modules/@types/geojson": { - "version": "7946.0.16", - "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", - "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", - "license": "MIT" - }, - "node_modules/@types/lodash": { - "version": "4.17.25", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.25.tgz", - "integrity": "sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==", - "license": "MIT" - }, - "node_modules/@types/node": { - "version": "25.9.5", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz", - "integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==", + "node_modules/@radix-ui/react-use-effect-event": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-effect-event/-/react-use-effect-event-0.0.2.tgz", + "integrity": "sha512-Qp8WbZOBe+blgpuUT+lw2xheLP8q0oatc9UpmiemEICxGvFLYmHm9QowVZGHtJlGbS6A6yJ3iViad/2cVjnOiA==", "license": "MIT", "dependencies": { - "undici-types": ">=7.24.0 <7.24.7" + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@types/pg": { - "version": "8.21.0", - "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.21.0.tgz", - "integrity": "sha512-AYdtudzabjLZgVgRZmAnU8bAnVUXzuJX2IYHeSIiIHm68olD+LgQYCGWdtcNYnP0uq9c4S4NibVG3Ni7VbKW7Q==", + "node_modules/@radix-ui/react-use-escape-keydown": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-escape-keydown/-/react-use-escape-keydown-1.1.1.tgz", + "integrity": "sha512-Il0+boE7w/XebUHyBjroE+DbByORGR9KKmITzbR7MyQ4akpORYP/ZmbhAr0DG7RmmBqoOnZdy2QlvajJ2QA59g==", "license": "MIT", "dependencies": { - "@types/node": "*", - "pg-protocol": "*", - "pg-types": "^2.2.0" + "@radix-ui/react-use-callback-ref": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@types/react": { - "version": "19.2.18", - "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", - "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "node_modules/@radix-ui/react-use-is-hydrated": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-is-hydrated/-/react-use-is-hydrated-0.1.0.tgz", + "integrity": "sha512-U+UORVEq+cTnRIaostJv9AGdV3G6Y+zbVd+12e18jQ5A3c0xL03IhnHuiU4UV69wolOQp5GfR58NW/EgdQhwOA==", "license": "MIT", "dependencies": { - "csstype": "^3.2.2" - } - }, - "node_modules/@types/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==", - "devOptional": true, + "use-sync-external-store": "^1.5.0" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-layout-effect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-layout-effect/-/react-use-layout-effect-1.1.1.tgz", + "integrity": "sha512-RbJRS4UWQFkzHTTwVymMTUv8EqYhOp8dOOviLj2ugtTiXRaRQS7GLGxZTLL1jWhMeoSCf5zmcZkqTl9IiYfXcQ==", "license": "MIT", "peerDependencies": { - "@types/react": "^19.2.0" + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } } }, - "node_modules/@typescript/typescript-aix-ppc64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", - "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "node_modules/@radix-ui/react-use-previous": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-previous/-/react-use-previous-1.1.1.tgz", + "integrity": "sha512-2dHfToCj/pzca2Ck724OZ5L0EVrr3eHRNsG/b3xQJLA2hZpVCS99bLAX+hm1IHXDEnzU6by5z/5MIY794/a8NQ==", + "license": "MIT", + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-rect/-/react-use-rect-1.1.1.tgz", + "integrity": "sha512-QTYuDesS0VtuHNNvMh+CjlKJ4LJickCMUAqjlE3+j8w+RlRpwyX3apEQKGFzbZGdo7XNG1tXa+bQqIE7HIXT2w==", + "license": "MIT", + "dependencies": { + "@radix-ui/rect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-use-size": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/react-use-size/-/react-use-size-1.1.1.tgz", + "integrity": "sha512-ewrXRDTAqAXlkl6t/fkXWNAhFX9I+CkKlw6zjEwk86RSPKwZr3xpBRso655aqYafwtnbpHLj6toFzmd6xdVptQ==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-use-layout-effect": "1.1.1" + }, + "peerDependencies": { + "@types/react": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + } + } + }, + "node_modules/@radix-ui/react-visually-hidden": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@radix-ui/react-visually-hidden/-/react-visually-hidden-1.2.3.tgz", + "integrity": "sha512-pzJq12tEaaIhqjbzpCuv/OypJY/BPavOofm+dbab+MHLajy277+1lLm6JFcGgF5eskJ6mquGirhXY2GD/8u8Ug==", + "license": "MIT", + "dependencies": { + "@radix-ui/react-primitive": "2.1.3" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@radix-ui/rect": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@radix-ui/rect/-/rect-1.1.1.tgz", + "integrity": "sha512-HPwpGIzkl28mWyZqG52jiqDJ12waP11Pa1lGoiyUkIEuMLBP0oeK/C89esbXrxsky5we7dfd8U58nm0SgAWpVw==", + "license": "MIT" + }, + "node_modules/@radix-ui/themes": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@radix-ui/themes/-/themes-3.3.0.tgz", + "integrity": "sha512-I0/h2CRNTpYNB7Mi3xFIvSsQq5a108d7kK8dTO5zp5b9HR5QJXKag6B8tjpz2ITkVYkFdkGk45doNkSr7OxwNw==", + "license": "MIT", + "dependencies": { + "@radix-ui/colors": "^3.0.0", + "classnames": "^2.3.2", + "radix-ui": "^1.1.3", + "react-remove-scroll-bar": "^2.3.8" + }, + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@react-router/node": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@react-router/node/-/node-7.18.3.tgz", + "integrity": "sha512-wIBFSsmp+uA/F2MEHN1BxFoWAhh9rdIH/Zd39KYyLhZSeb35YlRi8ARtOMDYj7EqhhZfkoetf/SEmYywK3nUkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@mjackson/node-fetch-server": "^0.2.0" + }, + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "react-router": "7.18.3", + "typescript": "^5.1.0 || ^6.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@redocly/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/@redocly/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-io1JpnwtIcvojV7QKDUSIuMN/ikdOUd1ReEnUnMKGfDVridQZ31J0MmIuqwuRjWDZfmvr+Q0MqCcfHM2gTivOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js-replace": "^1.0.1" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@redocly/config": { + "version": "0.22.0", + "resolved": "https://registry.npmjs.org/@redocly/config/-/config-0.22.0.tgz", + "integrity": "sha512-gAy93Ddo01Z3bHuVdPWfCwzgfaYgMdaZPcfL7JZ7hWJoK9V0lXDbigTWkhiPFAaLWzbOJ+kbUQG1+XwIm0KRGQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@redocly/openapi-core": { + "version": "1.34.19", + "resolved": "https://registry.npmjs.org/@redocly/openapi-core/-/openapi-core-1.34.19.tgz", + "integrity": "sha512-o/0VgsBXgwcY1lyeqcVtSGdTQAPnVggo0fbFVPlxl5XVDKUcVH0OLRqt3CbkwByT5FU305E0iE0O7MzThjDblw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@redocly/ajv": "8.11.2", + "@redocly/config": "0.22.0", + "colorette": "1.4.0", + "https-proxy-agent": "7.0.6", + "js-levenshtein": "1.1.6", + "js-yaml": "4.3.1", + "minimatch": "5.1.9", + "pluralize": "8.0.0", + "yaml-ast-parser": "0.0.43" + }, + "engines": { + "node": ">=18.17.0", + "npm": ">=9.5.0" + } + }, + "node_modules/@remix-run/node-fetch-server": { + "version": "0.13.3", + "resolved": "https://registry.npmjs.org/@remix-run/node-fetch-server/-/node-fetch-server-0.13.3.tgz", + "integrity": "sha512-UfjOXed/DQteaM5VyTfqTeGpHwyL2J5aoRGY6cydip4tt1ehNNeSwuXCC7AEGE0RWBs/7bgKxYkL/B/+UDe4AA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rolldown/binding-android-arm-eabi": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm-eabi/-/binding-android-arm-eabi-1.2.7.tgz", + "integrity": "sha512-EypzgnYCwyVY4NDHKzGmNJT5b+XaQEBniHxsMdeIQLB/tcCzZnhqrzHpZFbX9iaxx+5RiB8caATBtfvZP7zVxQ==", "cpu": [ - "ppc64" + "arm" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "aix" + "android" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-darwin-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", - "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", + "node_modules/@rolldown/binding-android-arm64": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.2.7.tgz", + "integrity": "sha512-l17HE9EweWaqJZhuUuNBN/FzM62xw+DECVnJyvMsxn8vJFAGLy5QfLDoYAcronkAN8VxKZHezDpulHDPx95vFw==", "cpu": [ "arm64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "darwin" + "android" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-darwin-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", - "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", + "node_modules/@rolldown/binding-darwin-arm64": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.2.7.tgz", + "integrity": "sha512-8ED8ELFvHXc6OCETIn4gXObPiaR6bckM/ipXtbzlPVDRMBfEGjCKgO90F9YtfdpDatVx/ZQw7aZ1vUMf/+T3Mw==", "cpu": [ - "x64" + "arm64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-freebsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", - "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", + "node_modules/@rolldown/binding-darwin-x64": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.2.7.tgz", + "integrity": "sha512-/WPripjtiAIZ2tWY7ddijORT0Ujg87wxWW/qcoFVCKAWVDPhtY0xr7Dj0M3GyNGz60jGwTElhro/mkF9dT7dDQ==", "cpu": [ - "arm64" + "x64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "freebsd" + "darwin" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-freebsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", - "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", + "node_modules/@rolldown/binding-freebsd-x64": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.2.7.tgz", + "integrity": "sha512-14DI4NcqpvbICxSnGLx3PmtDaWqRP/KGSGb6C+JLLVPeZRl6dKdHba3pGsqT3vpdTqhEYIPG0MMQ8c0xYqoJxA==", "cpu": [ "x64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-linux-arm": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", - "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", + "node_modules/@rolldown/binding-linux-arm-gnueabihf": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.2.7.tgz", + "integrity": "sha512-bxrWIRvHWQvbJwi+VIie/kDJmQxcNE6xxWwZdqF/ExVAigtHkv54WTLQPb+QsZdnFy18fg7JPfWGL0RH6vwIlQ==", "cpu": [ "arm" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-linux-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", - "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", + "node_modules/@rolldown/binding-linux-arm64-gnu": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.2.7.tgz", + "integrity": "sha512-toOY2BChBZyuxU7OYX6Tn389di4IzAqPTycVcci0O7FSfBqzRB3RZn+K5Is6ANf4tmgRd/K1yZTsNTXbkXsnLg==", "cpu": [ "arm64" ], "dev": true, - "license": "Apache-2.0", + "libc": [ + "glibc" + ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-linux-loong64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", - "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", + "node_modules/@rolldown/binding-linux-arm64-musl": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.2.7.tgz", + "integrity": "sha512-lAIXTH/aiLRLxsTgQvfhjo4K1ydWIp00+V0voOr9beb/9ZmkUFrSIb03dXNFRgMNvkE6oGsF10ioQ6UsI+vS5Q==", "cpu": [ - "loong64" + "arm64" ], "dev": true, - "license": "Apache-2.0", + "libc": [ + "musl" + ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-linux-mips64el": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", - "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", + "node_modules/@rolldown/binding-linux-ppc64-gnu": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.2.7.tgz", + "integrity": "sha512-kdnwS28Pkenp/mZMRwjXXXwxQ7pIsm+bF919LUK93BOyhcLsrVKdP2p9fxpiPNPAbNuch8ypQt0pm2P2LYCAGg==", "cpu": [ - "mips64el" + "ppc64" ], "dev": true, - "license": "Apache-2.0", + "libc": [ + "glibc" + ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-linux-ppc64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", - "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "node_modules/@rolldown/binding-linux-s390x-gnu": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.2.7.tgz", + "integrity": "sha512-516OdsyLdr5E65paF3yBF55t8mfm9+gmtCsK3xI7XKXIT7EfRlHhxL8K/NR6Hu8BWSgF5+1w74lTL0+nxcc8Qw==", "cpu": [ - "ppc64" + "s390x" ], "dev": true, - "license": "Apache-2.0", + "libc": [ + "glibc" + ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-linux-riscv64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", - "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", + "node_modules/@rolldown/binding-linux-x64-gnu": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.2.7.tgz", + "integrity": "sha512-r8/z8n7GFaYRln3xmP1Cxy0HH/HLM0uBUPkEuSVEfKGDA89M0FsZRZJRSwe/tJjRx+fpH/gjorfhB8tmEbSFLA==", "cpu": [ - "riscv64" + "x64" ], "dev": true, - "license": "Apache-2.0", + "libc": [ + "glibc" + ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-linux-s390x": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", - "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "node_modules/@rolldown/binding-linux-x64-musl": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.2.7.tgz", + "integrity": "sha512-pAsE8iiDxUg1xBqdhrTfg45AVDVpirjz00sblEYClGNNcMnDb+e8beQgqIAw6LvauX/APvgxUnwrgun/YYGBhw==", "cpu": [ - "s390x" + "x64" ], "dev": true, - "license": "Apache-2.0", + "libc": [ + "musl" + ], + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-linux-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", - "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", + "node_modules/@rolldown/binding-openharmony-arm64": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.2.7.tgz", + "integrity": "sha512-lTcIYmmnQQA8Or/2DatS6oSqcdLHvendjS+zLu+FwgToynWMRSmQdpM65fTANJgIS4mjbMOo5KT2lnT9SAb96w==", "cpu": [ - "x64" + "arm64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "linux" + "openharmony" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-netbsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", - "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "node_modules/@rolldown/binding-win32-arm64-msvc": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.2.7.tgz", + "integrity": "sha512-e3Gu3WxbNk/UqQhxqU7YIYO+9ZBvWNz3U+h/qRFosscMFzdRPbXYSaSWgSnklv2fz1TgzBTcti2z35c/7irsHw==", "cpu": [ "arm64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "netbsd" + "win32" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-netbsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", - "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "node_modules/@rolldown/binding-win32-x64-msvc": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.2.7.tgz", + "integrity": "sha512-W/jg5qoRSqjsEv0+dZi4e687mcHqmVuU0P4fK6qS/xjetW2Gmc1W8j//z5nAeNcC8Ttm0hV46IjcYeuVwYhuiw==", "cpu": [ "x64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "netbsd" + "win32" ], "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" } }, - "node_modules/@typescript/typescript-openbsd-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", - "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", + "node_modules/@rolldown/pluginutils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.1.tgz", + "integrity": "sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.63.1.tgz", + "integrity": "sha512-UZ8sUxPTiHWYX9QNdJedb1kDZSpS1t/VPWBWGSgqHNi9w3Cu6IXvu2mzbhiTiPvtrqgTQJ+zqiAq2iPIPilpaQ==", "cpu": [ - "arm64" + "arm" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "openbsd" - ], - "engines": { - "node": ">=16.20.0" - } + "android" + ] }, - "node_modules/@typescript/typescript-openbsd-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", - "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.63.1.tgz", + "integrity": "sha512-cQ4nFQABN5cDvDpbvJ7bMStCpnaVxynZrRMfUJYgxcIk9Sh54FIO1vtfkg0B69REjER77ioZ/ov+eAApx/KmLQ==", "cpu": [ - "x64" + "arm64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "openbsd" + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.63.1.tgz", + "integrity": "sha512-FQNqd1lRy/0QhDk3xeRIkSBiCpXCiDnZO3YLVdcDKN1UBiKToNftCzcXYNLshmPDUMlu2TdeS8tGcsU6f3YF1Q==", + "cpu": [ + "arm64" ], - "engines": { - "node": ">=16.20.0" - } + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] }, - "node_modules/@typescript/typescript-sunos-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", - "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.63.1.tgz", + "integrity": "sha512-pvD16V939D3CloK0+qikpGaxiPrDUXTe7Y5cWOMkMSy7m1cawa8EGy/kXYi/G/cKAC4HDAbSnzCIk1WmsoOKXg==", "cpu": [ "x64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "sunos" - ], - "engines": { - "node": ">=16.20.0" - } + "darwin" + ] }, - "node_modules/@typescript/typescript-win32-arm64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", - "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "node_modules/@rollup/rollup-freebsd-arm64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.63.1.tgz", + "integrity": "sha512-pcFGeL2345VwdTnJhA6zLbew+YgWB0qBG2+dMtXjCicf6+rm6kO6cOoh5VnTe0ZMrMRgRyuHmCJxZWrIdzYuOw==", "cpu": [ "arm64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">=16.20.0" - } + "freebsd" + ] }, - "node_modules/@typescript/typescript-win32-x64": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", - "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", + "node_modules/@rollup/rollup-freebsd-x64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.63.1.tgz", + "integrity": "sha512-mRJlqSRulVzcKq/LKA6ICSIc3K/l4fzlVn/gePn2nXIHy8seRi5z/eeRE0d/XMBxcMldiXtQTSpRj0tkkC3g8Q==", "cpu": [ "x64" ], "dev": true, - "license": "Apache-2.0", + "license": "MIT", "optional": true, "os": [ - "win32" - ], - "engines": { - "node": ">=16.20.0" - } + "freebsd" + ] }, - "node_modules/@typespec/asset-emitter": { - "version": "0.79.1", - "resolved": "https://registry.npmjs.org/@typespec/asset-emitter/-/asset-emitter-0.79.1.tgz", - "integrity": "sha512-53s3GLu5BwNkl7Itr/OizfhymTV2u7k5/cwjUOAt03AUDfiKlwbsp+iCIsq1vccJuoDOiXOceJOfL8rAf4/9LQ==", + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.63.1.tgz", + "integrity": "sha512-YDUNvVM85TI3g/1OpnqKP1h4NeW/j64DfWMf+G3M809xNk1bJSnpFp4sh83NpmVE5DXnkh8ULor4LTVZKoYLHw==", + "cpu": [ + "arm" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "engines": { - "node": ">=20.0.0" - }, - "peerDependencies": { - "@typespec/compiler": "^1.10.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@typespec/compiler": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.15.0.tgz", - "integrity": "sha512-NbCIRAIzyozchlSaGPVuyV43bC+y+OpXYCuT+8M8kt35Ln9zWzLFcIt7irofQ5QUXBZrHsBFpI5fTOFdCGeWCA==", + "node_modules/@rollup/rollup-linux-arm-musleabihf": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.63.1.tgz", + "integrity": "sha512-7Mcn71p9ZuQFAj+h+dhQXy/yeLePRS2yKRnmW1DijA9thKO5qap0GNOIQK4yQ6iP3SU0Mrb/yWo8h8vgRba8lw==", + "cpu": [ + "arm" + ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.29.0", - "@inquirer/prompts": "^8.4.1", - "ajv": "^8.18.0", - "change-case": "^5.4.4", - "env-paths": "^4.0.0", - "is-unicode-supported": "^2.1.0", - "mustache": "^4.2.0", - "picocolors": "^1.1.1", - "prettier": "^3.9.5", - "semver": "^7.7.4", - "tar": "^7.5.21", - "temporal-polyfill": "^1.0.1", - "vscode-languageserver": "^10.0.0", - "vscode-languageserver-textdocument": "^1.0.12", - "yaml": "^2.8.3", - "yargs": "^18.0.0" - }, - "bin": { - "tsp": "cmd/tsp.js", - "tsp-server": "cmd/tsp-server.js" - }, - "engines": { - "node": ">=22.0.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@typespec/http": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.15.0.tgz", - "integrity": "sha512-LNyzYHyX3C0xyQQ262jhvIaVzTn7DqiDB2gz45w1m6ngJH9ArGU8XjO3o7PaZkl/nuB5MTpImnsXpHIV1rbi4Q==", - "dev": true, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.63.1.tgz", + "integrity": "sha512-4YiLQTX6U4CSl0L9cluep9A9W6UmTfqBDc2/CH6wlu54pl4E7Jn3cOD8oxzvBDEGk/JMKgJ47C8g+radF7mwvg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "engines": { - "node": ">=22.0.0" - }, - "peerDependencies": { - "@typespec/compiler": "^1.15.0", - "@typespec/streams": "^0.85.0" - }, - "peerDependenciesMeta": { - "@typespec/streams": { - "optional": true - } - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@typespec/openapi": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.15.0.tgz", - "integrity": "sha512-lHd3H5W23KOIGKyBPKpBLPHVOxcxuvqOBXGqlyPvGmHDgmD74mrUtHWxNoGx+QQESjx4tS8Tu6URNQBU6y6Q1Q==", + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.63.1.tgz", + "integrity": "sha512-2ra8F7w8OquwZN9z2/fKFnli69wa8PLwaVzRMIPGb13ByMJwC28Fbp8YcVGoUhlYMTt7j5j9bNgpysrN2UM+vw==", + "cpu": [ + "arm64" + ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "engines": { - "node": ">=22.0.0" - }, - "peerDependencies": { - "@typespec/compiler": "^1.15.0", - "@typespec/http": "^1.15.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@typespec/openapi3": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/@typespec/openapi3/-/openapi3-1.15.0.tgz", - "integrity": "sha512-Gc6OjBiAtPo3ohlkrDxQKt8+xdeR54tC+Cgu3YLlxUxrWHWYOfWQXzp4NX+sraiFjF6kX7t0G1A1kY7rgy73qw==", + "node_modules/@rollup/rollup-linux-loong64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-gnu/-/rollup-linux-loong64-gnu-4.63.1.tgz", + "integrity": "sha512-Sy20ncyhjmBP0Ml+UvQbimjlk6VFgjW5uNP+qqwHB00mTE8Bl2C1TuHTlRwK2YoXeZbee5lP2XevBWVkAQAtSQ==", + "cpu": [ + "loong64" + ], "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@scalar/json-magic": "^0.12.15", - "@scalar/openapi-parser": "^0.28.6", - "@scalar/openapi-types": "^0.9.1", - "@typespec/asset-emitter": "^0.79.1", - "yaml": "^2.8.3" - }, - "bin": { - "tsp-openapi3": "cmd/tsp-openapi3.js" - }, - "engines": { - "node": ">=22.0.0" - }, - "peerDependencies": { - "@typespec/compiler": "^1.15.0", - "@typespec/events": "^0.85.0", - "@typespec/http": "^1.15.0", - "@typespec/json-schema": "^1.15.0", - "@typespec/openapi": "^1.15.0", - "@typespec/sse": "^0.85.0", - "@typespec/streams": "^0.85.0", - "@typespec/versioning": "^0.85.0" - }, - "peerDependenciesMeta": { - "@typespec/events": { - "optional": true - }, - "@typespec/json-schema": { - "optional": true - }, - "@typespec/sse": { - "optional": true - }, - "@typespec/streams": { - "optional": true - }, - "@typespec/versioning": { - "optional": true - }, - "@typespec/xml": { - "optional": true - } - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@typespec/rest": { - "version": "0.85.0", - "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.85.0.tgz", - "integrity": "sha512-ogbot1wp8jLn0rSOzwHjMjgDot+1u7WFZOWluRHL3cuRw9l8+ZjlixBrkXZ84dKP54RoYUN3buBjfOZ7qyHeyg==", + "node_modules/@rollup/rollup-linux-loong64-musl": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loong64-musl/-/rollup-linux-loong64-musl-4.63.1.tgz", + "integrity": "sha512-noITLp8oNjYliPnGWmLyelIHwULGqbHloQHGw1rtxbWhTuWooRpnZarZQJ1y9EUC4szuCusCc+HEpUtxpIwYvA==", + "cpu": [ + "loong64" + ], "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "engines": { - "node": ">=22.0.0" - }, - "peerDependencies": { - "@typespec/compiler": "^1.15.0", - "@typespec/http": "^1.15.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@visx/curve": { - "version": "4.0.1-alpha.0", - "resolved": "https://registry.npmjs.org/@visx/curve/-/curve-4.0.1-alpha.0.tgz", - "integrity": "sha512-jRu61Uz274pV1zyioXmboyrLutYbnKsgjj4njSGCnhdXj5GkZvZbg+ThDb6oOzoAnJOBRLz4rzPlWvNJOzuVMg==", + "node_modules/@rollup/rollup-linux-ppc64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-gnu/-/rollup-linux-ppc64-gnu-4.63.1.tgz", + "integrity": "sha512-hlxxXd+F1mWiAcaFR7Sv9ZQT6m6UfI8+Vy/kFJzztq2pDMU/0wZ9sish0iszNZvsQDo8Gc0i5yuFEOz5dDf6fA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@visx/vendor": "4.0.0-alpha.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@visx/event": { - "version": "4.0.1-alpha.0", - "resolved": "https://registry.npmjs.org/@visx/event/-/event-4.0.1-alpha.0.tgz", - "integrity": "sha512-EQqCMSv/s8NbFjo+hz3FKsvvYfP+2QslsFJ/24/O5l/W+7UC6J6aAvO0ujVwrTwdYbuQ+vhxKi1xdPdKR/qj1g==", + "node_modules/@rollup/rollup-linux-ppc64-musl": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-ppc64-musl/-/rollup-linux-ppc64-musl-4.63.1.tgz", + "integrity": "sha512-EF7OpqQTQ/BvGqLzUi4rEHuagCV9MugAUXSHemwPW5vxZ75RR+jxO/2j95Ph2dalMpFHSVECjRoioHZgA9zOYA==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@types/react": "*", - "@visx/point": "4.0.1-alpha.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@visx/grid": { - "version": "4.0.1-alpha.0", - "resolved": "https://registry.npmjs.org/@visx/grid/-/grid-4.0.1-alpha.0.tgz", - "integrity": "sha512-rycutGmTHO+znNdPumheWMglm7YfpffvRwUkVy5zy4WoORIuKTMkDxwnOzHG2xMxU3EE/YCd37xFV5AxA30yeg==", + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.63.1.tgz", + "integrity": "sha512-wQO3JesW9PRkwlabQ27y7sPfVOOTLRG73I4F2UYHG5PXun3J9U3y+b7ezVKSYbsvSKGQ1k1cq8Qlun4C9kLt3w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@types/react": "*", - "@visx/curve": "4.0.1-alpha.0", - "@visx/group": "4.0.1-alpha.0", - "@visx/point": "4.0.1-alpha.0", - "@visx/scale": "4.0.1-alpha.0", - "@visx/shape": "4.0.1-alpha.0", - "classnames": "^2.3.1" - }, - "peerDependencies": { - "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@visx/group": { - "version": "4.0.1-alpha.0", - "resolved": "https://registry.npmjs.org/@visx/group/-/group-4.0.1-alpha.0.tgz", - "integrity": "sha512-V19l7iQ7jccBv8kao/EByuI6o4xtxzzLV9nqVI1hRvmdzTVsuLpqlwzYCZUXJaTVvUWf8s4D2SQFjGkj/Nw+0w==", + "node_modules/@rollup/rollup-linux-riscv64-musl": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-musl/-/rollup-linux-riscv64-musl-4.63.1.tgz", + "integrity": "sha512-ouAGwhO6wHRXdnOVCOsB0tRFkA7nhNB2Nwax6oECXN0YiN8EYUTBAOudADOB1PI+yDL61TeNx/u7MVCzksNbkQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@types/react": "*", - "classnames": "^2.3.1" - }, - "peerDependencies": { - "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" - } - }, - "node_modules/@visx/point": { - "version": "4.0.1-alpha.0", - "resolved": "https://registry.npmjs.org/@visx/point/-/point-4.0.1-alpha.0.tgz", - "integrity": "sha512-ijTfr/Nx09f03vIj9nyTr3z4Xth4Y75427UaogJh6dnIRLMEFHQOwNu791sbfiNj0a+ZXuaE32h0vKrFe4/8Qg==", - "license": "MIT" + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@visx/responsive": { - "version": "4.0.1-alpha.0", - "resolved": "https://registry.npmjs.org/@visx/responsive/-/responsive-4.0.1-alpha.0.tgz", - "integrity": "sha512-o+1zGywQZY0+yOx3Iw87wc4bbPJRr/HnIukTwfOz4UVyj9pB1OQNVHB7OORO1+LBHJceWpB31co/ZV9KHncKrA==", + "node_modules/@rollup/rollup-linux-s390x-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.63.1.tgz", + "integrity": "sha512-q2R38Sn+1J8RxhfJ+T54wSWmyKXWec+9jgDfqO2AtArEqHO5R2aeayp5H5OYLr5UYDVGsVaZPEFUooMhYCdz5A==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@types/lodash": "^4.17.13", - "@types/react": "*", - "lodash": "^4.17.21" - }, - "peerDependencies": { - "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@visx/scale": { - "version": "4.0.1-alpha.0", - "resolved": "https://registry.npmjs.org/@visx/scale/-/scale-4.0.1-alpha.0.tgz", - "integrity": "sha512-nzjeE87vFSAXGWFiiNfBpNLAf0Q8Qmf6syvKLjqNi4kGZkdhbUll3E/59YsgWXmjM8+llPLWzGsP+JPvo5eq1A==", + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.63.1.tgz", + "integrity": "sha512-gfI5T24WLLuFfSKw7Go/zDXjAAV0fny0swTaDv+WjK7vqcw4cRhFfdsyKL1n+ukI+ooBxn3bVQnyrn06WpI50w==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], "license": "MIT", - "dependencies": { - "@visx/vendor": "4.0.0-alpha.0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@visx/shape": { - "version": "4.0.1-alpha.0", - "resolved": "https://registry.npmjs.org/@visx/shape/-/shape-4.0.1-alpha.0.tgz", - "integrity": "sha512-62QeiVNmPlterQGwhkEDcbq7M0MqY0lBsK5QKXtM9ZoPZWkuGV3aykA3+Xu20B2FAvyJq4LqJzBc7Sxr+EAdbA==", + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.63.1.tgz", + "integrity": "sha512-4h6XqthmB4Hspji84wvgk+ElodTsGj+dbZqHJHHtKxj4mYq0ANSEEPX9ys3moJueqsRjwpaJYH7874Itwnj2ow==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], "license": "MIT", - "dependencies": { - "@types/lodash": "^4.17.13", - "@types/react": "*", - "@visx/curve": "4.0.1-alpha.0", - "@visx/group": "4.0.1-alpha.0", - "@visx/scale": "4.0.1-alpha.0", - "@visx/vendor": "4.0.0-alpha.0", - "classnames": "^2.3.1", - "lodash": "^4.17.21" - }, - "peerDependencies": { - "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" - } + "optional": true, + "os": [ + "linux" + ] }, - "node_modules/@visx/vendor": { - "version": "4.0.0-alpha.0", - "resolved": "https://registry.npmjs.org/@visx/vendor/-/vendor-4.0.0-alpha.0.tgz", - "integrity": "sha512-6I+MuqXBcv9jnlcVowHoHKSdk9gXTWkHLKyqBwRWg7LY6A3Ei8SHfubpqGV5rBUSppxMq2RszPJUS6w+H0YgmQ==", - "license": "MIT and ISC", - "dependencies": { - "@types/d3-array": "3.0.3", - "@types/d3-color": "3.1.0", - "@types/d3-delaunay": "6.0.1", - "@types/d3-format": "3.0.1", - "@types/d3-geo": "3.1.0", - "@types/d3-interpolate": "3.0.1", - "@types/d3-path": "3.1.1", - "@types/d3-scale": "4.0.2", - "@types/d3-shape": "3.1.7", - "@types/d3-time": "3.0.0", - "@types/d3-time-format": "2.1.0", - "d3-array": "3.2.1", - "d3-color": "3.1.0", - "d3-delaunay": "6.0.2", - "d3-format": "3.1.0", - "d3-geo": "3.1.0", - "d3-interpolate": "3.0.1", - "d3-path": "3.1.0", - "d3-scale": "4.0.2", - "d3-shape": "3.2.0", - "d3-time": "3.1.0", - "d3-time-format": "4.1.0", - "internmap": "2.0.3" + "node_modules/@rollup/rollup-openbsd-x64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openbsd-x64/-/rollup-openbsd-x64-4.63.1.tgz", + "integrity": "sha512-dlfCOa87o1VAYegLQ9EKilx2JCeRofiyPGhTCmqnuXZ6bMPiycO1rq1+sKoulAp7pGLIsTIw+1x5R+zgh5LhhA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openbsd" + ] + }, + "node_modules/@rollup/rollup-openharmony-arm64": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-openharmony-arm64/-/rollup-openharmony-arm64-4.63.1.tgz", + "integrity": "sha512-cjkLbOlfcm3QGhMM1J5zaZjsw1GggbN6rw9UTSSRrPrR1KkcXnN7Uq9rPw34xImQ9VOY9GN+6u2Zj80B9ptkcw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "openharmony" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.63.1.tgz", + "integrity": "sha512-Li1KdUnWGE4N3e1F/B4RTB1ms+nG4WBgjByO46pkeBVX/2UBsY53xf5vK9WygVmnH3RwncIST7lkSdLSY6P9lg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.63.1.tgz", + "integrity": "sha512-t4ZYOSoLTgwhuFMrmTMLx/+i1DQVK7HYqMc6kY46EApwi8X0nIVphzdNoThU3xt6n+N5urG1/gxBdCaKDLavfg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-gnu": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-gnu/-/rollup-win32-x64-gnu-4.63.1.tgz", + "integrity": "sha512-RgroPfMmKlD1RzSDxvwgcPiy2HNQKoYV7OmwIXDsk73uKW5t6B/V8KIy27SMv/FNXFo/oSBtWc9J0X7t91ezZg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.63.1.tgz", + "integrity": "sha512-at8QVep6S3h5Y6gSbdGU06bRY5WJkf6WUduM9YtvYMbYhB1MOFfUgc6kehitQXzOtMSaT70q7f9ydPhpqu821w==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@scalar/helpers": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@scalar/helpers/-/helpers-0.10.0.tgz", + "integrity": "sha512-IAfnpIZnXY6ni+zyFMwWHBa5b/7yr4mCSvoTGR84oS9q4Quy2wjgafnr7CyfL65ney3iilBZHigZYLYqdqCu3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22" } }, - "node_modules/@visx/vendor/node_modules/d3-array": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.1.tgz", - "integrity": "sha512-gUY/qeHq/yNqqoCKNq4vtpFLdoCdvyNpWoC/KNjhGbhDuQpAM9sIQQKkXSNpXa9h5KySs/gzm7R88WkUutgwWQ==", - "license": "ISC", + "node_modules/@scalar/json-magic": { + "version": "0.12.20", + "resolved": "https://registry.npmjs.org/@scalar/json-magic/-/json-magic-0.12.20.tgz", + "integrity": "sha512-5JawJ1L3+ddDoKefkXsklKs6CmmTIcPDmkJPpAkbRi9QQiU9MUONQ4VSi2z3ij+8Ka4neNhsXBNG4itPjurBLg==", + "dev": true, + "license": "MIT", "dependencies": { - "internmap": "1 - 2" + "@scalar/helpers": "0.10.0", + "pathe": "^2.0.3", + "yaml": "^2.9.0" }, "engines": { - "node": ">=12" + "node": ">=22" } }, - "node_modules/@vitejs/plugin-react": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.5.tgz", - "integrity": "sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==", + "node_modules/@scalar/openapi-parser": { + "version": "0.28.12", + "resolved": "https://registry.npmjs.org/@scalar/openapi-parser/-/openapi-parser-0.28.12.tgz", + "integrity": "sha512-s9XgyuWOJ2hQuojulgVm86upBF6vG8IQ8XSCpZxemm6Z2qVncNw2qsZKZ3+6eJOqCQEgJLmvgHSlXpRKq1si9Q==", "dev": true, "license": "MIT", "dependencies": { - "@rolldown/pluginutils": "^1.0.1" + "@scalar/helpers": "0.10.0", + "@scalar/json-magic": "0.12.20", + "@scalar/openapi-types": "0.9.4", + "@scalar/openapi-upgrader": "0.2.13", + "ajv": "^8.17.1", + "ajv-draft-04": "^1.0.0", + "ajv-formats": "^3.0.1", + "jsonpointer": "^5.0.1", + "leven": "^4.0.0", + "yaml": "^2.9.0" }, "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", - "babel-plugin-react-compiler": "^1.0.0", - "vite": "^8.0.0" - }, - "peerDependenciesMeta": { - "@rolldown/plugin-babel": { - "optional": true - }, - "babel-plugin-react-compiler": { - "optional": true - } + "node": ">=22" } }, - "node_modules/@vitest/browser": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.10.tgz", - "integrity": "sha512-UDwuWGwXj646CBx/bQHOaJSX7np0I8JL/UKQYa1e4QrVHH8VdWtx8eaOuf8sy0ShwDgR6NjJAsp5eF6vjF6qng==", + "node_modules/@scalar/openapi-types": { + "version": "0.9.4", + "resolved": "https://registry.npmjs.org/@scalar/openapi-types/-/openapi-types-0.9.4.tgz", + "integrity": "sha512-eUSIjZEBLEF2i2pvcNdzXhzlKx6qt+hZsNklLmCyzPBoXWxHcQaEClgMFavXDRRvJDdi6LkyjqGUqqf0XgRgFg==", + "dev": true, "license": "MIT", - "dependencies": { - "@blazediff/core": "1.9.1", - "@vitest/mocker": "4.1.10", - "@vitest/utils": "4.1.10", - "magic-string": "^0.30.21", - "pngjs": "^7.0.0", - "sirv": "^3.0.2", - "tinyrainbow": "^3.1.0", - "ws": "^8.19.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "vitest": "4.1.10" + "engines": { + "node": ">=22" } }, - "node_modules/@vitest/browser-preview": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/browser-preview/-/browser-preview-4.1.10.tgz", - "integrity": "sha512-14MJrL59ZFkqXLjwfSk6RzTDy5Czf9UG4+8q8L6Gxjs2aPjEce/cVNYV14bXAc2BvMjUNu904+ZEZA1Xc1wtvQ==", + "node_modules/@scalar/openapi-upgrader": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/@scalar/openapi-upgrader/-/openapi-upgrader-0.2.13.tgz", + "integrity": "sha512-bPTkDsthDXj/3bgO7RDmRra1OfwxG/uQio6LP0h9Z8NCCgoZQ4E+V7S6bwF/9TWxbMRlb9djRNpbXCTh/L3C5g==", + "dev": true, "license": "MIT", "dependencies": { - "@testing-library/dom": "^10.4.1", - "@testing-library/user-event": "^14.6.1", - "@vitest/browser": "4.1.10" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "@scalar/openapi-types": "0.9.4" }, - "peerDependencies": { - "vitest": "4.1.10" + "engines": { + "node": ">=22" } }, - "node_modules/@vitest/expect": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", - "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", - "license": "MIT", + "node_modules/@standard-schema/spec": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@standard-schema/spec/-/spec-1.1.0.tgz", + "integrity": "sha512-l2aFy5jALhniG5HgqrD6jXLi/rUWrKvqN/qJx6yoJsgKhblVd+iqqU4RCXavm/jPityDo5TCvKMnpjKnOriy0w==", + "license": "MIT" + }, + "node_modules/@swc/helpers": { + "version": "0.5.15", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.15.tgz", + "integrity": "sha512-JQ5TuMi45Owi4/BIMAJBoSQoOJu12oOk/gADqlcUL9JEdHB8vyjUSsxqeNXnmXHjYKMi2WcYtezGEEhqUI/E2g==", + "license": "Apache-2.0", "dependencies": { - "@standard-schema/spec": "^1.1.0", - "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.10", - "@vitest/utils": "4.1.10", - "chai": "^6.2.2", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "tslib": "^2.8.0" } }, - "node_modules/@vitest/mocker": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", - "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "node_modules/@tailwindcss/node": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/node/-/node-4.3.3.tgz", + "integrity": "sha512-/T8IKEsf9VTU6tLjgC7+sv2mOPtQxzE2jMw7u4Tt40Tx+QSZxpzh95/H6cMKoja9XuW7iMdLJYBB0o9G1CaAgg==", + "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.10", - "estree-walker": "^3.0.3", - "magic-string": "^0.30.21" - }, - "funding": { - "url": "https://opencollective.com/vitest" - }, - "peerDependencies": { - "msw": "^2.4.9", - "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" - }, - "peerDependenciesMeta": { - "msw": { - "optional": true - }, - "vite": { - "optional": true - } - } - }, - "node_modules/@vitest/pretty-format": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", - "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", - "license": "MIT", - "dependencies": { - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/runner": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", - "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", - "license": "MIT", - "dependencies": { - "@vitest/utils": "4.1.10", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/snapshot": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", - "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "@vitest/utils": "4.1.10", + "@jridgewell/remapping": "^2.3.5", + "enhanced-resolve": "^5.24.1", + "jiti": "^2.7.0", + "lightningcss": "1.32.0", "magic-string": "^0.30.21", - "pathe": "^2.0.3" - }, - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/spy": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", - "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", - "license": "MIT", - "funding": { - "url": "https://opencollective.com/vitest" - } - }, - "node_modules/@vitest/utils": { - "version": "4.1.10", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", - "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", - "license": "MIT", - "dependencies": { - "@vitest/pretty-format": "4.1.10", - "convert-source-map": "^2.0.0", - "tinyrainbow": "^3.1.0" - }, - "funding": { - "url": "https://opencollective.com/vitest" + "source-map-js": "^1.2.1", + "tailwindcss": "4.3.3" } }, - "node_modules/@voidzero-dev/vite-plus-core": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-core/-/vite-plus-core-0.2.9.tgz", - "integrity": "sha512-dWqScAAwa8h/i9jCiGAMs7YarzQWInHZ5gCJNbQkHXA6Zp6A2T2anN9YMFVPpb7CwVFwkI2iPF5yl/DXtq+zUA==", + "node_modules/@tailwindcss/oxide": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide/-/oxide-4.3.3.tgz", + "integrity": "sha512-krXjAikiaFSPaK/FkAQT5UTx3VormQaiZ5hBFlJZ9UFQGB/rwg1MZIhHAG9smMQRTdyJxP6Qt5MwMtdyU5FWrA==", + "dev": true, "license": "MIT", - "dependencies": { - "@oxc-project/runtime": "=0.143.0", - "@oxc-project/types": "=0.143.0", - "lightningcss": "^1.33.0", - "postcss": "^8.5.6", - "yuku-codegen": "^0.5.44", - "yuku-parser": "^0.5.44" - }, - "engines": { - "node": "^20.19.0 || ^22.18.0 || >=24.11.0" - }, - "optionalDependencies": { - "@voidzero-dev/vite-plus-darwin-arm64": "0.2.9", - "@voidzero-dev/vite-plus-darwin-x64": "0.2.9", - "@voidzero-dev/vite-plus-linux-arm64-gnu": "0.2.9", - "@voidzero-dev/vite-plus-linux-arm64-musl": "0.2.9", - "@voidzero-dev/vite-plus-linux-x64-gnu": "0.2.9", - "@voidzero-dev/vite-plus-linux-x64-musl": "0.2.9", - "@voidzero-dev/vite-plus-win32-arm64-msvc": "0.2.9", - "@voidzero-dev/vite-plus-win32-x64-msvc": "0.2.9", - "fsevents": "~2.3.3" - }, - "peerDependencies": { - "@arethetypeswrong/core": "^0.18.1", - "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0", - "esbuild": "^0.27.0 || ^0.28.0", - "jiti": ">=1.21.0", - "less": "^4.0.0", - "publint": "^0.3.8", - "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", - "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0", - "unplugin-unused": "^0.5.0", - "unrun": "*", - "yaml": "^2.4.2" - }, - "peerDependenciesMeta": { - "@arethetypeswrong/core": { - "optional": true - }, - "@types/node": { - "optional": true - }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, - "jiti": { - "optional": true - }, - "less": { - "optional": true - }, - "publint": { - "optional": true - }, - "sass": { - "optional": true - }, - "sass-embedded": { - "optional": true - }, - "stylus": { - "optional": true - }, - "sugarss": { - "optional": true - }, - "terser": { - "optional": true - }, - "tsx": { - "optional": true - }, - "typescript": { - "optional": true - }, - "unplugin-unused": { - "optional": true - }, - "unrun": { - "optional": true - }, - "yaml": { - "optional": true - } - } - }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", - "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", - "license": "MPL-2.0", - "dependencies": { - "detect-libc": "^2.0.3" - }, "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.33.0", - "lightningcss-darwin-arm64": "1.33.0", - "lightningcss-darwin-x64": "1.33.0", - "lightningcss-freebsd-x64": "1.33.0", - "lightningcss-linux-arm-gnueabihf": "1.33.0", - "lightningcss-linux-arm64-gnu": "1.33.0", - "lightningcss-linux-arm64-musl": "1.33.0", - "lightningcss-linux-x64-gnu": "1.33.0", - "lightningcss-linux-x64-musl": "1.33.0", - "lightningcss-win32-arm64-msvc": "1.33.0", - "lightningcss-win32-x64-msvc": "1.33.0" + "@tailwindcss/oxide-android-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-arm64": "4.3.3", + "@tailwindcss/oxide-darwin-x64": "4.3.3", + "@tailwindcss/oxide-freebsd-x64": "4.3.3", + "@tailwindcss/oxide-linux-arm-gnueabihf": "4.3.3", + "@tailwindcss/oxide-linux-arm64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-arm64-musl": "4.3.3", + "@tailwindcss/oxide-linux-x64-gnu": "4.3.3", + "@tailwindcss/oxide-linux-x64-musl": "4.3.3", + "@tailwindcss/oxide-wasm32-wasi": "4.3.3", + "@tailwindcss/oxide-win32-arm64-msvc": "4.3.3", + "@tailwindcss/oxide-win32-x64-msvc": "4.3.3" } }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-android-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", - "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "node_modules/@tailwindcss/oxide-android-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-android-arm64/-/oxide-android-arm64-4.3.3.tgz", + "integrity": "sha512-Y85A2gmPSkl5Ve5qR86GL4HT509cFqQh1aes9p3sSkyTPwt0Pppf3GkwGe4JPACcRYjgJIEhQgM6dBClnr0NYw==", "cpu": [ "arm64" ], - "license": "MPL-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ "android" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-darwin-arm64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", - "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "node_modules/@tailwindcss/oxide-darwin-arm64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-arm64/-/oxide-darwin-arm64-4.3.3.tgz", + "integrity": "sha512-BiaWatpBcERQFDlOjRDpIVXuFK5PJez5SA4JMg6VYZdBYU+qKfV/vqjcIs+IYmtitf1xYQZTwXvU/8y4lfZUGw==", "cpu": [ "arm64" ], - "license": "MPL-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-darwin-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", - "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "node_modules/@tailwindcss/oxide-darwin-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-darwin-x64/-/oxide-darwin-x64-4.3.3.tgz", + "integrity": "sha512-fAeUqfV5ndhxRwai8cXGzdLvul9utWOmeTkv69unv4ZXixjn61Z+p9lCWdwOwA3TYboG3BwdVuN/RDjhBRl0mw==", "cpu": [ "x64" ], - "license": "MPL-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ "darwin" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-freebsd-x64": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", - "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "node_modules/@tailwindcss/oxide-freebsd-x64": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-freebsd-x64/-/oxide-freebsd-x64-4.3.3.tgz", + "integrity": "sha512-iyf5bV6+wnAlflVeEy7R25dupxTNECZN5QMI0qNT6eT+EgaGdZcKhGkr5SdoaWiLJ3spLqIY9VCeSGrwmtg4kw==", "cpu": [ "x64" ], - "license": "MPL-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ "freebsd" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", - "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "node_modules/@tailwindcss/oxide-linux-arm-gnueabihf": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm-gnueabihf/-/oxide-linux-arm-gnueabihf-4.3.3.tgz", + "integrity": "sha512-aAYUprJAJQWWbRrPvtjdroZ56Md+JM8pMiopS6xGEwDfLhqj+2ver2p4nU4Mb3CRqcMmNBjo8KkUgcxhkzVQGQ==", "cpu": [ "arm" ], - "license": "MPL-2.0", + "dev": true, + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", - "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "node_modules/@tailwindcss/oxide-linux-arm64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-gnu/-/oxide-linux-arm64-gnu-4.3.3.tgz", + "integrity": "sha512-nDxldcEENOxZRzC2uu9jrutZdAAQtb+8WWDCSnWL1zvBk1+FN+x6MtDViPB5AJMfttVCUhehGWus3XBPgatM/w==", "cpu": [ "arm64" ], + "dev": true, "libc": [ "glibc" ], - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-linux-arm64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", - "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "node_modules/@tailwindcss/oxide-linux-arm64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-arm64-musl/-/oxide-linux-arm64-musl-4.3.3.tgz", + "integrity": "sha512-Md44bD6veX/PC5iyF8cDVnw4HBIANZepRZZ7a8DQOvkfo5WUBwcp6iAuCUz23u+4SUkhJlD3eL7hNdW8ezd/kA==", "cpu": [ "arm64" ], + "dev": true, "libc": [ "musl" ], - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-linux-x64-gnu": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", - "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "node_modules/@tailwindcss/oxide-linux-x64-gnu": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-gnu/-/oxide-linux-x64-gnu-4.3.3.tgz", + "integrity": "sha512-tx7us1muwOKAKWao2v/GaafFeQboE6aj88vC6ziN2NCGcRm8gWUhwjzg+YdVB1e4boAtdtma4L43onunI6NS4w==", "cpu": [ "x64" ], + "dev": true, "libc": [ "glibc" ], - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-linux-x64-musl": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", - "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "node_modules/@tailwindcss/oxide-linux-x64-musl": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-linux-x64-musl/-/oxide-linux-x64-musl-4.3.3.tgz", + "integrity": "sha512-SJxX60smvHgasZoBy11dX6YRjXJFovwWBoedhbQPOBzgFWBHGB+TVPWB9BxzR7TTxU8FQZAI2AyiNCMzFm8Img==", "cpu": [ "x64" ], + "dev": true, "libc": [ "musl" ], - "license": "MPL-2.0", + "license": "MIT", "optional": true, "os": [ "linux" ], "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", - "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", - "cpu": [ - "arm64" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" + "node_modules/@tailwindcss/oxide-wasm32-wasi": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-wasm32-wasi/-/oxide-wasm32-wasi-4.3.3.tgz", + "integrity": "sha512-jx1+rPhY/5Ympkktd656HBWEBLxP7dH06losBLjjf5vgCODXvi9KhtftWcMIwTFIDqBr7cRnQkdLnAG+IOlGvQ==", + "bundleDependencies": [ + "@napi-rs/wasm-runtime", + "@emnapi/core", + "@emnapi/runtime", + "@tybys/wasm-util", + "@emnapi/wasi-threads", + "tslib" ], - "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-win32-x64-msvc": { - "version": "1.33.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", - "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", "cpu": [ - "x64" + "wasm32" ], - "license": "MPL-2.0", + "dev": true, + "license": "MIT", "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">= 12.0.0" + "dependencies": { + "@emnapi/core": "^1.11.1", + "@emnapi/runtime": "^1.11.1", + "@emnapi/wasi-threads": "^1.2.2", + "@napi-rs/wasm-runtime": "^1.1.4", + "@tybys/wasm-util": "^0.10.2", + "tslib": "^2.8.1" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "engines": { + "node": ">=14.0.0" } }, - "node_modules/@voidzero-dev/vite-plus-darwin-arm64": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-darwin-arm64/-/vite-plus-darwin-arm64-0.2.9.tgz", - "integrity": "sha512-/qJHqMfyy/LiCJk4UYZfFW6Comsfm8zDuy4P8UFWnFqRjmefYvZbMK4ThYNM87tKNWYWjsnClzssjJOmDTAc8w==", + "node_modules/@tailwindcss/oxide-win32-arm64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-arm64-msvc/-/oxide-win32-arm64-msvc-4.3.3.tgz", + "integrity": "sha512-3rc292Ca2ceK6Ulcc/bAVnTs/3nDtoPhyEKlgPv+yQJQi/JS/AMJlqzxvlDacL1nekbrcf6bTqp/jV4qgnPxNQ==", "cpu": [ "arm64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "win32" ], "engines": { - "node": ">=20.0.0" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-darwin-x64": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-darwin-x64/-/vite-plus-darwin-x64-0.2.9.tgz", - "integrity": "sha512-3MGnNeazgYAqQTaC7JIbZyrTHmxSXTWFr9G1yAdeItKasB1R8HKIkCS1Qnr49Ge4S/cyOODivdbcpqFkrT93ng==", + "node_modules/@tailwindcss/oxide-win32-x64-msvc": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/oxide-win32-x64-msvc/-/oxide-win32-x64-msvc-4.3.3.tgz", + "integrity": "sha512-yJ0pwIVc/nYeGoV02WtsN8KYyLQv7kyI2wDnkezyJlGGjkd4QLwDGAwl47YpPJeuI0M0ObaXGSPjvWDPeTPggw==", "cpu": [ "x64" ], + "dev": true, "license": "MIT", "optional": true, "os": [ - "darwin" + "win32" ], "engines": { - "node": ">=20.0.0" + "node": ">= 20" } }, - "node_modules/@voidzero-dev/vite-plus-linux-arm64-gnu": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-linux-arm64-gnu/-/vite-plus-linux-arm64-gnu-0.2.9.tgz", - "integrity": "sha512-6LmukER8qD4UBIRqMNv4Ilq7CxfRhngLUXlMv8vbTupeLRWPJSKvKEHyRxCwr6JP57Gxfr8KrX1ye42WzcZF0g==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], + "node_modules/@tailwindcss/postcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/@tailwindcss/postcss/-/postcss-4.3.3.tgz", + "integrity": "sha512-JTSZZGQi1AyKirbLN3azmjVzef92tcX7h+iSqPdaeStyFpGpDlKvvpxeOE8njhbUanbRwr3z8DyzhICWnMtQeg==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.0.0" + "dependencies": { + "@alloc/quick-lru": "^5.2.0", + "@tailwindcss/node": "4.3.3", + "@tailwindcss/oxide": "4.3.3", + "postcss": "^8.5.16", + "tailwindcss": "4.3.3" } }, - "node_modules/@voidzero-dev/vite-plus-linux-arm64-musl": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-linux-arm64-musl/-/vite-plus-linux-arm64-musl-0.2.9.tgz", - "integrity": "sha512-cBs626GWkyJlwKP0nsdHlMWpuTl9xOWRxAUoqtxXPtw80bVy4WM5eNS4SXPC5pX10jR7DRIkRpzNAsy7fv8Faw==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], + "node_modules/@testing-library/dom": { + "version": "10.4.1", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.1.tgz", + "integrity": "sha512-o4PXJQidqJl82ckFaXUeoAW+XysPLauYI43Abki5hABd853iMhitooc6znOnczgbTYmEP6U6/y1ZyKAIsvMKGg==", "license": "MIT", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">=20.0.0" - } - }, - "node_modules/@voidzero-dev/vite-plus-linux-x64-gnu": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-linux-x64-gnu/-/vite-plus-linux-x64-gnu-0.2.9.tgz", - "integrity": "sha512-2Iy8x4PCPMNzXeu3pREevlggoeK8PwtdUiCpoSybAZBtR/aqMxsJREyt/eKv45F8lsiNlA8PbIWEvPxLSgzFLQ==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, "engines": { - "node": ">=20.0.0" + "node": ">=18" } }, - "node_modules/@voidzero-dev/vite-plus-linux-x64-musl": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-linux-x64-musl/-/vite-plus-linux-x64-musl-0.2.9.tgz", - "integrity": "sha512-zuGx+eRotWPd9cmh1X9AfsC2tN/Ad9Hk6LAzlxoKJUjEkTsY3WjVJ6Da0z48SAUFuenI0JkdqXnMCrePtGvWHg==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" - ], + "node_modules/@testing-library/react": { + "version": "16.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.3.tgz", + "integrity": "sha512-Uo193NgQbPMz6lrrhtRQQFcMC6Re/ELLFbbuVL30WDlZxlpZf9/lMHTAVxPRLw1q1iu9OJmR1c2BLiENRstdBg==", + "dev": true, "license": "MIT", - "optional": true, - "os": [ - "linux" - ], + "dependencies": { + "@babel/runtime": "^7.12.5" + }, "engines": { - "node": ">=20.0.0" + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/@voidzero-dev/vite-plus-win32-arm64-msvc": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-win32-arm64-msvc/-/vite-plus-win32-arm64-msvc-0.2.9.tgz", - "integrity": "sha512-kaKb5Q8ReYTBfvLgUhdpLJG3aoNF8HOVJpf8qBm+THsd4WRrkRwsBHp2ITsU8oXl2gnDjFGhPDaURegd/z6Wxw==", - "cpu": [ - "arm64" - ], + "node_modules/@testing-library/user-event": { + "version": "14.6.4", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.4.tgz", + "integrity": "sha512-QCGwP6QrjypBLwyj5cuyfVamkaIEy/XGY+1VDehbtbQqOggYmTFpFOdWR5mPz14vX8vXLMVjDHlRNBcClyO9ew==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], "engines": { - "node": ">=20.0.0" + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" } }, - "node_modules/@voidzero-dev/vite-plus-win32-x64-msvc": { - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-win32-x64-msvc/-/vite-plus-win32-x64-msvc-0.2.9.tgz", - "integrity": "sha512-/fEk3gbQTJknCiYM/GTL/L++Azsav8rCAjmtKrjmCbqEif5IMzqTfvM68n+PiLB3JVoQJGF/mg2niODr0IE/2w==", - "cpu": [ - "x64" - ], + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", "license": "MIT", - "optional": true, - "os": [ - "win32" - ], - "engines": { - "node": ">=20.0.0" + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" } }, - "node_modules/@yuku-codegen/binding-darwin-arm64": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-darwin-arm64/-/binding-darwin-arm64-0.5.48.tgz", - "integrity": "sha512-yo96Oef12WzqnphInfz/eexVse3+kWgfGS5g2S3rFS3dcGn1ENW9xLFDZUP9rh+yP76DOq38wBoFi1+I9+6qBg==", - "cpu": [ - "arm64" - ], - "optional": true, - "os": [ - "darwin" - ] - }, - "node_modules/@yuku-codegen/binding-darwin-x64": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-darwin-x64/-/binding-darwin-x64-0.5.48.tgz", - "integrity": "sha512-aRCTw0EZC4bVosmw//0OMYP5tGWFE0Cu5yUBFkUbhXx/iBzvORcJ2xPNlOp/vtCCo9Ys4vp8b0DigJV6uOVb2g==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "darwin" - ] + "node_modules/@types/d3-array": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@types/d3-array/-/d3-array-3.0.3.tgz", + "integrity": "sha512-Reoy+pKnvsksN0lQUlcH6dOGjRZ/3WRwXR//m+/8lt1BXeI4xyaUZoqULNjyXXRuh0Mj4LNpkCvhUpQlY3X5xQ==", + "license": "MIT" }, - "node_modules/@yuku-codegen/binding-freebsd-x64": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-freebsd-x64/-/binding-freebsd-x64-0.5.48.tgz", - "integrity": "sha512-CA0AQAEApDkbw51PdLWMtKPJ41/7rvXsS3SJs+phG7fHJI+MuFzWuLbkucZfZoEOiDscmcsfYIdgL8BsfuyKKQ==", - "cpu": [ - "x64" - ], - "optional": true, - "os": [ - "freebsd" - ] + "node_modules/@types/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-HKuicPHJuvPgCD+np6Se9MQvS6OCbJmOjGvylzMJRlDwUXjKTTXs6Pwgk79O09Vj/ho3u1ofXnhFOaEWWPrlwA==", + "license": "MIT" }, - "node_modules/@yuku-codegen/binding-linux-arm-gnu": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm-gnu/-/binding-linux-arm-gnu-0.5.48.tgz", - "integrity": "sha512-DuSQlk8bH4gpmW3/00P0NLagAcMv8jOxjT40cQmxKRkktr+SUOALCfkT89tdDq3qtY95NR2GXOZ7AjNh7KKqCw==", - "cpu": [ - "arm" - ], - "libc": [ - "glibc" - ], - "optional": true, - "os": [ - "linux" - ] + "node_modules/@types/d3-delaunay": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-delaunay/-/d3-delaunay-6.0.1.tgz", + "integrity": "sha512-tLxQ2sfT0p6sxdG75c6f/ekqxjyYR0+LwPrsO1mbC9YDBzPJhs2HbJJRrn8Ez1DBoHRo2yx7YEATI+8V1nGMnQ==", + "license": "MIT" }, - "node_modules/@yuku-codegen/binding-linux-arm-musl": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm-musl/-/binding-linux-arm-musl-0.5.48.tgz", - "integrity": "sha512-bxj4Ee+wlaJcWJwft2ReJXWw5sfl1qavDz6+dlRdU1xfTEtjPSNiAWhiCHnJR0R4Ygd57DnzSQmAVGvFv6RcGw==", - "cpu": [ - "arm" - ], - "libc": [ - "musl" - ], - "optional": true, - "os": [ - "linux" - ] + "node_modules/@types/d3-format": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-format/-/d3-format-3.0.1.tgz", + "integrity": "sha512-5KY70ifCCzorkLuIkDe0Z9YTf9RR2CjBX1iaJG+rgM/cPP+sO+q9YdQ9WdhQcgPj1EQiJ2/0+yUkkziTG6Lubg==", + "license": "MIT" }, - "node_modules/@yuku-codegen/binding-linux-arm64-gnu": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.5.48.tgz", - "integrity": "sha512-mk5JVWh+0JOe5ue8k17kbYX8uGBoKt3ZqoCyxNh4nYAAcX7+X1tFUiU7jbjctu4vHeejCBFSTdQ021+V31cUCQ==", - "cpu": [ - "arm64" - ], - "libc": [ - "glibc" - ], - "optional": true, - "os": [ - "linux" - ] + "node_modules/@types/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-856sckF0oP/diXtS4jNsiQw/UuK5fQG8l/a9VVLeSouf1/PPbBE1i1W852zVwKwYCBkFJJB7nCFTbk6UMEXBOQ==", + "license": "MIT", + "dependencies": { + "@types/geojson": "*" + } }, - "node_modules/@yuku-codegen/binding-linux-arm64-musl": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.5.48.tgz", - "integrity": "sha512-4q3vkrNghbllyxOm2KesFLxCPKHF7r3JyQ7BWZccY1j2Y05yKoIFhoWCqIuQ2W/dpte9RI0+OVfwyxnrKg6fkA==", - "cpu": [ - "arm64" - ], - "libc": [ - "musl" - ], - "optional": true, - "os": [ - "linux" - ] + "node_modules/@types/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-jx5leotSeac3jr0RePOH1KdR9rISG91QIE4Q2PYTu4OymLTZfA3SrnURSLzKH48HmXVUru50b8nje4E79oQSQw==", + "license": "MIT", + "dependencies": { + "@types/d3-color": "*" + } }, - "node_modules/@yuku-codegen/binding-linux-x64-gnu": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.5.48.tgz", - "integrity": "sha512-csd4M1EVrGaohM8acM6gq1zpUA/Rwe2ulUMBKUcwQXm/k6n7cq1A++qdew78SOVb4do3JH1WE+WFwoGQAcWc1w==", - "cpu": [ - "x64" - ], - "libc": [ - "glibc" - ], - "optional": true, - "os": [ - "linux" - ] + "node_modules/@types/d3-path": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@types/d3-path/-/d3-path-3.1.1.tgz", + "integrity": "sha512-VMZBYyQvbGmWyWVea0EHs/BwLgxc+MKi1zLDCONksozI4YJMcTt8ZEuIR4Sb1MMTE8MMW49v0IwI5+b7RmfWlg==", + "license": "MIT" }, - "node_modules/@yuku-codegen/binding-linux-x64-musl": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-x64-musl/-/binding-linux-x64-musl-0.5.48.tgz", - "integrity": "sha512-KcDuEOT+GFoVKdvAWOv1v9iYjwnmvMZlO+j1Rw+5PYdeFLGWGzv/DD11y4SAAdwXIFcil4T0hibeIaF82WStMg==", - "cpu": [ - "x64" - ], - "libc": [ - "musl" + "node_modules/@types/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-Yk4htunhPAwN0XGlIwArRomOjdoBFXC3+kCxK2Ubg7I9shQlVSJy/pG/Ht5ASN+gdMIalpk8TJ5xV74jFsetLA==", + "license": "MIT", + "dependencies": { + "@types/d3-time": "*" + } + }, + "node_modules/@types/d3-shape": { + "version": "3.1.7", + "resolved": "https://registry.npmjs.org/@types/d3-shape/-/d3-shape-3.1.7.tgz", + "integrity": "sha512-VLvUQ33C+3J+8p+Daf+nYSOsjB4GXp19/S/aGo60m9h1v6XaxjiT82lKVWJCfzhtuZ3yD7i/TPeC/fuKLLOSmg==", + "license": "MIT", + "dependencies": { + "@types/d3-path": "*" + } + }, + "node_modules/@types/d3-time": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/d3-time/-/d3-time-3.0.0.tgz", + "integrity": "sha512-sZLCdHvBUcNby1cB6Fd3ZBrABbjz3v1Vm90nysCQ6Vt7vd6e/h9Lt7SiJUoEX0l4Dzc7P5llKyhqSi1ycSf1Hg==", + "license": "MIT" + }, + "node_modules/@types/d3-time-format": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@types/d3-time-format/-/d3-time-format-2.1.0.tgz", + "integrity": "sha512-/myT3I7EwlukNOX2xVdMzb8FRgNzRMpsZddwst9Ld/VFe6LyJyRp0s32l/V9XoUzk+Gqu56F/oGk6507+8BxrA==", + "license": "MIT" + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "license": "MIT" + }, + "node_modules/@types/geojson": { + "version": "7946.0.16", + "resolved": "https://registry.npmjs.org/@types/geojson/-/geojson-7946.0.16.tgz", + "integrity": "sha512-6C8nqWur3j98U6+lXDfTUWIfgvZU+EumvpHKcYjujKH7woYyLj2sUmff0tRhrqM7BohUw7Pz3ZB1jj2gW9Fvmg==", + "license": "MIT" + }, + "node_modules/@types/lodash": { + "version": "4.17.25", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.25.tgz", + "integrity": "sha512-+K1NIO8I+F9/wNulfVvu23QYd0Pe9/OCqRrim4NoYIf1VoEDL90Ve4ClzpyqBLc7NpGGWRvYNCKZ1BE/Jpf8dQ==", + "license": "MIT" + }, + "node_modules/@types/node": { + "version": "25.9.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.9.5.tgz", + "integrity": "sha512-OScDchr2fwuUmWdf4kZ9h7PcJiYDVInhJizG/biAq3cAvqwYktuy/TYGGdZNMtNTFUP7rnb0NU4TUdm82kt4Rg==", + "license": "MIT", + "dependencies": { + "undici-types": ">=7.24.0 <7.24.7" + } + }, + "node_modules/@types/pg": { + "version": "8.21.0", + "resolved": "https://registry.npmjs.org/@types/pg/-/pg-8.21.0.tgz", + "integrity": "sha512-AYdtudzabjLZgVgRZmAnU8bAnVUXzuJX2IYHeSIiIHm68olD+LgQYCGWdtcNYnP0uq9c4S4NibVG3Ni7VbKW7Q==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "pg-protocol": "*", + "pg-types": "^2.2.0" + } + }, + "node_modules/@types/react": { + "version": "19.2.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.18.tgz", + "integrity": "sha512-AnzbBERsrLKtk2XSfTbYRLjQPdy116Sty4q+T+Bp3IC4l6jNBvreVPAHmpq9qhXQM7CXZPjLVmGMw9sy+hxQ3w==", + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.2.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.2.4.tgz", + "integrity": "sha512-Bsc+QHgp+P/F02XDzNCY9jnZNCUuLki36KT7VKrTXXLdHf+vHMNZnW1rVu5DNW/rCK+fya3DATySbLM4yhtKUw==", + "devOptional": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.2.0" + } + }, + "node_modules/@types/whatwg-mimetype": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-mimetype/-/whatwg-mimetype-3.0.2.tgz", + "integrity": "sha512-c2AKvDT8ToxLIOUlN51gTiHXflsfIFisS4pO7pDPoKouJCESkhZnEy623gwP9laCy5lnLDAw1vAzu2vM2YLOrA==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript/typescript-aix-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-aix-ppc64/-/typescript-aix-ppc64-7.0.2.tgz", + "integrity": "sha512-MTKKkWB7p/0E9xi1d1tHtZ5PiLkGEMIq88pK2CubZjOsLtYTLqhgIgi6zepFa+9GHZ6h05NMCkQxGKiPXMxXtQ==", + "cpu": [ + "ppc64" ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ - "linux" - ] + "aix" + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-codegen/binding-win32-arm64": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-win32-arm64/-/binding-win32-arm64-0.5.48.tgz", - "integrity": "sha512-HI8qNrI8dWM5BuqIMKsqornRvTNFrE6sm5zToIJ9YIa9zt5+29P7fJ7Nr39EVf6dAWSb6q7JSpScJnRsQ+FgZA==", + "node_modules/@typescript/typescript-darwin-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-arm64/-/typescript-darwin-arm64-7.0.2.tgz", + "integrity": "sha512-gowzar9MwS/aRWp6f3a4KUqzRjAZjOsmGNCM6LcTgXum+dBfgsBVMN+AgvOCCbguXyick6LJhpBszxMebJ8syA==", "cpu": [ "arm64" ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ - "win32" - ] + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-codegen/binding-win32-x64": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-win32-x64/-/binding-win32-x64-0.5.48.tgz", - "integrity": "sha512-X5YWJLO6EfBZpeBqO0AYESnUizbpFDWArcvVD61w0PEWQ3CaFRLnbQXs+kpM4ZZfGMfIE22zfA08QSY67q7TNQ==", + "node_modules/@typescript/typescript-darwin-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-darwin-x64/-/typescript-darwin-x64-7.0.2.tgz", + "integrity": "sha512-SZ9xZInqApNlNGc9s0W1VSsktYSOe9cFqNOIqmN1Gs8SmkjKZYFt017G4VwPxASInODuAdbTW7sXiFUf893RgA==", "cpu": [ "x64" ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ - "win32" - ] + "darwin" + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-parser/binding-darwin-arm64": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.5.48.tgz", - "integrity": "sha512-If8mb7HH3vqghJ2NNZ8SuHfhsnjVzOxJpB8xcNOXS5WjYrs2mUhHIh5KOIvK13hDOzh0htGeGK3A6MsiEqE7HQ==", + "node_modules/@typescript/typescript-freebsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-arm64/-/typescript-freebsd-arm64-7.0.2.tgz", + "integrity": "sha512-W5NH4y/J0plIIS5b2xvTEkU7JFxyqdMAOgf+Ilhl0vHQXKO5dZoxd+C/jEtq56c4F3wk71RB4BMRQ2XdI+bwYQ==", "cpu": [ "arm64" ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ - "darwin" - ] - }, - "node_modules/@yuku-parser/binding-darwin-x64": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-darwin-x64/-/binding-darwin-x64-0.5.48.tgz", - "integrity": "sha512-EimvPXfspzxf1K11eB6tCW5oiQEXB8g84T2wP1TwzQagdDKo33bkmmVF0B32vTIpXnk/Ifu5IB61izZ1MylljA==", - "cpu": [ - "x64" + "freebsd" ], - "optional": true, - "os": [ - "darwin" - ] + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-parser/binding-freebsd-x64": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.5.48.tgz", - "integrity": "sha512-0GcUMrumLHheThY9r5Tp46gaZYzn0irWPS1Zba6WY+vVQfhUtzGiWgXxI6tuXX0N32kEaaEVRpkKctvo6Kx3aQ==", + "node_modules/@typescript/typescript-freebsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-freebsd-x64/-/typescript-freebsd-x64-7.0.2.tgz", + "integrity": "sha512-UMGDx5sTpzNw3WiPebH7l90IWfJggEd+egHt/q6p7/Cm3zqoV7VxkGXt+3DxPIw8CcmvAB0j3sVVfbhX+M4Tpw==", "cpu": [ "x64" ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "freebsd" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-parser/binding-linux-arm-gnu": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm-gnu/-/binding-linux-arm-gnu-0.5.48.tgz", - "integrity": "sha512-8S5T5wjCC73dmmpQeZ49aYsSunIUM3D4Fc6rdK96c+Ayg/p3FmeSPF3xuLZHejcTmqJIIvnbfPlUF+rB6DITjQ==", + "node_modules/@typescript/typescript-linux-arm": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm/-/typescript-linux-arm-7.0.2.tgz", + "integrity": "sha512-gffT3xPz9sR7j/YJExkyPntrI0P2EP9XbOyWzth2/Gs0RstK+90RBcO0ncXoXy/beYll1SXw846Nf2zdnEz0QQ==", "cpu": [ "arm" ], - "libc": [ - "glibc" - ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-parser/binding-linux-arm-musl": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm-musl/-/binding-linux-arm-musl-0.5.48.tgz", - "integrity": "sha512-tTmbxvnUHcK2/crS9547vk2SMmsajH1yqJ8ltXhIuHJgqR1v+d9n9KT+kSayo/5CS76LegeYxhMFjEivBH2hFA==", + "node_modules/@typescript/typescript-linux-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-arm64/-/typescript-linux-arm64-7.0.2.tgz", + "integrity": "sha512-Qh4eU4/y3yDjnfjjyPYihMj5/ODIlmt+Bzu17OI+fiSRDW57QmU5SiN63exPRNJPKUzcc1INa1NXdrJ+MqHjUQ==", "cpu": [ - "arm" - ], - "libc": [ - "musl" + "arm64" ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-parser/binding-linux-arm64-gnu": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.5.48.tgz", - "integrity": "sha512-KGYCBMqI2zfwyhgq5tpPVNe7jpUeYTBm8DhjdS+zqWNumde/PEC170QE5RHxcOAlsirIDeIUk0jqx+r/axoFSw==", + "node_modules/@typescript/typescript-linux-loong64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-loong64/-/typescript-linux-loong64-7.0.2.tgz", + "integrity": "sha512-uEHck9i8hoAzXPiYRib1O7miOnz23SxIeVl6F4LXox+qov1K35jHcEW6VHKvZI+pyvl7fZEP4MCU5LYvIq1GuQ==", "cpu": [ - "arm64" - ], - "libc": [ - "glibc" + "loong64" ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-parser/binding-linux-arm64-musl": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.5.48.tgz", - "integrity": "sha512-2wTSMsCSXLTc2lZUjMAuU5X4cje55u205WJqfV5NWNF6j9pW/tXyxr15dJeekj8ziLqBXzIsj4DbRh4sY/WcjA==", + "node_modules/@typescript/typescript-linux-mips64el": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-mips64el/-/typescript-linux-mips64el-7.0.2.tgz", + "integrity": "sha512-R4KvAMnE43W5Qeqb0Ly56O3mWMWIAgsMyz36DCaycd5nbg/9kzm0liw3JocfRqyJY0KPmzFjbswozXyW0DnIYA==", "cpu": [ - "arm64" + "mips64el" ], - "libc": [ - "musl" + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-ppc64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-ppc64/-/typescript-linux-ppc64-7.0.2.tgz", + "integrity": "sha512-DORx5b3sd/4S7eayxm4FQv+A7CrkUIGRaHiwI8oiHTAI1fAPWhF4J0vAlkC8biAlHSVVwxMQ3tjZ2/DVbnQiiA==", + "cpu": [ + "ppc64" ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-parser/binding-linux-x64-gnu": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.5.48.tgz", - "integrity": "sha512-d/6v9UnGglVu1WC2JQyv/5aWSi5fXZeGSlidCfmHp4+N65N1GDKUnFtys5MK5eAPeAjTgSHGGtOc/yCcKTlv3A==", + "node_modules/@typescript/typescript-linux-riscv64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-riscv64/-/typescript-linux-riscv64-7.0.2.tgz", + "integrity": "sha512-wf0jqEDOjrPRnKwYRyyJDRo11KMbvMFrU+q4zqKyChODBzvlkbhNQfKvLxQCcwTpdDaXSHZTVuh0JoCrKCUMHQ==", "cpu": [ - "x64" + "riscv64" ], - "libc": [ - "glibc" + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-linux-s390x": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-s390x/-/typescript-linux-s390x-7.0.2.tgz", + "integrity": "sha512-IkwJc3L7yhytWd/ewjyxNDfOmswCm9GWMJT/ue/dU4aZNbwZeYAetq42VyLmsmSjvoX7z74X6ZaYCtzAr0EuGw==", + "cpu": [ + "s390x" ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-parser/binding-linux-x64-musl": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.5.48.tgz", - "integrity": "sha512-gX19gw6u4ApPy7SYMPKfFlEkrtj6WlORvrTKK3sBQqjyV+8+mUAkQgxXNjHw4RnOiAmVYg7TOlZcg8d+Qqod9A==", + "node_modules/@typescript/typescript-linux-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-linux-x64/-/typescript-linux-x64-7.0.2.tgz", + "integrity": "sha512-EYdf2cNg7rgCWJnxCdJ+F3V39O8ihb37eHAu1LK8oAFizgTQbPOK7zHHXbPt8rX24COqODXeI3sIf0fCXG7H/A==", "cpu": [ "x64" ], - "libc": [ - "musl" - ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "linux" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-parser/binding-win32-arm64": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-win32-arm64/-/binding-win32-arm64-0.5.48.tgz", - "integrity": "sha512-w6cQQLbqj3Jcom5Q7ifm103NUOQ9d+Cb4VU5lkrZDjMnwVJ9Hzzg1vCQR7miJuF44vhCXldbme5UryE3giEKlA==", + "node_modules/@typescript/typescript-netbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-arm64/-/typescript-netbsd-arm64-7.0.2.tgz", + "integrity": "sha512-+polYF4MF04aPpO5FTkHran9yUQDSXqy5GiSDKpsll5jy3l3+g9QLhpf39T+ePtefhXLOGrLl0QIjkQP6VnelA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-netbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-netbsd-x64/-/typescript-netbsd-x64-7.0.2.tgz", + "integrity": "sha512-8YIT0EHM/3dq10ZOVF/A7pc/YSMtbcecct4rWtexrnSCHOPcpC2KTLXfTCR6vDpnSiY12heNb1GiN/wu+T/FyA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-arm64/-/typescript-openbsd-arm64-7.0.2.tgz", + "integrity": "sha512-APT8+ClYnuYm1u9+kgGXoMj2VzWzcymwh2gNSQVySHfkRDGOTVkoWLjCmOQSaO+PoqQ57B0flRp9SA+7GnnkzQ==", "cpu": [ "arm64" ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-openbsd-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-openbsd-x64/-/typescript-openbsd-x64-7.0.2.tgz", + "integrity": "sha512-yX7s+Q0Dln0Dt9tEzZsAjXXR/+ytBM7AlglaqyeMPxQszJ1JhlJdZ6jLA+IzldHtflX81em7lDao1xXu+aRRkg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-sunos-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-sunos-x64/-/typescript-sunos-x64-7.0.2.tgz", + "integrity": "sha512-dLJDGaLZ1D4HPQn62u1n8mBDkJREwMsAkCdkwd4Ieqw+x3TUyTsqY0YiBCtE6H6OzzgGk3iuZ3vFWRS+E8/d1g==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=16.20.0" + } + }, + "node_modules/@typescript/typescript-win32-arm64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-arm64/-/typescript-win32-arm64-7.0.2.tgz", + "integrity": "sha512-Gyl1Vy6OsWesLzmq+EP0Fb7b4Nid5232AvcA2SFcdYreldpNtYFFofPjnt62y9hQy7VTaZp65ICJjuAQRaVcIQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-parser/binding-win32-x64": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/@yuku-parser/binding-win32-x64/-/binding-win32-x64-0.5.48.tgz", - "integrity": "sha512-4gO0HmG7fzFxrw1rs0dUdnnaY9YgennjETqDWrTSp7x9fmTUOAoN4VsMfP7YyliQeG1WJJHc55O+rOhmsLppow==", + "node_modules/@typescript/typescript-win32-x64": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/@typescript/typescript-win32-x64/-/typescript-win32-x64-7.0.2.tgz", + "integrity": "sha512-0BQ3HkAHHlKLSp1qRvf3SUhGpGsDuhB/jgFw75guyqbxJqEaS0Cw/VFO8i2nHglJUzQCRtMMR/IBAKE3ETMC4g==", "cpu": [ "x64" ], + "dev": true, + "license": "Apache-2.0", "optional": true, "os": [ "win32" - ] + ], + "engines": { + "node": ">=16.20.0" + } }, - "node_modules/@yuku-toolchain/types": { - "version": "0.5.43", - "resolved": "https://registry.npmjs.org/@yuku-toolchain/types/-/types-0.5.43.tgz", - "integrity": "sha512-kSpvPntnXw5+lYjO71ffBEnQ5ycQ74KGIYknh0TS4xeyCuBkOqxyJumxZkMhLBBUCLjDAbx2+Icnr3Zh4ftjpQ==", - "license": "MIT" + "node_modules/@typespec/asset-emitter": { + "version": "0.79.1", + "resolved": "https://registry.npmjs.org/@typespec/asset-emitter/-/asset-emitter-0.79.1.tgz", + "integrity": "sha512-53s3GLu5BwNkl7Itr/OizfhymTV2u7k5/cwjUOAt03AUDfiKlwbsp+iCIsq1vccJuoDOiXOceJOfL8rAf4/9LQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.10.0" + } }, - "node_modules/agent-base": { - "version": "7.1.4", - "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", - "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "node_modules/@typespec/compiler": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@typespec/compiler/-/compiler-1.15.0.tgz", + "integrity": "sha512-NbCIRAIzyozchlSaGPVuyV43bC+y+OpXYCuT+8M8kt35Ln9zWzLFcIt7irofQ5QUXBZrHsBFpI5fTOFdCGeWCA==", "dev": true, "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.0", + "@inquirer/prompts": "^8.4.1", + "ajv": "^8.18.0", + "change-case": "^5.4.4", + "env-paths": "^4.0.0", + "is-unicode-supported": "^2.1.0", + "mustache": "^4.2.0", + "picocolors": "^1.1.1", + "prettier": "^3.9.5", + "semver": "^7.7.4", + "tar": "^7.5.21", + "temporal-polyfill": "^1.0.1", + "vscode-languageserver": "^10.0.0", + "vscode-languageserver-textdocument": "^1.0.12", + "yaml": "^2.8.3", + "yargs": "^18.0.0" + }, + "bin": { + "tsp": "cmd/tsp.js", + "tsp-server": "cmd/tsp-server.js" + }, "engines": { - "node": ">= 14" + "node": ">=22.0.0" } }, - "node_modules/ajv": { - "version": "8.18.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", - "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "node_modules/@typespec/http": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@typespec/http/-/http-1.15.0.tgz", + "integrity": "sha512-LNyzYHyX3C0xyQQ262jhvIaVzTn7DqiDB2gz45w1m6ngJH9ArGU8XjO3o7PaZkl/nuB5MTpImnsXpHIV1rbi4Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.15.0", + "@typespec/streams": "^0.85.0" + }, + "peerDependenciesMeta": { + "@typespec/streams": { + "optional": true + } + } + }, + "node_modules/@typespec/openapi": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi/-/openapi-1.15.0.tgz", + "integrity": "sha512-lHd3H5W23KOIGKyBPKpBLPHVOxcxuvqOBXGqlyPvGmHDgmD74mrUtHWxNoGx+QQESjx4tS8Tu6URNQBU6y6Q1Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.15.0", + "@typespec/http": "^1.15.0" + } + }, + "node_modules/@typespec/openapi3": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@typespec/openapi3/-/openapi3-1.15.0.tgz", + "integrity": "sha512-Gc6OjBiAtPo3ohlkrDxQKt8+xdeR54tC+Cgu3YLlxUxrWHWYOfWQXzp4NX+sraiFjF6kX7t0G1A1kY7rgy73qw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@scalar/json-magic": "^0.12.15", + "@scalar/openapi-parser": "^0.28.6", + "@scalar/openapi-types": "^0.9.1", + "@typespec/asset-emitter": "^0.79.1", + "yaml": "^2.8.3" + }, + "bin": { + "tsp-openapi3": "cmd/tsp-openapi3.js" + }, + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.15.0", + "@typespec/events": "^0.85.0", + "@typespec/http": "^1.15.0", + "@typespec/json-schema": "^1.15.0", + "@typespec/openapi": "^1.15.0", + "@typespec/sse": "^0.85.0", + "@typespec/streams": "^0.85.0", + "@typespec/versioning": "^0.85.0" + }, + "peerDependenciesMeta": { + "@typespec/events": { + "optional": true + }, + "@typespec/json-schema": { + "optional": true + }, + "@typespec/sse": { + "optional": true + }, + "@typespec/streams": { + "optional": true + }, + "@typespec/versioning": { + "optional": true + }, + "@typespec/xml": { + "optional": true + } + } + }, + "node_modules/@typespec/rest": { + "version": "0.85.0", + "resolved": "https://registry.npmjs.org/@typespec/rest/-/rest-0.85.0.tgz", + "integrity": "sha512-ogbot1wp8jLn0rSOzwHjMjgDot+1u7WFZOWluRHL3cuRw9l8+ZjlixBrkXZ84dKP54RoYUN3buBjfOZ7qyHeyg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=22.0.0" + }, + "peerDependencies": { + "@typespec/compiler": "^1.15.0", + "@typespec/http": "^1.15.0" + } + }, + "node_modules/@visx/curve": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/curve/-/curve-4.0.1-alpha.0.tgz", + "integrity": "sha512-jRu61Uz274pV1zyioXmboyrLutYbnKsgjj4njSGCnhdXj5GkZvZbg+ThDb6oOzoAnJOBRLz4rzPlWvNJOzuVMg==", + "license": "MIT", + "dependencies": { + "@visx/vendor": "4.0.0-alpha.0" + } + }, + "node_modules/@visx/event": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/event/-/event-4.0.1-alpha.0.tgz", + "integrity": "sha512-EQqCMSv/s8NbFjo+hz3FKsvvYfP+2QslsFJ/24/O5l/W+7UC6J6aAvO0ujVwrTwdYbuQ+vhxKi1xdPdKR/qj1g==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/point": "4.0.1-alpha.0" + } + }, + "node_modules/@visx/grid": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/grid/-/grid-4.0.1-alpha.0.tgz", + "integrity": "sha512-rycutGmTHO+znNdPumheWMglm7YfpffvRwUkVy5zy4WoORIuKTMkDxwnOzHG2xMxU3EE/YCd37xFV5AxA30yeg==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "@visx/curve": "4.0.1-alpha.0", + "@visx/group": "4.0.1-alpha.0", + "@visx/point": "4.0.1-alpha.0", + "@visx/scale": "4.0.1-alpha.0", + "@visx/shape": "4.0.1-alpha.0", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/group": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/group/-/group-4.0.1-alpha.0.tgz", + "integrity": "sha512-V19l7iQ7jccBv8kao/EByuI6o4xtxzzLV9nqVI1hRvmdzTVsuLpqlwzYCZUXJaTVvUWf8s4D2SQFjGkj/Nw+0w==", + "license": "MIT", + "dependencies": { + "@types/react": "*", + "classnames": "^2.3.1" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/point": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/point/-/point-4.0.1-alpha.0.tgz", + "integrity": "sha512-ijTfr/Nx09f03vIj9nyTr3z4Xth4Y75427UaogJh6dnIRLMEFHQOwNu791sbfiNj0a+ZXuaE32h0vKrFe4/8Qg==", + "license": "MIT" + }, + "node_modules/@visx/responsive": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/responsive/-/responsive-4.0.1-alpha.0.tgz", + "integrity": "sha512-o+1zGywQZY0+yOx3Iw87wc4bbPJRr/HnIukTwfOz4UVyj9pB1OQNVHB7OORO1+LBHJceWpB31co/ZV9KHncKrA==", + "license": "MIT", + "dependencies": { + "@types/lodash": "^4.17.13", + "@types/react": "*", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/scale": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/scale/-/scale-4.0.1-alpha.0.tgz", + "integrity": "sha512-nzjeE87vFSAXGWFiiNfBpNLAf0Q8Qmf6syvKLjqNi4kGZkdhbUll3E/59YsgWXmjM8+llPLWzGsP+JPvo5eq1A==", + "license": "MIT", + "dependencies": { + "@visx/vendor": "4.0.0-alpha.0" + } + }, + "node_modules/@visx/shape": { + "version": "4.0.1-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/shape/-/shape-4.0.1-alpha.0.tgz", + "integrity": "sha512-62QeiVNmPlterQGwhkEDcbq7M0MqY0lBsK5QKXtM9ZoPZWkuGV3aykA3+Xu20B2FAvyJq4LqJzBc7Sxr+EAdbA==", + "license": "MIT", + "dependencies": { + "@types/lodash": "^4.17.13", + "@types/react": "*", + "@visx/curve": "4.0.1-alpha.0", + "@visx/group": "4.0.1-alpha.0", + "@visx/scale": "4.0.1-alpha.0", + "@visx/vendor": "4.0.0-alpha.0", + "classnames": "^2.3.1", + "lodash": "^4.17.21" + }, + "peerDependencies": { + "react": "^16.14.0 || ^17.0.0-0 || ^18.0.0-0 || ^19.0.0-0" + } + }, + "node_modules/@visx/vendor": { + "version": "4.0.0-alpha.0", + "resolved": "https://registry.npmjs.org/@visx/vendor/-/vendor-4.0.0-alpha.0.tgz", + "integrity": "sha512-6I+MuqXBcv9jnlcVowHoHKSdk9gXTWkHLKyqBwRWg7LY6A3Ei8SHfubpqGV5rBUSppxMq2RszPJUS6w+H0YgmQ==", + "license": "MIT and ISC", + "dependencies": { + "@types/d3-array": "3.0.3", + "@types/d3-color": "3.1.0", + "@types/d3-delaunay": "6.0.1", + "@types/d3-format": "3.0.1", + "@types/d3-geo": "3.1.0", + "@types/d3-interpolate": "3.0.1", + "@types/d3-path": "3.1.1", + "@types/d3-scale": "4.0.2", + "@types/d3-shape": "3.1.7", + "@types/d3-time": "3.0.0", + "@types/d3-time-format": "2.1.0", + "d3-array": "3.2.1", + "d3-color": "3.1.0", + "d3-delaunay": "6.0.2", + "d3-format": "3.1.0", + "d3-geo": "3.1.0", + "d3-interpolate": "3.0.1", + "d3-path": "3.1.0", + "d3-scale": "4.0.2", + "d3-shape": "3.2.0", + "d3-time": "3.1.0", + "d3-time-format": "4.1.0", + "internmap": "2.0.3" + } + }, + "node_modules/@visx/vendor/node_modules/d3-array": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.1.tgz", + "integrity": "sha512-gUY/qeHq/yNqqoCKNq4vtpFLdoCdvyNpWoC/KNjhGbhDuQpAM9sIQQKkXSNpXa9h5KySs/gzm7R88WkUutgwWQ==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@vitejs/plugin-react": { + "version": "6.0.5", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-react/-/plugin-react-6.0.5.tgz", + "integrity": "sha512-BOVzne/NL162sMdResB25mUv+vWMF5NoAjNf09TeGlE7ZpszZWSD3winycicLJw72yeVsoCn/2kOhEuCvEShMA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rolldown/plugin-babel": "^0.1.7 || ^0.2.0", + "babel-plugin-react-compiler": "^1.0.0", + "vite": "^8.0.0" + }, + "peerDependenciesMeta": { + "@rolldown/plugin-babel": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + } + } + }, + "node_modules/@vitest/browser": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/browser/-/browser-4.1.10.tgz", + "integrity": "sha512-UDwuWGwXj646CBx/bQHOaJSX7np0I8JL/UKQYa1e4QrVHH8VdWtx8eaOuf8sy0ShwDgR6NjJAsp5eF6vjF6qng==", + "license": "MIT", + "dependencies": { + "@blazediff/core": "1.9.1", + "@vitest/mocker": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pngjs": "^7.0.0", + "sirv": "^3.0.2", + "tinyrainbow": "^3.1.0", + "ws": "^8.19.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.1.10" + } + }, + "node_modules/@vitest/browser-preview": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/browser-preview/-/browser-preview-4.1.10.tgz", + "integrity": "sha512-14MJrL59ZFkqXLjwfSk6RzTDy5Czf9UG4+8q8L6Gxjs2aPjEce/cVNYV14bXAc2BvMjUNu904+ZEZA1Xc1wtvQ==", + "license": "MIT", + "dependencies": { + "@testing-library/dom": "^10.4.1", + "@testing-library/user-event": "^14.6.1", + "@vitest/browser": "4.1.10" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "vitest": "4.1.10" + } + }, + "node_modules/@vitest/expect": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.10.tgz", + "integrity": "sha512-YsCn+qAk1GWjQOWFEsEcL2gNQ0zmVmQu3T03qP6UyjhtmdtwtbuI+DASn/7iQB3HGTXkdBwGddzxPlmiql5vlA==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.1.0", + "@types/chai": "^5.2.2", + "@vitest/spy": "4.1.10", + "@vitest/utils": "4.1.10", + "chai": "^6.2.2", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/mocker": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.10.tgz", + "integrity": "sha512-v0xaezt+DKEmKfaxg133ldzADrwLGd7Ze1MfQQTYfvs8OqZIwbxyxaYURivwV7sWy5fqn3rH5uOrSp07bp44Ow==", + "license": "MIT", + "dependencies": { + "@vitest/spy": "4.1.10", + "estree-walker": "^3.0.3", + "magic-string": "^0.30.21" + }, + "funding": { + "url": "https://opencollective.com/vitest" + }, + "peerDependencies": { + "msw": "^2.4.9", + "vite": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "msw": { + "optional": true + }, + "vite": { + "optional": true + } + } + }, + "node_modules/@vitest/pretty-format": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.10.tgz", + "integrity": "sha512-W1HsjSH4MXQ9YfmmhLAoIYf1HRfekQCGngeIgcei6MP5QQGWUe0gkopdZQaVCFO+JDJMrAJGwa5pRpNpvy4P8Q==", + "license": "MIT", + "dependencies": { + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/runner": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.10.tgz", + "integrity": "sha512-IKI6kpIH+LmpROplyLwBBaCfMgOZOMsygVa6BARD6ahA04VRuJSa6OaVG7kRvSEMD870Vd91rSSw0eegtWyLGg==", + "license": "MIT", + "dependencies": { + "@vitest/utils": "4.1.10", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/snapshot": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.10.tgz", + "integrity": "sha512-xRkfOT1qpTAi/Ti4Y1LtfRc3kEuqxGw59eN2jN9pRWMtS/XDevekhcFSqvQqjUNGksfjMJu3Y+oJ+4Ypn2OaJw==", + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "@vitest/utils": "4.1.10", + "magic-string": "^0.30.21", + "pathe": "^2.0.3" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/spy": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.10.tgz", + "integrity": "sha512-PLf/Ugvoq5wO/b4rwYCR1h2PSIdXz7wnkQFMiUpLdtM7l6pqVFcQIBEHyT1+l+cj7mNwAfZHzqXqDyjvOuwbDw==", + "license": "MIT", + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@vitest/utils": { + "version": "4.1.10", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.10.tgz", + "integrity": "sha512-fy9am/HWxbaGt/Sawrp90vt6Y6jQwf1RX77cz3uwoJwJVMli/e1IEwRPnMNJ7vKfPTwo0diXifkpPvwH9v7nGA==", + "license": "MIT", + "dependencies": { + "@vitest/pretty-format": "4.1.10", + "convert-source-map": "^2.0.0", + "tinyrainbow": "^3.1.0" + }, + "funding": { + "url": "https://opencollective.com/vitest" + } + }, + "node_modules/@voidzero-dev/vite-plus-core": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-core/-/vite-plus-core-0.2.9.tgz", + "integrity": "sha512-dWqScAAwa8h/i9jCiGAMs7YarzQWInHZ5gCJNbQkHXA6Zp6A2T2anN9YMFVPpb7CwVFwkI2iPF5yl/DXtq+zUA==", + "license": "MIT", + "dependencies": { + "@oxc-project/runtime": "=0.143.0", + "@oxc-project/types": "=0.143.0", + "lightningcss": "^1.33.0", + "postcss": "^8.5.6", + "yuku-codegen": "^0.5.44", + "yuku-parser": "^0.5.44" + }, + "engines": { + "node": "^20.19.0 || ^22.18.0 || >=24.11.0" + }, + "optionalDependencies": { + "@voidzero-dev/vite-plus-darwin-arm64": "0.2.9", + "@voidzero-dev/vite-plus-darwin-x64": "0.2.9", + "@voidzero-dev/vite-plus-linux-arm64-gnu": "0.2.9", + "@voidzero-dev/vite-plus-linux-arm64-musl": "0.2.9", + "@voidzero-dev/vite-plus-linux-x64-gnu": "0.2.9", + "@voidzero-dev/vite-plus-linux-x64-musl": "0.2.9", + "@voidzero-dev/vite-plus-win32-arm64-msvc": "0.2.9", + "@voidzero-dev/vite-plus-win32-x64-msvc": "0.2.9", + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@arethetypeswrong/core": "^0.18.1", + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "publint": "^0.3.8", + "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", + "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0", + "unplugin-unused": "^0.5.0", + "unrun": "*", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@arethetypeswrong/core": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "publint": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "typescript": { + "optional": true + }, + "unplugin-unused": { + "optional": true + }, + "unrun": { + "optional": true + }, + "yaml": { + "optional": true + } + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "license": "MPL-2.0", + "dependencies": { + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-core/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "node_modules/@voidzero-dev/vite-plus-darwin-arm64": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-darwin-arm64/-/vite-plus-darwin-arm64-0.2.9.tgz", + "integrity": "sha512-/qJHqMfyy/LiCJk4UYZfFW6Comsfm8zDuy4P8UFWnFqRjmefYvZbMK4ThYNM87tKNWYWjsnClzssjJOmDTAc8w==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@voidzero-dev/vite-plus-darwin-x64": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-darwin-x64/-/vite-plus-darwin-x64-0.2.9.tgz", + "integrity": "sha512-3MGnNeazgYAqQTaC7JIbZyrTHmxSXTWFr9G1yAdeItKasB1R8HKIkCS1Qnr49Ge4S/cyOODivdbcpqFkrT93ng==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@voidzero-dev/vite-plus-linux-arm64-gnu": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-linux-arm64-gnu/-/vite-plus-linux-arm64-gnu-0.2.9.tgz", + "integrity": "sha512-6LmukER8qD4UBIRqMNv4Ilq7CxfRhngLUXlMv8vbTupeLRWPJSKvKEHyRxCwr6JP57Gxfr8KrX1ye42WzcZF0g==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@voidzero-dev/vite-plus-linux-arm64-musl": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-linux-arm64-musl/-/vite-plus-linux-arm64-musl-0.2.9.tgz", + "integrity": "sha512-cBs626GWkyJlwKP0nsdHlMWpuTl9xOWRxAUoqtxXPtw80bVy4WM5eNS4SXPC5pX10jR7DRIkRpzNAsy7fv8Faw==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@voidzero-dev/vite-plus-linux-x64-gnu": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-linux-x64-gnu/-/vite-plus-linux-x64-gnu-0.2.9.tgz", + "integrity": "sha512-2Iy8x4PCPMNzXeu3pREevlggoeK8PwtdUiCpoSybAZBtR/aqMxsJREyt/eKv45F8lsiNlA8PbIWEvPxLSgzFLQ==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@voidzero-dev/vite-plus-linux-x64-musl": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-linux-x64-musl/-/vite-plus-linux-x64-musl-0.2.9.tgz", + "integrity": "sha512-zuGx+eRotWPd9cmh1X9AfsC2tN/Ad9Hk6LAzlxoKJUjEkTsY3WjVJ6Da0z48SAUFuenI0JkdqXnMCrePtGvWHg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@voidzero-dev/vite-plus-win32-arm64-msvc": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-win32-arm64-msvc/-/vite-plus-win32-arm64-msvc-0.2.9.tgz", + "integrity": "sha512-kaKb5Q8ReYTBfvLgUhdpLJG3aoNF8HOVJpf8qBm+THsd4WRrkRwsBHp2ITsU8oXl2gnDjFGhPDaURegd/z6Wxw==", + "cpu": [ + "arm64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@voidzero-dev/vite-plus-win32-x64-msvc": { + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-win32-x64-msvc/-/vite-plus-win32-x64-msvc-0.2.9.tgz", + "integrity": "sha512-/fEk3gbQTJknCiYM/GTL/L++Azsav8rCAjmtKrjmCbqEif5IMzqTfvM68n+PiLB3JVoQJGF/mg2niODr0IE/2w==", + "cpu": [ + "x64" + ], + "license": "MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@yuku-codegen/binding-darwin-arm64": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-darwin-arm64/-/binding-darwin-arm64-0.5.48.tgz", + "integrity": "sha512-yo96Oef12WzqnphInfz/eexVse3+kWgfGS5g2S3rFS3dcGn1ENW9xLFDZUP9rh+yP76DOq38wBoFi1+I9+6qBg==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@yuku-codegen/binding-darwin-x64": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-darwin-x64/-/binding-darwin-x64-0.5.48.tgz", + "integrity": "sha512-aRCTw0EZC4bVosmw//0OMYP5tGWFE0Cu5yUBFkUbhXx/iBzvORcJ2xPNlOp/vtCCo9Ys4vp8b0DigJV6uOVb2g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@yuku-codegen/binding-freebsd-x64": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-freebsd-x64/-/binding-freebsd-x64-0.5.48.tgz", + "integrity": "sha512-CA0AQAEApDkbw51PdLWMtKPJ41/7rvXsS3SJs+phG7fHJI+MuFzWuLbkucZfZoEOiDscmcsfYIdgL8BsfuyKKQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@yuku-codegen/binding-linux-arm-gnu": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm-gnu/-/binding-linux-arm-gnu-0.5.48.tgz", + "integrity": "sha512-DuSQlk8bH4gpmW3/00P0NLagAcMv8jOxjT40cQmxKRkktr+SUOALCfkT89tdDq3qtY95NR2GXOZ7AjNh7KKqCw==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-linux-arm-musl": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm-musl/-/binding-linux-arm-musl-0.5.48.tgz", + "integrity": "sha512-bxj4Ee+wlaJcWJwft2ReJXWw5sfl1qavDz6+dlRdU1xfTEtjPSNiAWhiCHnJR0R4Ygd57DnzSQmAVGvFv6RcGw==", + "cpu": [ + "arm" + ], + "libc": [ + "musl" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-linux-arm64-gnu": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.5.48.tgz", + "integrity": "sha512-mk5JVWh+0JOe5ue8k17kbYX8uGBoKt3ZqoCyxNh4nYAAcX7+X1tFUiU7jbjctu4vHeejCBFSTdQ021+V31cUCQ==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-linux-arm64-musl": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.5.48.tgz", + "integrity": "sha512-4q3vkrNghbllyxOm2KesFLxCPKHF7r3JyQ7BWZccY1j2Y05yKoIFhoWCqIuQ2W/dpte9RI0+OVfwyxnrKg6fkA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-linux-x64-gnu": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.5.48.tgz", + "integrity": "sha512-csd4M1EVrGaohM8acM6gq1zpUA/Rwe2ulUMBKUcwQXm/k6n7cq1A++qdew78SOVb4do3JH1WE+WFwoGQAcWc1w==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-linux-x64-musl": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-linux-x64-musl/-/binding-linux-x64-musl-0.5.48.tgz", + "integrity": "sha512-KcDuEOT+GFoVKdvAWOv1v9iYjwnmvMZlO+j1Rw+5PYdeFLGWGzv/DD11y4SAAdwXIFcil4T0hibeIaF82WStMg==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-codegen/binding-win32-arm64": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-win32-arm64/-/binding-win32-arm64-0.5.48.tgz", + "integrity": "sha512-HI8qNrI8dWM5BuqIMKsqornRvTNFrE6sm5zToIJ9YIa9zt5+29P7fJ7Nr39EVf6dAWSb6q7JSpScJnRsQ+FgZA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@yuku-codegen/binding-win32-x64": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-codegen/binding-win32-x64/-/binding-win32-x64-0.5.48.tgz", + "integrity": "sha512-X5YWJLO6EfBZpeBqO0AYESnUizbpFDWArcvVD61w0PEWQ3CaFRLnbQXs+kpM4ZZfGMfIE22zfA08QSY67q7TNQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@yuku-parser/binding-darwin-arm64": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-darwin-arm64/-/binding-darwin-arm64-0.5.48.tgz", + "integrity": "sha512-If8mb7HH3vqghJ2NNZ8SuHfhsnjVzOxJpB8xcNOXS5WjYrs2mUhHIh5KOIvK13hDOzh0htGeGK3A6MsiEqE7HQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@yuku-parser/binding-darwin-x64": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-darwin-x64/-/binding-darwin-x64-0.5.48.tgz", + "integrity": "sha512-EimvPXfspzxf1K11eB6tCW5oiQEXB8g84T2wP1TwzQagdDKo33bkmmVF0B32vTIpXnk/Ifu5IB61izZ1MylljA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@yuku-parser/binding-freebsd-x64": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-freebsd-x64/-/binding-freebsd-x64-0.5.48.tgz", + "integrity": "sha512-0GcUMrumLHheThY9r5Tp46gaZYzn0irWPS1Zba6WY+vVQfhUtzGiWgXxI6tuXX0N32kEaaEVRpkKctvo6Kx3aQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ] + }, + "node_modules/@yuku-parser/binding-linux-arm-gnu": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm-gnu/-/binding-linux-arm-gnu-0.5.48.tgz", + "integrity": "sha512-8S5T5wjCC73dmmpQeZ49aYsSunIUM3D4Fc6rdK96c+Ayg/p3FmeSPF3xuLZHejcTmqJIIvnbfPlUF+rB6DITjQ==", + "cpu": [ + "arm" + ], + "libc": [ + "glibc" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-parser/binding-linux-arm-musl": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm-musl/-/binding-linux-arm-musl-0.5.48.tgz", + "integrity": "sha512-tTmbxvnUHcK2/crS9547vk2SMmsajH1yqJ8ltXhIuHJgqR1v+d9n9KT+kSayo/5CS76LegeYxhMFjEivBH2hFA==", + "cpu": [ + "arm" + ], + "libc": [ + "musl" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-parser/binding-linux-arm64-gnu": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-0.5.48.tgz", + "integrity": "sha512-KGYCBMqI2zfwyhgq5tpPVNe7jpUeYTBm8DhjdS+zqWNumde/PEC170QE5RHxcOAlsirIDeIUk0jqx+r/axoFSw==", + "cpu": [ + "arm64" + ], + "libc": [ + "glibc" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-parser/binding-linux-arm64-musl": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-arm64-musl/-/binding-linux-arm64-musl-0.5.48.tgz", + "integrity": "sha512-2wTSMsCSXLTc2lZUjMAuU5X4cje55u205WJqfV5NWNF6j9pW/tXyxr15dJeekj8ziLqBXzIsj4DbRh4sY/WcjA==", + "cpu": [ + "arm64" + ], + "libc": [ + "musl" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-parser/binding-linux-x64-gnu": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-x64-gnu/-/binding-linux-x64-gnu-0.5.48.tgz", + "integrity": "sha512-d/6v9UnGglVu1WC2JQyv/5aWSi5fXZeGSlidCfmHp4+N65N1GDKUnFtys5MK5eAPeAjTgSHGGtOc/yCcKTlv3A==", + "cpu": [ + "x64" + ], + "libc": [ + "glibc" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-parser/binding-linux-x64-musl": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-linux-x64-musl/-/binding-linux-x64-musl-0.5.48.tgz", + "integrity": "sha512-gX19gw6u4ApPy7SYMPKfFlEkrtj6WlORvrTKK3sBQqjyV+8+mUAkQgxXNjHw4RnOiAmVYg7TOlZcg8d+Qqod9A==", + "cpu": [ + "x64" + ], + "libc": [ + "musl" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@yuku-parser/binding-win32-arm64": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-win32-arm64/-/binding-win32-arm64-0.5.48.tgz", + "integrity": "sha512-w6cQQLbqj3Jcom5Q7ifm103NUOQ9d+Cb4VU5lkrZDjMnwVJ9Hzzg1vCQR7miJuF44vhCXldbme5UryE3giEKlA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@yuku-parser/binding-win32-x64": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/@yuku-parser/binding-win32-x64/-/binding-win32-x64-0.5.48.tgz", + "integrity": "sha512-4gO0HmG7fzFxrw1rs0dUdnnaY9YgennjETqDWrTSp7x9fmTUOAoN4VsMfP7YyliQeG1WJJHc55O+rOhmsLppow==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@yuku-toolchain/types": { + "version": "0.5.43", + "resolved": "https://registry.npmjs.org/@yuku-toolchain/types/-/types-0.5.43.tgz", + "integrity": "sha512-kSpvPntnXw5+lYjO71ffBEnQ5ycQ74KGIYknh0TS4xeyCuBkOqxyJumxZkMhLBBUCLjDAbx2+Icnr3Zh4ftjpQ==", + "license": "MIT" + }, + "node_modules/agent-base": { + "version": "7.1.4", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.4.tgz", + "integrity": "sha512-MnA+YT8fwfJPgBx3m60MNqakm30XOkyIoH1y6huTQvC0PwZG7ki8NacLBcrPbNoo8vEZy7Jpuk7+jMO+CUovTQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, + "node_modules/ajv": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.18.0.tgz", + "integrity": "sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A==", + "license": "MIT", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-draft-04": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", + "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "ajv": "^8.5.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-regex": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", + "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/api": { + "resolved": "packages/api", + "link": true + }, + "node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "dev": true, + "license": "MIT" + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true, + "license": "Python-2.0" + }, + "node_modules/aria-hidden": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", + "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", + "license": "MIT", + "dependencies": { + "tslib": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "node_modules/aws-ssl-profiles": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", + "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", + "license": "MIT", + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/babel-dead-code-elimination": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/babel-dead-code-elimination/-/babel-dead-code-elimination-1.0.12.tgz", + "integrity": "sha512-GERT7L2TiYcYDtYk1IpD+ASAYXjKbLTDPhBtYj7X1NuRMDTMtAx9kyBenub1Ev41lo91OHCKdmP+egTDmfQ7Ig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.23.7", + "@babel/parser": "^7.23.6", + "@babel/traverse": "^7.23.7", + "@babel/types": "^7.23.6" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.21", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.21.tgz", + "integrity": "sha512-uh8vpY/1/YyFkunIDFH/12p7/7VdPKA1hejMVEbdkEaWnUz0Hesvx5EbiU6XxjyHZIOju+ZMbQJkRh+es3/spQ==", + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/better-result": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/better-result/-/better-result-2.10.0.tgz", + "integrity": "sha512-oQhh0y1qo2/ZKdAAEvHZAqKKiHOFU5k/bW96fE2ScgQOVkJRiHwB+nOS1SgFsYqRlxMDWvefXi9Q3px7QvgNDw==", + "license": "MIT" + }, + "node_modules/bidi-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", + "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/bin": { + "resolved": "packages/bin", + "link": true + }, + "node_modules/brace-expansion": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", + "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/browserslist": { + "version": "4.28.9", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.28.9.tgz", + "integrity": "sha512-EWazOblFYUvlGZcfGhPUPmYh3nikUxBVb+y9MJun5f3hBi812X+8MSQTujLBtgK3cf51fJWbWfOjyeO954d+Eg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.20", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.420", + "node-releases": "^2.0.54", + "update-browserslist-db": "^1.3.2" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/buffer-image-size": { + "version": "0.6.4", + "resolved": "https://registry.npmjs.org/buffer-image-size/-/buffer-image-size-0.6.4.tgz", + "integrity": "sha512-nEh+kZOPY1w+gcCMobZ6ETUp9WfibndnosbpwB1iJk/8Gt5ZF2bhS6+B6bPYz424KtwsR6Rflc3tCz1/ghX2dQ==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/c12": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.4.tgz", + "integrity": "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==", + "license": "MIT", + "dependencies": { + "chokidar": "^5.0.0", + "confbox": "^0.2.4", + "defu": "^6.1.6", + "dotenv": "^17.3.1", + "exsolve": "^1.0.8", + "giget": "^3.2.0", + "jiti": "^2.6.1", + "ohash": "^2.0.11", + "pathe": "^2.0.3", + "perfect-debounce": "^2.1.0", + "pkg-types": "^2.3.0", + "rc9": "^3.0.1" + }, + "peerDependencies": { + "magicast": "*" + }, + "peerDependenciesMeta": { + "magicast": { + "optional": true + } + } + }, + "node_modules/cac": { + "version": "6.7.14", + "resolved": "https://registry.npmjs.org/cac/-/cac-6.7.14.tgz", + "integrity": "sha512-b6Ilus+c3RrdDk+JhLKUAQfzzgLEPy6wcXqS7f/xe1EETvsDP6GORG7SFuOs6cID5YkqchW/LXZbX5bc8j7ZcQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chai": { + "version": "6.2.2", + "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", + "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/change-case": { + "version": "5.4.4", + "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", + "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", + "dev": true, + "license": "MIT" + }, + "node_modules/chardet": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", + "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", + "dev": true, + "license": "MIT" + }, + "node_modules/chokidar": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", + "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", + "license": "MIT", + "dependencies": { + "readdirp": "^5.0.0" + }, + "engines": { + "node": ">= 20.19.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/chownr": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", + "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/classnames": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", + "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", + "license": "MIT" + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">= 12" + } + }, + "node_modules/client": { + "resolved": "packages/client", + "link": true + }, + "node_modules/client-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", + "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "license": "MIT" + }, + "node_modules/cliui": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", + "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^7.2.0", + "strip-ansi": "^7.1.0", + "wrap-ansi": "^9.0.0" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true, + "license": "MIT" + }, + "node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently": { + "version": "9.2.4", + "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.4.tgz", + "integrity": "sha512-TZ0CEhyzvFjgtAvHTusDMgj7wNdihCh7LLLrzdUOXIhdlnL2JBBGA9eJxR24rtqgmdjh3OA3hrN1rCHj6HM8qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "chalk": "4.1.2", + "rxjs": "7.8.2", + "shell-quote": "1.9.0", + "supports-color": "8.1.1", + "tree-kill": "1.2.2", + "yargs": "17.7.2" + }, + "bin": { + "conc": "dist/bin/concurrently.js", + "concurrently": "dist/bin/concurrently.js" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/concurrently/node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true, + "license": "MIT" + }, + "node_modules/concurrently/node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/concurrently/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/concurrently/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/confbox": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", + "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "license": "MIT" + }, + "node_modules/cookie": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-1.1.1.tgz", + "integrity": "sha512-ei8Aos7ja0weRpFzJnEA9UHJ/7XQmqglbRwnf2ATjcB9Wq874VKH9kfjjirM6UhU2/E5fFYadylyhFldcqSidQ==", "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-uri": "^3.0.1", - "json-schema-traverse": "^1.0.0", - "require-from-string": "^2.0.2" + "engines": { + "node": ">=18" }, "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/ajv-draft-04": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/ajv-draft-04/-/ajv-draft-04-1.0.0.tgz", - "integrity": "sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==", - "dev": true, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "license": "MIT", - "peerDependencies": { - "ajv": "^8.5.0" + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "engines": { + "node": ">= 8" } }, - "node_modules/ajv-formats": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", - "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", - "dev": true, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "devOptional": true, "license": "MIT", "dependencies": { - "ajv": "^8.0.0" - }, - "peerDependencies": { - "ajv": "^8.0.0" + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" }, - "peerDependenciesMeta": { - "ajv": { - "optional": true - } + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" } }, - "node_modules/ansi-colors": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", - "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, - "license": "MIT", + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "license": "MIT" + }, + "node_modules/d3-array": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", + "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "license": "ISC", + "dependencies": { + "internmap": "1 - 2" + }, "engines": { - "node": ">=6" + "node": ">=12" } }, - "node_modules/ansi-regex": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.2.2.tgz", - "integrity": "sha512-Bq3SmSpyFHaWjPk8If9yc6svM8c56dB5BAtW4Qbw5jHTwwXXcTLoRMkpDJp6VL0XzlWaCHTXrkFURMYmD0sLqg==", - "dev": true, - "license": "MIT", + "node_modules/d3-color": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", + "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", + "license": "ISC", "engines": { "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" } }, - "node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "license": "MIT", + "node_modules/d3-delaunay": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", + "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", + "license": "ISC", "dependencies": { - "color-convert": "^2.0.1" + "delaunator": "5" }, "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "node": ">=12" } }, - "node_modules/api": { - "resolved": "packages/api", - "link": true - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", - "dev": true, - "license": "Python-2.0" + "node_modules/d3-format": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", + "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/aria-hidden": { - "version": "1.2.6", - "resolved": "https://registry.npmjs.org/aria-hidden/-/aria-hidden-1.2.6.tgz", - "integrity": "sha512-ik3ZgC9dY/lYVVM++OISsaYDeg1tb0VtP5uL3ouh1koGOaUMDPpbFIei4JkFimWUFPn90sbMNMXQAIVOlnYKJA==", - "license": "MIT", + "node_modules/d3-geo": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", + "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "license": "ISC", "dependencies": { - "tslib": "^2.0.0" + "d3-array": "2.5.0 - 3" }, "engines": { - "node": ">=10" + "node": ">=12" } }, - "node_modules/aria-query": { - "version": "5.3.0", - "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", - "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", - "license": "Apache-2.0", + "node_modules/d3-interpolate": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", + "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", + "license": "ISC", "dependencies": { - "dequal": "^2.0.3" + "d3-color": "1 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/assertion-error": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", - "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", - "license": "MIT", + "node_modules/d3-path": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", + "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", + "license": "ISC", "engines": { "node": ">=12" } }, - "node_modules/aws-ssl-profiles": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/aws-ssl-profiles/-/aws-ssl-profiles-1.1.2.tgz", - "integrity": "sha512-NZKeq9AfyQvEeNlN0zSYAaWrmBffJh3IELMZfRpJVWgrpEbtEpnjvzqBPf+mxoI287JohRDoa+/nsfqqiZmF6g==", - "license": "MIT", + "node_modules/d3-scale": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", + "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", + "license": "ISC", + "dependencies": { + "d3-array": "2.10.0 - 3", + "d3-format": "1 - 3", + "d3-interpolate": "1.2.0 - 3", + "d3-time": "2.1.1 - 3", + "d3-time-format": "2 - 4" + }, "engines": { - "node": ">= 6.0.0" + "node": ">=12" } }, - "node_modules/balanced-match": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", - "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", - "dev": true, - "license": "MIT" - }, - "node_modules/baseline-browser-mapping": { - "version": "2.10.10", - "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.10.10.tgz", - "integrity": "sha512-sUoJ3IMxx4AyRqO4MLeHlnGDkyXRoUG0/AI9fjK+vS72ekpV0yWVY7O0BVjmBcRtkNcsAO2QDZ4tdKKGoI6YaQ==", - "license": "Apache-2.0", - "bin": { - "baseline-browser-mapping": "dist/cli.cjs" + "node_modules/d3-shape": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", + "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", + "license": "ISC", + "dependencies": { + "d3-path": "^3.1.0" }, "engines": { - "node": ">=6.0.0" + "node": ">=12" } }, - "node_modules/better-result": { - "version": "2.10.0", - "resolved": "https://registry.npmjs.org/better-result/-/better-result-2.10.0.tgz", - "integrity": "sha512-oQhh0y1qo2/ZKdAAEvHZAqKKiHOFU5k/bW96fE2ScgQOVkJRiHwB+nOS1SgFsYqRlxMDWvefXi9Q3px7QvgNDw==", - "license": "MIT" - }, - "node_modules/bidi-js": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz", - "integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==", - "devOptional": true, - "license": "MIT", + "node_modules/d3-time": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", + "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", + "license": "ISC", "dependencies": { - "require-from-string": "^2.0.2" + "d3-array": "2 - 3" + }, + "engines": { + "node": ">=12" } }, - "node_modules/bin": { - "resolved": "packages/bin", - "link": true + "node_modules/d3-time-format": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", + "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", + "license": "ISC", + "dependencies": { + "d3-time": "1 - 3" + }, + "engines": { + "node": ">=12" + } }, - "node_modules/brace-expansion": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.1.4.tgz", - "integrity": "sha512-hGfVzPxthbf3+2yjg/RBs60cB0FhqBS/zvdV/4wn4/BmN0bNMMHPc4V/BbFieqf1TKAGGAHnY4eSjajCl0f2Xg==", - "dev": true, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "devOptional": true, "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0" + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/c12": { - "version": "3.3.4", - "resolved": "https://registry.npmjs.org/c12/-/c12-3.3.4.tgz", - "integrity": "sha512-cM0ApFQSBXuourJejzwv/AuPRvAxordTyParRVcHjjtXirtkzM0uK2L9TTn9s0cXZbG7E55jCivRQzoxYmRAlA==", + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, "license": "MIT", "dependencies": { - "chokidar": "^5.0.0", - "confbox": "^0.2.4", - "defu": "^6.1.6", - "dotenv": "^17.3.1", - "exsolve": "^1.0.8", - "giget": "^3.2.0", - "jiti": "^2.6.1", - "ohash": "^2.0.11", - "pathe": "^2.0.3", - "perfect-debounce": "^2.1.0", - "pkg-types": "^2.3.0", - "rc9": "^3.0.1" + "ms": "^2.1.3" }, - "peerDependencies": { - "magicast": "*" + "engines": { + "node": ">=6.0" }, "peerDependenciesMeta": { - "magicast": { + "supports-color": { "optional": true } } }, - "node_modules/caniuse-lite": { - "version": "1.0.30001781", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001781.tgz", - "integrity": "sha512-RdwNCyMsNBftLjW6w01z8bKEvT6e/5tpPVEgtn22TiLGlstHOVecsX2KHFkD5e/vRnIE4EGzpuIODb3mtswtkw==", - "funding": [ - { - "type": "opencollective", - "url": "https://opencollective.com/browserslist" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/caniuse-lite" - }, - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], - "license": "CC-BY-4.0" + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "devOptional": true, + "license": "MIT" }, - "node_modules/chai": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/chai/-/chai-6.2.2.tgz", - "integrity": "sha512-NUPRluOfOiTKBKvWPtSD4PhFvWCqOi0BGStNWs57X9js7XGTprSmFoz5F0tWhR4WPjNeR9jXqdC7/UpSJTnlRg==", + "node_modules/dedent": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-1.7.2.tgz", + "integrity": "sha512-WzMx3mW98SN+zn3hgemf4OzdmyNhhhKz5Ay0pUfQiMQ3e1g+xmTJWp/pKdwKVXhdSkAEGIIzqeuWrL3mV/AXbA==", + "dev": true, "license": "MIT", + "peerDependencies": { + "babel-plugin-macros": "^3.1.0" + }, + "peerDependenciesMeta": { + "babel-plugin-macros": { + "optional": true + } + } + }, + "node_modules/deepmerge-ts": { + "version": "7.1.5", + "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", + "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", + "license": "BSD-3-Clause", "engines": { - "node": ">=18" + "node": ">=16.0.0" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "dev": true, - "license": "MIT", + "node_modules/defu": { + "version": "6.1.7", + "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", + "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", + "license": "MIT" + }, + "node_modules/delaunator": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", + "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", + "license": "ISC", "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, + "robust-predicates": "^3.0.2" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "license": "Apache-2.0", "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" + "node": ">=0.10" } }, - "node_modules/chalk/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, + "node_modules/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, + "engines": { + "node": ">=6" + } + }, + "node_modules/destr": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", + "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", + "license": "MIT" + }, + "node_modules/detect-libc": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", + "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", + "license": "Apache-2.0", "engines": { "node": ">=8" } }, - "node_modules/change-case": { - "version": "5.4.4", - "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", - "integrity": "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w==", - "dev": true, + "node_modules/detect-node-es": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", + "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", "license": "MIT" }, - "node_modules/chardet": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-2.2.0.tgz", - "integrity": "sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA==", - "dev": true, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", "license": "MIT" }, - "node_modules/chokidar": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-5.0.0.tgz", - "integrity": "sha512-TQMmc3w+5AxjpL8iIiwebF73dRDF4fBIieAqGn9RGCWaEVwQ6Fb2cGe31Yns0RRIzii5goJ1Y7xbMwo1TxMplw==", - "license": "MIT", - "dependencies": { - "readdirp": "^5.0.0" - }, + "node_modules/dotenv": { + "version": "17.4.2", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", + "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", + "license": "BSD-2-Clause", "engines": { - "node": ">= 20.19.0" + "node": ">=12" }, "funding": { - "url": "https://paulmillr.com/funding/" + "url": "https://dotenvx.com" } }, - "node_modules/chownr": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chownr/-/chownr-3.0.0.tgz", - "integrity": "sha512-+IxzY9BZOQd/XuYPRmrvEVjF/nqj5kgT4kEq7VofrDoM1MxoRjEWkrCC3EtLi59TVawxTAn+orJwFQcrqEN1+g==", - "dev": true, - "license": "BlueOak-1.0.0", - "engines": { - "node": ">=18" + "node_modules/effect": { + "version": "3.20.0", + "resolved": "https://registry.npmjs.org/effect/-/effect-3.20.0.tgz", + "integrity": "sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==", + "license": "MIT", + "dependencies": { + "@standard-schema/spec": "^1.0.0", + "fast-check": "^3.23.1" } }, - "node_modules/classnames": { - "version": "2.5.1", - "resolved": "https://registry.npmjs.org/classnames/-/classnames-2.5.1.tgz", - "integrity": "sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==", - "license": "MIT" - }, - "node_modules/cli-width": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", - "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "node_modules/electron-to-chromium": { + "version": "1.5.423", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.423.tgz", + "integrity": "sha512-rRZfTSY8ptHYMQxa+uIycJMFKmY1T0GIApNMXJYGehguTZa56TEEl19pKPCoBqk5Gpf7QizZn/jt7xur+DYxag==", "dev": true, - "license": "ISC", - "engines": { - "node": ">= 12" - } + "license": "ISC" }, - "node_modules/client": { - "resolved": "packages/client", - "link": true + "node_modules/elkjs": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.11.1.tgz", + "integrity": "sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg==", + "license": "EPL-2.0" }, - "node_modules/client-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/client-only/-/client-only-0.0.1.tgz", - "integrity": "sha512-IV3Ou0jSMzZrd3pZ48nLkT9DA7Ag1pnPzaiQhpW7c3RbcqqzvzzVu+L8gfqMp/8IM2MQtSiqaCxrrcfu8I8rMA==", + "node_modules/emoji-regex": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", + "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "dev": true, "license": "MIT" }, - "node_modules/cliui": { - "version": "9.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz", - "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==", + "node_modules/empathic": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", + "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "license": "MIT", + "engines": { + "node": ">=14" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.24.5", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", + "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "string-width": "^7.2.0", - "strip-ansi": "^7.1.0", - "wrap-ansi": "^9.0.0" + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" }, "engines": { - "node": ">=20" + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", + "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" } }, - "node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "node_modules/env-paths": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", + "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", "dev": true, "license": "MIT", "dependencies": { - "color-name": "~1.1.4" + "is-safe-filename": "^0.1.0" }, "engines": { - "node": ">=7.0.0" + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true, - "license": "MIT" - }, - "node_modules/colorette": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", - "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", - "dev": true, + "node_modules/es-module-lexer": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", + "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", "license": "MIT" }, - "node_modules/concurrently": { - "version": "9.2.4", - "resolved": "https://registry.npmjs.org/concurrently/-/concurrently-9.2.4.tgz", - "integrity": "sha512-TZ0CEhyzvFjgtAvHTusDMgj7wNdihCh7LLLrzdUOXIhdlnL2JBBGA9eJxR24rtqgmdjh3OA3hrN1rCHj6HM8qA==", - "dev": true, + "node_modules/esbuild": { + "version": "0.28.2", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.28.2.tgz", + "integrity": "sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==", + "devOptional": true, + "hasInstallScript": true, "license": "MIT", - "dependencies": { - "chalk": "4.1.2", - "rxjs": "7.8.2", - "shell-quote": "1.9.0", - "supports-color": "8.1.1", - "tree-kill": "1.2.2", - "yargs": "17.7.2" - }, "bin": { - "conc": "dist/bin/concurrently.js", - "concurrently": "dist/bin/concurrently.js" + "esbuild": "bin/esbuild" }, "engines": { "node": ">=18" }, - "funding": { - "url": "https://github.com/open-cli-tools/concurrently?sponsor=1" + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.28.2", + "@esbuild/android-arm": "0.28.2", + "@esbuild/android-arm64": "0.28.2", + "@esbuild/android-x64": "0.28.2", + "@esbuild/darwin-arm64": "0.28.2", + "@esbuild/darwin-x64": "0.28.2", + "@esbuild/freebsd-arm64": "0.28.2", + "@esbuild/freebsd-x64": "0.28.2", + "@esbuild/linux-arm": "0.28.2", + "@esbuild/linux-arm64": "0.28.2", + "@esbuild/linux-ia32": "0.28.2", + "@esbuild/linux-loong64": "0.28.2", + "@esbuild/linux-mips64el": "0.28.2", + "@esbuild/linux-ppc64": "0.28.2", + "@esbuild/linux-riscv64": "0.28.2", + "@esbuild/linux-s390x": "0.28.2", + "@esbuild/linux-x64": "0.28.2", + "@esbuild/netbsd-arm64": "0.28.2", + "@esbuild/netbsd-x64": "0.28.2", + "@esbuild/openbsd-arm64": "0.28.2", + "@esbuild/openbsd-x64": "0.28.2", + "@esbuild/openharmony-arm64": "0.28.2", + "@esbuild/sunos-x64": "0.28.2", + "@esbuild/win32-arm64": "0.28.2", + "@esbuild/win32-ia32": "0.28.2", + "@esbuild/win32-x64": "0.28.2" } }, - "node_modules/concurrently/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "dev": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=6" } }, - "node_modules/concurrently/node_modules/cliui": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", - "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", - "dev": true, - "license": "ISC", + "node_modules/estree-walker": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", + "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "license": "MIT", "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.1", - "wrap-ansi": "^7.0.0" + "@types/estree": "^1.0.0" + } + }, + "node_modules/exit-hook": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/exit-hook/-/exit-hook-2.2.1.tgz", + "integrity": "sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/expect-type": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", + "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", + "license": "Apache-2.0", "engines": { - "node": ">=12" + "node": ">=12.0.0" } }, - "node_modules/concurrently/node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", - "dev": true, + "node_modules/exsolve": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.1.tgz", + "integrity": "sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==", "license": "MIT" }, - "node_modules/concurrently/node_modules/string-width": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "dev": true, + "node_modules/fast-check": { + "version": "3.23.2", + "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", + "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ], "license": "MIT", "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" + "pure-rand": "^6.1.0" }, "engines": { - "node": ">=8" + "node": ">=8.0.0" } }, - "node_modules/concurrently/node_modules/strip-ansi": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "dev": true, + "node_modules/fast-decode-uri-component": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", + "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", + "license": "MIT" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "license": "MIT" + }, + "node_modules/fast-querystring": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", + "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" + "fast-decode-uri-component": "^1.0.1" } }, - "node_modules/concurrently/node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "node_modules/fast-string-truncated-width": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", + "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-string-width": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", + "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", "dev": true, "license": "MIT", "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "fast-string-truncated-width": "^3.0.2" } }, - "node_modules/concurrently/node_modules/yargs": { - "version": "17.7.2", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", - "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "node_modules/fast-uri": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", + "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/fast-wrap-ansi": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", + "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", "dev": true, "license": "MIT", "dependencies": { - "cliui": "^8.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.3", - "y18n": "^5.0.5", - "yargs-parser": "^21.1.1" - }, - "engines": { - "node": ">=12" + "fast-string-width": "^3.0.2" } }, - "node_modules/confbox": { - "version": "0.2.4", - "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.2.4.tgz", - "integrity": "sha512-ysOGlgTFbN2/Y6Cg3Iye8YKulHw+R2fNXHrgSmXISQdMnomY6eNDprVdW9R5xBguEqI954+S6709UyiO7B+6OQ==", - "license": "MIT" - }, - "node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "license": "MIT" - }, - "node_modules/cross-spawn": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", - "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "node_modules/fdir": { + "version": "6.5.0", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", + "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", "license": "MIT", - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, "engines": { - "node": ">= 8" + "node": ">=12.0.0" + }, + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } } }, - "node_modules/css-tree": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", - "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", - "devOptional": true, + "node_modules/find-my-way": { + "version": "9.7.0", + "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.7.0.tgz", + "integrity": "sha512-f2JHn75x2JlwUwLenZypgczR7YWMb/uO9BvUXtus+JMgkbIkLADd38cI4EiV+OQqrGo1Zlq6V8wnqMJ8e62wUQ==", "license": "MIT", "dependencies": { - "mdn-data": "2.27.1", - "source-map-js": "^1.2.1" + "fast-deep-equal": "^3.1.3", + "fast-querystring": "^1.0.0", + "safe-regex2": "^5.0.0" }, "engines": { - "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + "node": ">=20" } }, - "node_modules/csstype": { - "version": "3.2.3", - "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", - "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", - "license": "MIT" - }, - "node_modules/d3-array": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/d3-array/-/d3-array-3.2.4.tgz", - "integrity": "sha512-tdQAmyA18i4J7wprpYq8ClcxZy3SC31QMeByyCFyRt7BVHdREQZ5lpzoe5mFEYZUWe+oq8HBvk9JjpibyEV4Jg==", + "node_modules/foreground-child": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", + "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", "license": "ISC", "dependencies": { - "internmap": "1 - 2" + "cross-spawn": "^7.0.6", + "signal-exit": "^4.0.1" }, "engines": { - "node": ">=12" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/d3-color": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-color/-/d3-color-3.1.0.tgz", - "integrity": "sha512-zg/chbXyeBtMQ1LbD/WSoW2DpC3I0mpmPdW+ynRTj/x2DAWYrIY7qeZIHidozwV24m4iavr15lNwIwLxRmOxhA==", - "license": "ISC", + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12" + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" } }, - "node_modules/d3-delaunay": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/d3-delaunay/-/d3-delaunay-6.0.2.tgz", - "integrity": "sha512-IMLNldruDQScrcfT+MWnazhHbDJhcRJyOEBAJfwQnHle1RPh6WDuLvxNArUju2VSMSUuKlY5BGHRJ2cYyoFLQQ==", - "license": "ISC", + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "license": "MIT", "dependencies": { - "delaunator": "5" - }, - "engines": { - "node": ">=12" + "is-property": "^1.0.2" } }, - "node_modules/d3-format": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-format/-/d3-format-3.1.0.tgz", - "integrity": "sha512-YyUI6AEuY/Wpt8KWLgZHsIU86atmikuoOmCfommt0LYHiQSPjvX2AcFc38PX0CBpr2RCyZhjex+NS/LPOv6YqA==", - "license": "ISC", + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=6.9.0" } }, - "node_modules/d3-geo": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-geo/-/d3-geo-3.1.0.tgz", - "integrity": "sha512-JEo5HxXDdDYXCaWdwLRt79y7giK8SbhZJbFWXqbRTolCHFI5jRqteLzCsq51NKbUoX0PjBVSohxrx+NoOUujYA==", + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, "license": "ISC", - "dependencies": { - "d3-array": "2.5.0 - 3" - }, "engines": { - "node": ">=12" + "node": "6.* || 8.* || >= 10.*" } }, - "node_modules/d3-interpolate": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/d3-interpolate/-/d3-interpolate-3.0.1.tgz", - "integrity": "sha512-3bYs1rOD33uo8aqJfKP3JWPAibgw8Zm2+L9vBKEHJ2Rg+viTR7o5Mmv5mZcieN+FRYaAOWX5SJATX6k1PWz72g==", - "license": "ISC", - "dependencies": { - "d3-color": "1 - 3" - }, + "node_modules/get-east-asian-width": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", + "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/d3-path": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-path/-/d3-path-3.1.0.tgz", - "integrity": "sha512-p3KP5HCf/bvjBSSKuXid6Zqijx7wIfNW+J/maPs+iwR35at5JCbLUT0LzF1cnjbCHWhqzQTIN2Jpe8pRebIEFQ==", - "license": "ISC", + "node_modules/get-nonce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", + "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=6" } }, - "node_modules/d3-scale": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/d3-scale/-/d3-scale-4.0.2.tgz", - "integrity": "sha512-GZW464g1SH7ag3Y7hXjf8RoUuAFIqklOAq3MRl4OaWabTFJY9PN/E1YklhXLh+OQ3fM9yS2nOkCoS+WLZ6kvxQ==", - "license": "ISC", + "node_modules/get-port-please": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz", + "integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==", + "license": "MIT" + }, + "node_modules/giget": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/giget/-/giget-3.3.1.tgz", + "integrity": "sha512-r+mvuDjrjMpsdw46Kmeydb8bdHm7wOKw8wNBtTndkjbPjgAp5oUJUxRE76wZFknxIPokfWvep2qSXK37aXE6zg==", + "license": "MIT", + "bin": { + "giget": "dist/cli.mjs" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "license": "ISC" + }, + "node_modules/grammex": { + "version": "3.1.13", + "resolved": "https://registry.npmjs.org/grammex/-/grammex-3.1.13.tgz", + "integrity": "sha512-LnPnhOBLEJEVKS8WFDVaA397L9Kq55Q9oSITJiVLHVdhAclfUkWzQv74KhvZHKL2Q09Pb1XdsrOsZ4LfTFFTEg==", + "license": "MIT" + }, + "node_modules/graphmatch": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/graphmatch/-/graphmatch-1.1.1.tgz", + "integrity": "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==", + "license": "MIT" + }, + "node_modules/happy-dom": { + "version": "20.14.0", + "resolved": "https://registry.npmjs.org/happy-dom/-/happy-dom-20.14.0.tgz", + "integrity": "sha512-4bRh1KzRvKDnFNTlLhzT1RZTpkKhQbQDl9j+7GXszWsvuspYdo29k6OHRf4PwiM6oLb8r/pMWeYiJjkfod5AvQ==", + "devOptional": true, + "license": "MIT", "dependencies": { - "d3-array": "2.10.0 - 3", - "d3-format": "1 - 3", - "d3-interpolate": "1.2.0 - 3", - "d3-time": "2.1.1 - 3", - "d3-time-format": "2 - 4" + "@types/node": ">=20.0.0", + "@types/whatwg-mimetype": "^3.0.2", + "@types/ws": "^8.18.1", + "buffer-image-size": "^0.6.4", + "entities": "^7.0.1", + "whatwg-mimetype": "^3.0.0", + "ws": "^8.21.0" }, "engines": { - "node": ">=12" + "node": ">=20.0.0" } }, - "node_modules/d3-shape": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/d3-shape/-/d3-shape-3.2.0.tgz", - "integrity": "sha512-SaLBuwGm3MOViRq2ABk3eLoxwZELpH6zhl3FbAoJ7Vm1gofKx6El1Ib5z23NUEhF9AsGl7y+dzLe5Cw2AArGTA==", - "license": "ISC", - "dependencies": { - "d3-path": "^3.1.0" + "node_modules/happy-dom/node_modules/entities": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-7.0.1.tgz", + "integrity": "sha512-TWrgLOFUQTH994YUyl1yT4uyavY5nNB5muff+RtWaqNVCAK408b5ZnnbNAUEWLTCpum9w6arT70i1XdQ4UeOPA==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/happy-dom/node_modules/whatwg-mimetype": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-3.0.0.tgz", + "integrity": "sha512-nt+N2dzIutVRxARx1nghPKGv1xHikU7HKdfafKkLNLindmPU/ch3U31NOCGGA/dmPcmb1VlofO0vnKAcsm0o/Q==", + "devOptional": true, + "license": "MIT", "engines": { "node": ">=12" } }, - "node_modules/d3-time": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/d3-time/-/d3-time-3.1.0.tgz", - "integrity": "sha512-VqKjzBLejbSMT4IgbmVgDjpkYrNWUYJnbCGo874u7MMKIWsILRX+OpX/gTk8MqjpT1A/c6HY2dCA77ZN0lkQ2Q==", - "license": "ISC", - "dependencies": { - "d3-array": "2 - 3" - }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=8" } }, - "node_modules/d3-time-format": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/d3-time-format/-/d3-time-format-4.1.0.tgz", - "integrity": "sha512-dJxPBlzC7NugB2PDLwo9Q8JiTR3M3e4/XANkreKSUxF8vvXKqm1Yfq4Q5dl8budlunRVlUUaDUgFt7eA8D6NLg==", - "license": "ISC", - "dependencies": { - "d3-time": "1 - 3" - }, + "node_modules/hono": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.1.tgz", + "integrity": "sha512-kdJoFVv2xmayw6cY09H7AbMJMt8Jn5jdlEdXsP7AGBdF2DIptVlKlOLKXP41yPip4/a3yQPv9gVcJYI8YY04dw==", + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=16.9.0" } }, - "node_modules/data-urls": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", - "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", "devOptional": true, "license": "MIT", "dependencies": { - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^16.0.0" + "@exodus/bytes": "^1.6.0" }, "engines": { "node": "^20.19.0 || ^22.12.0 || >=24.0.0" } }, - "node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "node_modules/https-proxy-agent": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", + "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", "dev": true, "license": "MIT", "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "node_modules/decimal.js": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", - "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/deepmerge-ts": { - "version": "7.1.5", - "resolved": "https://registry.npmjs.org/deepmerge-ts/-/deepmerge-ts-7.1.5.tgz", - "integrity": "sha512-HOJkrhaYsweh+W+e74Yn7YStZOilkoPb6fycpwNLKzSPtruFs48nYis0zy5yJz1+ktUhHxoRDJ27RQAWLIJVJw==", - "license": "BSD-3-Clause", + "agent-base": "^7.1.2", + "debug": "4" + }, "engines": { - "node": ">=16.0.0" + "node": ">= 14" } }, - "node_modules/defu": { - "version": "6.1.7", - "resolved": "https://registry.npmjs.org/defu/-/defu-6.1.7.tgz", - "integrity": "sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==", - "license": "MIT" - }, - "node_modules/delaunator": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", - "integrity": "sha512-AGrQ4QSgssa1NGmWmLPqN5NY2KajF5MqxetNEO+o0n3ZwZZeTmt7bBnvzHWrmkZFxGgr4HdyFgelzgi06otLuQ==", - "license": "ISC", + "node_modules/iconv-lite": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", + "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "license": "MIT", "dependencies": { - "robust-predicates": "^3.0.2" + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" } }, - "node_modules/denque": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", - "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", - "license": "Apache-2.0", + "node_modules/index-to-position": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", + "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=0.10" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/dequal": { + "node_modules/internmap": { "version": "2.0.3", - "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", - "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", - "license": "MIT", + "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", + "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", + "license": "ISC", "engines": { - "node": ">=6" + "node": ">=12" } }, - "node_modules/destr": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/destr/-/destr-2.0.5.tgz", - "integrity": "sha512-ugFTXCtDZunbzasqBxrK93Ik/DRYsO6S/fedkWEMKqt04xZ4csmnmwGDBAb07QWNaGMAmnTIemsYZCksjATwsA==", - "license": "MIT" - }, - "node_modules/detect-libc": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.1.2.tgz", - "integrity": "sha512-Btj2BOOO83o3WyH59e8MgXsxEQVcarkUOpEYrubB0urwnN10yQ364rsiByU11nZlqWYZm05i/of7io4mzihBtQ==", - "license": "Apache-2.0", + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/detect-node-es": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/detect-node-es/-/detect-node-es-1.1.0.tgz", - "integrity": "sha512-ypdmJU/TbBby2Dxibuv7ZLW3Bs1QEmM7nHjEANfohJLvE0XVujisn1qPJcZxg+qDucsr+bP6fLD1rPS3AhJ7EQ==", + "node_modules/is-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "devOptional": true, "license": "MIT" }, - "node_modules/dom-accessibility-api": { - "version": "0.5.16", - "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", - "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", "license": "MIT" }, - "node_modules/dotenv": { - "version": "17.4.2", - "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-17.4.2.tgz", - "integrity": "sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==", - "license": "BSD-2-Clause", + "node_modules/is-safe-filename": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz", + "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=12" + "node": ">=20" }, "funding": { - "url": "https://dotenvx.com" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/effect": { - "version": "3.20.0", - "resolved": "https://registry.npmjs.org/effect/-/effect-3.20.0.tgz", - "integrity": "sha512-qMLfDJscrNG8p/aw+IkT9W7fgj50Z4wG5bLBy0Txsxz8iUHjDIkOgO3SV0WZfnQbNG2VJYb0b+rDLMrhM4+Krw==", + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, "license": "MIT", - "dependencies": { - "@standard-schema/spec": "^1.0.0", - "fast-check": "^3.23.1" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/elkjs": { - "version": "0.11.1", - "resolved": "https://registry.npmjs.org/elkjs/-/elkjs-0.11.1.tgz", - "integrity": "sha512-zxxR9k+rx5ktMwT/FwyLdPCrq7xN6e4VGGHH8hA01vVYKjTFik7nHOxBnAYtrgYUB1RpAiLvA1/U2YraWxyKKg==", - "license": "EPL-2.0" - }, - "node_modules/emoji-regex": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz", - "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==", + "node_modules/isbot": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/isbot/-/isbot-5.2.2.tgz", + "integrity": "sha512-iQcBXcd+Rv/pkubRyGh2utW2j1oPG5hZY6TUhVPpqK4G+o3IbxpJNx04hgksjc/N7GK5pEorUxDeg31cFgEk/w==", "dev": true, - "license": "MIT" + "license": "Unlicense", + "engines": { + "node": ">=18" + } }, - "node_modules/empathic": { + "node_modules/isexe": { "version": "2.0.0", - "resolved": "https://registry.npmjs.org/empathic/-/empathic-2.0.0.tgz", - "integrity": "sha512-i6UzDscO/XfAcNYD75CfICkmfLedpyPDdozrLMmQc5ORaQcdMoc21OnlEylMIqI7U8eniKrPMxxtj8k0vhmJhA==", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "license": "ISC" + }, + "node_modules/jiti": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", + "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "license": "MIT", + "bin": { + "jiti": "lib/jiti-cli.mjs" + } + }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "dev": true, "license": "MIT", "engines": { - "node": ">=14" + "node": ">=0.10.0" } }, - "node_modules/enhanced-resolve": { - "version": "5.24.5", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.24.5.tgz", - "integrity": "sha512-L1l8TNvomm6UVW5B253AGxQagSQr+vGwhMlrrfRS2qmhx46AMpMVJKQYLvWYbysTMY8VoicOvzHzoHMbyzB+4A==", + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", + "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.4", - "tapable": "^2.3.3" + "argparse": "^2.0.1" }, - "engines": { - "node": ">=10.13.0" + "bin": { + "js-yaml": "bin/js-yaml.js" } }, - "node_modules/entities": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-8.0.0.tgz", - "integrity": "sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==", + "node_modules/jsdom": { + "version": "30.0.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-30.0.1.tgz", + "integrity": "sha512-52v7mUVUfNQVYYqE1lcdaymWL0njO7lTLUog6ZvW2U5KsbiLk/GnZlVJ+qx0xfNJZ6Gn+KSpPNE52vurbxZwrA==", "devOptional": true, - "license": "BSD-2-Clause", + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^6.0.5", + "@asamuzakjp/dom-selector": "^8.3.0", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.7", + "@exodus/bytes": "^1.15.1", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.5.2", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.2", + "undici": "^8.9.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^17.1.0", + "xml-name-validator": "^5.0.0" + }, "engines": { - "node": ">=20.19.0" + "node": "^22.22.2 || ^24.15.0 || >=26.0.0" }, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" + "peerDependencies": { + "canvas": "^3.2.3" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } } }, - "node_modules/env-paths": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-4.0.0.tgz", - "integrity": "sha512-pxP8eL2SwwaTRi/KHYwLYXinDs7gL3jxFcBYmEdYfZmZXbaVDvdppd0XBU8qVz03rDfKZMXg1omHCbsJjZrMsw==", + "node_modules/jsdom/node_modules/whatwg-url": { + "version": "17.1.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-17.1.0.tgz", + "integrity": "sha512-3GeworPmc2ZfEEHP7lEbUfBX/L75wdEsi0rLNhXcXxnoN5jyq0SL5gCy06SGW2cyTIZdTvWIDQNQoza++vKeaw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.15.1", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^22.14.0 || >=24.0.0" + } + }, + "node_modules/jsesc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.0.2.tgz", + "integrity": "sha512-xKqzzWXDttJuOcawBt4KnKHHIf5oQ/Cxax+0PWFG+DFDgHNAdi+TXECADI+RYiFUMmx8792xsMbbgXj4CwnP4g==", "dev": true, "license": "MIT", - "dependencies": { - "is-safe-filename": "^0.1.0" + "bin": { + "jsesc": "bin/jsesc" }, "engines": { - "node": ">=20" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=6" } }, - "node_modules/es-module-lexer": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.1.tgz", - "integrity": "sha512-shc1dbU90Yl/xq1QrC7QRtfcwURZuVRfPhZbDoldJ1cn1gzDvBaBWlv0eFolj5+0znnPJz5TXLxsN77X/12KTA==", + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", "license": "MIT" }, - "node_modules/escalade": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", - "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, "engines": { "node": ">=6" } }, - "node_modules/estree-walker": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz", - "integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==", + "node_modules/jsonpointer": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", + "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "dev": true, "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0" - } - }, - "node_modules/expect-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/expect-type/-/expect-type-1.4.0.tgz", - "integrity": "sha512-KfYbmpRm0VbLjEvVa9yGwCi9GI34xvi7A/HXYWQO65CSD2u3MczUJSuwXKFIxlGsgBQizV9q5J9NHj4VG0n+pA==", - "license": "Apache-2.0", "engines": { - "node": ">=12.0.0" + "node": ">=0.10.0" } }, - "node_modules/exsolve": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/exsolve/-/exsolve-1.1.1.tgz", - "integrity": "sha512-9U/jZUgjnSGyntRr6y5Muu1MJcwFl6kPu7k8qLF0IMNfLqvw0NZ4nnVDq0RVoZ0RvCyumib4Ez3KYrVfilrw+g==", - "license": "MIT" - }, - "node_modules/fast-check": { - "version": "3.23.2", - "resolved": "https://registry.npmjs.org/fast-check/-/fast-check-3.23.2.tgz", - "integrity": "sha512-h5+1OzzfCC3Ef7VbtKdcv7zsstUQwUDlYpUTvjeUsJAssPgLn7QzbboPtL5ro04Mq0rPOsMzl7q5hIbRs2wD1A==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], + "node_modules/leven": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-4.1.0.tgz", + "integrity": "sha512-KZ9W9nWDT7rF7Dazg8xyLHGLrmpgq2nVNFUckhqdW3szVP6YhCpp/RAnpmVExA9JvrMynjwSLVrEj3AepHR6ew==", + "dev": true, "license": "MIT", - "dependencies": { - "pure-rand": "^6.1.0" - }, "engines": { - "node": ">=8.0.0" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/fast-decode-uri-component": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/fast-decode-uri-component/-/fast-decode-uri-component-1.0.1.tgz", - "integrity": "sha512-WKgKWg5eUxvRZGwW8FvfbaH7AXSh2cL+3j5fMGzUMCxWBJ3dV3a7Wz8y2f/uQ0e3B6WmodD3oS54jTQ9HVTIIg==", - "license": "MIT" - }, - "node_modules/fast-deep-equal": { - "version": "3.1.3", - "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", - "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", - "license": "MIT" - }, - "node_modules/fast-querystring": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/fast-querystring/-/fast-querystring-1.1.2.tgz", - "integrity": "sha512-g6KuKWmFXc0fID8WWH0jit4g0AGBoJhCkJMb1RmbsSEUNvQ+ZC8D6CUZ+GtF8nMzSPXnhiePyyqqipzNNEnHjg==", - "license": "MIT", + "node_modules/lightningcss": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", + "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", + "dev": true, + "license": "MPL-2.0", "dependencies": { - "fast-decode-uri-component": "^1.0.1" + "detect-libc": "^2.0.3" + }, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.32.0", + "lightningcss-darwin-arm64": "1.32.0", + "lightningcss-darwin-x64": "1.32.0", + "lightningcss-freebsd-x64": "1.32.0", + "lightningcss-linux-arm-gnueabihf": "1.32.0", + "lightningcss-linux-arm64-gnu": "1.32.0", + "lightningcss-linux-arm64-musl": "1.32.0", + "lightningcss-linux-x64-gnu": "1.32.0", + "lightningcss-linux-x64-musl": "1.32.0", + "lightningcss-win32-arm64-msvc": "1.32.0", + "lightningcss-win32-x64-msvc": "1.32.0" } }, - "node_modules/fast-string-truncated-width": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz", - "integrity": "sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g==", + "node_modules/lightningcss-android-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", + "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT" + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } }, - "node_modules/fast-string-width": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/fast-string-width/-/fast-string-width-3.0.2.tgz", - "integrity": "sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg==", + "node_modules/lightningcss-darwin-arm64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", + "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "dependencies": { - "fast-string-truncated-width": "^3.0.2" + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/fast-uri": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.5.tgz", - "integrity": "sha512-gHwA1O9LDIcKunMKhObS/HimwtehO1nPUECKAu5TpKgaO19fcWEl4bliWe1jWxVFvIXztJjjQ4L8XQ1EU9f7Jw==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } + "node_modules/lightningcss-darwin-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", + "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", + "cpu": [ + "x64" ], - "license": "BSD-3-Clause" - }, - "node_modules/fast-wrap-ansi": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz", - "integrity": "sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q==", "dev": true, - "license": "MIT", - "dependencies": { - "fast-string-width": "^3.0.2" + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/fdir": { - "version": "6.5.0", - "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.5.0.tgz", - "integrity": "sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg==", - "license": "MIT", + "node_modules/lightningcss-freebsd-x64": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", + "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=12.0.0" - }, - "peerDependencies": { - "picomatch": "^3 || ^4" + "node": ">= 12.0.0" }, - "peerDependenciesMeta": { - "picomatch": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/find-my-way": { - "version": "9.7.0", - "resolved": "https://registry.npmjs.org/find-my-way/-/find-my-way-9.7.0.tgz", - "integrity": "sha512-f2JHn75x2JlwUwLenZypgczR7YWMb/uO9BvUXtus+JMgkbIkLADd38cI4EiV+OQqrGo1Zlq6V8wnqMJ8e62wUQ==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.3", - "fast-querystring": "^1.0.0", - "safe-regex2": "^5.0.0" - }, + "node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", + "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/foreground-child": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.3.1.tgz", - "integrity": "sha512-gIXjKqtFuWEgzFRJA9WCQeSJLZDjgJUOMCMzxtvFq/37KojM1BFGufqsCy0r4qSQmYLsZYMeyRqzIWOMup03sw==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.6", - "signal-exit": "^4.0.1" - }, + "node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", + "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=14" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/isaacs" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/fsevents": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", - "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", - "hasInstallScript": true, - "license": "MIT", + "node_modules/lightningcss-linux-arm64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", + "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", "optional": true, "os": [ - "darwin" + "linux" ], "engines": { - "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/generate-function": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", - "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", - "license": "MIT", - "dependencies": { - "is-property": "^1.0.2" + "node_modules/lightningcss-linux-x64-gnu": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", + "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "node_modules/lightningcss-linux-x64-musl": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", + "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "ISC", + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": "6.* || 8.* || >= 10.*" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-east-asian-width": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.5.0.tgz", - "integrity": "sha512-CQ+bEO+Tva/qlmw24dCejulK5pMzVnUOFOijVogd3KQs07HnRIgp8TGipvCCRT06xeYEbpbgwaCxglFyiuIcmA==", + "node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", + "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=18" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-nonce": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/get-nonce/-/get-nonce-1.0.1.tgz", - "integrity": "sha512-FJhYRoDaiatfEkUK8HKlicmu/3SGFD51q3itKDGoSTysQJBnfOcxU5GxnhE1E6soB76MbT0MBtnKJuXyAx+96Q==", - "license": "MIT", + "node_modules/lightningcss-win32-x64-msvc": { + "version": "1.32.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", + "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/get-port-please": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/get-port-please/-/get-port-please-3.2.0.tgz", - "integrity": "sha512-I9QVvBw5U/hw3RmWpYKRumUeaDgxTPd401x364rLmWBJcOQ753eov1eTgzDqRG9bqFIfDc7gfzcQEWrUri3o1A==", + "node_modules/lodash": { + "version": "4.18.1", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", + "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", "license": "MIT" }, - "node_modules/giget": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/giget/-/giget-3.3.1.tgz", - "integrity": "sha512-r+mvuDjrjMpsdw46Kmeydb8bdHm7wOKw8wNBtTndkjbPjgAp5oUJUxRE76wZFknxIPokfWvep2qSXK37aXE6zg==", - "license": "MIT", - "bin": { - "giget": "dist/cli.mjs" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.11", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", - "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", - "license": "ISC" - }, - "node_modules/grammex": { - "version": "3.1.13", - "resolved": "https://registry.npmjs.org/grammex/-/grammex-3.1.13.tgz", - "integrity": "sha512-LnPnhOBLEJEVKS8WFDVaA397L9Kq55Q9oSITJiVLHVdhAclfUkWzQv74KhvZHKL2Q09Pb1XdsrOsZ4LfTFFTEg==", - "license": "MIT" + "node_modules/long": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", + "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", + "license": "Apache-2.0" }, - "node_modules/graphmatch": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/graphmatch/-/graphmatch-1.1.1.tgz", - "integrity": "sha512-5ykVn/EXM1hF0XCaWh05VbYvEiOL2lY1kBxZtaYsyvjp7cmWOU1XsAdfQBwClraEofXDT197lFbXOEVMHpvQOg==", - "license": "MIT" + "node_modules/lru-cache": { + "version": "11.5.2", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", + "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", + "devOptional": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } }, - "node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, + "node_modules/lru.min": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz", + "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==", "license": "MIT", "engines": { - "node": ">=8" + "bun": ">=1.0.0", + "deno": ">=1.30.0", + "node": ">=8.0.0" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wellwelwel" } }, - "node_modules/hono": { - "version": "4.13.1", - "resolved": "https://registry.npmjs.org/hono/-/hono-4.13.1.tgz", - "integrity": "sha512-kdJoFVv2xmayw6cY09H7AbMJMt8Jn5jdlEdXsP7AGBdF2DIptVlKlOLKXP41yPip4/a3yQPv9gVcJYI8YY04dw==", + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", "license": "MIT", - "engines": { - "node": ">=16.9.0" + "bin": { + "lz-string": "bin/bin.js" } }, - "node_modules/html-encoding-sniffer": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", - "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "node_modules/magic-string": { + "version": "0.30.21", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", + "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.5" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", "devOptional": true, - "license": "MIT", + "license": "CC0-1.0" + }, + "node_modules/minimatch": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", + "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "dev": true, + "license": "ISC", "dependencies": { - "@exodus/bytes": "^1.6.0" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "node": ">=10" } }, - "node_modules/https-proxy-agent": { - "version": "7.0.6", - "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.6.tgz", - "integrity": "sha512-vK9P5/iUfdl95AI+JVyUuIcVtd4ofvtrOr3HNtM2yxC9bnMbEdp3x01OhQNnjb8IJYi38VlTE3mBXwcfvywuSw==", + "node_modules/minipass": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", + "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", "dev": true, - "license": "MIT", - "dependencies": { - "agent-base": "^7.1.2", - "debug": "4" - }, + "license": "BlueOak-1.0.0", "engines": { - "node": ">= 14" + "node": ">=16 || 14 >=14.17" } }, - "node_modules/iconv-lite": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.7.2.tgz", - "integrity": "sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw==", + "node_modules/minizlib": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", + "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", + "dev": true, "license": "MIT", "dependencies": { - "safer-buffer": ">= 2.1.2 < 3.0.0" + "minipass": "^7.1.2" }, "engines": { - "node": ">=0.10.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/express" + "node": ">= 18" } }, - "node_modules/index-to-position": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/index-to-position/-/index-to-position-1.2.0.tgz", - "integrity": "sha512-Yg7+ztRkqslMAS2iFaU+Oa4KTSidr63OsFGlOrJoW981kIYO3CGCS3wA95P1mUi/IVSJkn0D479KTJpVpvFNuw==", - "dev": true, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "node": ">=10" } }, - "node_modules/internmap": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/internmap/-/internmap-2.0.3.tgz", - "integrity": "sha512-5Hh7Y1wQbvY5ooGgPbDaL5iYLAPzMTUrjMulskHLH6wnv/A+1q5rgEaiuqEjB+oxGXIVZs1FF+R/KPN3ZSQYYg==", - "license": "ISC", - "engines": { - "node": ">=12" + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/mustache": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", + "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", + "dev": true, + "license": "MIT", + "bin": { + "mustache": "bin/mustache" } }, - "node_modules/is-fullwidth-code-point": { + "node_modules/mute-stream": { "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", + "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">=8" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/is-potential-custom-element-name": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", - "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/is-property": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", - "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==", - "license": "MIT" - }, - "node_modules/is-safe-filename": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/is-safe-filename/-/is-safe-filename-0.1.1.tgz", - "integrity": "sha512-4SrR7AdnY11LHfDKTZY1u6Ga3RuxZdl3YKWWShO5iyuG5h8QS4GD2tOb04peBJ5I7pXbR+CGBNEhTcwK+FzN3g==", - "dev": true, + "node_modules/mysql2": { + "version": "3.15.3", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz", + "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==", "license": "MIT", - "engines": { - "node": ">=20" + "dependencies": { + "aws-ssl-profiles": "^1.1.1", + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.7.0", + "long": "^5.2.1", + "lru.min": "^1.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">= 8.0" } }, - "node_modules/is-unicode-supported": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", - "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", - "dev": true, + "node_modules/named-placeholders": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", + "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", "license": "MIT", - "engines": { - "node": ">=18" + "dependencies": { + "lru.min": "^1.1.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=8.0.0" } }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "license": "ISC" - }, - "node_modules/jiti": { - "version": "2.7.0", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.7.0.tgz", - "integrity": "sha512-AC/7JofJvZGrrneWNaEnJeOLUx+JlGt7tNa0wZiRPT4MY1wmfKjt2+6O2p2uz2+skll8OZZmJMNqeke7kKbNgQ==", + "node_modules/nanoid": { + "version": "3.3.18", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", + "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "bin": { - "jiti": "lib/jiti-cli.mjs" + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/js-levenshtein": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", - "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", - "dev": true, + "node_modules/next": { + "version": "16.3.0", + "resolved": "https://registry.npmjs.org/next/-/next-16.3.0.tgz", + "integrity": "sha512-NEdGOzH+08eTXMUp9UYkA99Nhi5N6Thrhc1jgFOQgfgnGK/dA2hRwBpXep+exdFQrnwlRf/3Wixyp8lLBUpE2A==", "license": "MIT", + "dependencies": { + "@next/env": "16.3.0", + "@swc/helpers": "0.5.15", + "baseline-browser-mapping": "^2.9.19", + "caniuse-lite": "^1.0.30001579", + "postcss": "8.5.23", + "styled-jsx": "5.1.6" + }, + "bin": { + "next": "dist/bin/next" + }, "engines": { - "node": ">=0.10.0" + "node": ">=20.9.0" + }, + "optionalDependencies": { + "@next/swc-darwin-arm64": "16.3.0", + "@next/swc-darwin-x64": "16.3.0", + "@next/swc-linux-arm64-gnu": "16.3.0", + "@next/swc-linux-arm64-musl": "16.3.0", + "@next/swc-linux-x64-gnu": "16.3.0", + "@next/swc-linux-x64-musl": "16.3.0", + "@next/swc-win32-arm64-msvc": "16.3.0", + "@next/swc-win32-x64-msvc": "16.3.0", + "sharp": "^0.35.3" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.1.0", + "@playwright/test": "^1.51.1", + "babel-plugin-react-compiler": "*", + "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", + "sass": "^1.3.0" + }, + "peerDependenciesMeta": { + "@opentelemetry/api": { + "optional": true + }, + "@playwright/test": { + "optional": true + }, + "babel-plugin-react-compiler": { + "optional": true + }, + "sass": { + "optional": true + } } }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "license": "MIT" - }, - "node_modules/js-yaml": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.3.1.tgz", - "integrity": "sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==", - "dev": true, + "node_modules/next/node_modules/postcss": { + "version": "8.5.23", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", + "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", "funding": [ { - "type": "github", - "url": "https://github.com/sponsors/puzrin" + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" }, { "type": "github", - "url": "https://github.com/sponsors/nodeca" + "url": "https://github.com/sponsors/ai" } ], "license": "MIT", "dependencies": { - "argparse": "^2.0.1" + "nanoid": "^3.3.16", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": "^10 || ^12 || >=14" } }, - "node_modules/jsdom": { - "version": "30.0.1", - "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-30.0.1.tgz", - "integrity": "sha512-52v7mUVUfNQVYYqE1lcdaymWL0njO7lTLUog6ZvW2U5KsbiLk/GnZlVJ+qx0xfNJZ6Gn+KSpPNE52vurbxZwrA==", - "devOptional": true, + "node_modules/node-releases": { + "version": "2.0.54", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.54.tgz", + "integrity": "sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==", + "dev": true, "license": "MIT", - "dependencies": { - "@asamuzakjp/css-color": "^6.0.5", - "@asamuzakjp/dom-selector": "^8.3.0", - "@bramus/specificity": "^2.4.2", - "@csstools/css-syntax-patches-for-csstree": "^1.1.7", - "@exodus/bytes": "^1.15.1", - "css-tree": "^3.2.1", - "data-urls": "^7.0.0", - "decimal.js": "^10.6.0", - "html-encoding-sniffer": "^6.0.0", - "is-potential-custom-element-name": "^1.0.1", - "lru-cache": "^11.5.2", - "parse5": "^8.0.1", - "saxes": "^6.0.0", - "symbol-tree": "^3.2.4", - "tough-cookie": "^6.0.2", - "undici": "^8.9.0", - "w3c-xmlserializer": "^5.0.0", - "webidl-conversions": "^8.0.1", - "whatwg-mimetype": "^5.0.0", - "whatwg-url": "^17.1.0", - "xml-name-validator": "^5.0.0" - }, "engines": { - "node": "^22.22.2 || ^24.15.0 || >=26.0.0" - }, - "peerDependencies": { - "canvas": "^3.2.3" - }, - "peerDependenciesMeta": { - "canvas": { - "optional": true - } + "node": ">=18" } }, - "node_modules/jsdom/node_modules/whatwg-url": { - "version": "17.1.0", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-17.1.0.tgz", - "integrity": "sha512-3GeworPmc2ZfEEHP7lEbUfBX/L75wdEsi0rLNhXcXxnoN5jyq0SL5gCy06SGW2cyTIZdTvWIDQNQoza++vKeaw==", - "devOptional": true, + "node_modules/obug": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", + "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", + "funding": [ + "https://github.com/sponsors/sxzz", + "https://opencollective.com/debug" + ], "license": "MIT", - "dependencies": { - "@exodus/bytes": "^1.15.1", - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.1" - }, "engines": { - "node": "^22.14.0 || >=24.0.0" + "node": ">=12.20.0" } }, - "node_modules/json-schema-traverse": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", - "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "node_modules/ohash": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", + "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", "license": "MIT" }, - "node_modules/jsonpointer": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/jsonpointer/-/jsonpointer-5.0.1.tgz", - "integrity": "sha512-p/nXbhSEcu3pZRdkW1OfJhpsVtW1gd4Wa1fnQc9YLiTfAjn0312eMKimbdIQzuZl9aa9xUGaRlP9T/CJE/ditQ==", + "node_modules/openapi-typescript": { + "version": "7.13.0", + "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.13.0.tgz", + "integrity": "sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "@redocly/openapi-core": "^1.34.6", + "ansi-colors": "^4.1.3", + "change-case": "^5.4.4", + "parse-json": "^8.3.0", + "supports-color": "^10.2.2", + "yargs-parser": "^21.1.1" + }, + "bin": { + "openapi-typescript": "bin/cli.js" + }, + "peerDependencies": { + "typescript": "^5.x" } }, - "node_modules/leven": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/leven/-/leven-4.1.0.tgz", - "integrity": "sha512-KZ9W9nWDT7rF7Dazg8xyLHGLrmpgq2nVNFUckhqdW3szVP6YhCpp/RAnpmVExA9JvrMynjwSLVrEj3AepHR6ew==", + "node_modules/openapi-typescript/node_modules/supports-color": { + "version": "10.2.2", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", + "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", "dev": true, "license": "MIT", "engines": { - "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + "node": ">=18" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/lightningcss": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.32.0.tgz", - "integrity": "sha512-NXYBzinNrblfraPGyrbPoD19C1h9lfI/1mzgWYvXUTe414Gz/X1FD2XBZSZM7rRTrMA8JL3OtAaGifrIKhQ5yQ==", - "dev": true, - "license": "MPL-2.0", + "node_modules/oxfmt": { + "version": "0.62.0", + "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.62.0.tgz", + "integrity": "sha512-vxgGHTmnDU9j4CX7dDBLzxgmHxfda/yPcgJkGCMUSCwRmz+euo/V08xXLNgXTeqAB9Fhf3Pe2nO1RNKLCVgphQ==", + "license": "MIT", "dependencies": { - "detect-libc": "^2.0.3" + "tinypool": "2.1.0" + }, + "bin": { + "oxfmt": "bin/oxfmt" }, "engines": { - "node": ">= 12.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/Boshen" }, "optionalDependencies": { - "lightningcss-android-arm64": "1.32.0", - "lightningcss-darwin-arm64": "1.32.0", - "lightningcss-darwin-x64": "1.32.0", - "lightningcss-freebsd-x64": "1.32.0", - "lightningcss-linux-arm-gnueabihf": "1.32.0", - "lightningcss-linux-arm64-gnu": "1.32.0", - "lightningcss-linux-arm64-musl": "1.32.0", - "lightningcss-linux-x64-gnu": "1.32.0", - "lightningcss-linux-x64-musl": "1.32.0", - "lightningcss-win32-arm64-msvc": "1.32.0", - "lightningcss-win32-x64-msvc": "1.32.0" - } - }, - "node_modules/lightningcss-android-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.32.0.tgz", - "integrity": "sha512-YK7/ClTt4kAK0vo6w3X+Pnm0D2cf2vPHbhOXdoNti1Ga0al1P4TBZhwjATvjNwLEBCnKvjJc2jQgHXH0NEwlAg==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "android" - ], - "engines": { - "node": ">= 12.0.0" + "@oxfmt/binding-android-arm-eabi": "0.62.0", + "@oxfmt/binding-android-arm64": "0.62.0", + "@oxfmt/binding-darwin-arm64": "0.62.0", + "@oxfmt/binding-darwin-x64": "0.62.0", + "@oxfmt/binding-freebsd-x64": "0.62.0", + "@oxfmt/binding-linux-arm-gnueabihf": "0.62.0", + "@oxfmt/binding-linux-arm-musleabihf": "0.62.0", + "@oxfmt/binding-linux-arm64-gnu": "0.62.0", + "@oxfmt/binding-linux-arm64-musl": "0.62.0", + "@oxfmt/binding-linux-ppc64-gnu": "0.62.0", + "@oxfmt/binding-linux-riscv64-gnu": "0.62.0", + "@oxfmt/binding-linux-riscv64-musl": "0.62.0", + "@oxfmt/binding-linux-s390x-gnu": "0.62.0", + "@oxfmt/binding-linux-x64-gnu": "0.62.0", + "@oxfmt/binding-linux-x64-musl": "0.62.0", + "@oxfmt/binding-openharmony-arm64": "0.62.0", + "@oxfmt/binding-win32-arm64-msvc": "0.62.0", + "@oxfmt/binding-win32-ia32-msvc": "0.62.0", + "@oxfmt/binding-win32-x64-msvc": "0.62.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependencies": { + "svelte": "^5.0.0", + "vite-plus": "*" + }, + "peerDependenciesMeta": { + "svelte": { + "optional": true + }, + "vite-plus": { + "optional": true + } } }, - "node_modules/lightningcss-darwin-arm64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.32.0.tgz", - "integrity": "sha512-RzeG9Ju5bag2Bv1/lwlVJvBE3q6TtXskdZLLCyfg5pt+HLz9BqlICO7LZM7VHNTTn/5PRhHFBSjk5lc4cmscPQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], + "node_modules/oxlint": { + "version": "1.77.0", + "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.77.0.tgz", + "integrity": "sha512-qnGh8XJHaQ0dprrDXNQZgS0FgjI6v+V3+X8DwmaV++5Aamy6jGKfDdQ1TUvhUxtmKFAbEf4/WeO5QZX+5WSngg==", + "license": "MIT", + "bin": { + "oxlint": "bin/oxlint" + }, "engines": { - "node": ">= 12.0.0" + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-darwin-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.32.0.tgz", - "integrity": "sha512-U+QsBp2m/s2wqpUYT/6wnlagdZbtZdndSmut/NJqlCcMLTWp5muCrID+K5UJ6jqD2BFshejCYXniPDbNh73V8w==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "darwin" - ], - "engines": { - "node": ">= 12.0.0" + "url": "https://github.com/sponsors/Boshen" + }, + "optionalDependencies": { + "@oxlint/binding-android-arm-eabi": "1.77.0", + "@oxlint/binding-android-arm64": "1.77.0", + "@oxlint/binding-darwin-arm64": "1.77.0", + "@oxlint/binding-darwin-x64": "1.77.0", + "@oxlint/binding-freebsd-x64": "1.77.0", + "@oxlint/binding-linux-arm-gnueabihf": "1.77.0", + "@oxlint/binding-linux-arm-musleabihf": "1.77.0", + "@oxlint/binding-linux-arm64-gnu": "1.77.0", + "@oxlint/binding-linux-arm64-musl": "1.77.0", + "@oxlint/binding-linux-ppc64-gnu": "1.77.0", + "@oxlint/binding-linux-riscv64-gnu": "1.77.0", + "@oxlint/binding-linux-riscv64-musl": "1.77.0", + "@oxlint/binding-linux-s390x-gnu": "1.77.0", + "@oxlint/binding-linux-x64-gnu": "1.77.0", + "@oxlint/binding-linux-x64-musl": "1.77.0", + "@oxlint/binding-openharmony-arm64": "1.77.0", + "@oxlint/binding-win32-arm64-msvc": "1.77.0", + "@oxlint/binding-win32-ia32-msvc": "1.77.0", + "@oxlint/binding-win32-x64-msvc": "1.77.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" - } - }, - "node_modules/lightningcss-freebsd-x64": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.32.0.tgz", - "integrity": "sha512-JCTigedEksZk3tHTTthnMdVfGf61Fky8Ji2E4YjUTEQX14xiy/lTzXnu1vwiZe3bYe0q+SpsSH/CTeDXK6WHig==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "freebsd" - ], - "engines": { - "node": ">= 12.0.0" + "peerDependencies": { + "oxlint-tsgolint": ">=7.0.2001", + "vite-plus": "*" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "peerDependenciesMeta": { + "oxlint-tsgolint": { + "optional": true + }, + "vite-plus": { + "optional": true + } } }, - "node_modules/lightningcss-linux-arm-gnueabihf": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.32.0.tgz", - "integrity": "sha512-x6rnnpRa2GL0zQOkt6rts3YDPzduLpWvwAF6EMhXFVZXD4tPrBkEFqzGowzCsIWsPjqSK+tyNEODUBXeeVHSkw==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" + "node_modules/oxlint-tsgolint": { + "version": "7.0.2001", + "resolved": "https://registry.npmjs.org/oxlint-tsgolint/-/oxlint-tsgolint-7.0.2001.tgz", + "integrity": "sha512-KjK/XLcXr1DSyonKhsuFqJRiuKqcyG9j3LJ8nkOsrLzGvodBPqzHOKauy10asLMDI0sUpvb+1sxlzff3udZvfg==", + "license": "MIT", + "bin": { + "tsgolint": "bin/tsgolint.js" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "optionalDependencies": { + "@oxlint-tsgolint/darwin-arm64": "7.0.2001", + "@oxlint-tsgolint/darwin-x64": "7.0.2001", + "@oxlint-tsgolint/linux-arm64": "7.0.2001", + "@oxlint-tsgolint/linux-x64": "7.0.2001", + "@oxlint-tsgolint/win32-arm64": "7.0.2001", + "@oxlint-tsgolint/win32-x64": "7.0.2001" } }, - "node_modules/lightningcss-linux-arm64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.32.0.tgz", - "integrity": "sha512-0nnMyoyOLRJXfbMOilaSRcLH3Jw5z9HDNGfT/gwCPgaDjnx0i8w7vBzFLFR1f6CMLKF8gVbebmkUN3fa/kQJpQ==", - "cpu": [ - "arm64" - ], + "node_modules/p-map": { + "version": "7.0.7", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-7.0.7.tgz", + "integrity": "sha512-VaWRu2i4FJNRtiRWCuuQRgfQ1B7a6+gMSrO+3j0EQi/k0ULfS9kosRxGoiqwzIjZTDI02tGfk5mXXltLg6QtfQ==", "dev": true, - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", "engines": { - "node": ">= 12.0.0" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-linux-arm64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.32.0.tgz", - "integrity": "sha512-UpQkoenr4UJEzgVIYpI80lDFvRmPVg6oqboNHfoH4CQIfNA+HOrZ7Mo7KZP02dC6LjghPQJeBsvXhJod/wnIBg==", - "cpu": [ - "arm64" - ], + "node_modules/parse-json": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", + "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", "dev": true, - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.26.2", + "index-to-position": "^1.1.0", + "type-fest": "^4.39.1" + }, "engines": { - "node": ">= 12.0.0" + "node": ">=18" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/lightningcss-linux-x64-gnu": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.32.0.tgz", - "integrity": "sha512-V7Qr52IhZmdKPVr+Vtw8o+WLsQJYCTd8loIfpDaMRWGUZfBOYEJeyJIkqGIDMZPwPx24pUMfwSxxI8phr/MbOA==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], - "engines": { - "node": ">= 12.0.0" + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "url": "https://github.com/inikulin/parse5?sponsor=1" } }, - "node_modules/lightningcss-linux-x64-musl": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.32.0.tgz", - "integrity": "sha512-bYcLp+Vb0awsiXg/80uCRezCYHNg1/l3mt0gzHnWV9XP1W5sKa5/TCdGWaR/zBM2PeF/HbsQv/j2URNOiVuxWg==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MPL-2.0", - "optional": true, - "os": [ - "linux" - ], + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "license": "MIT", "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">=8" } }, - "node_modules/lightningcss-win32-arm64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.32.0.tgz", - "integrity": "sha512-8SbC8BR40pS6baCM8sbtYDSwEVQd4JlFTOlaD3gWGHfThTcABnNDBda6eTZeqbofalIJhFx0qKzgHJmcPTnGdw==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], + "node_modules/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "license": "MIT" + }, + "node_modules/perfect-debounce": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", + "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", + "license": "MIT" + }, + "node_modules/pg": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", + "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", + "license": "MIT", + "dependencies": { + "pg-connection-string": "^2.12.0", + "pg-pool": "^3.13.0", + "pg-protocol": "^1.13.0", + "pg-types": "2.2.0", + "pgpass": "1.0.5" + }, "engines": { - "node": ">= 12.0.0" + "node": ">= 16.0.0" }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "optionalDependencies": { + "pg-cloudflare": "^1.3.0" + }, + "peerDependencies": { + "pg-native": ">=3.0.1" + }, + "peerDependenciesMeta": { + "pg-native": { + "optional": true + } } }, - "node_modules/lightningcss-win32-x64-msvc": { - "version": "1.32.0", - "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.32.0.tgz", - "integrity": "sha512-Amq9B/SoZYdDi1kFrojnoqPLxYhQ4Wo5XiL8EVJrVsB8ARoC1PWW6VGtT0WKCemjy8aC+louJnjS7U18x3b06Q==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MPL-2.0", - "optional": true, - "os": [ - "win32" - ], + "node_modules/pg-cloudflare": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", + "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", + "license": "MIT", + "optional": true + }, + "node_modules/pg-connection-string": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz", + "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", + "license": "MIT" + }, + "node_modules/pg-int8": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", + "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", + "license": "ISC", "engines": { - "node": ">= 12.0.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/parcel" + "node": ">=4.0.0" } }, - "node_modules/lodash": { - "version": "4.18.1", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.18.1.tgz", - "integrity": "sha512-dMInicTPVE8d1e5otfwmmjlxkZoUpiVLwyeTdUsi/Caj/gfzzblBcCE5sRHV/AsjuCmxWrte2TNGSYuCeCq+0Q==", - "license": "MIT" + "node_modules/pg-pool": { + "version": "3.13.0", + "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", + "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", + "license": "MIT", + "peerDependencies": { + "pg": ">=8.0" + } }, - "node_modules/long": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/long/-/long-5.3.2.tgz", - "integrity": "sha512-mNAgZ1GmyNhD7AuqnTG3/VQ26o760+ZYBPKjPvugO8+nLbYfX6TVpJPseBvopbdY+qpZ/lKUnmEc1LeZYS3QAA==", - "license": "Apache-2.0" + "node_modules/pg-protocol": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", + "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", + "license": "MIT" }, - "node_modules/lru-cache": { - "version": "11.5.2", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.2.tgz", - "integrity": "sha512-4pfM1Ff0x50o0tQwb5ucw/RzNyD0/YJME6IVcStalZuMWxdt3sR3huStTtxz4PUmvZfRguvDejasvQ2kifR11g==", - "devOptional": true, - "license": "BlueOak-1.0.0", + "node_modules/pg-types": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", + "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "license": "MIT", + "dependencies": { + "pg-int8": "1.0.1", + "postgres-array": "~2.0.0", + "postgres-bytea": "~1.0.0", + "postgres-date": "~1.0.4", + "postgres-interval": "^1.1.0" + }, "engines": { - "node": "20 || >=22" + "node": ">=4" } }, - "node_modules/lru.min": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/lru.min/-/lru.min-1.1.4.tgz", - "integrity": "sha512-DqC6n3QQ77zdFpCMASA1a3Jlb64Hv2N2DciFGkO/4L9+q/IpIAuRlKOvCXabtRW6cQf8usbmM6BE/TOPysCdIA==", + "node_modules/pg-types/node_modules/postgres-array": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", + "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", "license": "MIT", "engines": { - "bun": ">=1.0.0", - "deno": ">=1.30.0", - "node": ">=8.0.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/wellwelwel" + "node": ">=4" } }, - "node_modules/lz-string": { - "version": "1.5.0", - "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", - "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "node_modules/pgpass": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", + "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", "license": "MIT", - "bin": { - "lz-string": "bin/bin.js" + "dependencies": { + "split2": "^4.1.0" } }, - "node_modules/magic-string": { - "version": "0.30.21", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.21.tgz", - "integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==", + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.5.5" + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" } }, - "node_modules/mdn-data": { - "version": "2.27.1", - "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", - "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", - "devOptional": true, - "license": "CC0-1.0" + "node_modules/pkg-types": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", + "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", + "license": "MIT", + "dependencies": { + "confbox": "^0.2.4", + "exsolve": "^1.0.8", + "pathe": "^2.0.3" + } }, - "node_modules/minimatch": { - "version": "5.1.9", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.9.tgz", - "integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==", + "node_modules/pluralize": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", + "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, + "license": "MIT", "engines": { - "node": ">=10" + "node": ">=4" } }, - "node_modules/minipass": { - "version": "7.1.3", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.3.tgz", - "integrity": "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A==", - "dev": true, - "license": "BlueOak-1.0.0", + "node_modules/pngjs": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", + "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", + "license": "MIT", "engines": { - "node": ">=16 || 14 >=14.17" + "node": ">=14.19.0" } }, - "node_modules/minizlib": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-3.1.0.tgz", - "integrity": "sha512-KZxYo1BUkWD2TVFLr0MQoM8vUUigWD3LlD83a/75BqC+4qE0Hb1Vo5v1FgcfaNXvfXzr+5EhQ6ing/CaBijTlw==", - "dev": true, + "node_modules/postcss": { + "version": "8.5.26", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", + "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", "dependencies": { - "minipass": "^7.1.2" + "nanoid": "^3.3.17", + "picocolors": "^1.1.1", + "source-map-js": "^1.2.1" }, "engines": { - "node": ">= 18" + "node": "^10 || ^12 || >=14" } }, - "node_modules/mrmime": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", - "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", - "license": "MIT", + "node_modules/postgres": { + "version": "3.4.7", + "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz", + "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==", + "license": "Unlicense", "engines": { - "node": ">=10" + "node": ">=12" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/porsager" } }, - "node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, - "license": "MIT" + "node_modules/postgres-array": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.4.tgz", + "integrity": "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==", + "license": "MIT", + "engines": { + "node": ">=12" + } }, - "node_modules/mustache": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", - "integrity": "sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==", - "dev": true, + "node_modules/postgres-bytea": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", + "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", "license": "MIT", - "bin": { - "mustache": "bin/mustache" + "engines": { + "node": ">=0.10.0" } }, - "node_modules/mute-stream": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-3.0.0.tgz", - "integrity": "sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw==", - "dev": true, - "license": "ISC", + "node_modules/postgres-date": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", + "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", + "license": "MIT", "engines": { - "node": "^20.17.0 || >=22.9.0" + "node": ">=0.10.0" } }, - "node_modules/mysql2": { - "version": "3.15.3", - "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.15.3.tgz", - "integrity": "sha512-FBrGau0IXmuqg4haEZRBfHNWB5mUARw6hNwPDXXGg0XzVJ50mr/9hb267lvpVMnhZ1FON3qNd4Xfcez1rbFwSg==", + "node_modules/postgres-interval": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", + "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", "license": "MIT", "dependencies": { - "aws-ssl-profiles": "^1.1.1", - "denque": "^2.1.0", - "generate-function": "^2.3.1", - "iconv-lite": "^0.7.0", - "long": "^5.2.1", - "lru.min": "^1.0.0", - "named-placeholders": "^1.1.3", - "seq-queue": "^0.0.5", - "sqlstring": "^2.3.2" + "xtend": "^4.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/prettier": { + "version": "3.9.6", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", + "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", + "dev": true, + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" }, "engines": { - "node": ">= 8.0" + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/named-placeholders": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.6.tgz", - "integrity": "sha512-Tz09sEL2EEuv5fFowm419c1+a/jSMiBjI9gHxVLrVdbUkkNUUfjsVYs9pVZu5oCon/kmRh9TfLEObFtkVxmY0w==", + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", "license": "MIT", "dependencies": { - "lru.min": "^1.1.0" + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" }, "engines": { - "node": ">=8.0.0" + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" } }, - "node_modules/nanoid": { - "version": "3.3.18", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.18.tgz", - "integrity": "sha512-DTg4MJbGMWkfi6VZFdNt2/caMbQy4Ou+Op/hJQvGEWcnVfoA1QA+xzRKAzw9jD6+GVOOeYr/mIcuDSdug6F6+w==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/ai" - } - ], + "node_modules/pretty-format/node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", "license": "MIT", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + "node": ">=8" } }, - "node_modules/next": { - "version": "16.3.0", - "resolved": "https://registry.npmjs.org/next/-/next-16.3.0.tgz", - "integrity": "sha512-NEdGOzH+08eTXMUp9UYkA99Nhi5N6Thrhc1jgFOQgfgnGK/dA2hRwBpXep+exdFQrnwlRf/3Wixyp8lLBUpE2A==", + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prisma": { + "version": "7.9.1", + "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.9.1.tgz", + "integrity": "sha512-aPqePoZIqwlAchbgbFDO/wHqGB+7H1nj9gaM+OsL9h77S5S3TnLd9BgD3LnoeDikULo7cl2HSUrEyQ55Z7DYbg==", + "hasInstallScript": true, + "license": "Apache-2.0", "dependencies": { - "@next/env": "16.3.0", - "@swc/helpers": "0.5.15", - "baseline-browser-mapping": "^2.9.19", - "caniuse-lite": "^1.0.30001579", - "postcss": "8.5.23", - "styled-jsx": "5.1.6" + "@prisma/config": "7.9.1", + "@prisma/dev": "0.24.17", + "@prisma/engines": "7.9.1", + "@prisma/studio-core": "0.33.0", + "mysql2": "3.15.3", + "postgres": "3.4.7" }, "bin": { - "next": "dist/bin/next" + "prisma": "build/index.js" }, "engines": { - "node": ">=20.9.0" - }, - "optionalDependencies": { - "@next/swc-darwin-arm64": "16.3.0", - "@next/swc-darwin-x64": "16.3.0", - "@next/swc-linux-arm64-gnu": "16.3.0", - "@next/swc-linux-arm64-musl": "16.3.0", - "@next/swc-linux-x64-gnu": "16.3.0", - "@next/swc-linux-x64-musl": "16.3.0", - "@next/swc-win32-arm64-msvc": "16.3.0", - "@next/swc-win32-x64-msvc": "16.3.0", - "sharp": "^0.35.3" + "node": "^20.19 || ^22.12 || >=24.0" }, "peerDependencies": { - "@opentelemetry/api": "^1.1.0", - "@playwright/test": "^1.51.1", - "babel-plugin-react-compiler": "*", - "react": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "react-dom": "^18.2.0 || 19.0.0-rc-de68d2f4-20241204 || ^19.0.0", - "sass": "^1.3.0" + "better-sqlite3": ">=9.0.0", + "typescript": ">=5.4.0" }, "peerDependenciesMeta": { - "@opentelemetry/api": { - "optional": true - }, - "@playwright/test": { - "optional": true - }, - "babel-plugin-react-compiler": { + "better-sqlite3": { "optional": true }, - "sass": { + "typescript": { "optional": true } } }, - "node_modules/next/node_modules/postcss": { - "version": "8.5.23", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.23.tgz", - "integrity": "sha512-g50586zr4bZmwFiTlflMu8E0bDTb5I5gertgwAKmsdUlTQIhZtunzUlD1WSzwcVWPoAVpsrA6vlfCD7oXvRwgg==", + "node_modules/proper-lockfile": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", + "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.4", + "retry": "^0.12.0", + "signal-exit": "^3.0.2" + } + }, + "node_modules/proper-lockfile/node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, + "node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", + "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" }, { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "opencollective", + "url": "https://opencollective.com/fast-check" } ], + "license": "MIT" + }, + "node_modules/radix-ui": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz", + "integrity": "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==", "license": "MIT", "dependencies": { - "nanoid": "^3.3.16", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" + "@radix-ui/primitive": "1.1.3", + "@radix-ui/react-accessible-icon": "1.1.7", + "@radix-ui/react-accordion": "1.2.12", + "@radix-ui/react-alert-dialog": "1.1.15", + "@radix-ui/react-arrow": "1.1.7", + "@radix-ui/react-aspect-ratio": "1.1.7", + "@radix-ui/react-avatar": "1.1.10", + "@radix-ui/react-checkbox": "1.3.3", + "@radix-ui/react-collapsible": "1.1.12", + "@radix-ui/react-collection": "1.1.7", + "@radix-ui/react-compose-refs": "1.1.2", + "@radix-ui/react-context": "1.1.2", + "@radix-ui/react-context-menu": "2.2.16", + "@radix-ui/react-dialog": "1.1.15", + "@radix-ui/react-direction": "1.1.1", + "@radix-ui/react-dismissable-layer": "1.1.11", + "@radix-ui/react-dropdown-menu": "2.1.16", + "@radix-ui/react-focus-guards": "1.1.3", + "@radix-ui/react-focus-scope": "1.1.7", + "@radix-ui/react-form": "0.1.8", + "@radix-ui/react-hover-card": "1.1.15", + "@radix-ui/react-label": "2.1.7", + "@radix-ui/react-menu": "2.1.16", + "@radix-ui/react-menubar": "1.1.16", + "@radix-ui/react-navigation-menu": "1.2.14", + "@radix-ui/react-one-time-password-field": "0.1.8", + "@radix-ui/react-password-toggle-field": "0.1.3", + "@radix-ui/react-popover": "1.1.15", + "@radix-ui/react-popper": "1.2.8", + "@radix-ui/react-portal": "1.1.9", + "@radix-ui/react-presence": "1.1.5", + "@radix-ui/react-primitive": "2.1.3", + "@radix-ui/react-progress": "1.1.7", + "@radix-ui/react-radio-group": "1.3.8", + "@radix-ui/react-roving-focus": "1.1.11", + "@radix-ui/react-scroll-area": "1.2.10", + "@radix-ui/react-select": "2.2.6", + "@radix-ui/react-separator": "1.1.7", + "@radix-ui/react-slider": "1.3.6", + "@radix-ui/react-slot": "1.2.3", + "@radix-ui/react-switch": "1.2.6", + "@radix-ui/react-tabs": "1.1.13", + "@radix-ui/react-toast": "1.2.15", + "@radix-ui/react-toggle": "1.1.10", + "@radix-ui/react-toggle-group": "1.1.11", + "@radix-ui/react-toolbar": "1.1.11", + "@radix-ui/react-tooltip": "1.2.8", + "@radix-ui/react-use-callback-ref": "1.1.1", + "@radix-ui/react-use-controllable-state": "1.2.2", + "@radix-ui/react-use-effect-event": "0.0.2", + "@radix-ui/react-use-escape-keydown": "1.1.1", + "@radix-ui/react-use-is-hydrated": "0.1.0", + "@radix-ui/react-use-layout-effect": "1.1.1", + "@radix-ui/react-use-size": "1.1.1", + "@radix-ui/react-visually-hidden": "1.2.3" }, - "engines": { - "node": "^10 || ^12 || >=14" + "peerDependencies": { + "@types/react": "*", + "@types/react-dom": "*", + "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", + "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } } }, - "node_modules/obug": { - "version": "2.1.4", - "resolved": "https://registry.npmjs.org/obug/-/obug-2.1.4.tgz", - "integrity": "sha512-4a+OsYv9UktOJKE+l1A4OufDgdRF9PifWj+tJnHURo/P+WOxpG4GzUFL9qCalmWauao6ogiG+QvnCovwPoyAWA==", - "funding": [ - "https://github.com/sponsors/sxzz", - "https://opencollective.com/debug" - ], + "node_modules/rc9": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz", + "integrity": "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==", + "license": "MIT", + "dependencies": { + "defu": "^6.1.6", + "destr": "^2.0.5" + } + }, + "node_modules/react": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", + "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", "license": "MIT", "engines": { - "node": ">=12.20.0" + "node": ">=0.10.0" } }, - "node_modules/ohash": { - "version": "2.0.11", - "resolved": "https://registry.npmjs.org/ohash/-/ohash-2.0.11.tgz", - "integrity": "sha512-RdR9FQrFwNBNXAr4GixM8YaRZRJ5PUWbKYbE5eOsrwAjJW0q2REGcf79oYPsLyskQCZG1PLN+S/K1V00joZAoQ==", - "license": "MIT" - }, - "node_modules/openapi-typescript": { - "version": "7.13.0", - "resolved": "https://registry.npmjs.org/openapi-typescript/-/openapi-typescript-7.13.0.tgz", - "integrity": "sha512-EFP392gcqXS7ntPvbhBzbF8TyBA+baIYEm791Hy5YkjDYKTnk/Tn5OQeKm5BIZvJihpp8Zzr4hzx0Irde1LNGQ==", - "dev": true, + "node_modules/react-dom": { + "version": "19.2.8", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", + "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", "license": "MIT", "dependencies": { - "@redocly/openapi-core": "^1.34.6", - "ansi-colors": "^4.1.3", - "change-case": "^5.4.4", - "parse-json": "^8.3.0", - "supports-color": "^10.2.2", - "yargs-parser": "^21.1.1" - }, - "bin": { - "openapi-typescript": "bin/cli.js" + "scheduler": "^0.27.0" }, "peerDependencies": { - "typescript": "^5.x" + "react": "^19.2.8" } }, - "node_modules/openapi-typescript/node_modules/supports-color": { - "version": "10.2.2", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-10.2.2.tgz", - "integrity": "sha512-SS+jx45GF1QjgEXQx4NJZV9ImqmO2NPz5FNsIHrsDjh2YsHnawpan7SNQ1o8NuhrbHZy9AZhIoCUiCeaW/C80g==", + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.14.2", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.14.2.tgz", + "integrity": "sha512-jCvmsr+1IUSMUyzOkRcvnVbX3ZYC6g9TDrDbFuFmRDq7PD4yaGbLKNQL6k2jnArV8hjYxh7hVhAZB6s9HDGpZA==", "dev": true, "license": "MIT", "engines": { - "node": ">=18" - }, - "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "node": ">=0.10.0" } }, - "node_modules/oxfmt": { - "version": "0.62.0", - "resolved": "https://registry.npmjs.org/oxfmt/-/oxfmt-0.62.0.tgz", - "integrity": "sha512-vxgGHTmnDU9j4CX7dDBLzxgmHxfda/yPcgJkGCMUSCwRmz+euo/V08xXLNgXTeqAB9Fhf3Pe2nO1RNKLCVgphQ==", + "node_modules/react-remove-scroll": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", + "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", "license": "MIT", "dependencies": { - "tinypool": "2.1.0" - }, - "bin": { - "oxfmt": "bin/oxfmt" + "react-remove-scroll-bar": "^2.3.7", + "react-style-singleton": "^2.2.3", + "tslib": "^2.1.0", + "use-callback-ref": "^1.3.3", + "use-sidecar": "^1.1.3" }, "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/Boshen" - }, - "optionalDependencies": { - "@oxfmt/binding-android-arm-eabi": "0.62.0", - "@oxfmt/binding-android-arm64": "0.62.0", - "@oxfmt/binding-darwin-arm64": "0.62.0", - "@oxfmt/binding-darwin-x64": "0.62.0", - "@oxfmt/binding-freebsd-x64": "0.62.0", - "@oxfmt/binding-linux-arm-gnueabihf": "0.62.0", - "@oxfmt/binding-linux-arm-musleabihf": "0.62.0", - "@oxfmt/binding-linux-arm64-gnu": "0.62.0", - "@oxfmt/binding-linux-arm64-musl": "0.62.0", - "@oxfmt/binding-linux-ppc64-gnu": "0.62.0", - "@oxfmt/binding-linux-riscv64-gnu": "0.62.0", - "@oxfmt/binding-linux-riscv64-musl": "0.62.0", - "@oxfmt/binding-linux-s390x-gnu": "0.62.0", - "@oxfmt/binding-linux-x64-gnu": "0.62.0", - "@oxfmt/binding-linux-x64-musl": "0.62.0", - "@oxfmt/binding-openharmony-arm64": "0.62.0", - "@oxfmt/binding-win32-arm64-msvc": "0.62.0", - "@oxfmt/binding-win32-ia32-msvc": "0.62.0", - "@oxfmt/binding-win32-x64-msvc": "0.62.0" + "node": ">=10" }, "peerDependencies": { - "svelte": "^5.0.0", - "vite-plus": "*" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { - "svelte": { - "optional": true - }, - "vite-plus": { + "@types/react": { "optional": true } } }, - "node_modules/oxlint": { - "version": "1.77.0", - "resolved": "https://registry.npmjs.org/oxlint/-/oxlint-1.77.0.tgz", - "integrity": "sha512-qnGh8XJHaQ0dprrDXNQZgS0FgjI6v+V3+X8DwmaV++5Aamy6jGKfDdQ1TUvhUxtmKFAbEf4/WeO5QZX+5WSngg==", + "node_modules/react-remove-scroll-bar": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", + "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", "license": "MIT", - "bin": { - "oxlint": "bin/oxlint" + "dependencies": { + "react-style-singleton": "^2.2.2", + "tslib": "^2.0.0" }, "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "funding": { - "url": "https://github.com/sponsors/Boshen" - }, - "optionalDependencies": { - "@oxlint/binding-android-arm-eabi": "1.77.0", - "@oxlint/binding-android-arm64": "1.77.0", - "@oxlint/binding-darwin-arm64": "1.77.0", - "@oxlint/binding-darwin-x64": "1.77.0", - "@oxlint/binding-freebsd-x64": "1.77.0", - "@oxlint/binding-linux-arm-gnueabihf": "1.77.0", - "@oxlint/binding-linux-arm-musleabihf": "1.77.0", - "@oxlint/binding-linux-arm64-gnu": "1.77.0", - "@oxlint/binding-linux-arm64-musl": "1.77.0", - "@oxlint/binding-linux-ppc64-gnu": "1.77.0", - "@oxlint/binding-linux-riscv64-gnu": "1.77.0", - "@oxlint/binding-linux-riscv64-musl": "1.77.0", - "@oxlint/binding-linux-s390x-gnu": "1.77.0", - "@oxlint/binding-linux-x64-gnu": "1.77.0", - "@oxlint/binding-linux-x64-musl": "1.77.0", - "@oxlint/binding-openharmony-arm64": "1.77.0", - "@oxlint/binding-win32-arm64-msvc": "1.77.0", - "@oxlint/binding-win32-ia32-msvc": "1.77.0", - "@oxlint/binding-win32-x64-msvc": "1.77.0" + "node": ">=10" }, "peerDependencies": { - "oxlint-tsgolint": ">=7.0.2001", - "vite-plus": "*" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" }, "peerDependenciesMeta": { - "oxlint-tsgolint": { - "optional": true - }, - "vite-plus": { + "@types/react": { "optional": true } } }, - "node_modules/oxlint-tsgolint": { - "version": "7.0.2001", - "resolved": "https://registry.npmjs.org/oxlint-tsgolint/-/oxlint-tsgolint-7.0.2001.tgz", - "integrity": "sha512-KjK/XLcXr1DSyonKhsuFqJRiuKqcyG9j3LJ8nkOsrLzGvodBPqzHOKauy10asLMDI0sUpvb+1sxlzff3udZvfg==", - "license": "MIT", - "bin": { - "tsgolint": "bin/tsgolint.js" - }, - "optionalDependencies": { - "@oxlint-tsgolint/darwin-arm64": "7.0.2001", - "@oxlint-tsgolint/darwin-x64": "7.0.2001", - "@oxlint-tsgolint/linux-arm64": "7.0.2001", - "@oxlint-tsgolint/linux-x64": "7.0.2001", - "@oxlint-tsgolint/win32-arm64": "7.0.2001", - "@oxlint-tsgolint/win32-x64": "7.0.2001" - } - }, - "node_modules/parse-json": { - "version": "8.3.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-8.3.0.tgz", - "integrity": "sha512-ybiGyvspI+fAoRQbIPRddCcSTV9/LsJbf0e/S85VLowVGzRmokfneg2kwVW/KU5rOXrPSbF1qAKPMgNTqqROQQ==", - "dev": true, + "node_modules/react-router": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.18.3.tgz", + "integrity": "sha512-gyXgtdr5uACJ5b1Q4udzjVV+tb/rlHIMJKuJ0e89R4Kzgz47z/rgP0dIKxktqIEUhDHluGTPJJH/wRha7CyqsA==", "license": "MIT", "dependencies": { - "@babel/code-frame": "^7.26.2", - "index-to-position": "^1.1.0", - "type-fest": "^4.39.1" + "cookie": "^1.0.1", + "set-cookie-parser": "^2.6.0" }, "engines": { - "node": ">=18" + "node": ">=20.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/parse5": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", - "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "entities": "^8.0.0" + "peerDependencies": { + "react": ">=18", + "react-dom": ">=18" }, - "funding": { - "url": "https://github.com/inikulin/parse5?sponsor=1" - } - }, - "node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "license": "MIT", - "engines": { - "node": ">=8" + "peerDependenciesMeta": { + "react-dom": { + "optional": true + } } }, - "node_modules/pathe": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", - "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", - "license": "MIT" - }, - "node_modules/perfect-debounce": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/perfect-debounce/-/perfect-debounce-2.1.0.tgz", - "integrity": "sha512-LjgdTytVFXeUgtHZr9WYViYSM/g8MkcTPYDlPa3cDqMirHjKiSZPYd6DoL7pK8AJQr+uWkQvCjHNdiMqsrJs+g==", - "license": "MIT" - }, - "node_modules/pg": { - "version": "8.20.0", - "resolved": "https://registry.npmjs.org/pg/-/pg-8.20.0.tgz", - "integrity": "sha512-ldhMxz2r8fl/6QkXnBD3CR9/xg694oT6DZQ2s6c/RI28OjtSOpxnPrUCGOBJ46RCUxcWdx3p6kw/xnDHjKvaRA==", + "node_modules/react-style-singleton": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", + "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", "license": "MIT", "dependencies": { - "pg-connection-string": "^2.12.0", - "pg-pool": "^3.13.0", - "pg-protocol": "^1.13.0", - "pg-types": "2.2.0", - "pgpass": "1.0.5" + "get-nonce": "^1.0.0", + "tslib": "^2.0.0" }, "engines": { - "node": ">= 16.0.0" - }, - "optionalDependencies": { - "pg-cloudflare": "^1.3.0" + "node": ">=10" }, "peerDependencies": { - "pg-native": ">=3.0.1" + "@types/react": "*", + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" }, "peerDependenciesMeta": { - "pg-native": { + "@types/react": { "optional": true } } }, - "node_modules/pg-cloudflare": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/pg-cloudflare/-/pg-cloudflare-1.3.0.tgz", - "integrity": "sha512-6lswVVSztmHiRtD6I8hw4qP/nDm1EJbKMRhf3HCYaqud7frGysPv7FYJ5noZQdhQtN2xJnimfMtvQq21pdbzyQ==", - "license": "MIT", - "optional": true - }, - "node_modules/pg-connection-string": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.12.0.tgz", - "integrity": "sha512-U7qg+bpswf3Cs5xLzRqbXbQl85ng0mfSV/J0nnA31MCLgvEaAo7CIhmeyrmJpOr7o+zm0rXK+hNnT5l9RHkCkQ==", - "license": "MIT" - }, - "node_modules/pg-int8": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/pg-int8/-/pg-int8-1.0.1.tgz", - "integrity": "sha512-WCtabS6t3c8SkpDBUlb1kjOs7l66xsGdKpIPZsg4wR+B3+u9UAum2odSsF9tnvxg80h4ZxLWMy4pRjOsFIqQpw==", - "license": "ISC", + "node_modules/readdirp": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", + "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "license": "MIT", "engines": { - "node": ">=4.0.0" + "node": ">= 20.19.0" + }, + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "node_modules/pg-pool": { - "version": "3.13.0", - "resolved": "https://registry.npmjs.org/pg-pool/-/pg-pool-3.13.0.tgz", - "integrity": "sha512-gB+R+Xud1gLFuRD/QgOIgGOBE2KCQPaPwkzBBGC9oG69pHTkhQeIuejVIk3/cnDyX39av2AxomQiyPT13WKHQA==", + "node_modules/remeda": { + "version": "2.33.4", + "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.33.4.tgz", + "integrity": "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==", "license": "MIT", - "peerDependencies": { - "pg": ">=8.0" + "funding": { + "url": "https://github.com/sponsors/remeda" } }, - "node_modules/pg-protocol": { - "version": "1.13.0", - "resolved": "https://registry.npmjs.org/pg-protocol/-/pg-protocol-1.13.0.tgz", - "integrity": "sha512-zzdvXfS6v89r6v7OcFCHfHlyG/wvry1ALxZo4LqgUoy7W9xhBDMaqOuMiF3qEV45VqsN6rdlcehHrfDtlCPc8w==", - "license": "MIT" - }, - "node_modules/pg-types": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/pg-types/-/pg-types-2.2.0.tgz", - "integrity": "sha512-qTAAlrEsl8s4OiEQY69wDvcMIdQN6wdz5ojQiOy6YRMuynxenON0O5oCpJI6lshc6scgAY8qvJ2On/p+CXY0GA==", + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, "license": "MIT", - "dependencies": { - "pg-int8": "1.0.1", - "postgres-array": "~2.0.0", - "postgres-bytea": "~1.0.0", - "postgres-date": "~1.0.4", - "postgres-interval": "^1.1.0" - }, "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/pg-types/node_modules/postgres-array": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-2.0.0.tgz", - "integrity": "sha512-VpZrUqU5A69eQyW2c5CA1jtLecCsN2U/bD6VilrFDWq5+5UIEVO7nazS3TEcHf1zuPYO/sqGvUvW62g86RXZuA==", + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", "license": "MIT", "engines": { - "node": ">=4" + "node": ">=0.10.0" } }, - "node_modules/pgpass": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/pgpass/-/pgpass-1.0.5.tgz", - "integrity": "sha512-FdW9r/jQZhSeohs1Z3sI1yxFQNFvMcnmfuj4WBMUTxOrAyLMaTcE1aAMBiTlbMNaXvBCQuVi0R7hd8udDSP7ug==", + "node_modules/ret": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", + "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==", "license": "MIT", - "dependencies": { - "split2": "^4.1.0" + "engines": { + "node": ">=10" } }, - "node_modules/picocolors": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", - "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", - "license": "ISC" - }, - "node_modules/picomatch": { - "version": "4.0.5", - "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", - "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", "license": "MIT", "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/jonschlinkert" + "node": ">= 4" } }, - "node_modules/pkg-types": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/pkg-types/-/pkg-types-2.3.1.tgz", - "integrity": "sha512-y+ichcgc2LrADuhLNAx8DFjVfgz91pRxfZdI3UDhxHvcVEZsenLO+7XaU5vOp0u/7V/wZ+plyuQxtrDlZJ+yeg==", + "node_modules/robust-predicates": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", + "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", + "license": "Unlicense" + }, + "node_modules/rolldown": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.2.7.tgz", + "integrity": "sha512-g0EtLvBjTUB7jhyV0S/TCup3v/XSVl45vUIGbOGU4QPiyjTenCe4mKuFvW9fEgYmS2Fo42AUssRmNuMziXdrig==", + "dev": true, "license": "MIT", "dependencies": { - "confbox": "^0.2.4", - "exsolve": "^1.0.8", - "pathe": "^2.0.3" + "@oxc-project/types": "=0.148.0", + "@rolldown/pluginutils": "^1.0.0" + }, + "bin": { + "rolldown": "bin/cli.mjs" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "optionalDependencies": { + "@rolldown/binding-android-arm-eabi": "1.2.7", + "@rolldown/binding-android-arm64": "1.2.7", + "@rolldown/binding-darwin-arm64": "1.2.7", + "@rolldown/binding-darwin-x64": "1.2.7", + "@rolldown/binding-freebsd-x64": "1.2.7", + "@rolldown/binding-linux-arm-gnueabihf": "1.2.7", + "@rolldown/binding-linux-arm64-gnu": "1.2.7", + "@rolldown/binding-linux-arm64-musl": "1.2.7", + "@rolldown/binding-linux-ppc64-gnu": "1.2.7", + "@rolldown/binding-linux-s390x-gnu": "1.2.7", + "@rolldown/binding-linux-x64-gnu": "1.2.7", + "@rolldown/binding-linux-x64-musl": "1.2.7", + "@rolldown/binding-openharmony-arm64": "1.2.7", + "@rolldown/binding-win32-arm64-msvc": "1.2.7", + "@rolldown/binding-win32-x64-msvc": "1.2.7" + } + }, + "node_modules/rolldown/node_modules/@oxc-project/types": { + "version": "0.148.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.148.0.tgz", + "integrity": "sha512-Nm4s/jB+4FpFsPhWGEC4h7rzksesmtnMXomo6rCMcg/b8zLQuOziRgkCS1fxDCXOlJB/6Q8oABOZ/OP6RIPj9A==", + "dev": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/oxc-project" } }, - "node_modules/pluralize": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/pluralize/-/pluralize-8.0.0.tgz", - "integrity": "sha512-Nc3IT5yHzflTfbjgqWcCPpo7DaKy4FnpB0l/zCAW0Tc7jxAiuqSxHasntB3D7887LSrA93kDJ9IXovxJYxyLCA==", + "node_modules/rollup": { + "version": "4.63.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.63.1.tgz", + "integrity": "sha512-3Df9jsstwhccuEfmAMi9l8XUh/GOkVObmFTU7CCVBysEbcOZLl84jCtaAZMcPiMz2EGKsATzQcU+Xr3n/wU6cg==", "dev": true, "license": "MIT", + "dependencies": { + "@types/estree": "1.0.9" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, "engines": { - "node": ">=4" + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@napi-rs/lzma-linux-x64-gnu": "1.5.1", + "@rollup/rollup-android-arm-eabi": "4.63.1", + "@rollup/rollup-android-arm64": "4.63.1", + "@rollup/rollup-darwin-arm64": "4.63.1", + "@rollup/rollup-darwin-x64": "4.63.1", + "@rollup/rollup-freebsd-arm64": "4.63.1", + "@rollup/rollup-freebsd-x64": "4.63.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.63.1", + "@rollup/rollup-linux-arm-musleabihf": "4.63.1", + "@rollup/rollup-linux-arm64-gnu": "4.63.1", + "@rollup/rollup-linux-arm64-musl": "4.63.1", + "@rollup/rollup-linux-loong64-gnu": "4.63.1", + "@rollup/rollup-linux-loong64-musl": "4.63.1", + "@rollup/rollup-linux-ppc64-gnu": "4.63.1", + "@rollup/rollup-linux-ppc64-musl": "4.63.1", + "@rollup/rollup-linux-riscv64-gnu": "4.63.1", + "@rollup/rollup-linux-riscv64-musl": "4.63.1", + "@rollup/rollup-linux-s390x-gnu": "4.63.1", + "@rollup/rollup-linux-x64-gnu": "4.63.1", + "@rollup/rollup-linux-x64-musl": "4.63.1", + "@rollup/rollup-openbsd-x64": "4.63.1", + "@rollup/rollup-openharmony-arm64": "4.63.1", + "@rollup/rollup-win32-arm64-msvc": "4.63.1", + "@rollup/rollup-win32-ia32-msvc": "4.63.1", + "@rollup/rollup-win32-x64-gnu": "4.63.1", + "@rollup/rollup-win32-x64-msvc": "4.63.1", + "fsevents": "~2.3.2" } }, - "node_modules/pngjs": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-7.0.0.tgz", - "integrity": "sha512-LKWqWJRhstyYo9pGvgor/ivk2w94eSjE3RGVuzLGlr3NmD8bf7RcYGze1mNdEHRP6TRP6rMuDHk5t44hnTRyow==", - "license": "MIT", - "engines": { - "node": ">=14.19.0" + "node_modules/rxjs": { + "version": "7.8.2", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", + "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.1.0" } }, - "node_modules/postcss": { - "version": "8.5.26", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.26.tgz", - "integrity": "sha512-u82N74LFzG8ca+dD8puPnplTXoGH4fTPpVGuIbt36G3qvNlkvfD0lEAZSxaly3KX8TS/L1A1gsCEmvKmBcVbkQ==", + "node_modules/safe-regex2": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.1.1.tgz", + "integrity": "sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==", "funding": [ { - "type": "opencollective", - "url": "https://opencollective.com/postcss/" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/postcss" + "type": "github", + "url": "https://github.com/sponsors/fastify" }, { - "type": "github", - "url": "https://github.com/sponsors/ai" + "type": "opencollective", + "url": "https://opencollective.com/fastify" } ], "license": "MIT", "dependencies": { - "nanoid": "^3.3.17", - "picocolors": "^1.1.1", - "source-map-js": "^1.2.1" - }, - "engines": { - "node": "^10 || ^12 || >=14" - } - }, - "node_modules/postgres": { - "version": "3.4.7", - "resolved": "https://registry.npmjs.org/postgres/-/postgres-3.4.7.tgz", - "integrity": "sha512-Jtc2612XINuBjIl/QTWsV5UvE8UHuNblcO3vVADSrKsrc6RqGX6lOW1cEo3CM2v0XG4Nat8nI+YM7/f26VxXLw==", - "license": "Unlicense", - "engines": { - "node": ">=12" + "ret": "~0.5.0" }, - "funding": { - "type": "individual", - "url": "https://github.com/sponsors/porsager" + "bin": { + "safe-regex2": "bin/safe-regex2.js" } }, - "node_modules/postgres-array": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/postgres-array/-/postgres-array-3.0.4.tgz", - "integrity": "sha512-nAUSGfSDGOaOAEGwqsRY27GPOea7CNipJPOA7lPbdEpx5Kg3qzdP0AaWC5MlhTWV9s4hFX39nomVZ+C4tnGOJQ==", - "license": "MIT", - "engines": { - "node": ">=12" - } + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "license": "MIT" }, - "node_modules/postgres-bytea": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/postgres-bytea/-/postgres-bytea-1.0.1.tgz", - "integrity": "sha512-5+5HqXnsZPE65IJZSMkZtURARZelel2oXUEO8rH83VS/hxH5vv1uHquPg5wZs8yMAfdv971IU+kcPUczi7NVBQ==", - "license": "MIT", + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "devOptional": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, "engines": { - "node": ">=0.10.0" + "node": ">=v12.22.7" } }, - "node_modules/postgres-date": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/postgres-date/-/postgres-date-1.0.7.tgz", - "integrity": "sha512-suDmjLVQg78nMK2UZ454hAG+OAW+HQPZ6n++TNDUX+L0+uUlLywnoxJKDou51Zm+zTCjrCl0Nq6J9C5hP9vK/Q==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } + "node_modules/scheduler": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", + "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", + "license": "MIT" }, - "node_modules/postgres-interval": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/postgres-interval/-/postgres-interval-1.2.0.tgz", - "integrity": "sha512-9ZhXKM/rw350N1ovuWHbGxnGh/SNJ4cnxHiM0rxE4VN41wsg8P8zWn9hv/buK00RP4WvlOyr/RBDiptyxVbkZQ==", - "license": "MIT", - "dependencies": { - "xtend": "^4.0.0" + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "devOptional": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" }, "engines": { - "node": ">=0.10.0" + "node": ">=10" } }, - "node_modules/prettier": { - "version": "3.9.6", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.9.6.tgz", - "integrity": "sha512-OpN0zzVdiaiAhxpuuj5efpIS4sY9j7bY6uR5mnj5yPzGkdkjNKSJeUThPb60Jw29QuAZgA4o+/iB49kFiaBX6g==", - "dev": true, - "license": "MIT", - "bin": { - "prettier": "bin/prettier.cjs" + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "node_modules/server-only": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", + "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==", + "license": "MIT" + }, + "node_modules/set-cookie-parser": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/set-cookie-parser/-/set-cookie-parser-2.7.2.tgz", + "integrity": "sha512-oeM1lpU/UvhTxw+g3cIfxXHyJRc/uidd3yK1P242gzHds0udQBYzs3y8j4gCCW+ZJ7ad0yctld8RYO+bdurlvw==", + "license": "MIT" + }, + "node_modules/shared": { + "resolved": "packages/shared", + "link": true + }, + "node_modules/sharp": { + "version": "0.35.3", + "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", + "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@img/colour": "^1.1.0", + "detect-libc": "^2.1.2", + "semver": "^7.8.5" }, "engines": { - "node": ">=14" + "node": ">=20.9.0" }, "funding": { - "url": "https://github.com/prettier/prettier?sponsor=1" + "url": "https://opencollective.com/libvips" + }, + "optionalDependencies": { + "@img/sharp-darwin-arm64": "0.35.3", + "@img/sharp-darwin-x64": "0.35.3", + "@img/sharp-freebsd-wasm32": "0.35.3", + "@img/sharp-libvips-darwin-arm64": "1.3.2", + "@img/sharp-libvips-darwin-x64": "1.3.2", + "@img/sharp-libvips-linux-arm": "1.3.2", + "@img/sharp-libvips-linux-arm64": "1.3.2", + "@img/sharp-libvips-linux-ppc64": "1.3.2", + "@img/sharp-libvips-linux-riscv64": "1.3.2", + "@img/sharp-libvips-linux-s390x": "1.3.2", + "@img/sharp-libvips-linux-x64": "1.3.2", + "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", + "@img/sharp-libvips-linuxmusl-x64": "1.3.2", + "@img/sharp-linux-arm": "0.35.3", + "@img/sharp-linux-arm64": "0.35.3", + "@img/sharp-linux-ppc64": "0.35.3", + "@img/sharp-linux-riscv64": "0.35.3", + "@img/sharp-linux-s390x": "0.35.3", + "@img/sharp-linux-x64": "0.35.3", + "@img/sharp-linuxmusl-arm64": "0.35.3", + "@img/sharp-linuxmusl-x64": "0.35.3", + "@img/sharp-webcontainers-wasm32": "0.35.3", + "@img/sharp-win32-arm64": "0.35.3", + "@img/sharp-win32-ia32": "0.35.3", + "@img/sharp-win32-x64": "0.35.3" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + } } }, - "node_modules/pretty-format": { - "version": "27.5.1", - "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", - "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", "license": "MIT", "dependencies": { - "ansi-regex": "^5.0.1", - "ansi-styles": "^5.0.0", - "react-is": "^17.0.1" + "shebang-regex": "^3.0.0" }, "engines": { - "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + "node": ">=8" } }, - "node_modules/pretty-format/node_modules/ansi-regex": { - "version": "5.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", - "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", "license": "MIT", "engines": { "node": ">=8" } }, - "node_modules/pretty-format/node_modules/ansi-styles": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", - "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "node_modules/shell-quote": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz", + "integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==", + "dev": true, "license": "MIT", "engines": { - "node": ">=10" + "node": ">= 0.4" }, "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/prisma": { - "version": "7.9.1", - "resolved": "https://registry.npmjs.org/prisma/-/prisma-7.9.1.tgz", - "integrity": "sha512-aPqePoZIqwlAchbgbFDO/wHqGB+7H1nj9gaM+OsL9h77S5S3TnLd9BgD3LnoeDikULo7cl2HSUrEyQ55Z7DYbg==", - "hasInstallScript": true, - "license": "Apache-2.0", - "dependencies": { - "@prisma/config": "7.9.1", - "@prisma/dev": "0.24.17", - "@prisma/engines": "7.9.1", - "@prisma/studio-core": "0.33.0", - "mysql2": "3.15.3", - "postgres": "3.4.7" - }, - "bin": { - "prisma": "build/index.js" - }, + "node_modules/siginfo": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", + "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", + "license": "ISC" + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", "engines": { - "node": "^20.19 || ^22.12 || >=24.0" - }, - "peerDependencies": { - "better-sqlite3": ">=9.0.0", - "typescript": ">=5.4.0" + "node": ">=14" }, - "peerDependenciesMeta": { - "better-sqlite3": { - "optional": true - }, - "typescript": { - "optional": true - } + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/proper-lockfile": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/proper-lockfile/-/proper-lockfile-4.1.2.tgz", - "integrity": "sha512-TjNPblN4BwAWMXU8s9AEz4JmQxnD1NNL7bNOY/AKUzyamc379FWASUhc/K1pL2noVb+XmZKLL68cjzLsiOAMaA==", + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", "license": "MIT", "dependencies": { - "graceful-fs": "^4.2.4", - "retry": "^0.12.0", - "signal-exit": "^3.0.2" + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/proper-lockfile/node_modules/signal-exit": { - "version": "3.0.7", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", - "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", - "license": "ISC" - }, - "node_modules/punycode": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", - "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", - "devOptional": true, - "license": "MIT", + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "license": "BSD-3-Clause", "engines": { - "node": ">=6" + "node": ">=0.10.0" } }, - "node_modules/pure-rand": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.1.0.tgz", - "integrity": "sha512-bVWawvoZoBYpp6yIoQtQXHZjmz35RSVHnUOTefl8Vcjr8snTPY1wnpSPMWekcFwbxI6gtmT7rSYPFvz71ldiOA==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/dubzzz" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fast-check" - } - ], - "license": "MIT" - }, - "node_modules/radix-ui": { - "version": "1.4.3", - "resolved": "https://registry.npmjs.org/radix-ui/-/radix-ui-1.4.3.tgz", - "integrity": "sha512-aWizCQiyeAenIdUbqEpXgRA1ya65P13NKn/W8rWkcN0OPkRDxdBVLWnIEDsS2RpwCK2nobI7oMUSmexzTDyAmA==", - "license": "MIT", - "dependencies": { - "@radix-ui/primitive": "1.1.3", - "@radix-ui/react-accessible-icon": "1.1.7", - "@radix-ui/react-accordion": "1.2.12", - "@radix-ui/react-alert-dialog": "1.1.15", - "@radix-ui/react-arrow": "1.1.7", - "@radix-ui/react-aspect-ratio": "1.1.7", - "@radix-ui/react-avatar": "1.1.10", - "@radix-ui/react-checkbox": "1.3.3", - "@radix-ui/react-collapsible": "1.1.12", - "@radix-ui/react-collection": "1.1.7", - "@radix-ui/react-compose-refs": "1.1.2", - "@radix-ui/react-context": "1.1.2", - "@radix-ui/react-context-menu": "2.2.16", - "@radix-ui/react-dialog": "1.1.15", - "@radix-ui/react-direction": "1.1.1", - "@radix-ui/react-dismissable-layer": "1.1.11", - "@radix-ui/react-dropdown-menu": "2.1.16", - "@radix-ui/react-focus-guards": "1.1.3", - "@radix-ui/react-focus-scope": "1.1.7", - "@radix-ui/react-form": "0.1.8", - "@radix-ui/react-hover-card": "1.1.15", - "@radix-ui/react-label": "2.1.7", - "@radix-ui/react-menu": "2.1.16", - "@radix-ui/react-menubar": "1.1.16", - "@radix-ui/react-navigation-menu": "1.2.14", - "@radix-ui/react-one-time-password-field": "0.1.8", - "@radix-ui/react-password-toggle-field": "0.1.3", - "@radix-ui/react-popover": "1.1.15", - "@radix-ui/react-popper": "1.2.8", - "@radix-ui/react-portal": "1.1.9", - "@radix-ui/react-presence": "1.1.5", - "@radix-ui/react-primitive": "2.1.3", - "@radix-ui/react-progress": "1.1.7", - "@radix-ui/react-radio-group": "1.3.8", - "@radix-ui/react-roving-focus": "1.1.11", - "@radix-ui/react-scroll-area": "1.2.10", - "@radix-ui/react-select": "2.2.6", - "@radix-ui/react-separator": "1.1.7", - "@radix-ui/react-slider": "1.3.6", - "@radix-ui/react-slot": "1.2.3", - "@radix-ui/react-switch": "1.2.6", - "@radix-ui/react-tabs": "1.1.13", - "@radix-ui/react-toast": "1.2.15", - "@radix-ui/react-toggle": "1.1.10", - "@radix-ui/react-toggle-group": "1.1.11", - "@radix-ui/react-toolbar": "1.1.11", - "@radix-ui/react-tooltip": "1.2.8", - "@radix-ui/react-use-callback-ref": "1.1.1", - "@radix-ui/react-use-controllable-state": "1.2.2", - "@radix-ui/react-use-effect-event": "0.0.2", - "@radix-ui/react-use-escape-keydown": "1.1.1", - "@radix-ui/react-use-is-hydrated": "0.1.0", - "@radix-ui/react-use-layout-effect": "1.1.1", - "@radix-ui/react-use-size": "1.1.1", - "@radix-ui/react-visually-hidden": "1.2.3" - }, - "peerDependencies": { - "@types/react": "*", - "@types/react-dom": "*", - "react": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc", - "react-dom": "^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc" - }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - }, - "@types/react-dom": { - "optional": true - } - } + "node_modules/spa": { + "resolved": "packages/spa", + "link": true }, - "node_modules/rc9": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/rc9/-/rc9-3.0.1.tgz", - "integrity": "sha512-gMDyleLWVE+i6Sgtc0QbbY6pEKqYs97NGi6isHQPqYlLemPoO8dxQ3uGi0f4NiP98c+jMW6cG1Kx9dDwfvqARQ==", - "license": "MIT", - "dependencies": { - "defu": "^6.1.6", - "destr": "^2.0.5" + "node_modules/split2": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", + "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", + "license": "ISC", + "engines": { + "node": ">= 10.x" } }, - "node_modules/react": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.8.tgz", - "integrity": "sha512-PWaYA1L/q9u2u7xYQi+Y3L3Yfnie7XyLeaJICV1MGD6LprsBxcAqGjYyr0eY3p+QdsA+x/Irkt4Qif8D63+Sbw==", + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">= 0.6" } }, - "node_modules/react-dom": { - "version": "19.2.8", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.8.tgz", - "integrity": "sha512-rVprimfGBG3DR+Tq0IQG2DT5PxKth1WIGDmj5yPmlzr4YBe7uyE+Du4oVqTDXZSHGGGXRtTJEGSSePyQCMBglQ==", + "node_modules/stackback": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", + "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", + "license": "MIT" + }, + "node_modules/std-env": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", + "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", + "license": "MIT" + }, + "node_modules/string-width": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", + "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", + "dev": true, "license": "MIT", "dependencies": { - "scheduler": "^0.27.0" + "emoji-regex": "^10.3.0", + "get-east-asian-width": "^1.0.0", + "strip-ansi": "^7.1.0" }, - "peerDependencies": { - "react": "^19.2.8" + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/react-is": { - "version": "17.0.2", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", - "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", - "license": "MIT" - }, - "node_modules/react-remove-scroll": { - "version": "2.7.2", - "resolved": "https://registry.npmjs.org/react-remove-scroll/-/react-remove-scroll-2.7.2.tgz", - "integrity": "sha512-Iqb9NjCCTt6Hf+vOdNIZGdTiH1QSqr27H/Ek9sv/a97gfueI/5h1s3yRi1nngzMUaOOToin5dI1dXKdXiF+u0Q==", + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, "license": "MIT", "dependencies": { - "react-remove-scroll-bar": "^2.3.7", - "react-style-singleton": "^2.2.3", - "tslib": "^2.1.0", - "use-callback-ref": "^1.3.3", - "use-sidecar": "^1.1.3" + "ansi-regex": "^6.2.2" }, "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + "node": ">=12" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/react-remove-scroll-bar": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/react-remove-scroll-bar/-/react-remove-scroll-bar-2.3.8.tgz", - "integrity": "sha512-9r+yi9+mgU33AKcj6IbT9oRCO78WriSj6t/cF8DWBZJ9aOGPOTEDvdUDz1FwKim7QXWwmHqtdHnRJfhAxEG46Q==", + "node_modules/styled-jsx": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", + "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", "license": "MIT", "dependencies": { - "react-style-singleton": "^2.2.2", - "tslib": "^2.0.0" + "client-only": "0.0.1" }, "engines": { - "node": ">=10" + "node": ">= 12.0.0" }, "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" }, "peerDependenciesMeta": { - "@types/react": { + "@babel/core": { + "optional": true + }, + "babel-plugin-macros": { "optional": true } } }, - "node_modules/react-style-singleton": { - "version": "2.2.3", - "resolved": "https://registry.npmjs.org/react-style-singleton/-/react-style-singleton-2.2.3.tgz", - "integrity": "sha512-b6jSvxvVnyptAiLjbkWLE/lOnR4lfTtDAl+eUC7RZy+QQWc6wRzIV2CE6xBuMmDxc2qIihtDCZD5NPOFl7fRBQ==", + "node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, "license": "MIT", "dependencies": { - "get-nonce": "^1.0.0", - "tslib": "^2.0.0" + "has-flag": "^4.0.0" }, "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 - } + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" } }, - "node_modules/readdirp": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-5.1.1.tgz", - "integrity": "sha512-Kko+Y5XQ6fM+Ce3dq3m9YGxnacYZYl9cA1wZjaF3Vbry2L3i1qVg8+CAgNPsXRArPMUMCaOR7oa9Nqntc43JKA==", + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/tailwindcss": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", + "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, "license": "MIT", "engines": { - "node": ">= 20.19.0" + "node": ">=6" }, "funding": { - "type": "individual", - "url": "https://paulmillr.com/funding/" + "type": "opencollective", + "url": "https://opencollective.com/webpack" } }, - "node_modules/remeda": { - "version": "2.33.4", - "resolved": "https://registry.npmjs.org/remeda/-/remeda-2.33.4.tgz", - "integrity": "sha512-ygHswjlc/opg2VrtiYvUOPLjxjtdKvjGz1/plDhkG66hjNjFr1xmfrs2ClNFo/E6TyUFiwYNh53bKV26oBoMGQ==", - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/remeda" + "node_modules/tar": { + "version": "7.5.22", + "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", + "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", + "dev": true, + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/fs-minipass": "^4.0.0", + "chownr": "^3.0.0", + "minipass": "^7.1.2", + "minizlib": "^3.1.0", + "yallist": "^5.0.0" + }, + "engines": { + "node": ">=18" } }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "node_modules/task": { + "resolved": "packages/task", + "link": true + }, + "node_modules/temporal-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-1.0.3.tgz", + "integrity": "sha512-U8vuzZBc+dfMIfl8wXWcedfI7AJCxJjjVBIRpJUvIz5+UAp555UJDHguKsfZqHWaHRSdVUThm7mqqIWhN/xPBQ==", "dev": true, "license": "MIT", - "engines": { - "node": ">=0.10.0" + "dependencies": { + "temporal-spec": "1.0.1", + "temporal-utils": "1.0.1" } }, - "node_modules/require-from-string": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", - "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "node_modules/temporal-spec": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-1.0.1.tgz", + "integrity": "sha512-wxVoanmDeavXie1vu2JaQ3WIc3JZnWAOYFBsJyATaVsXsycKYUflGsyBmrRSnoCpZJpwPyr38VpgSUlQ8CbFxg==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/temporal-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/temporal-utils/-/temporal-utils-1.0.1.tgz", + "integrity": "sha512-HAixuesxFQIUaQk3ptX2jhfO/FsOkgVkDDMawvp6n/fkB1q6BKfs3lURw9I+pK/2e2e/q/vrLrxmeqauBoyGMQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/tinybench": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", + "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", + "license": "MIT" + }, + "node_modules/tinyexec": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", + "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", "license": "MIT", "engines": { - "node": ">=0.10.0" + "node": ">=18" } }, - "node_modules/ret": { - "version": "0.5.0", - "resolved": "https://registry.npmjs.org/ret/-/ret-0.5.0.tgz", - "integrity": "sha512-I1XxrZSQ+oErkRR4jYbAyEEu2I0avBvvMM5JN+6EBprOGRCs63ENqZ3vjavq8fBw2+62G5LF5XelKwuJpcvcxw==", + "node_modules/tinyglobby": { + "version": "0.2.17", + "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", + "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", "license": "MIT", + "dependencies": { + "fdir": "^6.5.0", + "picomatch": "^4.0.4" + }, "engines": { - "node": ">=10" + "node": ">=12.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/SuperchupuDev" } }, - "node_modules/retry": { - "version": "0.12.0", - "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", - "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "node_modules/tinypool": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-2.1.0.tgz", + "integrity": "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==", "license": "MIT", "engines": { - "node": ">= 4" + "node": "^20.0.0 || >=22.0.0" } }, - "node_modules/robust-predicates": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/robust-predicates/-/robust-predicates-3.0.3.tgz", - "integrity": "sha512-NS3levdsRIUOmiJ8FZWCP7LG3QpJyrs/TE0Zpf1yvZu8cAJJ6QMW92H1c7kWpdIHo8RvmLxN/o2JXTKHp74lUA==", - "license": "Unlicense" - }, - "node_modules/rxjs": { - "version": "7.8.2", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.2.tgz", - "integrity": "sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "tslib": "^2.1.0" + "node_modules/tinyrainbow": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", + "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", + "license": "MIT", + "engines": { + "node": ">=14.0.0" } }, - "node_modules/safe-regex2": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/safe-regex2/-/safe-regex2-5.1.1.tgz", - "integrity": "sha512-mOSBvHGDZMuIEZMdOz/aCEYDCv0E7nfcNsIhUF+/P+xC7Hyf3FkvymqgPbg9D1EdSGu+uKbJgy09K/RKKc7kJA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/fastify" - }, - { - "type": "opencollective", - "url": "https://opencollective.com/fastify" - } - ], + "node_modules/tldts": { + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.10.tgz", + "integrity": "sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog==", + "devOptional": true, "license": "MIT", "dependencies": { - "ret": "~0.5.0" + "tldts-core": "^7.4.10" }, "bin": { - "safe-regex2": "bin/safe-regex2.js" + "tldts": "bin/cli.js" } }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "node_modules/tldts-core": { + "version": "7.4.10", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.10.tgz", + "integrity": "sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==", + "devOptional": true, "license": "MIT" }, - "node_modules/saxes": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", - "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", "devOptional": true, - "license": "ISC", + "license": "BSD-3-Clause", "dependencies": { - "xmlchars": "^2.2.0" + "tldts": "^7.0.5" }, "engines": { - "node": ">=v12.22.7" + "node": ">=16" } }, - "node_modules/scheduler": { - "version": "0.27.0", - "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.27.0.tgz", - "integrity": "sha512-eNv+WrVbKu1f3vbYJT/xtiF5syA5HPIMtf9IgY/nKg0sWqzAUEvqY/xm7OcZc/qafLx/iO9FgOmeSAp4v5ti/Q==", - "license": "MIT" - }, - "node_modules/semver": { - "version": "7.8.5", - "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", - "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", "devOptional": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" }, "engines": { - "node": ">=10" + "node": ">=20" } }, - "node_modules/seq-queue": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", - "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" - }, - "node_modules/server-only": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/server-only/-/server-only-0.0.1.tgz", - "integrity": "sha512-qepMx2JxAa5jjfzxG79yPPq+8BuFToHd1hm7kI+Z4zAq1ftQiP7HcxMhDDItrbtwVeLg/cY2JnKnrcFkmiswNA==", - "license": "MIT" + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "dev": true, + "license": "MIT", + "bin": { + "tree-kill": "cli.js" + } }, - "node_modules/shared": { - "resolved": "packages/shared", - "link": true + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" }, - "node_modules/sharp": { - "version": "0.35.3", - "resolved": "https://registry.npmjs.org/sharp/-/sharp-0.35.3.tgz", - "integrity": "sha512-ej0zVHuZGHCiABXcNxeYhpRnPNPAcvbG8RMdBAhDAxLKkCRVSpK3Iyu7qbqw3JMzoj0REeM6f3tJLtVwl0023Q==", - "license": "Apache-2.0", - "optional": true, - "dependencies": { - "@img/colour": "^1.1.0", - "detect-libc": "^2.1.2", - "semver": "^7.8.5" - }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", "engines": { - "node": ">=20.9.0" + "node": ">=16" }, "funding": { - "url": "https://opencollective.com/libvips" - }, - "optionalDependencies": { - "@img/sharp-darwin-arm64": "0.35.3", - "@img/sharp-darwin-x64": "0.35.3", - "@img/sharp-freebsd-wasm32": "0.35.3", - "@img/sharp-libvips-darwin-arm64": "1.3.2", - "@img/sharp-libvips-darwin-x64": "1.3.2", - "@img/sharp-libvips-linux-arm": "1.3.2", - "@img/sharp-libvips-linux-arm64": "1.3.2", - "@img/sharp-libvips-linux-ppc64": "1.3.2", - "@img/sharp-libvips-linux-riscv64": "1.3.2", - "@img/sharp-libvips-linux-s390x": "1.3.2", - "@img/sharp-libvips-linux-x64": "1.3.2", - "@img/sharp-libvips-linuxmusl-arm64": "1.3.2", - "@img/sharp-libvips-linuxmusl-x64": "1.3.2", - "@img/sharp-linux-arm": "0.35.3", - "@img/sharp-linux-arm64": "0.35.3", - "@img/sharp-linux-ppc64": "0.35.3", - "@img/sharp-linux-riscv64": "0.35.3", - "@img/sharp-linux-s390x": "0.35.3", - "@img/sharp-linux-x64": "0.35.3", - "@img/sharp-linuxmusl-arm64": "0.35.3", - "@img/sharp-linuxmusl-x64": "0.35.3", - "@img/sharp-webcontainers-wasm32": "0.35.3", - "@img/sharp-win32-arm64": "0.35.3", - "@img/sharp-win32-ia32": "0.35.3", - "@img/sharp-win32-x64": "0.35.3" - }, - "peerDependenciesMeta": { - "@types/node": { - "optional": true - } + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "license": "MIT", - "dependencies": { - "shebang-regex": "^3.0.0" + "node_modules/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "devOptional": true, + "license": "Apache-2.0", + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">=8" + "node": ">=14.17" } }, - "node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "node_modules/undici": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.0.tgz", + "integrity": "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ==", + "devOptional": true, "license": "MIT", "engines": { - "node": ">=8" + "node": ">=22.19.0" } }, - "node_modules/shell-quote": { - "version": "1.9.0", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.9.0.tgz", - "integrity": "sha512-Iov+JwFv/2HcTpcwNMKd8+IWNb8tboQJNQTkAY/LLVK7gGH9jy+LGkVqPxfekHl+yMmiqXszdGWXgkfml7hjqA==", + "node_modules/undici-types": { + "version": "7.24.6", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", + "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", + "license": "MIT" + }, + "node_modules/update-browserslist-db": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz", + "integrity": "sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==", "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/siginfo": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/siginfo/-/siginfo-2.0.0.tgz", - "integrity": "sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==", - "license": "ISC" - }, - "node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" } }, - "node_modules/sirv": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", - "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "node_modules/uri-js-replace": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.1.tgz", + "integrity": "sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==", + "dev": true, + "license": "MIT" + }, + "node_modules/use-callback-ref": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", + "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", "license": "MIT", "dependencies": { - "@polka/url": "^1.0.0-next.24", - "mrmime": "^2.0.0", - "totalist": "^3.0.0" + "tslib": "^2.0.0" }, "engines": { - "node": ">=18" + "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 + } } }, - "node_modules/source-map-js": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", - "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", - "license": "BSD-3-Clause", + "node_modules/use-sidecar": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", + "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "license": "MIT", + "dependencies": { + "detect-node-es": "^1.1.0", + "tslib": "^2.0.0" + }, "engines": { - "node": ">=0.10.0" + "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 + } } }, - "node_modules/split2": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/split2/-/split2-4.2.0.tgz", - "integrity": "sha512-UcjcJOWknrNkF6PLX83qcHM6KHgVKNkV62Y8a5uYDVv9ydGQVwAHMKqHdJje1VTWpljG0WYpCDhrCdAOYH4TWg==", - "license": "ISC", - "engines": { - "node": ">= 10.x" + "node_modules/use-sync-external-store": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", + "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", + "license": "MIT", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" } }, - "node_modules/sqlstring": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", - "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "node_modules/valibot": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.4.2.tgz", + "integrity": "sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg==", "license": "MIT", - "engines": { - "node": ">= 0.6" + "peerDependencies": { + "typescript": ">=5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } } }, - "node_modules/stackback": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/stackback/-/stackback-0.0.2.tgz", - "integrity": "sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==", - "license": "MIT" - }, - "node_modules/std-env": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.2.0.tgz", - "integrity": "sha512-oCUKSupKTHX53EyjDtuZQ64pjLJ6yYCtpmEw0goYxtjG9KpbRe8KAsl2tBUGU9DyMcJ0RwJ8GqJAFzMXcXW1Rw==", - "license": "MIT" - }, - "node_modules/string-width": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", - "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==", - "dev": true, + "node_modules/vite": { + "name": "@voidzero-dev/vite-plus-core", + "version": "0.2.9", + "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-core/-/vite-plus-core-0.2.9.tgz", + "integrity": "sha512-dWqScAAwa8h/i9jCiGAMs7YarzQWInHZ5gCJNbQkHXA6Zp6A2T2anN9YMFVPpb7CwVFwkI2iPF5yl/DXtq+zUA==", "license": "MIT", "dependencies": { - "emoji-regex": "^10.3.0", - "get-east-asian-width": "^1.0.0", - "strip-ansi": "^7.1.0" + "@oxc-project/runtime": "=0.143.0", + "@oxc-project/types": "=0.143.0", + "lightningcss": "^1.33.0", + "postcss": "^8.5.6", + "yuku-codegen": "^0.5.44", + "yuku-parser": "^0.5.44" }, "engines": { - "node": ">=18" + "node": "^20.19.0 || ^22.18.0 || >=24.11.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "optionalDependencies": { + "@voidzero-dev/vite-plus-darwin-arm64": "0.2.9", + "@voidzero-dev/vite-plus-darwin-x64": "0.2.9", + "@voidzero-dev/vite-plus-linux-arm64-gnu": "0.2.9", + "@voidzero-dev/vite-plus-linux-arm64-musl": "0.2.9", + "@voidzero-dev/vite-plus-linux-x64-gnu": "0.2.9", + "@voidzero-dev/vite-plus-linux-x64-musl": "0.2.9", + "@voidzero-dev/vite-plus-win32-arm64-msvc": "0.2.9", + "@voidzero-dev/vite-plus-win32-x64-msvc": "0.2.9", + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@arethetypeswrong/core": "^0.18.1", + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "publint": "^0.3.8", + "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", + "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0", + "unplugin-unused": "^0.5.0", + "unrun": "*", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@arethetypeswrong/core": { + "optional": true + }, + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "publint": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "typescript": { + "optional": true + }, + "unplugin-unused": { + "optional": true + }, + "unrun": { + "optional": true + }, + "yaml": { + "optional": true + } } }, - "node_modules/strip-ansi": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", - "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "node_modules/vite-cli": { + "name": "vite", + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", "dev": true, "license": "MIT", "dependencies": { - "ansi-regex": "^6.2.2" + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", + "tinyglobby": "^0.2.17" + }, + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": ">=12" + "node": "^20.19.0 || >=22.12.0" }, "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/styled-jsx": { - "version": "5.1.6", - "resolved": "https://registry.npmjs.org/styled-jsx/-/styled-jsx-5.1.6.tgz", - "integrity": "sha512-qSVyDTeMotdvQYoHWLNGwRFJHC+i+ZvdBRYosOFgC+Wg1vx4frN2/RG/NA7SYqqvKNLf39P2LSRA2pu6n0XYZA==", - "license": "MIT", - "dependencies": { - "client-only": "0.0.1" + "url": "https://github.com/vitejs/vite?sponsor=1" }, - "engines": { - "node": ">= 12.0.0" + "optionalDependencies": { + "fsevents": "~2.3.3" }, "peerDependencies": { - "react": ">= 16.8.0 || 17.x.x || ^18.0.0-0 || ^19.0.0-0" + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" }, "peerDependenciesMeta": { - "@babel/core": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { "optional": true }, - "babel-plugin-macros": { + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { "optional": true } } }, - "node_modules/supports-color": { - "version": "8.1.1", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", - "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "node_modules/vite-cli/node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", "dev": true, - "license": "MIT", + "license": "MPL-2.0", "dependencies": { - "has-flag": "^4.0.0" + "detect-libc": "^2.0.3" }, "engines": { - "node": ">=10" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/chalk/supports-color?sponsor=1" + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" } }, - "node_modules/symbol-tree": { - "version": "3.2.4", - "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", - "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/tailwindcss": { - "version": "4.3.3", - "resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-4.3.3.tgz", - "integrity": "sha512-gOhV3P7ufE62QDGg1zVaTgCR+EtPv92k2nIhVcVKcLmxT1sUBsQGhnZj175j+MqRt4zLF7ic+sCYjfhxMxj7YQ==", - "dev": true, - "license": "MIT" - }, - "node_modules/tapable": { - "version": "2.3.3", - "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", - "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "node_modules/vite-cli/node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], "engines": { - "node": ">=6" + "node": ">= 12.0.0" }, "funding": { "type": "opencollective", - "url": "https://opencollective.com/webpack" + "url": "https://opencollective.com/parcel" } }, - "node_modules/tar": { - "version": "7.5.22", - "resolved": "https://registry.npmjs.org/tar/-/tar-7.5.22.tgz", - "integrity": "sha512-MFO/QzvtAOmJbkhOaCTvbGcFN9L9b+JunIsDwaKljSOdcLMea3NJ1k9Usz/rjdfSXTq4dfzfeS7W4p4YOAAHeA==", + "node_modules/vite-cli/node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/fs-minipass": "^4.0.0", - "chownr": "^3.0.0", - "minipass": "^7.1.2", - "minizlib": "^3.1.0", - "yallist": "^5.0.0" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=18" - } - }, - "node_modules/task": { - "resolved": "packages/task", - "link": true - }, - "node_modules/temporal-polyfill": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/temporal-polyfill/-/temporal-polyfill-1.0.3.tgz", - "integrity": "sha512-U8vuzZBc+dfMIfl8wXWcedfI7AJCxJjjVBIRpJUvIz5+UAp555UJDHguKsfZqHWaHRSdVUThm7mqqIWhN/xPBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "temporal-spec": "1.0.1", - "temporal-utils": "1.0.1" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/temporal-spec": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/temporal-spec/-/temporal-spec-1.0.1.tgz", - "integrity": "sha512-wxVoanmDeavXie1vu2JaQ3WIc3JZnWAOYFBsJyATaVsXsycKYUflGsyBmrRSnoCpZJpwPyr38VpgSUlQ8CbFxg==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/temporal-utils": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/temporal-utils/-/temporal-utils-1.0.1.tgz", - "integrity": "sha512-HAixuesxFQIUaQk3ptX2jhfO/FsOkgVkDDMawvp6n/fkB1q6BKfs3lURw9I+pK/2e2e/q/vrLrxmeqauBoyGMQ==", + "node_modules/vite-cli/node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/tinybench": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/tinybench/-/tinybench-2.9.0.tgz", - "integrity": "sha512-0+DUvqWMValLmha6lr4kD8iAMK1HzV0/aKnCtWb9v9641TnP/MFb7Pc2bxoxQjTXAErryXVgUOfv2YqNllqGeg==", - "license": "MIT" - }, - "node_modules/tinyexec": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/tinyexec/-/tinyexec-1.3.0.tgz", - "integrity": "sha512-QKAl9m8gWWGHV8jZcPeym6j+XULi6tOf1mT83WYJ4Lk2ytW/uwAWkrP0uFsdoYMdueVJ0qs26wZ+23xeB4ibNQ==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "node_modules/tinyglobby": { - "version": "0.2.17", - "resolved": "https://registry.npmjs.org/tinyglobby/-/tinyglobby-0.2.17.tgz", - "integrity": "sha512-wXR/dYpcqKmfWpEdZjiKJOwCNFndD0DMnrW/cYjVGttEkBfVgcLFHoNrlj47mjOVic9yyNu65alsgF4NQyTa2g==", - "license": "MIT", - "dependencies": { - "fdir": "^6.5.0", - "picomatch": "^4.0.4" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], "engines": { - "node": ">=12.0.0" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/SuperchupuDev" - } - }, - "node_modules/tinypool": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/tinypool/-/tinypool-2.1.0.tgz", - "integrity": "sha512-Pugqs6M0m7Lv1I7FtxN4aoyToKg1C4tu+/381vH35y8oENM/Ai7f7C4StcoK4/+BSw9ebcS8jRiVrORFKCALLw==", - "license": "MIT", - "engines": { - "node": "^20.0.0 || >=22.0.0" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/tinyrainbow": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/tinyrainbow/-/tinyrainbow-3.1.1.tgz", - "integrity": "sha512-yau8yJdTt989Mm0Bd/236QnzEiPf2xLLTqUZRUJOo/3CB078LSwzei343DgtJVmfJKJE3TMINY1u42SQsP6mXw==", - "license": "MIT", + "node_modules/vite-cli/node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/tldts": { - "version": "7.4.10", - "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.10.tgz", - "integrity": "sha512-GgouD1B+sWwvkaEq8vXC15DjQitxbvs12oIXELpconwm+Tg3zfcEv4jgzq3vtKverDXsg3VI8aRgNL2Nra0Iog==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "tldts-core": "^7.4.10" + "node": ">= 12.0.0" }, - "bin": { - "tldts": "bin/cli.js" - } - }, - "node_modules/tldts-core": { - "version": "7.4.10", - "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.10.tgz", - "integrity": "sha512-KnQjp53ZekKgm/r3l+u8kJGGzYgrWdP8+Mql7a4vijh2WE0IrZWspQj/TpTxDho/YxO+AnOZnIjQcCD+q6iJsw==", - "devOptional": true, - "license": "MIT" - }, - "node_modules/totalist": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", - "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", - "license": "MIT", - "engines": { - "node": ">=6" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/tough-cookie": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", - "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", - "devOptional": true, - "license": "BSD-3-Clause", - "dependencies": { - "tldts": "^7.0.5" - }, + "node_modules/vite-cli/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=16" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/tr46": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", - "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", - "devOptional": true, - "license": "MIT", - "dependencies": { - "punycode": "^2.3.1" - }, + "node_modules/vite-cli/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=20" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/tree-kill": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", - "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "node_modules/vite-cli/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "MIT", - "bin": { - "tree-kill": "cli.js" + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/tslib": { - "version": "2.8.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", - "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", - "license": "0BSD" - }, - "node_modules/type-fest": { - "version": "4.41.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", - "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "node_modules/vite-cli/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], "dev": true, - "license": "(MIT OR CC0-1.0)", + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=16" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/typescript": { - "version": "5.9.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", - "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", - "devOptional": true, - "license": "Apache-2.0", - "peer": true, - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, + "node_modules/vite-cli/node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], "engines": { - "node": ">=14.17" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/undici": { - "version": "8.10.0", - "resolved": "https://registry.npmjs.org/undici/-/undici-8.10.0.tgz", - "integrity": "sha512-HvltHd7avK13QIw/oLe4qoOLyoVSoafqJ2jYOrtMRBkbYT31eiBQ8O0ehRKZiEZCMEyLFQNIADpgCWC5fALvYQ==", - "devOptional": true, - "license": "MIT", + "node_modules/vite-cli/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=22.19.0" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/undici-types": { - "version": "7.24.6", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.24.6.tgz", - "integrity": "sha512-WRNW+sJgj5OBN4/0JpHFqtqzhpbnV0GuB+OozA9gCL7a993SmU+1JBZCzLNxYsbMfIeDL+lTsphD5jN5N+n0zg==", - "license": "MIT" - }, - "node_modules/uri-js-replace": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/uri-js-replace/-/uri-js-replace-1.0.1.tgz", - "integrity": "sha512-W+C9NWNLFOoBI2QWDp4UT9pv65r2w5Cx+3sTYFvtMdDBxkKt1syCqsUdSFAChbEe1uK5TfS04wt/nGwmaeIQ0g==", + "node_modules/vite-cli/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "MIT" - }, - "node_modules/use-callback-ref": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/use-callback-ref/-/use-callback-ref-1.3.3.tgz", - "integrity": "sha512-jQL3lRnocaFtu3V00JToYz/4QkNWswxijDaCVNZRiRTO3HQDLsdu1ZtmIUvV4yPp+rvWm5j0y0TG/S61cuijTg==", - "license": "MIT", - "dependencies": { - "tslib": "^2.0.0" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], "engines": { - "node": ">=10" - }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + "node": ">= 12.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/use-sidecar": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/use-sidecar/-/use-sidecar-1.1.3.tgz", - "integrity": "sha512-Fedw0aZvkhynoPYlA5WXrMCAMm+nSWdZt6lzJQ7Ok8S6Q+VsHmHpRWndVRJ8Be0ZbkfPc5LRYH+5XrzXcEeLRQ==", + "node_modules/vite-node": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-3.2.4.tgz", + "integrity": "sha512-EbKSKh+bh1E1IFxeO0pg1n4dvoOTt0UDiXMd/qn++r98+jPO1xtJilvXldeuQ8giIB5IkpjCgMleHMNEsGH6pg==", + "dev": true, "license": "MIT", "dependencies": { - "detect-node-es": "^1.1.0", - "tslib": "^2.0.0" + "cac": "^6.7.14", + "debug": "^4.4.1", + "es-module-lexer": "^1.7.0", + "pathe": "^2.0.3", + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0-0" }, - "engines": { - "node": ">=10" + "bin": { + "vite-node": "vite-node.mjs" }, - "peerDependencies": { - "@types/react": "*", - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 || ^19.0.0-rc" + "engines": { + "node": "^18.0.0 || ^20.0.0 || >=22.0.0" }, - "peerDependenciesMeta": { - "@types/react": { - "optional": true - } - } - }, - "node_modules/use-sync-external-store": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/use-sync-external-store/-/use-sync-external-store-1.6.0.tgz", - "integrity": "sha512-Pp6GSwGP/NrPIrxVFAIkOQeyw8lFenOHijQWkUTrDvrF4ALqylP2C/KCkeS9dpUM3KvYRQhna5vt7IL95+ZQ9w==", - "license": "MIT", - "peerDependencies": { - "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + "funding": { + "url": "https://opencollective.com/vitest" } }, - "node_modules/valibot": { - "version": "1.4.2", - "resolved": "https://registry.npmjs.org/valibot/-/valibot-1.4.2.tgz", - "integrity": "sha512-gjdCvJ6d3RyHAneqxMYMW9QMCwYMb3jpOO0IyHZV1bnRHFBHrX3VkIILt5XYR0WhwHiH7Mty8ovuPZ/O3gamrg==", - "license": "MIT", - "peerDependencies": { - "typescript": ">=5" - }, - "peerDependenciesMeta": { - "typescript": { - "optional": true - } - } + "node_modules/vite-node/node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, + "license": "MIT" }, - "node_modules/vite": { - "name": "@voidzero-dev/vite-plus-core", - "version": "0.2.9", - "resolved": "https://registry.npmjs.org/@voidzero-dev/vite-plus-core/-/vite-plus-core-0.2.9.tgz", - "integrity": "sha512-dWqScAAwa8h/i9jCiGAMs7YarzQWInHZ5gCJNbQkHXA6Zp6A2T2anN9YMFVPpb7CwVFwkI2iPF5yl/DXtq+zUA==", + "node_modules/vite-node/node_modules/vite": { + "version": "7.3.6", + "resolved": "https://registry.npmjs.org/vite/-/vite-7.3.6.tgz", + "integrity": "sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==", + "dev": true, "license": "MIT", - "dependencies": { - "@oxc-project/runtime": "=0.143.0", - "@oxc-project/types": "=0.143.0", - "lightningcss": "^1.33.0", + "dependencies": { + "esbuild": "^0.27.0 || ^0.28.0", + "fdir": "^6.5.0", + "picomatch": "^4.0.3", "postcss": "^8.5.6", - "yuku-codegen": "^0.5.44", - "yuku-parser": "^0.5.44" + "rollup": "^4.43.0", + "tinyglobby": "^0.2.15" + }, + "bin": { + "vite": "bin/vite.js" }, "engines": { - "node": "^20.19.0 || ^22.18.0 || >=24.11.0" + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "@voidzero-dev/vite-plus-darwin-arm64": "0.2.9", - "@voidzero-dev/vite-plus-darwin-x64": "0.2.9", - "@voidzero-dev/vite-plus-linux-arm64-gnu": "0.2.9", - "@voidzero-dev/vite-plus-linux-arm64-musl": "0.2.9", - "@voidzero-dev/vite-plus-linux-x64-gnu": "0.2.9", - "@voidzero-dev/vite-plus-linux-x64-musl": "0.2.9", - "@voidzero-dev/vite-plus-win32-arm64-msvc": "0.2.9", - "@voidzero-dev/vite-plus-win32-x64-msvc": "0.2.9", "fsevents": "~2.3.3" }, "peerDependencies": { - "@arethetypeswrong/core": "^0.18.1", "@types/node": "^20.19.0 || >=22.12.0", - "@vitejs/devtools": "^0.4.0", - "esbuild": "^0.27.0 || ^0.28.0", "jiti": ">=1.21.0", "less": "^4.0.0", - "publint": "^0.3.8", + "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", - "typescript": "^5.0.0 || ^6.0.0 || ^7.0.0", - "unplugin-unused": "^0.5.0", - "unrun": "*", "yaml": "^2.4.2" }, "peerDependenciesMeta": { - "@arethetypeswrong/core": { - "optional": true - }, "@types/node": { "optional": true }, - "@vitejs/devtools": { - "optional": true - }, - "esbuild": { - "optional": true - }, "jiti": { "optional": true }, "less": { "optional": true }, - "publint": { + "lightningcss": { "optional": true }, "sass": { @@ -9698,15 +12267,6 @@ "tsx": { "optional": true }, - "typescript": { - "optional": true - }, - "unplugin-unused": { - "optional": true - }, - "unrun": { - "optional": true - }, "yaml": { "optional": true } @@ -10122,549 +12682,1060 @@ "resolved": "https://registry.npmjs.org/vscode-jsonrpc/-/vscode-jsonrpc-9.0.1.tgz", "integrity": "sha512-rfuA6T75H6m5EkbhtEPzre9pT0HPcDI2MMy4+nPFIBks5J8JBAUHD4tRYSgaBOijIEC7SRkC1kKyXTLqbmh9jw==", "dev": true, - "license": "MIT", + "license": "MIT", + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/vscode-languageserver": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-10.1.0.tgz", + "integrity": "sha512-9gEWpXkYGXoqG7pBnE8O8hx/yP7+Aabn4+peQ3KDicQv6qunHSWyLTud3OF0w4S2+HfDD+5HqYKiXQW9HAU6mA==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-languageserver-protocol": "3.18.2" + }, + "bin": { + "installServerIntoExtension": "bin/installServerIntoExtension" + } + }, + "node_modules/vscode-languageserver-protocol": { + "version": "3.18.2", + "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.2.tgz", + "integrity": "sha512-XRyDbT0Pp3sSNti3JmxVEUMySWCSi1hhM+/KUlCy1hV1zmrqpM1OwO12EAki8blhmLuIMpaJrYbo0OzGVfK2Qg==", + "dev": true, + "license": "MIT", + "dependencies": { + "vscode-jsonrpc": "9.0.1", + "vscode-languageserver-types": "3.18.0" + } + }, + "node_modules/vscode-languageserver-textdocument": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", + "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "dev": true, + "license": "MIT" + }, + "node_modules/vscode-languageserver-types": { + "version": "3.18.0", + "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.0.tgz", + "integrity": "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g==", + "dev": true, + "license": "MIT" + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "devOptional": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "devOptional": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "devOptional": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/why-is-node-running": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", + "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", + "license": "MIT", + "dependencies": { + "siginfo": "^2.0.0", + "stackback": "0.0.2" + }, + "bin": { + "why-is-node-running": "cli.js" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", + "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.2.1", + "string-width": "^7.0.0", + "strip-ansi": "^7.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", + "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "devOptional": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "devOptional": true, + "license": "MIT" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", + "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "dev": true, + "license": "BlueOak-1.0.0", "engines": { - "node": ">=14.0.0" + "node": ">=18" } }, - "node_modules/vscode-languageserver": { - "version": "10.1.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver/-/vscode-languageserver-10.1.0.tgz", - "integrity": "sha512-9gEWpXkYGXoqG7pBnE8O8hx/yP7+Aabn4+peQ3KDicQv6qunHSWyLTud3OF0w4S2+HfDD+5HqYKiXQW9HAU6mA==", - "dev": true, - "license": "MIT", - "dependencies": { - "vscode-languageserver-protocol": "3.18.2" - }, + "node_modules/yaml": { + "version": "2.9.0", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", + "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", + "devOptional": true, + "license": "ISC", "bin": { - "installServerIntoExtension": "bin/installServerIntoExtension" + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14.6" + }, + "funding": { + "url": "https://github.com/sponsors/eemeli" } }, - "node_modules/vscode-languageserver-protocol": { - "version": "3.18.2", - "resolved": "https://registry.npmjs.org/vscode-languageserver-protocol/-/vscode-languageserver-protocol-3.18.2.tgz", - "integrity": "sha512-XRyDbT0Pp3sSNti3JmxVEUMySWCSi1hhM+/KUlCy1hV1zmrqpM1OwO12EAki8blhmLuIMpaJrYbo0OzGVfK2Qg==", + "node_modules/yaml-ast-parser": { + "version": "0.0.43", + "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", + "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/yargs": { + "version": "18.0.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", + "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", "dev": true, "license": "MIT", "dependencies": { - "vscode-jsonrpc": "9.0.1", - "vscode-languageserver-types": "3.18.0" + "cliui": "^9.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "string-width": "^7.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^22.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" } }, - "node_modules/vscode-languageserver-textdocument": { - "version": "1.0.12", - "resolved": "https://registry.npmjs.org/vscode-languageserver-textdocument/-/vscode-languageserver-textdocument-1.0.12.tgz", - "integrity": "sha512-cxWNPesCnQCcMPeenjKKsOCKQZ/L6Tv19DTRIGuLWe32lyzWhihGVJ/rcckZXJxfdKCFvRLS3fpBIsV/ZGX4zA==", + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", "dev": true, - "license": "MIT" + "license": "ISC", + "engines": { + "node": ">=12" + } }, - "node_modules/vscode-languageserver-types": { - "version": "3.18.0", - "resolved": "https://registry.npmjs.org/vscode-languageserver-types/-/vscode-languageserver-types-3.18.0.tgz", - "integrity": "sha512-8TsGPNMIMiiBdkORgRSvLjuiEIiAFtO+KssmYWxQ+uSVvlf7RjK8YKCOjPzZ+YA04jXEV7+7LvkSmHkhpNS99g==", + "node_modules/yargs/node_modules/yargs-parser": { + "version": "22.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", + "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", "dev": true, - "license": "MIT" + "license": "ISC", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=23" + } }, - "node_modules/w3c-xmlserializer": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", - "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", - "devOptional": true, + "node_modules/yuku-codegen": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/yuku-codegen/-/yuku-codegen-0.5.48.tgz", + "integrity": "sha512-p7HxD5Xl4jzDzqMrGePAOeSHmRY4g58h4HuGq15weQFPxuPWd/W6e7nqp/+Lea6JfpOdBwJOAyXFqIZ/J9Zfnw==", "license": "MIT", "dependencies": { - "xml-name-validator": "^5.0.0" + "@yuku-toolchain/types": "0.5.43" }, - "engines": { - "node": ">=18" + "optionalDependencies": { + "@yuku-codegen/binding-darwin-arm64": "0.5.48", + "@yuku-codegen/binding-darwin-x64": "0.5.48", + "@yuku-codegen/binding-freebsd-x64": "0.5.48", + "@yuku-codegen/binding-linux-arm-gnu": "0.5.48", + "@yuku-codegen/binding-linux-arm-musl": "0.5.48", + "@yuku-codegen/binding-linux-arm64-gnu": "0.5.48", + "@yuku-codegen/binding-linux-arm64-musl": "0.5.48", + "@yuku-codegen/binding-linux-x64-gnu": "0.5.48", + "@yuku-codegen/binding-linux-x64-musl": "0.5.48", + "@yuku-codegen/binding-win32-arm64": "0.5.48", + "@yuku-codegen/binding-win32-x64": "0.5.48" } }, - "node_modules/webidl-conversions": { - "version": "8.0.1", - "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", - "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", - "devOptional": true, - "license": "BSD-2-Clause", - "engines": { - "node": ">=20" + "node_modules/yuku-parser": { + "version": "0.5.48", + "resolved": "https://registry.npmjs.org/yuku-parser/-/yuku-parser-0.5.48.tgz", + "integrity": "sha512-OWBfhrpgK9+/4+IXG9oT8Bao4AhViQA7vdyNNH7EUg8dQYgwa70XtIBWTpCEme1P1ECyoDNYkn0wT63f8XRcVA==", + "license": "MIT", + "dependencies": { + "@yuku-toolchain/types": "0.5.43" + }, + "optionalDependencies": { + "@yuku-parser/binding-darwin-arm64": "0.5.48", + "@yuku-parser/binding-darwin-x64": "0.5.48", + "@yuku-parser/binding-freebsd-x64": "0.5.48", + "@yuku-parser/binding-linux-arm-gnu": "0.5.48", + "@yuku-parser/binding-linux-arm-musl": "0.5.48", + "@yuku-parser/binding-linux-arm64-gnu": "0.5.48", + "@yuku-parser/binding-linux-arm64-musl": "0.5.48", + "@yuku-parser/binding-linux-x64-gnu": "0.5.48", + "@yuku-parser/binding-linux-x64-musl": "0.5.48", + "@yuku-parser/binding-win32-arm64": "0.5.48", + "@yuku-parser/binding-win32-x64": "0.5.48" } }, - "node_modules/whatwg-mimetype": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", - "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", - "devOptional": true, + "node_modules/zeptomatch": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/zeptomatch/-/zeptomatch-2.1.0.tgz", + "integrity": "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==", "license": "MIT", - "engines": { - "node": ">=20" + "dependencies": { + "grammex": "^3.1.11", + "graphmatch": "^1.1.0" } }, - "node_modules/whatwg-url": { - "version": "16.0.1", - "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", - "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", - "devOptional": true, + "node_modules/zod": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", + "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, + "packages/api": { "dependencies": { - "@exodus/bytes": "^1.11.0", - "tr46": "^6.0.0", - "webidl-conversions": "^8.0.1" + "@hono/node-server": "^2.1.0", + "@prisma/adapter-pg": "^7.9.1", + "hono": "^4.13.1", + "zod": "^4.4.3" }, - "engines": { - "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + "devDependencies": { + "@types/node": "^25.9.5", + "concurrently": "^9.2.4", + "typescript": "^7.0.2" } }, - "node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "license": "ISC", - "dependencies": { - "isexe": "^2.0.0" + "packages/api/node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc" + }, + "engines": { + "node": ">=16.20.0" }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" + } + }, + "packages/bin": { + "devDependencies": { + "@types/node": "^25.9.5", + "typescript": "^7.0.2" + } + }, + "packages/bin/node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "dev": true, + "license": "Apache-2.0", "bin": { - "node-which": "bin/node-which" + "tsc": "bin/tsc" }, "engines": { - "node": ">= 8" + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" } }, - "node_modules/why-is-node-running": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/why-is-node-running/-/why-is-node-running-2.3.0.tgz", - "integrity": "sha512-hUrmaWBdVDcxvYqnyh09zunKzROWjbZTiNy8dBEjkS7ehEDQibXJ7XvlmtbwuTclUiIyN+CyXQD4Vmko8fNm8w==", - "license": "MIT", + "packages/client": { + "version": "0.1.0", "dependencies": { - "siginfo": "^2.0.0", - "stackback": "0.0.2" + "@radix-ui/react-icons": "^1.3.2", + "@radix-ui/themes": "^3.3.0", + "next": "^16.3.0", + "react": "^19.2.8", + "react-dom": "^19.2.8", + "server-only": "^0.0.1" }, + "devDependencies": { + "@tailwindcss/postcss": "^4.3.3", + "@types/node": "^25.9.5", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.4", + "@vitejs/plugin-react": "^6.0.5", + "jsdom": "^30.0.1", + "tailwindcss": "^4.3.3", + "typescript": "^7.0.2" + } + }, + "packages/client/node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "dev": true, + "license": "Apache-2.0", "bin": { - "why-is-node-running": "cli.js" + "tsc": "bin/tsc" }, "engines": { - "node": ">=8" + "node": ">=16.20.0" + }, + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" } }, - "node_modules/wrap-ansi": { - "version": "9.0.2", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz", - "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==", - "dev": true, - "license": "MIT", + "packages/shared": { "dependencies": { - "ansi-styles": "^6.2.1", - "string-width": "^7.0.0", - "strip-ansi": "^7.1.0" + "@prisma/adapter-pg": "^7.9.1", + "@prisma/client": "^7.9.1", + "prisma": "^7.9.1" }, - "engines": { - "node": ">=18" + "devDependencies": { + "@types/node": "^25.9.5", + "@typespec/compiler": "^1.15.0", + "@typespec/http": "^1.15.0", + "@typespec/openapi": "^1.15.0", + "@typespec/openapi3": "^1.15.0", + "@typespec/rest": "^0.85.0", + "concurrently": "^9.2.4", + "openapi-typescript": "^7.9.1", + "typescript": "^7.0.2" }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + "optionalDependencies": { + "@rollup/rollup-linux-x64-gnu": "^4.62.4" } }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "6.2.3", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz", - "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==", + "packages/shared/node_modules/typescript": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", + "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", "dev": true, - "license": "MIT", + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc" + }, "engines": { - "node": ">=12" + "node": ">=16.20.0" }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" + "optionalDependencies": { + "@typescript/typescript-aix-ppc64": "7.0.2", + "@typescript/typescript-darwin-arm64": "7.0.2", + "@typescript/typescript-darwin-x64": "7.0.2", + "@typescript/typescript-freebsd-arm64": "7.0.2", + "@typescript/typescript-freebsd-x64": "7.0.2", + "@typescript/typescript-linux-arm": "7.0.2", + "@typescript/typescript-linux-arm64": "7.0.2", + "@typescript/typescript-linux-loong64": "7.0.2", + "@typescript/typescript-linux-mips64el": "7.0.2", + "@typescript/typescript-linux-ppc64": "7.0.2", + "@typescript/typescript-linux-riscv64": "7.0.2", + "@typescript/typescript-linux-s390x": "7.0.2", + "@typescript/typescript-linux-x64": "7.0.2", + "@typescript/typescript-netbsd-arm64": "7.0.2", + "@typescript/typescript-netbsd-x64": "7.0.2", + "@typescript/typescript-openbsd-arm64": "7.0.2", + "@typescript/typescript-openbsd-x64": "7.0.2", + "@typescript/typescript-sunos-x64": "7.0.2", + "@typescript/typescript-win32-arm64": "7.0.2", + "@typescript/typescript-win32-x64": "7.0.2" } }, - "node_modules/ws": { - "version": "8.21.3", - "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", - "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", - "license": "MIT", + "packages/spa": { + "dependencies": { + "react": "^19.2.8", + "react-dom": "^19.2.8", + "react-router": "^7.18.3", + "zod": "^4.4.3" + }, + "devDependencies": { + "@react-router/dev": "^7.18.3", + "@testing-library/dom": "^10.4.0", + "@testing-library/react": "^16.3.0", + "@types/node": "^25.9.5", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.4", + "@vitejs/plugin-react": "^6.0.5", + "happy-dom": "^20.11.0", + "typescript": "^6.0.3", + "vite-cli": "npm:vite@^8.2.2" + } + }, + "packages/spa/node_modules/@react-router/dev": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@react-router/dev/-/dev-7.18.3.tgz", + "integrity": "sha512-smLBdktEcLw1BgjaeWZG+TDRpmK9Mry4DzgNv4q556/Kq9qDo9Lfxu9Gp4/4BGOctFQG2UuyvxOnOhz0tEyzWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/core": "^7.27.7", + "@babel/generator": "^7.27.5", + "@babel/parser": "^7.27.7", + "@babel/plugin-syntax-jsx": "^7.27.1", + "@babel/preset-typescript": "^7.27.1", + "@babel/traverse": "^7.27.7", + "@babel/types": "^7.27.7", + "@react-router/node": "7.18.3", + "@remix-run/node-fetch-server": "^0.13.0", + "arg": "^5.0.1", + "babel-dead-code-elimination": "^1.0.6", + "chokidar": "^4.0.0", + "dedent": "^1.5.3", + "es-module-lexer": "^1.3.1", + "exit-hook": "2.2.1", + "isbot": "^5.1.11", + "jsesc": "3.0.2", + "lodash": "^4.17.21", + "p-map": "^7.0.3", + "pathe": "^1.1.2", + "picocolors": "^1.1.1", + "pkg-types": "^2.3.0", + "prettier": "^3.6.2", + "react-refresh": "^0.14.0", + "semver": "^7.3.7", + "tinyglobby": "^0.2.14", + "valibot": "^1.2.0", + "vite-node": "^3.2.2" + }, + "bin": { + "react-router": "bin.js" + }, "engines": { - "node": ">=10.0.0" + "node": ">=20.0.0" }, "peerDependencies": { - "bufferutil": "^4.0.1", - "utf-8-validate": ">=5.0.2" + "@react-router/serve": "^7.18.3", + "@vitejs/plugin-rsc": "~0.5.21", + "react-router": "^7.18.3", + "react-server-dom-webpack": "^19.2.3", + "typescript": "^5.1.0 || ^6.0.0", + "vite": "^5.1.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "wrangler": "^3.28.2 || ^4.0.0" }, "peerDependenciesMeta": { - "bufferutil": { + "@react-router/serve": { "optional": true }, - "utf-8-validate": { + "@vitejs/plugin-rsc": { + "optional": true + }, + "react-server-dom-webpack": { + "optional": true + }, + "typescript": { + "optional": true + }, + "wrangler": { "optional": true } } }, - "node_modules/xml-name-validator": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", - "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", - "devOptional": true, - "license": "Apache-2.0", + "packages/spa/node_modules/chokidar": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", + "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "readdirp": "^4.0.1" + }, "engines": { - "node": ">=18" + "node": ">= 14.16.0" + }, + "funding": { + "url": "https://paulmillr.com/funding/" } }, - "node_modules/xmlchars": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", - "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", - "devOptional": true, + "packages/spa/node_modules/es-module-lexer": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.7.0.tgz", + "integrity": "sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==", + "dev": true, "license": "MIT" }, - "node_modules/xtend": { - "version": "4.0.2", - "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", - "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", - "license": "MIT", + "packages/spa/node_modules/lightningcss": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss/-/lightningcss-1.33.0.tgz", + "integrity": "sha512-WkUDrojuJs0xkgGf2udWxa3yGBRxPtxUkB79i6aCZLRgc7PM8fZe9TosfPDcvEpQZbuFASnHYmRLBLUbmLOIIA==", + "dev": true, + "license": "MPL-2.0", + "peer": true, + "dependencies": { + "detect-libc": "^2.0.3" + }, "engines": { - "node": ">=0.4" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + }, + "optionalDependencies": { + "lightningcss-android-arm64": "1.33.0", + "lightningcss-darwin-arm64": "1.33.0", + "lightningcss-darwin-x64": "1.33.0", + "lightningcss-freebsd-x64": "1.33.0", + "lightningcss-linux-arm-gnueabihf": "1.33.0", + "lightningcss-linux-arm64-gnu": "1.33.0", + "lightningcss-linux-arm64-musl": "1.33.0", + "lightningcss-linux-x64-gnu": "1.33.0", + "lightningcss-linux-x64-musl": "1.33.0", + "lightningcss-win32-arm64-msvc": "1.33.0", + "lightningcss-win32-x64-msvc": "1.33.0" } }, - "node_modules/y18n": { - "version": "5.0.8", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", - "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "packages/spa/node_modules/lightningcss-android-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-android-arm64/-/lightningcss-android-arm64-1.33.0.tgz", + "integrity": "sha512-gEpRTalKdosp4Bb8qWtc2iOgE5SeIHlpS1up9bFq2wAyYhl1UdTObYiHe98zEM9SQvSoqQZ1IQD0JNpg3Ml5pg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", + "license": "MPL-2.0", + "optional": true, + "os": [ + "android" + ], + "peer": true, "engines": { - "node": ">=10" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" + } + }, + "packages/spa/node_modules/lightningcss-darwin-arm64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-arm64/-/lightningcss-darwin-arm64-1.33.0.tgz", + "integrity": "sha512-Sciaz8eenNTKn9b3t7+xr0ipTp9YxKQY4npwQ3mrRuL0BAVHBLyZxofhaKBAVtzmtRZ/zTyo0/to4B1uWG/Djg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/yallist": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/yallist/-/yallist-5.0.0.tgz", - "integrity": "sha512-YgvUTfwqyc7UXVMrB+SImsVYSmTS8X/tSrtdNZMImM+n7+QTriRXyXim0mBrTXNeqzVF0KWGgHPeiyViFFrNDw==", + "packages/spa/node_modules/lightningcss-darwin-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-darwin-x64/-/lightningcss-darwin-x64-1.33.0.tgz", + "integrity": "sha512-Z5UPAxzrjlWNNyGy6i65cJzzvgJ5D3T6wMvs+gWpY9d7qRhANrxqAp6LhxIgZhWEw18RfJTGcRxjuLIBr+m8XQ==", + "cpu": [ + "x64" + ], "dev": true, - "license": "BlueOak-1.0.0", + "license": "MPL-2.0", + "optional": true, + "os": [ + "darwin" + ], + "peer": true, "engines": { - "node": ">=18" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/yaml": { - "version": "2.9.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.9.0.tgz", - "integrity": "sha512-2AvhNX3mb8zd6Zy7INTtSpl1F15HW6Wnqj0srWlkKLcpYl/gMIMJiyuGq2KeI2YFxUPjdlB+3Lc10seMLtL4cA==", - "devOptional": true, - "license": "ISC", - "bin": { - "yaml": "bin.mjs" - }, + "packages/spa/node_modules/lightningcss-freebsd-x64": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-freebsd-x64/-/lightningcss-freebsd-x64-1.33.0.tgz", + "integrity": "sha512-QQM/Ti/hQajJwCY+RiWuCZ9sdtI/XQk7nDK5vC8kkdwixezOlDgvDx7+RT+QjK6FcFT4MpsuoBnHIo/O3StRRg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "freebsd" + ], + "peer": true, "engines": { - "node": ">= 14.6" + "node": ">= 12.0.0" }, "funding": { - "url": "https://github.com/sponsors/eemeli" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/yaml-ast-parser": { - "version": "0.0.43", - "resolved": "https://registry.npmjs.org/yaml-ast-parser/-/yaml-ast-parser-0.0.43.tgz", - "integrity": "sha512-2PTINUwsRqSd+s8XxKaJWQlUuEMHJQyEuh2edBbW8KNJz0SJPwUSD2zRWqezFEdN7IzAgeuYHFUCF7o8zRdZ0A==", - "dev": true, - "license": "Apache-2.0" - }, - "node_modules/yargs": { - "version": "18.0.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.0.0.tgz", - "integrity": "sha512-4UEqdc2RYGHZc7Doyqkrqiln3p9X2DZVxaGbwhn2pi7MrRagKaOcIKe8L3OxYcbhXLgLFUS3zAYuQjKBQgmuNg==", + "packages/spa/node_modules/lightningcss-linux-arm-gnueabihf": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm-gnueabihf/-/lightningcss-linux-arm-gnueabihf-1.33.0.tgz", + "integrity": "sha512-N7FVBe6iS24MlM6R/4RBTxGhQheZGs7tiQ9U32UtF75NzP5Q7xWPRqLBCKxlRQRk3rY1jCIPLzx7WzOhuUIRLQ==", + "cpu": [ + "arm" + ], "dev": true, - "license": "MIT", - "dependencies": { - "cliui": "^9.0.1", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "string-width": "^7.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^22.0.0" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/yargs-parser": { - "version": "21.1.1", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", - "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "packages/spa/node_modules/lightningcss-linux-arm64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-gnu/-/lightningcss-linux-arm64-gnu-1.33.0.tgz", + "integrity": "sha512-j2v/itmy4HlNxlc6voKXYgBqNi0Ng2LShg4z7GufpEgs05P+2suBVyi9I6YHq5uoVFx9ETin3eCEhLVyXGQnKg==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": ">=12" + "node": ">= 12.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/yargs/node_modules/yargs-parser": { - "version": "22.0.0", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz", - "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==", + "packages/spa/node_modules/lightningcss-linux-arm64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-arm64-musl/-/lightningcss-linux-arm64-musl-1.33.0.tgz", + "integrity": "sha512-yiO5ROMuYQgXbC60yjZU5CYSFZGKXL0HFATXt9mHJn1+zW55oCtMI9NfcVhYLMFDL7gV7oBPon/EmMMGg2OvtQ==", + "cpu": [ + "arm64" + ], "dev": true, - "license": "ISC", + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, "engines": { - "node": "^20.19.0 || ^22.12.0 || >=23" - } - }, - "node_modules/yuku-codegen": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/yuku-codegen/-/yuku-codegen-0.5.48.tgz", - "integrity": "sha512-p7HxD5Xl4jzDzqMrGePAOeSHmRY4g58h4HuGq15weQFPxuPWd/W6e7nqp/+Lea6JfpOdBwJOAyXFqIZ/J9Zfnw==", - "license": "MIT", - "dependencies": { - "@yuku-toolchain/types": "0.5.43" + "node": ">= 12.0.0" }, - "optionalDependencies": { - "@yuku-codegen/binding-darwin-arm64": "0.5.48", - "@yuku-codegen/binding-darwin-x64": "0.5.48", - "@yuku-codegen/binding-freebsd-x64": "0.5.48", - "@yuku-codegen/binding-linux-arm-gnu": "0.5.48", - "@yuku-codegen/binding-linux-arm-musl": "0.5.48", - "@yuku-codegen/binding-linux-arm64-gnu": "0.5.48", - "@yuku-codegen/binding-linux-arm64-musl": "0.5.48", - "@yuku-codegen/binding-linux-x64-gnu": "0.5.48", - "@yuku-codegen/binding-linux-x64-musl": "0.5.48", - "@yuku-codegen/binding-win32-arm64": "0.5.48", - "@yuku-codegen/binding-win32-x64": "0.5.48" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/yuku-parser": { - "version": "0.5.48", - "resolved": "https://registry.npmjs.org/yuku-parser/-/yuku-parser-0.5.48.tgz", - "integrity": "sha512-OWBfhrpgK9+/4+IXG9oT8Bao4AhViQA7vdyNNH7EUg8dQYgwa70XtIBWTpCEme1P1ECyoDNYkn0wT63f8XRcVA==", - "license": "MIT", - "dependencies": { - "@yuku-toolchain/types": "0.5.43" + "packages/spa/node_modules/lightningcss-linux-x64-gnu": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-gnu/-/lightningcss-linux-x64-gnu-1.33.0.tgz", + "integrity": "sha512-ar+Ju7LmcN0Jo4FpL4hpFybwNG9/3A/Br5KW2n2jyODg3MEZXaDYADdemoNS+BDNfMgKvylJLj4S5tyRActuAg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" }, - "optionalDependencies": { - "@yuku-parser/binding-darwin-arm64": "0.5.48", - "@yuku-parser/binding-darwin-x64": "0.5.48", - "@yuku-parser/binding-freebsd-x64": "0.5.48", - "@yuku-parser/binding-linux-arm-gnu": "0.5.48", - "@yuku-parser/binding-linux-arm-musl": "0.5.48", - "@yuku-parser/binding-linux-arm64-gnu": "0.5.48", - "@yuku-parser/binding-linux-arm64-musl": "0.5.48", - "@yuku-parser/binding-linux-x64-gnu": "0.5.48", - "@yuku-parser/binding-linux-x64-musl": "0.5.48", - "@yuku-parser/binding-win32-arm64": "0.5.48", - "@yuku-parser/binding-win32-x64": "0.5.48" - } - }, - "node_modules/zeptomatch": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/zeptomatch/-/zeptomatch-2.1.0.tgz", - "integrity": "sha512-KiGErG2J0G82LSpniV0CtIzjlJ10E04j02VOudJsPyPwNZgGnRKQy7I1R7GMyg/QswnE4l7ohSGrQbQbjXPPDA==", - "license": "MIT", - "dependencies": { - "grammex": "^3.1.11", - "graphmatch": "^1.1.0" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "node_modules/zod": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/zod/-/zod-4.4.3.tgz", - "integrity": "sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==", - "license": "MIT", + "packages/spa/node_modules/lightningcss-linux-x64-musl": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-linux-x64-musl/-/lightningcss-linux-x64-musl-1.33.0.tgz", + "integrity": "sha512-RYiYbkokw0trfKqqzfF55lginwEPrD3OJDfTuJzFs1MK6iFnDenaz1fqLLtX4ITG3OktJQXOeTaw1awrBAlZPw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MPL-2.0", + "optional": true, + "os": [ + "linux" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" + }, "funding": { - "url": "https://github.com/sponsors/colinhacks" + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "packages/api": { - "dependencies": { - "@hono/node-server": "^2.1.0", - "@prisma/adapter-pg": "^7.9.1", - "hono": "^4.13.1", - "zod": "^4.4.3" + "packages/spa/node_modules/lightningcss-win32-arm64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-arm64-msvc/-/lightningcss-win32-arm64-msvc-1.33.0.tgz", + "integrity": "sha512-1K+MPfLSFVpphzpdbfkhlWk6wBrTObBzS2T6db10PNOZgR9GoVsAWzwNyuhUYYbTp23j+4RrncfujZ4uAzXvwA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, + "engines": { + "node": ">= 12.0.0" }, - "devDependencies": { - "@types/node": "^25.9.5", - "concurrently": "^9.2.4", - "typescript": "^7.0.2" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "packages/api/node_modules/typescript": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", - "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "packages/spa/node_modules/lightningcss-win32-x64-msvc": { + "version": "1.33.0", + "resolved": "https://registry.npmjs.org/lightningcss-win32-x64-msvc/-/lightningcss-win32-x64-msvc-1.33.0.tgz", + "integrity": "sha512-OlEICDx/Xl0FqSp4bry8zFnCvGpig3Gl4gCquvYwHuqJKEC1+n9NgDniFvqHGmMv1ZkqDJrDqKKSykTDX+ehuA==", + "cpu": [ + "x64" + ], "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc" - }, + "license": "MPL-2.0", + "optional": true, + "os": [ + "win32" + ], + "peer": true, "engines": { - "node": ">=16.20.0" + "node": ">= 12.0.0" }, - "optionalDependencies": { - "@typescript/typescript-aix-ppc64": "7.0.2", - "@typescript/typescript-darwin-arm64": "7.0.2", - "@typescript/typescript-darwin-x64": "7.0.2", - "@typescript/typescript-freebsd-arm64": "7.0.2", - "@typescript/typescript-freebsd-x64": "7.0.2", - "@typescript/typescript-linux-arm": "7.0.2", - "@typescript/typescript-linux-arm64": "7.0.2", - "@typescript/typescript-linux-loong64": "7.0.2", - "@typescript/typescript-linux-mips64el": "7.0.2", - "@typescript/typescript-linux-ppc64": "7.0.2", - "@typescript/typescript-linux-riscv64": "7.0.2", - "@typescript/typescript-linux-s390x": "7.0.2", - "@typescript/typescript-linux-x64": "7.0.2", - "@typescript/typescript-netbsd-arm64": "7.0.2", - "@typescript/typescript-netbsd-x64": "7.0.2", - "@typescript/typescript-openbsd-arm64": "7.0.2", - "@typescript/typescript-openbsd-x64": "7.0.2", - "@typescript/typescript-sunos-x64": "7.0.2", - "@typescript/typescript-win32-arm64": "7.0.2", - "@typescript/typescript-win32-x64": "7.0.2" + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/parcel" } }, - "packages/bin": { - "devDependencies": { - "@types/node": "^25.9.5", - "typescript": "^7.0.2" - } + "packages/spa/node_modules/pathe": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", + "integrity": "sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==", + "dev": true, + "license": "MIT" }, - "packages/bin/node_modules/typescript": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", - "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "packages/spa/node_modules/readdirp": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", + "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "dev": true, - "license": "Apache-2.0", - "bin": { - "tsc": "bin/tsc" - }, + "license": "MIT", "engines": { - "node": ">=16.20.0" - }, - "optionalDependencies": { - "@typescript/typescript-aix-ppc64": "7.0.2", - "@typescript/typescript-darwin-arm64": "7.0.2", - "@typescript/typescript-darwin-x64": "7.0.2", - "@typescript/typescript-freebsd-arm64": "7.0.2", - "@typescript/typescript-freebsd-x64": "7.0.2", - "@typescript/typescript-linux-arm": "7.0.2", - "@typescript/typescript-linux-arm64": "7.0.2", - "@typescript/typescript-linux-loong64": "7.0.2", - "@typescript/typescript-linux-mips64el": "7.0.2", - "@typescript/typescript-linux-ppc64": "7.0.2", - "@typescript/typescript-linux-riscv64": "7.0.2", - "@typescript/typescript-linux-s390x": "7.0.2", - "@typescript/typescript-linux-x64": "7.0.2", - "@typescript/typescript-netbsd-arm64": "7.0.2", - "@typescript/typescript-netbsd-x64": "7.0.2", - "@typescript/typescript-openbsd-arm64": "7.0.2", - "@typescript/typescript-openbsd-x64": "7.0.2", - "@typescript/typescript-sunos-x64": "7.0.2", - "@typescript/typescript-win32-arm64": "7.0.2", - "@typescript/typescript-win32-x64": "7.0.2" - } - }, - "packages/client": { - "version": "0.1.0", - "dependencies": { - "@radix-ui/react-icons": "^1.3.2", - "@radix-ui/themes": "^3.3.0", - "next": "^16.3.0", - "react": "^19.2.8", - "react-dom": "^19.2.8", - "server-only": "^0.0.1" + "node": ">= 14.18.0" }, - "devDependencies": { - "@tailwindcss/postcss": "^4.3.3", - "@types/node": "^25.9.5", - "@types/react": "^19.2.18", - "@types/react-dom": "^19.2.4", - "@vitejs/plugin-react": "^6.0.5", - "jsdom": "^30.0.1", - "tailwindcss": "^4.3.3", - "typescript": "^7.0.2" + "funding": { + "type": "individual", + "url": "https://paulmillr.com/funding/" } }, - "packages/client/node_modules/typescript": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", - "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", + "packages/spa/node_modules/typescript": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", + "integrity": "sha512-y2TvuxSZPDyQakkFRPZHKFm+KKVqIisdg9/CZwm9ftvKXLP8NRWj38/ODjNbr43SsoXqNuAisEf1GdCxqWcdBw==", "dev": true, "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc" + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" }, "engines": { - "node": ">=16.20.0" - }, - "optionalDependencies": { - "@typescript/typescript-aix-ppc64": "7.0.2", - "@typescript/typescript-darwin-arm64": "7.0.2", - "@typescript/typescript-darwin-x64": "7.0.2", - "@typescript/typescript-freebsd-arm64": "7.0.2", - "@typescript/typescript-freebsd-x64": "7.0.2", - "@typescript/typescript-linux-arm": "7.0.2", - "@typescript/typescript-linux-arm64": "7.0.2", - "@typescript/typescript-linux-loong64": "7.0.2", - "@typescript/typescript-linux-mips64el": "7.0.2", - "@typescript/typescript-linux-ppc64": "7.0.2", - "@typescript/typescript-linux-riscv64": "7.0.2", - "@typescript/typescript-linux-s390x": "7.0.2", - "@typescript/typescript-linux-x64": "7.0.2", - "@typescript/typescript-netbsd-arm64": "7.0.2", - "@typescript/typescript-netbsd-x64": "7.0.2", - "@typescript/typescript-openbsd-arm64": "7.0.2", - "@typescript/typescript-openbsd-x64": "7.0.2", - "@typescript/typescript-sunos-x64": "7.0.2", - "@typescript/typescript-win32-arm64": "7.0.2", - "@typescript/typescript-win32-x64": "7.0.2" + "node": ">=14.17" } }, - "packages/shared": { + "packages/spa/node_modules/vite": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.2.2.tgz", + "integrity": "sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==", + "dev": true, + "license": "MIT", + "peer": true, "dependencies": { - "@prisma/adapter-pg": "^7.9.1", - "@prisma/client": "^7.9.1", - "prisma": "^7.9.1" - }, - "devDependencies": { - "@types/node": "^25.9.5", - "@typespec/compiler": "^1.15.0", - "@typespec/http": "^1.15.0", - "@typespec/openapi": "^1.15.0", - "@typespec/openapi3": "^1.15.0", - "@typespec/rest": "^0.85.0", - "concurrently": "^9.2.4", - "openapi-typescript": "^7.9.1", - "typescript": "^7.0.2" + "lightningcss": "^1.33.0", + "picomatch": "^4.0.5", + "postcss": "^8.5.26", + "rolldown": "~1.2.4", + "tinyglobby": "^0.2.17" }, - "optionalDependencies": { - "@rollup/rollup-linux-x64-gnu": "^4.62.4" - } - }, - "packages/shared/node_modules/typescript": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-7.0.2.tgz", - "integrity": "sha512-8FYau96o3NKOhbjKi/qNvG/W5jhzxkbdm5sj9AbZ/5T5sWqn3hJgLfGx27sRKZWTvyzCP8dLRBTf5tBTSRVUNA==", - "dev": true, - "license": "Apache-2.0", "bin": { - "tsc": "bin/tsc" + "vite": "bin/vite.js" }, "engines": { - "node": ">=16.20.0" + "node": "^20.19.0 || >=22.12.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" }, "optionalDependencies": { - "@typescript/typescript-aix-ppc64": "7.0.2", - "@typescript/typescript-darwin-arm64": "7.0.2", - "@typescript/typescript-darwin-x64": "7.0.2", - "@typescript/typescript-freebsd-arm64": "7.0.2", - "@typescript/typescript-freebsd-x64": "7.0.2", - "@typescript/typescript-linux-arm": "7.0.2", - "@typescript/typescript-linux-arm64": "7.0.2", - "@typescript/typescript-linux-loong64": "7.0.2", - "@typescript/typescript-linux-mips64el": "7.0.2", - "@typescript/typescript-linux-ppc64": "7.0.2", - "@typescript/typescript-linux-riscv64": "7.0.2", - "@typescript/typescript-linux-s390x": "7.0.2", - "@typescript/typescript-linux-x64": "7.0.2", - "@typescript/typescript-netbsd-arm64": "7.0.2", - "@typescript/typescript-netbsd-x64": "7.0.2", - "@typescript/typescript-openbsd-arm64": "7.0.2", - "@typescript/typescript-openbsd-x64": "7.0.2", - "@typescript/typescript-sunos-x64": "7.0.2", - "@typescript/typescript-win32-arm64": "7.0.2", - "@typescript/typescript-win32-x64": "7.0.2" + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^20.19.0 || >=22.12.0", + "@vitejs/devtools": "^0.4.0 || ^0.5.0", + "esbuild": "^0.27.0 || ^0.28.0", + "jiti": ">=1.21.0", + "less": "^4.0.0", + "sass": "^1.70.0", + "sass-embedded": "^1.70.0", + "stylus": ">=0.54.8", + "sugarss": "^5.0.0", + "terser": "^5.16.0", + "tsx": "^4.8.1", + "yaml": "^2.4.2" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "@vitejs/devtools": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "jiti": { + "optional": true + }, + "less": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + }, + "tsx": { + "optional": true + }, + "yaml": { + "optional": true + } } }, "packages/task": { diff --git a/package.json b/package.json index a28dca4..ec4cda9 100644 --- a/package.json +++ b/package.json @@ -16,7 +16,13 @@ "middleware": "DOCKER_HOST_IP=$(hostname -I 2>/dev/null | awk '{print $1}') docker compose up" }, "overrides": { - "vite": "npm:@voidzero-dev/vite-plus-core@^0.2.9" + "vite": "npm:@voidzero-dev/vite-plus-core@^0.2.9", + "@react-router/dev": { + "vite": "npm:vite@^8.2.2" + }, + "vite-node": { + "vite": "7.3.6" + } }, "dependencies": { "vite-plus": "^0.2.9" diff --git a/packages/spa/.gitignore b/packages/spa/.gitignore new file mode 100644 index 0000000..af966af --- /dev/null +++ b/packages/spa/.gitignore @@ -0,0 +1,2 @@ +dist +.react-router/ diff --git a/packages/spa/app/components/DashboardView.test.tsx b/packages/spa/app/components/DashboardView.test.tsx new file mode 100644 index 0000000..7828395 --- /dev/null +++ b/packages/spa/app/components/DashboardView.test.tsx @@ -0,0 +1,70 @@ +// @vitest-environment happy-dom +import { cleanup, render, screen } from '@testing-library/react' +import { afterEach, expect, test } from 'vite-plus/test' + +import { HydrateFallback } from '../root' +import { DashboardView } from './DashboardView' +import type { UserResponse } from '../../src/api-contract' +import type { UserLoadResult } from '../lib/api-client' + +const successData = { + count: 2, + user: [ + { + id: 1, + name: 'Alice', + created_at: 1710000000, + updated_at: 1710003600 + }, + { + id: 2, + name: 'Bob', + created_at: 1710007200, + updated_at: 1710010800 + } + ] +} satisfies UserResponse + +const failureResult = { + ok: false, + status: 502, + body: 'Bad Gateway' +} satisfies UserLoadResult + +afterEach(() => { + cleanup() +}) + +test('loading fixture shows an accessible pending state', () => { + render() + + expect(screen.getByRole('status', { name: 'Service API 問い合わせ中' })).toBeTruthy() + expect(screen.getByRole('main').getAttribute('aria-busy')).toBe('true') + expect(screen.getByText('--')).toBeTruthy() +}) + +test('success fixture shows online state, summary, and every user', () => { + render() + + expect(screen.getByRole('status', { name: 'API ONLINE' })).toBeTruthy() + expect(screen.getByRole('heading', { name: '登録ユーザー' })).toBeTruthy() + expect(screen.getByText('2件')).toBeTruthy() + expect(screen.getByRole('heading', { name: 'Alice' })).toBeTruthy() + expect(screen.getByRole('heading', { name: 'Bob' })).toBeTruthy() +}) + +test('empty fixture shows a domain-specific empty state', () => { + render() + + expect(screen.getByRole('status', { name: 'API ONLINE' })).toBeTruthy() + expect(screen.getByRole('heading', { name: 'ユーザーがありません' })).toBeTruthy() + expect(screen.queryByRole('heading', { name: 'ユーザー一覧' })).toBeNull() +}) + +test('failure fixture shows offline status without exposing upstream details', () => { + render() + + expect(screen.getByRole('status', { name: 'API OFFLINE' })).toBeTruthy() + expect(screen.getByRole('alert').textContent).toContain('Service APIへ接続できません') + expect(screen.queryByText('Bad Gateway')).toBeNull() +}) diff --git a/packages/spa/app/components/DashboardView.tsx b/packages/spa/app/components/DashboardView.tsx new file mode 100644 index 0000000..5119983 --- /dev/null +++ b/packages/spa/app/components/DashboardView.tsx @@ -0,0 +1,113 @@ +import { Activity } from 'react' +import { formatJst } from '../lib/format' +import type { UserLoadResult } from '../lib/api-client' + +type DashboardViewProps = { + result: UserLoadResult +} + +type UserListProps = { + data: Extract['body'] +} + +function ApiState({ online }: { online: boolean }) { + if (online) { + return ( +

+ API ONLINE +

+ ) + } + return ( +

+ API OFFLINE +

+ ) +} + +function UserList({ data }: UserListProps) { + if (data.user.length === 0) { + return ( +
+

--

+

ユーザーがありません

+

Service APIに登録されたユーザーはありません。

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

Service API

+

登録ユーザー

+
+ {data.count} +
+
+
+
+

Directory

+

ユーザー一覧

+
+ {data.count}件 +
+
    + {data.user.map((user) => { + return ( +
  • +
    +

    {user.name}

    + ID {user.id} +
    +
    +
    +
    作成
    +
    {formatJst(user.created_at)}
    +
    +
    +
    更新
    +
    {formatJst(user.updated_at)}
    +
    +
    +
  • + ) + })} +
+
+ + ) +} + +function OfflineState() { + return ( +
+

OFFLINE

+

Service APIへ接続できません

+

Service APIの稼働状態と接続設定を確認してください。

+
+ ) +} + +export function DashboardView({ result }: DashboardViewProps) { + const successData = result.ok ? result.body : null + + return ( +
+
+
+

service template

+

Service Template

+
+ +
+ + {successData === null ? null : } + + + {successData === null ? : null} + +
+ ) +} diff --git a/packages/spa/app/entry.client.tsx b/packages/spa/app/entry.client.tsx new file mode 100644 index 0000000..098e345 --- /dev/null +++ b/packages/spa/app/entry.client.tsx @@ -0,0 +1,12 @@ +import { StrictMode, startTransition } from 'react' +import { hydrateRoot } from 'react-dom/client' +import { HydratedRouter } from 'react-router/dom' + +startTransition(() => { + hydrateRoot( + document, + + + + ) +}) diff --git a/packages/spa/app/entry.server.tsx b/packages/spa/app/entry.server.tsx new file mode 100644 index 0000000..11bd83d --- /dev/null +++ b/packages/spa/app/entry.server.tsx @@ -0,0 +1,27 @@ +import { renderToReadableStream } from 'react-dom/server' +import { type EntryContext, ServerRouter } from 'react-router' + +export default async function handleRequest( + request: Request, + responseStatusCode: number, + responseHeaders: Headers, + routerContext: EntryContext +) { + let statusCode = responseStatusCode + const stream = await renderToReadableStream( + , + { + onError(error: unknown) { + statusCode = 500 + console.error(error) + } + } + ) + await stream.allReady + + responseHeaders.set('Content-Type', 'text/html; charset=utf-8') + return new Response(stream, { + status: statusCode, + headers: responseHeaders + }) +} diff --git a/packages/spa/app/lib/api-client.test.ts b/packages/spa/app/lib/api-client.test.ts new file mode 100644 index 0000000..7fab66d --- /dev/null +++ b/packages/spa/app/lib/api-client.test.ts @@ -0,0 +1,51 @@ +import { expect, test } from 'vite-plus/test' +import { fetchUsers } from './api-client' +import type { UserResponse } from '../../src/api-contract' + +const responseBody = { + count: 1, + user: [ + { + id: 1, + name: 'Alice', + created_at: 1710000000, + updated_at: 1710003600 + } + ] +} satisfies UserResponse + +test('clientLoader fetches the same-origin endpoint exactly once', async () => { + const originalFetch = globalThis.fetch + let calls = 0 + globalThis.fetch = async () => { + calls += 1 + return new Response(JSON.stringify(responseBody), { + status: 200, + headers: { 'content-type': 'application/json' } + }) + } + + try { + const result = await fetchUsers() + expect(calls).toBe(1) + expect(result).toEqual({ ok: true, body: responseBody }) + } finally { + globalThis.fetch = originalFetch + } +}) + +test('invalid response shape becomes a sanitized failure', async () => { + const originalFetch = globalThis.fetch + globalThis.fetch = async () => { + return new Response(JSON.stringify({ count: 2, user: responseBody.user }), { + status: 200, + headers: { 'content-type': 'application/json' } + }) + } + + try { + await expect(fetchUsers()).resolves.toEqual({ ok: false, status: 502, body: 'Bad Gateway' }) + } finally { + globalThis.fetch = originalFetch + } +}) diff --git a/packages/spa/app/lib/api-client.ts b/packages/spa/app/lib/api-client.ts new file mode 100644 index 0000000..cfc8b85 --- /dev/null +++ b/packages/spa/app/lib/api-client.ts @@ -0,0 +1,27 @@ +import { parseUserResponse, type UserResponse } from '../../src/api-contract' + +export type UserLoadResult = + | { ok: true; body: UserResponse } + | { ok: false; status: number; body: 'Bad Gateway' } + +export async function fetchUsers() { + try { + const response = await fetch('/api/user', { + cache: 'no-store', + headers: { + Accept: 'application/json' + } + }) + if (!response.ok) { + return { ok: false, status: response.status, body: 'Bad Gateway' } satisfies UserLoadResult + } + + const parsed = parseUserResponse(await response.json()) + if (parsed === null) { + return { ok: false, status: 502, body: 'Bad Gateway' } satisfies UserLoadResult + } + return { ok: true, body: parsed } satisfies UserLoadResult + } catch { + return { ok: false, status: 502, body: 'Bad Gateway' } satisfies UserLoadResult + } +} diff --git a/packages/spa/app/lib/format.ts b/packages/spa/app/lib/format.ts new file mode 100644 index 0000000..889d79d --- /dev/null +++ b/packages/spa/app/lib/format.ts @@ -0,0 +1,19 @@ +const jstFormatter = new Intl.DateTimeFormat('ja-JP', { + timeZone: 'Asia/Tokyo', + month: '2-digit', + day: '2-digit', + hour: '2-digit', + minute: '2-digit', + hour12: false +}) + +export function formatJst(seconds: number) { + if (!Number.isSafeInteger(seconds) || seconds < 0) { + return '--' + } + const date = new Date(seconds * 1000) + if (Number.isNaN(date.getTime())) { + return '--' + } + return `${jstFormatter.format(date)} JST` +} diff --git a/packages/spa/app/root.tsx b/packages/spa/app/root.tsx new file mode 100644 index 0000000..3dc51b9 --- /dev/null +++ b/packages/spa/app/root.tsx @@ -0,0 +1,55 @@ +import { Links, Meta, Outlet, Scripts } from 'react-router' +import type { Route } from './+types/root' +import './styles.css' + +export const meta: Route.MetaFunction = () => { + return [ + { title: 'Service Template' }, + { name: 'viewport', content: 'width=device-width, initial-scale=1' } + ] +} + +export function Layout({ children }: { children: React.ReactNode }) { + return ( + + + + + + + + {children} + + + + ) +} + +export function HydrateFallback() { + return ( +
+
+
+

service template

+

Service Template

+
+

+ Service API 問い合わせ中 +

+
+
+

--

+

ユーザーデータを読み込んでいます

+
+
+ ) +} + +export default function App() { + return +} diff --git a/packages/spa/app/routes.ts b/packages/spa/app/routes.ts new file mode 100644 index 0000000..70b1421 --- /dev/null +++ b/packages/spa/app/routes.ts @@ -0,0 +1,3 @@ +import { index, type RouteConfig } from '@react-router/dev/routes' + +export default [index('routes/dashboard.tsx')] satisfies RouteConfig diff --git a/packages/spa/app/routes/dashboard.tsx b/packages/spa/app/routes/dashboard.tsx new file mode 100644 index 0000000..97d10a3 --- /dev/null +++ b/packages/spa/app/routes/dashboard.tsx @@ -0,0 +1,11 @@ +import type { Route } from './+types/dashboard' +import { DashboardView } from '../components/DashboardView' +import { fetchUsers } from '../lib/api-client' + +export function clientLoader() { + return fetchUsers() +} + +export default function Dashboard({ loaderData }: Route.ComponentProps) { + return +} diff --git a/packages/spa/app/styles.css b/packages/spa/app/styles.css new file mode 100644 index 0000000..6b04ca6 --- /dev/null +++ b/packages/spa/app/styles.css @@ -0,0 +1,265 @@ +:root { + --bg: #101418; + --panel: #1a2027; + --panel-border: #2a323c; + --text: #e6ebf0; + --text-dim: #8b98a5; + --online: #34c176; + --offline: #e5534b; + --accent: #83a9ff; +} + +* { + box-sizing: border-box; +} + +html, +body { + min-width: 0; + margin: 0; + padding: 0; + background: var(--bg); + color: var(--text); + font-family: + system-ui, + -apple-system, + 'Segoe UI', + 'Hiragino Sans', + 'Noto Sans JP', + sans-serif; + -webkit-text-size-adjust: 100%; +} + +body { + min-height: 100vh; +} + +button, +a, +input, +select, +textarea { + font: inherit; +} + +.dashboard { + width: 100%; + max-width: 960px; + min-width: 0; + margin: 0 auto; + padding: 16px; +} + +.dashboard-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + min-width: 0; + margin-bottom: 16px; +} + +.eyebrow, +.card-kicker { + margin: 0 0 4px; + color: var(--text-dim); + font-size: 0.7rem; + letter-spacing: 0.12em; + text-transform: uppercase; +} + +.dashboard-head h1, +.summary-card h2, +.users-panel h2, +.state-panel h2, +.user-card h3 { + margin: 0; +} + +.dashboard-head h1 { + font-size: clamp(1.25rem, 4vw, 1.6rem); + letter-spacing: -0.02em; +} + +.api-state { + flex: 0 0 auto; + margin: 0; + font-size: 0.78rem; + font-weight: 700; + letter-spacing: 0.04em; +} + +.api-online { + color: var(--online); +} + +.api-offline { + color: var(--offline); +} + +.api-pending { + color: var(--text-dim); +} + +.summary-card, +.users-panel, +.state-panel { + min-width: 0; + border: 1px solid var(--panel-border); + border-radius: 12px; + background: var(--panel); +} + +.summary-card { + display: flex; + align-items: center; + justify-content: space-between; + gap: 16px; + padding: 20px; +} + +.summary-card h2, +.users-panel h2 { + font-size: 1rem; +} + +.summary-value { + color: var(--accent); + font-size: clamp(2rem, 8vw, 3.2rem); + font-variant-numeric: tabular-nums; + line-height: 1; +} + +.users-panel { + margin-top: 16px; + padding: 16px; +} + +.panel-head { + display: flex; + align-items: flex-end; + justify-content: space-between; + gap: 16px; + margin-bottom: 16px; +} + +.panel-count, +.user-id { + color: var(--text-dim); + font-size: 0.75rem; + font-variant-numeric: tabular-nums; +} + +.user-list { + display: grid; + grid-template-columns: 1fr; + gap: 16px; + min-width: 0; + margin: 0; + padding: 0; + list-style: none; +} + +.user-card { + min-width: 0; + padding: 16px; + border: 1px solid var(--panel-border); + border-radius: 12px; + background: color-mix(in srgb, var(--panel) 72%, var(--bg)); +} + +.user-card-head { + display: flex; + align-items: baseline; + justify-content: space-between; + gap: 12px; + min-width: 0; +} + +.user-card h3 { + min-width: 0; + overflow-wrap: anywhere; + font-size: 1rem; +} + +.user-meta { + display: grid; + grid-template-columns: repeat(2, minmax(0, 1fr)); + gap: 12px; + margin: 16px 0 0; + padding-top: 12px; + border-top: 1px solid var(--panel-border); + font-size: 0.75rem; +} + +.user-meta dt { + margin-bottom: 4px; + color: var(--text-dim); +} + +.user-meta dd { + margin: 0; + overflow-wrap: anywhere; + font-variant-numeric: tabular-nums; +} + +.state-panel { + padding: 40px 16px; + text-align: center; + color: var(--text-dim); +} + +.state-value { + margin: 0 0 8px; + color: var(--panel-border); + font-size: clamp(2.3rem, 11vw, 4rem); + font-weight: 800; + letter-spacing: 0.04em; + line-height: 1; +} + +.state-panel h2 { + color: var(--text); + font-size: 1rem; +} + +.state-hint { + max-width: 38rem; + margin: 10px auto 0; + font-size: 0.78rem; + line-height: 1.6; +} + +.state-offline .state-value { + color: var(--offline); +} + +@media (min-width: 640px) { + .user-list { + grid-template-columns: repeat(auto-fit, minmax(260px, 1fr)); + } +} + +@media (max-width: 480px) { + .dashboard-head { + align-items: flex-start; + flex-direction: column; + } + + .user-card-head { + align-items: flex-start; + flex-direction: column; + gap: 4px; + } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + scroll-behavior: auto !important; + transition-duration: 0.01ms !important; + animation-duration: 0.01ms !important; + animation-iteration-count: 1 !important; + } +} diff --git a/packages/spa/app/styles.test.ts b/packages/spa/app/styles.test.ts new file mode 100644 index 0000000..e2974eb --- /dev/null +++ b/packages/spa/app/styles.test.ts @@ -0,0 +1,14 @@ +import fs from 'node:fs' +import path from 'node:path' +import { expect, test } from 'vite-plus/test' + +const styles = fs.readFileSync(path.join(process.cwd(), 'app/styles.css'), 'utf8') + +test('dashboard visual tokens and responsive layout are explicit', () => { + expect(styles).toContain('--bg: #101418') + expect(styles).toContain('--panel: #1a2027') + expect(styles).toContain('--online: #34c176') + expect(styles).toContain('@media (min-width: 640px)') + expect(styles).toContain('@media (max-width: 480px)') + expect(styles).toContain('overflow-wrap: anywhere') +}) diff --git a/packages/spa/package.json b/packages/spa/package.json new file mode 100644 index 0000000..b134e0a --- /dev/null +++ b/packages/spa/package.json @@ -0,0 +1,36 @@ +{ + "name": "spa", + "private": true, + "type": "module", + "scripts": { + "dev": "vite", + "pretsc": "npm run build -w shared", + "tsc": "react-router typegen && tsc --noEmit", + "build": "rm -rf dist && vp build && mv dist/spa/client dist/public && rm -rf dist/spa && tsc -p tsconfig.server.json", + "start": "node dist/server/index.js", + "test": "vp test --config=./vite.config.ts", + "test-ci": "vp test run --config=./vite.config.ts --maxWorkers=1", + "format": "vp fmt package.json react-router.config.ts vite.config.ts app src --write", + "format-check": "vp fmt package.json react-router.config.ts vite.config.ts app src --check", + "lint": "vp lint react-router.config.ts vite.config.ts app src", + "lint-fix": "vp lint react-router.config.ts vite.config.ts app src --fix" + }, + "dependencies": { + "react": "^19.2.8", + "react-dom": "^19.2.8", + "react-router": "^7.18.3", + "zod": "^4.4.3" + }, + "devDependencies": { + "@react-router/dev": "^7.18.3", + "@testing-library/dom": "^10.4.0", + "@testing-library/react": "^16.3.0", + "@types/node": "^25.9.5", + "@types/react": "^19.2.18", + "@types/react-dom": "^19.2.4", + "@vitejs/plugin-react": "^6.0.5", + "happy-dom": "^20.11.0", + "typescript": "^6.0.3", + "vite-cli": "npm:vite@^8.2.2" + } +} diff --git a/packages/spa/react-router.config.ts b/packages/spa/react-router.config.ts new file mode 100644 index 0000000..b43e5eb --- /dev/null +++ b/packages/spa/react-router.config.ts @@ -0,0 +1,9 @@ +import type { Config } from '@react-router/dev/config' + +export default { + ssr: false, + buildDirectory: 'dist/spa', + future: { + v8_viteEnvironmentApi: true + } +} satisfies Config diff --git a/packages/spa/src/api-contract.test.ts b/packages/spa/src/api-contract.test.ts new file mode 100644 index 0000000..d0d01d2cf --- /dev/null +++ b/packages/spa/src/api-contract.test.ts @@ -0,0 +1,43 @@ +import { expect, test } from 'vite-plus/test' +import { parseUserResponse } from './api-contract' + +test('runtime contract accepts the generated API shape', () => { + const parsed = parseUserResponse({ + count: 1, + user: [ + { + id: 1, + name: 'Alice', + created_at: 1710000000, + updated_at: 1710003600 + } + ] + }) + + expect(parsed).toEqual({ + count: 1, + user: [ + { + id: 1, + name: 'Alice', + created_at: 1710000000, + updated_at: 1710003600 + } + ] + }) +}) + +test('count mismatch and invalid timestamps are rejected', () => { + expect( + parseUserResponse({ + count: 2, + user: [{ id: 1, name: 'Alice', created_at: 1710000000, updated_at: 1710003600 }] + }) + ).toBeNull() + expect( + parseUserResponse({ + count: 1, + user: [{ id: 1, name: 'Alice', created_at: -1, updated_at: 1710003600 }] + }) + ).toBeNull() +}) diff --git a/packages/spa/src/api-contract.ts b/packages/spa/src/api-contract.ts new file mode 100644 index 0000000..313671d --- /dev/null +++ b/packages/spa/src/api-contract.ts @@ -0,0 +1,53 @@ +import type { paths } from 'shared/src/schema' +import * as z from 'zod/mini' + +export type UserResponse = + paths['/api/user']['get']['responses']['200']['content']['application/json'] + +const userSchema = z.object({ + id: z.number(), + name: z.string(), + created_at: z.number(), + updated_at: z.number() +}) + +const userResponseSchema = z.object({ + count: z.number(), + user: z.array(userSchema) +}) + +function isSafeNonNegativeInteger(value: number) { + return Number.isSafeInteger(value) && value >= 0 +} + +function isValidTimestampSeconds(value: number) { + if (!isSafeNonNegativeInteger(value)) { + return false + } + return !Number.isNaN(new Date(value * 1000).getTime()) +} + +export function parseUserResponse(input: unknown) { + const parsed = userResponseSchema.safeParse(input) + if (!parsed.success) { + return null + } + + const data = parsed.data + if (!isSafeNonNegativeInteger(data.count) || data.count !== data.user.length) { + return null + } + + for (const user of data.user) { + if ( + !isSafeNonNegativeInteger(user.id) || + !isValidTimestampSeconds(user.created_at) || + !isValidTimestampSeconds(user.updated_at) + ) { + return null + } + } + + const response: UserResponse = data + return response +} diff --git a/packages/spa/src/server/authority.test.ts b/packages/spa/src/server/authority.test.ts new file mode 100644 index 0000000..d6e9860 --- /dev/null +++ b/packages/spa/src/server/authority.test.ts @@ -0,0 +1,46 @@ +// @vitest-environment node +import { expect, test } from 'vite-plus/test' +import { validateAuthority } from './authority.js' + +test('authority accepts one exact Host and no Origin', () => { + expect( + validateAuthority({ + request: { rawHeaders: ['Host', '127.0.0.1:8789'] }, + authority: '127.0.0.1:8789', + origin: 'http://127.0.0.1:8789' + }) + ).toEqual({ ok: true }) +}) + +test('authority rejects missing, duplicate, and comma-joined Host fields', () => { + for (const rawHeaders of [ + [], + ['Host', '127.0.0.1:8789', 'Host', '127.0.0.1:8789'], + ['Host', '127.0.0.1:8789,127.0.0.1:8789'], + ['Host', '127.0.0.1:8790'] + ]) { + expect( + validateAuthority({ + request: { rawHeaders }, + authority: '127.0.0.1:8789', + origin: 'http://127.0.0.1:8789' + }) + ).toEqual({ ok: false, status: 400 }) + } +}) + +test('authority rejects duplicate, comma-joined, and mismatched Origin fields', () => { + for (const rawHeaders of [ + ['Host', '127.0.0.1:8789', 'Origin', 'http://127.0.0.1:8789', 'Origin', 'http://evil.test'], + ['Host', '127.0.0.1:8789', 'Origin', 'http://127.0.0.1:8789,http://evil.test'], + ['Host', '127.0.0.1:8789', 'Origin', 'http://evil.test'] + ]) { + expect( + validateAuthority({ + request: { rawHeaders }, + authority: '127.0.0.1:8789', + origin: 'http://127.0.0.1:8789' + }) + ).toEqual({ ok: false, status: 403 }) + } +}) diff --git a/packages/spa/src/server/authority.ts b/packages/spa/src/server/authority.ts new file mode 100644 index 0000000..ac619ef --- /dev/null +++ b/packages/spa/src/server/authority.ts @@ -0,0 +1,41 @@ +type HeaderRequest = { + rawHeaders: readonly string[] +} + +type AuthorityValidation = { ok: true } | { ok: false; status: 400 | 403 } + +function headerValues(request: HeaderRequest, name: string) { + const values: string[] = [] + for (let index = 0; index < request.rawHeaders.length; index += 2) { + const headerName = request.rawHeaders[index] + const headerValue = request.rawHeaders[index + 1] + if (headerName?.toLowerCase() === name && headerValue !== undefined) { + values.push(headerValue) + } + } + return values +} + +export function validateAuthority({ + request, + authority, + origin +}: { + request: HeaderRequest + authority: string + origin: string +}): AuthorityValidation { + const hosts = headerValues(request, 'host') + if (hosts.length !== 1 || hosts[0]?.includes(',') || hosts[0] !== authority) { + return { ok: false, status: 400 } + } + + const origins = headerValues(request, 'origin') + if (origins.length > 1 || origins.some((value) => value.includes(','))) { + return { ok: false, status: 403 } + } + if (origins.length === 1 && origins[0] !== origin) { + return { ok: false, status: 403 } + } + return { ok: true } +} diff --git a/packages/spa/src/server/config.test.ts b/packages/spa/src/server/config.test.ts new file mode 100644 index 0000000..73cbc7d --- /dev/null +++ b/packages/spa/src/server/config.test.ts @@ -0,0 +1,47 @@ +// @vitest-environment node +import fs from 'node:fs' +import os from 'node:os' +import path from 'node:path' +import { expect, test } from 'vite-plus/test' +import { assertDistribution, formatAuthority, loadConfig } from './config.js' + +test('config defaults to a loopback authority and a sanitized empty token', () => { + const config = loadConfig({}) + + expect(config.host).toBe('127.0.0.1') + expect(config.port).toBe(8789) + expect(config.authority).toBe('127.0.0.1:8789') + expect(config.origin).toBe('http://127.0.0.1:8789') + expect(config.apiUri).toBe('http://localhost:8000') + expect(config.apiToken).toBeNull() +}) + +test('config trims token edges but preserves internal whitespace', () => { + const config = loadConfig({ API_TOKEN: ' test token ' }) + expect(config.apiToken).toBe('test token') + expect(formatAuthority('::1', 8789)).toBe('[::1]:8789') +}) + +test('config trims only ASCII whitespace from token edges', () => { + const config = loadConfig({ API_TOKEN: '\u2003test\u2003' }) + expect(config.apiToken).toBe('\u2003test\u2003') +}) + +test('config rejects non-loopback hosts and malformed API origins', () => { + expect(() => loadConfig({ HOST: '0.0.0.0' })).toThrow(/HOST must be one of/) + expect(() => loadConfig({ API_URI: 'http://example.test/path' })).toThrow(/API_URI must be/) + expect(() => loadConfig({ API_URI: 'http://user:pass@example.test' })).toThrow(/API_URI must be/) +}) + +test('distribution root and index must be non-symlink filesystem entries', async () => { + const root = fs.mkdtempSync(path.join(os.tmpdir(), 'service-template-spa-')) + const index = path.join(root, 'index.html') + fs.writeFileSync(index, '') + await expect(assertDistribution(root)).resolves.toBeUndefined() + + const linkRoot = `${root}-link` + fs.symlinkSync(root, linkRoot, 'dir') + await expect(assertDistribution(linkRoot)).rejects.toThrow(/non-symlink directory/) + fs.rmSync(linkRoot, { force: true }) + fs.rmSync(root, { recursive: true, force: true }) +}) diff --git a/packages/spa/src/server/config.ts b/packages/spa/src/server/config.ts new file mode 100644 index 0000000..f40fcae --- /dev/null +++ b/packages/spa/src/server/config.ts @@ -0,0 +1,111 @@ +import fs from 'node:fs' +import path from 'node:path' + +const LOOPBACK_HOSTS = ['127.0.0.1', 'localhost', '::1'] as const + +type Environment = Record + +export type RuntimeConfig = { + apiUri: string + apiToken: string | null + host: string + port: number + spaDistDir: string + authority: string + origin: string +} + +function resolvePort(raw: string | undefined) { + const value = (raw ?? '').trim() + if (value.length === 0) { + return 8789 + } + const port = Number(value) + if (!Number.isInteger(port) || port < 1 || port > 65535) { + throw new Error('PORT must be an integer between 1 and 65535') + } + return port +} + +function isLoopbackHost(value: string): value is (typeof LOOPBACK_HOSTS)[number] { + for (const allowedHost of LOOPBACK_HOSTS) { + if (allowedHost === value) { + return true + } + } + return false +} + +function resolveHost(raw: string | undefined) { + const host = (raw ?? '').trim() || '127.0.0.1' + if (!isLoopbackHost(host)) { + throw new Error('HOST must be one of 127.0.0.1, localhost, or ::1') + } + return host +} + +function resolveApiUri(raw: string | undefined) { + const value = (raw ?? '').trim() || 'http://localhost:8000' + let url: URL + try { + url = new URL(value) + } catch { + throw new Error('API_URI must be an http or https origin') + } + if ( + (url.protocol !== 'http:' && url.protocol !== 'https:') || + url.username.length > 0 || + url.password.length > 0 || + url.pathname !== '/' || + url.search.length > 0 || + url.hash.length > 0 || + value.endsWith('/') + ) { + throw new Error('API_URI must be an http or https origin') + } + return url.origin +} + +function trimAsciiWhitespace(value: string) { + return value.replace(/^[\t-\r ]+|[\t-\r ]+$/g, '') +} + +export function formatAuthority(host: string, port: number) { + const authorityHost = host.includes(':') && !host.startsWith('[') ? `[${host}]` : host + return `${authorityHost}:${port}` +} + +export function loadConfig(environment: Environment = process.env) { + const host = resolveHost(environment.HOST) + const port = resolvePort(environment.PORT) + const authority = formatAuthority(host, port) + const token = trimAsciiWhitespace(environment.API_TOKEN ?? '') + const configuredDistDir = (environment.SPA_DIST_DIR ?? '').trim() + const spaDistDir = + configuredDistDir.length > 0 + ? path.resolve(configuredDistDir) + : path.resolve(import.meta.dirname, '../../dist/public') + + return { + apiUri: resolveApiUri(environment.API_URI), + apiToken: token.length > 0 ? token : null, + host, + port, + spaDistDir, + authority, + origin: `http://${authority}` + } satisfies RuntimeConfig +} + +export async function assertDistribution(distDir: string) { + const rootStats = await fs.promises.lstat(distDir) + if (rootStats.isSymbolicLink() || !rootStats.isDirectory()) { + throw new Error('SPA_DIST_DIR must be a non-symlink directory') + } + const indexStats = await fs.promises.lstat(path.join(distDir, 'index.html')) + if (indexStats.isSymbolicLink() || !indexStats.isFile()) { + throw new Error('SPA_DIST_DIR must contain a non-symlink index.html') + } +} + +export const config = loadConfig() diff --git a/packages/spa/src/server/http-response.ts b/packages/spa/src/server/http-response.ts new file mode 100644 index 0000000..18864e4 --- /dev/null +++ b/packages/spa/src/server/http-response.ts @@ -0,0 +1,56 @@ +import type { ServerResponse } from 'node:http' + +export function sendTextResponse({ + response, + method, + status, + body, + headers = {}, + headContentLength +}: { + response: ServerResponse + method: string + status: number + body: string + headers?: Record + headContentLength?: number +}) { + const payload = Buffer.from(body, 'utf8') + const contentLength = + method === 'HEAD' && headContentLength !== undefined ? headContentLength : payload.byteLength + response.writeHead(status, { + ...headers, + 'content-type': 'text/plain; charset=utf-8', + 'content-length': String(contentLength), + 'cache-control': 'no-store', + 'x-content-type-options': 'nosniff' + }) + if (method === 'HEAD' || body.length === 0) { + response.end() + return + } + response.end(payload) +} + +export function sendJsonResponse({ + response, + method, + body +}: { + response: ServerResponse + method: string + body: string +}) { + const payload = Buffer.from(body, 'utf8') + response.writeHead(200, { + 'content-type': 'application/json; charset=utf-8', + 'content-length': String(payload.byteLength), + 'cache-control': 'no-store', + 'x-content-type-options': 'nosniff' + }) + if (method === 'HEAD') { + response.end() + return + } + response.end(payload) +} diff --git a/packages/spa/src/server/index.ts b/packages/spa/src/server/index.ts new file mode 100644 index 0000000..b5f41bb --- /dev/null +++ b/packages/spa/src/server/index.ts @@ -0,0 +1,25 @@ +import { assertDistribution, config } from './config.js' +import { createApplicationServer } from './static-server.js' + +await assertDistribution(config.spaDistDir) + +const application = createApplicationServer({ config }) +const { server } = application + +server.on('error', () => { + process.exitCode = 1 +}) + +function shutdown() { + application.abortAll() + server.close(() => { + process.exit(0) + }) + setTimeout(() => { + process.exit(1) + }, 10_000).unref() +} + +process.once('SIGTERM', shutdown) +process.once('SIGINT', shutdown) +server.listen(config.port, config.host) diff --git a/packages/spa/src/server/proxy.test.ts b/packages/spa/src/server/proxy.test.ts new file mode 100644 index 0000000..3b8fffd --- /dev/null +++ b/packages/spa/src/server/proxy.test.ts @@ -0,0 +1,442 @@ +// @vitest-environment node +import fs from 'node:fs' +import http from 'node:http' +import os from 'node:os' +import path from 'node:path' +import { gzipSync } from 'node:zlib' +import { expect, test } from 'vite-plus/test' +import { formatAuthority, type RuntimeConfig } from './config.js' +import { createApplicationServer } from './static-server.js' + +type HttpResponse = { + status: number + headers: http.IncomingHttpHeaders + body: string +} + +type ProxyContext = { + port: number + authority: string + application: ReturnType +} + +async function reservePort() { + const probe = http.createServer() + await new Promise((resolve) => { + probe.listen(0, '127.0.0.1', resolve) + }) + const address = probe.address() + if (address === null || typeof address === 'string') { + throw new Error('probe did not bind') + } + const port = address.port + await new Promise((resolve, reject) => { + probe.close((error) => { + if (error === undefined) { + resolve() + return + } + reject(error) + }) + }) + return port +} + +async function closeServer(server: http.Server) { + await new Promise((resolve, reject) => { + server.close((error) => { + if (error === undefined) { + resolve() + return + } + reject(error) + }) + }) +} + +async function waitForPromise(promise: Promise, timeoutMs: number) { + await Promise.race([ + promise, + new Promise((_resolve, reject) => { + const timer = setTimeout(() => { + reject(new Error('timed out waiting for upstream disconnect')) + }, timeoutMs) + timer.unref() + }) + ]) +} + +function createDist() { + const root = fs.mkdtempSync(path.join(os.tmpdir(), 'service-template-spa-proxy-')) + fs.writeFileSync(path.join(root, 'index.html'), '') + return root +} + +async function withProxyServer( + { + apiUri = 'http://upstream.invalid', + apiToken = 'test-token', + fetchImplementation = fetch, + now + }: { + apiUri?: string + apiToken?: string | null + fetchImplementation?: typeof fetch + now?: () => number + }, + run: (context: ProxyContext) => Promise +) { + const root = createDist() + const port = await reservePort() + const authority = formatAuthority('127.0.0.1', port) + const config = { + apiUri, + apiToken, + host: '127.0.0.1', + port, + spaDistDir: root, + authority, + origin: `http://${authority}` + } satisfies RuntimeConfig + const application = createApplicationServer({ config, fetchImplementation, now }) + await new Promise((resolve) => { + application.server.listen(port, '127.0.0.1', resolve) + }) + + try { + await run({ port, authority, application }) + } finally { + application.abortAll() + await closeServer(application.server) + fs.rmSync(root, { recursive: true, force: true }) + } +} + +function request({ + port, + authority, + requestPath = '/api/user', + method = 'GET', + origin +}: { + port: number + authority: string + requestPath?: string + method?: string + origin?: string +}) { + return new Promise((resolve, reject) => { + const headers: http.OutgoingHttpHeaders = { Host: authority } + if (origin !== undefined) { + headers.Origin = origin + } + const client = http.request( + { + host: '127.0.0.1', + port, + path: requestPath, + method, + headers + }, + (response) => { + const chunks: Buffer[] = [] + response.on('data', (chunk: Buffer) => { + chunks.push(chunk) + }) + response.on('end', () => { + resolve({ + status: response.statusCode ?? 0, + headers: response.headers, + body: Buffer.concat(chunks).toString('utf8') + }) + }) + } + ) + client.on('error', reject) + client.end() + }) +} + +function repeatedName(length: number) { + return 'x'.repeat(length) +} + +function deterministicName(length: number) { + const alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_' + let state = 0x12345678 + let value = '' + for (let index = 0; index < length; index += 1) { + state = (state * 1_664_525 + 1_013_904_223) >>> 0 + value += alphabet[state % alphabet.length] + } + return value +} + +function userBodyWithSize(size: number, createName = repeatedName) { + const emptyBody = JSON.stringify({ + count: 1, + user: [{ id: 1, name: '', created_at: 0, updated_at: 0 }] + }) + const nameLength = size - Buffer.byteLength(emptyBody) + if (nameLength < 0) { + throw new Error('requested body size is too small') + } + const body = JSON.stringify({ + count: 1, + user: [{ id: 1, name: createName(nameLength), created_at: 0, updated_at: 0 }] + }) + if (Buffer.byteLength(body) !== size) { + throw new Error('could not create requested body size') + } + return body +} + +test('proxy accepts decoded bodies at and below one MiB and rejects larger bodies', async () => { + for (const size of [1_048_575, 1_048_576, 1_048_577]) { + const body = userBodyWithSize(size) + await withProxyServer( + { + fetchImplementation: async () => { + return new Response(body, { + status: 200, + headers: { 'content-type': 'application/json' } + }) + } + }, + async ({ port, authority }) => { + const response = await request({ port, authority }) + expect(response.status).toBe(size <= 1_048_576 ? 200 : 502) + expect(response.body).not.toContain('API token') + } + ) + } +}) + +test('proxy enforces decoded size for genuine gzip responses and aborts overflow', async () => { + for (const size of [1_048_575, 1_048_576, 1_048_577]) { + const decodedBody = userBodyWithSize(size, deterministicName) + const encodedBody = gzipSync(decodedBody) + let sentAll = false + let upstreamAbortedResolve: () => void = () => {} + const upstreamAborted = new Promise((resolve) => { + upstreamAbortedResolve = resolve + }) + const upstream = http.createServer((request, response) => { + response.on('error', () => {}) + response.once('close', () => { + if (!sentAll) { + upstreamAbortedResolve() + } + }) + response.writeHead(200, { + 'content-type': 'application/json', + 'content-encoding': 'gzip' + }) + let offset = 0 + function writeChunk() { + if (response.destroyed || request.destroyed) { + return + } + if (offset >= encodedBody.byteLength) { + const timer = setTimeout(() => { + if (response.destroyed) { + return + } + sentAll = true + response.end() + }, 250) + timer.unref() + return + } + const chunk = encodedBody.subarray(offset, offset + 16_384) + offset += chunk.byteLength + response.write(chunk) + const timer = setTimeout(writeChunk, 2) + timer.unref() + } + writeChunk() + }) + await new Promise((resolve) => { + upstream.listen(0, '127.0.0.1', resolve) + }) + const address = upstream.address() + if (address === null || typeof address === 'string') { + throw new Error('upstream did not bind') + } + let fetchAborted = false + const fetchImplementation: typeof fetch = async (input, init) => { + const signal = init?.signal + if (signal === undefined || signal === null) { + throw new Error('proxy signal was not provided') + } + signal.addEventListener('abort', () => { + fetchAborted = true + }) + return await fetch(input, init) + } + + try { + await withProxyServer( + { + apiUri: `http://127.0.0.1:${address.port}`, + fetchImplementation + }, + async ({ port, authority }) => { + const response = await request({ port, authority }) + expect(response.status).toBe(size <= 1_048_576 ? 200 : 502) + if (size > 1_048_576) { + expect(response.body).toBe('Bad Gateway\n') + } + } + ) + if (size > 1_048_576) { + await waitForPromise(upstreamAborted, 2_000) + expect(fetchAborted).toBe(true) + } + } finally { + await closeServer(upstream) + } + } +}) + +test('proxy rejects an upstream redirect', async () => { + const upstream = http.createServer((_request, response) => { + response.writeHead(302, { location: 'http://evil.test/api/user' }) + response.end() + }) + await new Promise((resolve) => { + upstream.listen(0, '127.0.0.1', resolve) + }) + const address = upstream.address() + if (address === null || typeof address === 'string') { + throw new Error('upstream did not bind') + } + + try { + await withProxyServer( + { apiUri: `http://127.0.0.1:${address.port}` }, + async ({ port, authority }) => { + const response = await request({ port, authority }) + expect(response.status).toBe(502) + expect(response.body).toBe('Bad Gateway\n') + } + ) + } finally { + await closeServer(upstream) + } +}) + +test('proxy aborts when the monotonic deadline expires during processing', async () => { + let clockCalls = 0 + let signalAborted = false + function now() { + clockCalls += 1 + return clockCalls < 3 ? 0 : 5_001 + } + const fetchImplementation: typeof fetch = async (_input, init) => { + const signal = init?.signal + if (signal === undefined || signal === null) { + throw new Error('proxy signal was not provided') + } + signal.addEventListener('abort', () => { + signalAborted = true + }) + return new Response( + JSON.stringify({ + count: 1, + user: [{ id: 1, name: 'Alice', created_at: 0, updated_at: 0 }] + }), + { status: 200, headers: { 'content-type': 'application/json' } } + ) + } + + await withProxyServer({ fetchImplementation, now }, async ({ port, authority }) => { + const response = await request({ port, authority }) + expect(response.status).toBe(502) + }) + expect(signalAborted).toBe(true) +}) + +test('proxy aborts an upstream fetch when the client disconnects', async () => { + let fetchStartedResolve: () => void = () => {} + const fetchStarted = new Promise((resolve) => { + fetchStartedResolve = resolve + }) + let fetchAbortedResolve: () => void = () => {} + const fetchAborted = new Promise((resolve) => { + fetchAbortedResolve = resolve + }) + const fetchImplementation: typeof fetch = async (_input, init) => { + fetchStartedResolve() + const signal = init?.signal + if (signal === undefined || signal === null) { + throw new Error('proxy signal was not provided') + } + return await new Promise((_resolve, reject) => { + signal.addEventListener( + 'abort', + () => { + fetchAbortedResolve() + reject(new Error('upstream fetch aborted')) + }, + { once: true } + ) + }) + } + + await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { + const client = http.request( + { + host: '127.0.0.1', + port, + path: '/api/user', + headers: { Host: authority } + }, + (response) => { + response.resume() + } + ) + client.on('error', () => {}) + client.end() + await fetchStarted + client.destroy() + await fetchAborted + }) +}) + +test('proxy aborts an upstream fetch during application shutdown', async () => { + let fetchStartedResolve: () => void = () => {} + const fetchStarted = new Promise((resolve) => { + fetchStartedResolve = resolve + }) + let fetchAbortedResolve: () => void = () => {} + const fetchAborted = new Promise((resolve) => { + fetchAbortedResolve = resolve + }) + const fetchImplementation: typeof fetch = async (_input, init) => { + fetchStartedResolve() + const signal = init?.signal + if (signal === undefined || signal === null) { + throw new Error('proxy signal was not provided') + } + return await new Promise((_resolve, reject) => { + signal.addEventListener( + 'abort', + () => { + fetchAbortedResolve() + reject(new Error('upstream fetch aborted')) + }, + { once: true } + ) + }) + } + + await withProxyServer({ fetchImplementation }, async ({ port, authority, application }) => { + const responsePromise = request({ port, authority }) + await fetchStarted + application.abortAll() + await fetchAborted + const response = await responsePromise + expect(response.status).toBe(502) + }) +}) diff --git a/packages/spa/src/server/proxy.ts b/packages/spa/src/server/proxy.ts new file mode 100644 index 0000000..8ae7670 --- /dev/null +++ b/packages/spa/src/server/proxy.ts @@ -0,0 +1,188 @@ +import { performance } from 'node:perf_hooks' +import type { IncomingMessage, ServerResponse } from 'node:http' +import type { RuntimeConfig } from './config.js' +import { parseUserResponse } from '../api-contract.js' +import { sendJsonResponse, sendTextResponse } from './http-response.js' + +const PROXY_TIMEOUT_MS = 5_000 +const MAX_BODY_BYTES = 1_048_576 + +export type ApiProxy = ReturnType + +type ProxyOptions = Pick & { + fetchImplementation?: typeof fetch + now?: () => number +} + +function assertDeadline(deadline: number, now: () => number, abort: () => void) { + if (now() >= deadline) { + abort() + throw new Error('proxy deadline exceeded') + } +} + +async function readResponseBody({ + response, + checkDeadline, + abort +}: { + response: Response + checkDeadline: () => void + abort: () => void +}) { + if (response.body === null) { + throw new Error('upstream response has no body') + } + + const reader = response.body.getReader() + const chunks: Buffer[] = [] + let totalBytes = 0 + try { + while (true) { + checkDeadline() + const next = await reader.read() + if (next.done) { + break + } + const chunk = Buffer.from(next.value) + if (totalBytes + chunk.byteLength > MAX_BODY_BYTES) { + abort() + await reader.cancel() + throw new Error('upstream response is too large') + } + chunks.push(chunk) + totalBytes += chunk.byteLength + } + } finally { + reader.releaseLock() + } + + checkDeadline() + return Buffer.concat(chunks, totalBytes).toString('utf8') +} + +export function createApiProxy({ + apiUri, + apiToken, + fetchImplementation = fetch, + now = () => performance.now() +}: ProxyOptions) { + const activeControllers = new Set() + + function abortAll() { + for (const controller of activeControllers) { + controller.abort() + } + } + + async function handleUserRequest({ + request, + response + }: { + request: IncomingMessage + response: ServerResponse + }) { + if (apiToken === null) { + sendTextResponse({ + response, + method: request.method ?? 'GET', + status: 503, + body: 'API token is not configured\n' + }) + return + } + + const controller = new AbortController() + activeControllers.add(controller) + let settled = false + const abortOnDisconnect = () => { + if (!settled) { + controller.abort() + } + } + request.once('aborted', abortOnDisconnect) + response.once('close', abortOnDisconnect) + const timeout = setTimeout(() => { + controller.abort() + }, PROXY_TIMEOUT_MS) + const deadline = now() + PROXY_TIMEOUT_MS + function checkDeadline() { + assertDeadline(deadline, now, () => { + controller.abort() + }) + } + + try { + checkDeadline() + const upstreamResponse = await fetchImplementation(new URL('/api/user', apiUri), { + method: 'GET', + redirect: 'error', + headers: { + Authorization: `Bearer ${apiToken}`, + Accept: 'application/json' + }, + signal: controller.signal + }) + checkDeadline() + if (upstreamResponse.status !== 200) { + throw new Error('upstream response was not successful') + } + + const upstreamBody = await readResponseBody({ + response: upstreamResponse, + checkDeadline, + abort: () => { + controller.abort() + } + }) + checkDeadline() + let payload: unknown + try { + payload = JSON.parse(upstreamBody) + } catch { + throw new Error('upstream response was not JSON') + } + checkDeadline() + const parsed = parseUserResponse(payload) + if (parsed === null) { + throw new Error('upstream response shape was invalid') + } + checkDeadline() + const serialized = JSON.stringify(parsed) + if (serialized === undefined) { + throw new Error('response serialization failed') + } + checkDeadline() + if (response.destroyed) { + return + } + settled = true + sendJsonResponse({ + response, + method: request.method ?? 'GET', + body: serialized + }) + } catch { + if (!response.headersSent && !response.destroyed) { + settled = true + sendTextResponse({ + response, + method: request.method ?? 'GET', + status: 502, + body: 'Bad Gateway\n' + }) + } + } finally { + clearTimeout(timeout) + activeControllers.delete(controller) + request.off('aborted', abortOnDisconnect) + response.off('close', abortOnDisconnect) + settled = true + } + } + + return { + handleUserRequest, + abortAll + } +} diff --git a/packages/spa/src/server/request-target.test.ts b/packages/spa/src/server/request-target.test.ts new file mode 100644 index 0000000..280805f --- /dev/null +++ b/packages/spa/src/server/request-target.test.ts @@ -0,0 +1,28 @@ +// @vitest-environment node +import { expect, test } from 'vite-plus/test' +import { parseRequestTarget } from './request-target.js' + +test('request target dispatch is exact and single-decode', () => { + expect(parseRequestTarget('/api/user')).toEqual({ kind: 'api-user', pathname: '/api/user' }) + expect(parseRequestTarget('/api/user?x=1')).toEqual({ kind: 'bad-request' }) + for (const target of ['/api/unknown', '/api%2Fuser', '/%61pi/user', '/api%252Fuser', '/apiary']) { + expect(parseRequestTarget(target)).toEqual({ + kind: 'reserved-api', + pathname: expect.any(String) + }) + } + expect(parseRequestTarget('/dashboard?x=1')).toEqual({ kind: 'static', pathname: '/dashboard' }) +}) + +test('request target rejects traversal, malformed encoding, and protocol-relative values', () => { + for (const target of [ + '//evil.test/a.js', + '/%2e%2e/secrets.env', + '/assets/..%2f..%2fsecret', + '/a%ZZ', + '/a%00.js', + '/a%5Cb' + ]) { + expect(parseRequestTarget(target)).toEqual({ kind: 'bad-request' }) + } +}) diff --git a/packages/spa/src/server/request-target.ts b/packages/spa/src/server/request-target.ts new file mode 100644 index 0000000..b1abb7d --- /dev/null +++ b/packages/spa/src/server/request-target.ts @@ -0,0 +1,54 @@ +export type RequestTarget = + | { kind: 'api-user'; pathname: '/api/user' } + | { kind: 'reserved-api'; pathname: string } + | { kind: 'static'; pathname: string } + | { kind: 'bad-request' } + +function firstSegment(pathname: string) { + return pathname.slice(1).split('/')[0] ?? '' +} + +export function parseRequestTarget(requestUrl: string | undefined): RequestTarget { + const rawTarget = requestUrl ?? '' + if (!rawTarget.startsWith('/') || rawTarget.startsWith('//')) { + return { kind: 'bad-request' } + } + + const queryIndex = rawTarget.indexOf('?') + const fragmentIndex = rawTarget.indexOf('#') + const suffixIndex = [queryIndex, fragmentIndex] + .filter((index) => index >= 0) + .reduce((minimum, index) => Math.min(minimum, index), rawTarget.length) + const rawPathname = rawTarget.slice(0, suffixIndex) + const hasSuffix = suffixIndex < rawTarget.length + + let pathname: string + try { + pathname = decodeURIComponent(rawPathname) + } catch { + return { kind: 'bad-request' } + } + + if ( + pathname.length === 0 || + pathname.startsWith('//') || + pathname.includes('\0') || + pathname.includes('\\') || + pathname.split('/').some((segment) => segment === '..') + ) { + return { kind: 'bad-request' } + } + + const reservedApi = firstSegment(pathname).toLowerCase().startsWith('api') + if (!reservedApi) { + return { kind: 'static', pathname } + } + + if (rawPathname === '/api/user' && pathname === '/api/user') { + if (hasSuffix) { + return { kind: 'bad-request' } + } + return { kind: 'api-user', pathname: '/api/user' } + } + return { kind: 'reserved-api', pathname } +} diff --git a/packages/spa/src/server/static-server.test.ts b/packages/spa/src/server/static-server.test.ts new file mode 100644 index 0000000..f1c7d00 --- /dev/null +++ b/packages/spa/src/server/static-server.test.ts @@ -0,0 +1,355 @@ +// @vitest-environment node +import fs from 'node:fs' +import http from 'node:http' +import os from 'node:os' +import path from 'node:path' +import { expect, test } from 'vite-plus/test' +import { formatAuthority, type RuntimeConfig } from './config.js' +import { createApiProxy } from './proxy.js' +import { createApplicationServer, contentTypeOf, handleDevApiBoundary } from './static-server.js' + +type HttpResponse = { + status: number + headers: http.IncomingHttpHeaders + body: string +} + +function createDist() { + const root = fs.mkdtempSync(path.join(os.tmpdir(), 'service-template-spa-dist-')) + fs.mkdirSync(path.join(root, 'assets')) + fs.writeFileSync(path.join(root, 'index.html'), 'service template') + fs.writeFileSync(path.join(root, 'assets', 'app-abcdef.js'), 'export const app = 1\n') + fs.writeFileSync(path.join(root, 'missing-target.txt'), 'not requested') + return root +} + +async function reservePort() { + const probe = http.createServer() + await new Promise((resolve) => { + probe.listen(0, '127.0.0.1', resolve) + }) + const address = probe.address() + if (address === null || typeof address === 'string') { + throw new Error('probe did not bind') + } + await new Promise((resolve, reject) => { + probe.close((error) => { + if (error === undefined) { + resolve() + return + } + reject(error) + }) + }) + return address.port +} + +async function withServer( + run: (context: { + port: number + authority: string + origin: string + root: string + upstreamCalls: () => number + }) => Promise +) { + const root = createDist() + const port = await reservePort() + const authority = formatAuthority('127.0.0.1', port) + let upstreamCallCount = 0 + const upstream = http.createServer((request, response) => { + if (request.url === '/api/user') { + upstreamCallCount += 1 + response.writeHead(200, { 'content-type': 'application/json' }) + response.end( + JSON.stringify({ + count: 2, + user: [ + { id: 1, name: 'Alice', created_at: 1710000000, updated_at: 1710003600 }, + { id: 2, name: 'Bob', created_at: 1710007200, updated_at: 1710010800 } + ] + }) + ) + return + } + response.writeHead(404) + response.end('missing') + }) + await new Promise((resolve) => { + upstream.listen(0, '127.0.0.1', resolve) + }) + const upstreamAddress = upstream.address() + if (upstreamAddress === null || typeof upstreamAddress === 'string') { + throw new Error('upstream did not bind') + } + const config = { + apiUri: `http://127.0.0.1:${upstreamAddress.port}`, + apiToken: 'test-token', + host: '127.0.0.1', + port, + spaDistDir: root, + authority, + origin: `http://${authority}` + } satisfies RuntimeConfig + const application = createApplicationServer({ config }) + await new Promise((resolve) => { + application.server.listen(port, '127.0.0.1', resolve) + }) + try { + function upstreamCalls() { + return upstreamCallCount + } + await run({ port, authority, origin: config.origin, root, upstreamCalls }) + } finally { + application.abortAll() + await new Promise((resolve) => { + application.server.close(() => { + resolve() + }) + }) + await new Promise((resolve) => { + upstream.close(() => { + resolve() + }) + }) + fs.rmSync(root, { recursive: true, force: true }) + } +} + +function request({ + port, + requestPath, + authority, + method = 'GET', + origin +}: { + port: number + requestPath: string + authority: string + method?: string + origin?: string +}) { + return new Promise((resolve, reject) => { + const headers: http.OutgoingHttpHeaders = { Host: authority } + if (origin !== undefined) { + headers.Origin = origin + } + const request = http.request( + { + host: '127.0.0.1', + port, + path: requestPath, + method, + headers + }, + (response) => { + const chunks: Buffer[] = [] + response.on('data', (chunk: Buffer) => { + chunks.push(chunk) + }) + response.on('end', () => { + resolve({ + status: response.statusCode ?? 0, + headers: response.headers, + body: Buffer.concat(chunks).toString('utf8') + }) + }) + } + ) + request.on('error', reject) + request.end() + }) +} + +test('static server serves SPA fallback and immutable assets', async () => { + await withServer(async ({ port, authority }) => { + const page = await request({ port, authority, requestPath: '/dashboard' }) + expect(page.status).toBe(200) + expect(page.body).toContain('service template') + expect(page.headers['cache-control']).toBe('no-store') + expect(page.headers['content-type']).toBe('text/html; charset=utf-8') + + const asset = await request({ port, authority, requestPath: '/assets/app-abcdef.js' }) + expect(asset.status).toBe(200) + expect(asset.headers['content-type']).toBe('text/javascript; charset=utf-8') + expect(asset.headers['cache-control']).toBe('public, max-age=31536000, immutable') + expect(asset.headers['x-content-type-options']).toBe('nosniff') + }) +}) + +test('static server keeps missing assets out of SPA fallback and supports HEAD', async () => { + await withServer(async ({ port, authority }) => { + const missing = await request({ port, authority, requestPath: '/assets/missing.js' }) + expect(missing.status).toBe(404) + expect(missing.body).toBe('Not Found\n') + expect(missing.headers['cache-control']).toBe('no-store') + + const head = await request({ + port, + authority, + requestPath: '/assets/app-abcdef.js', + method: 'HEAD' + }) + expect(head.status).toBe(200) + expect(head.body).toBe('') + expect(head.headers['content-length']).toBe(String(Buffer.byteLength('export const app = 1\n'))) + }) +}) + +test('static server enforces authority, origin, methods, and reserved API paths', async () => { + await withServer(async ({ port, authority, origin, upstreamCalls }) => { + const badHost = await request({ port, authority: '127.0.0.1:1', requestPath: '/' }) + expect(badHost.status).toBe(400) + expect(badHost.body).toBe('Bad Request\n') + + const badOrigin = await request({ + port, + authority, + origin: 'http://evil.test', + requestPath: '/' + }) + expect(badOrigin.status).toBe(403) + expect(badOrigin.body).toBe('Forbidden\n') + + const method = await request({ port, authority, requestPath: '/', method: 'POST' }) + expect(method.status).toBe(405) + expect(method.headers.allow).toBe('GET, HEAD') + + const reserved = await request({ port, authority, requestPath: '/api/unknown' }) + expect(reserved.status).toBe(404) + expect(reserved.body).toBe('Not Found\n') + + const query = await request({ port, authority, requestPath: '/api/user?x=1' }) + expect(query.status).toBe(400) + expect(query.body).toBe('Bad Request\n') + + for (const requestPath of ['/api%2Fuser', '/%61pi/user', '/api%252Fuser']) { + const encoded = await request({ port, authority, requestPath }) + expect(encoded.status).toBe(404) + expect(encoded.body).toBe('Not Found\n') + } + + const head = await request({ port, authority, requestPath: '/api/user', method: 'HEAD' }) + expect(head.status).toBe(405) + expect(head.headers.allow).toBe('GET') + expect(head.body).toBe('') + + const post = await request({ port, authority, requestPath: '/api/user', method: 'POST' }) + expect(post.status).toBe(405) + expect(post.headers.allow).toBe('GET') + expect(post.body).toBe('Method Not Allowed\n') + + const api = await request({ port, authority, origin, requestPath: '/api/user' }) + expect(api.status).toBe(200) + expect(JSON.parse(api.body)).toEqual({ + count: 2, + user: [ + { id: 1, name: 'Alice', created_at: 1710000000, updated_at: 1710003600 }, + { id: 2, name: 'Bob', created_at: 1710007200, updated_at: 1710010800 } + ] + }) + expect(api.headers['access-control-allow-origin']).toBeUndefined() + expect(upstreamCalls()).toBe(1) + }) +}) + +test('static server rejects preexisting file and directory symlinks', async () => { + await withServer(async ({ port, authority, root }) => { + fs.symlinkSync(path.join(root, 'index.html'), path.join(root, 'assets', 'linked.js')) + const file = await request({ port, authority, requestPath: '/assets/linked.js' }) + expect(file.status).toBe(400) + expect(file.body).toBe('Bad Request\n') + + fs.symlinkSync(root, path.join(root, 'assets', 'linked-directory'), 'dir') + const directory = await request({ + port, + authority, + requestPath: '/assets/linked-directory/app.js' + }) + expect(directory.status).toBe(400) + expect(directory.body).toBe('Bad Request\n') + }) +}) + +test('development API boundary fails closed before its authority is available', async () => { + const port = await reservePort() + const authority = formatAuthority('127.0.0.1', port) + const proxy = createApiProxy({ apiUri: 'http://upstream.invalid', apiToken: 'test-token' }) + const server = http.createServer((req, res) => { + void handleDevApiBoundary({ + req, + res, + next: () => { + res.writeHead(418) + res.end('next') + }, + config: null, + proxy + }) + }) + await new Promise((resolve) => { + server.listen(port, '127.0.0.1', resolve) + }) + + try { + const api = await request({ port, authority, requestPath: '/api/user' }) + expect(api.status).toBe(503) + expect(api.body).toBe('Development server is not ready\n') + expect(api.headers['cache-control']).toBe('no-store') + expect(api.headers['x-content-type-options']).toBe('nosniff') + + const malformed = await request({ port, authority, requestPath: '/a%ZZ' }) + expect(malformed.status).toBe(400) + expect(malformed.body).toBe('Bad Request\n') + + const staticResponse = await request({ port, authority, requestPath: '/' }) + expect(staticResponse.status).toBe(418) + expect(staticResponse.body).toBe('next') + } finally { + proxy.abortAll() + await new Promise((resolve) => { + server.close(() => { + resolve() + }) + }) + } +}) + +test('static server sanitizes missing tokens and upstream failures', async () => { + const root = createDist() + const port = await reservePort() + const authority = formatAuthority('127.0.0.1', port) + const config = { + apiUri: 'http://127.0.0.1:1', + apiToken: null, + host: '127.0.0.1', + port, + spaDistDir: root, + authority, + origin: `http://${authority}` + } satisfies RuntimeConfig + const application = createApplicationServer({ config }) + await new Promise((resolve) => { + application.server.listen(port, '127.0.0.1', resolve) + }) + try { + const response = await request({ port, authority, requestPath: '/api/user' }) + expect(response.status).toBe(503) + expect(response.body).toBe('API token is not configured\n') + expect(response.body).not.toContain('test-token') + } finally { + application.abortAll() + await new Promise((resolve) => { + application.server.close(() => { + resolve() + }) + }) + fs.rmSync(root, { recursive: true, force: true }) + } +}) + +test('known content types fail closed for unknown extensions', () => { + expect(contentTypeOf('/assets/app.js')).toBe('text/javascript; charset=utf-8') + expect(contentTypeOf('/assets/app.CSS')).toBe('text/css; charset=utf-8') + expect(contentTypeOf('/assets/app.bin')).toBe('application/octet-stream') +}) diff --git a/packages/spa/src/server/static-server.ts b/packages/spa/src/server/static-server.ts new file mode 100644 index 0000000..33515a0 --- /dev/null +++ b/packages/spa/src/server/static-server.ts @@ -0,0 +1,384 @@ +import fs from 'node:fs' +import fsp from 'node:fs/promises' +import http from 'node:http' +import path from 'node:path' +import type { RuntimeConfig } from './config.js' +import { validateAuthority } from './authority.js' +import { sendTextResponse } from './http-response.js' +import { parseRequestTarget, type RequestTarget } from './request-target.js' +import { createApiProxy, type ApiProxy } from './proxy.js' + +const CONTENT_TYPES = new Map([ + ['.html', 'text/html; charset=utf-8'], + ['.js', 'text/javascript; charset=utf-8'], + ['.mjs', 'text/javascript; charset=utf-8'], + ['.css', 'text/css; charset=utf-8'], + ['.json', 'application/json; charset=utf-8'], + ['.map', 'application/json; charset=utf-8'], + ['.svg', 'image/svg+xml'], + ['.png', 'image/png'], + ['.jpg', 'image/jpeg'], + ['.jpeg', 'image/jpeg'], + ['.gif', 'image/gif'], + ['.webp', 'image/webp'], + ['.ico', 'image/x-icon'], + ['.woff', 'font/woff'], + ['.woff2', 'font/woff2'], + ['.ttf', 'font/ttf'], + ['.wasm', 'application/wasm'], + ['.webmanifest', 'application/manifest+json'] +]) + +const IMMUTABLE_CACHE_CONTROL = 'public, max-age=31536000, immutable' +const DEFAULT_CONTENT_TYPE = 'application/octet-stream' + +type StaticFile = { + kind: 'file' + filePath: string + size: number +} + +type FileInspection = StaticFile | { kind: 'missing' } | { kind: 'symlink' } + +export function contentTypeOf(filePath: string) { + return CONTENT_TYPES.get(path.extname(filePath).toLowerCase()) ?? DEFAULT_CONTENT_TYPE +} + +export function resolveStaticPath({ distDir, pathname }: { distDir: string; pathname: string }) { + const root = path.resolve(distDir) + const filePath = path.resolve(root, `.${pathname}`) + if (filePath !== root && !filePath.startsWith(`${root}${path.sep}`)) { + return null + } + return { root, filePath } +} + +async function inspectTrustedFile(root: string, filePath: string): Promise { + const rootStats = await fsp.lstat(root) + if (rootStats.isSymbolicLink()) { + return { kind: 'symlink' } + } + if (!rootStats.isDirectory()) { + return { kind: 'missing' } + } + + const relativePath = path.relative(root, filePath) + if ( + relativePath.length === 0 || + relativePath.startsWith(`..${path.sep}`) || + path.isAbsolute(relativePath) + ) { + return { kind: 'missing' } + } + + let currentPath = root + const segments = relativePath.split(path.sep) + for (let index = 0; index < segments.length; index += 1) { + const segment = segments[index] + if (segment === undefined) { + return { kind: 'missing' } + } + currentPath = path.join(currentPath, segment) + let stats: fs.Stats + try { + stats = await fsp.lstat(currentPath) + } catch (error) { + if (error instanceof Error && 'code' in error && error.code === 'ENOENT') { + return { kind: 'missing' } + } + throw error + } + if (stats.isSymbolicLink()) { + return { kind: 'symlink' } + } + const isLast = index === segments.length - 1 + if (!isLast && !stats.isDirectory()) { + return { kind: 'missing' } + } + if (isLast && !stats.isFile()) { + return { kind: 'missing' } + } + if (isLast) { + return { kind: 'file', filePath: currentPath, size: stats.size } + } + } + return { kind: 'missing' } +} + +function cacheControlOf(root: string, filePath: string) { + const relativePath = path.relative(root, filePath) + if (relativePath.startsWith(`assets${path.sep}`)) { + return IMMUTABLE_CACHE_CONTROL + } + return 'no-store' +} + +async function sendFile({ + response, + method, + root, + filePath, + size +}: { + response: http.ServerResponse + method: string + root: string + filePath: string + size: number +}) { + const headers = { + 'content-type': contentTypeOf(filePath), + 'content-length': String(size), + 'cache-control': cacheControlOf(root, filePath), + 'x-content-type-options': 'nosniff' + } + if (method === 'HEAD') { + response.writeHead(200, headers) + response.end() + return + } + try { + const fileHandle = await fsp.open(filePath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW) + const stream = fileHandle.createReadStream({ autoClose: true }) + stream.on('error', () => { + response.destroy() + }) + response.writeHead(200, headers) + stream.pipe(response) + } catch { + if (!response.headersSent && !response.destroyed) { + sendBadRequest(response, method) + return + } + response.destroy() + } +} + +function sendBadRequest(response: http.ServerResponse, method: string) { + sendTextResponse({ response, method, status: 400, body: 'Bad Request\n' }) +} + +function sendDevelopmentUnavailable(response: http.ServerResponse, method: string) { + sendTextResponse({ + response, + method, + status: 503, + body: 'Development server is not ready\n' + }) +} + +function sendNotFound(response: http.ServerResponse, method: string) { + sendTextResponse({ response, method, status: 404, body: 'Not Found\n' }) +} + +function sendMethodNotAllowed(response: http.ServerResponse, method: string, allow: string) { + sendTextResponse({ + response, + method, + status: 405, + body: 'Method Not Allowed\n', + headers: { allow }, + headContentLength: method === 'HEAD' ? 0 : undefined + }) +} + +async function serveStatic({ + request, + response, + config, + target +}: { + request: http.IncomingMessage + response: http.ServerResponse + config: RuntimeConfig + target: Extract +}) { + const method = request.method ?? 'GET' + if (method !== 'GET' && method !== 'HEAD') { + sendMethodNotAllowed(response, method, 'GET, HEAD') + return + } + + const resolved = resolveStaticPath({ distDir: config.spaDistDir, pathname: target.pathname }) + if (resolved === null) { + sendBadRequest(response, method) + return + } + const direct = await inspectTrustedFile(resolved.root, resolved.filePath) + if (direct.kind === 'symlink') { + sendBadRequest(response, method) + return + } + if (direct.kind === 'file') { + await sendFile({ + response, + method, + root: resolved.root, + filePath: direct.filePath, + size: direct.size + }) + return + } + + if (path.extname(target.pathname) !== '') { + sendNotFound(response, method) + return + } + + const indexPath = path.join(resolved.root, 'index.html') + const index = await inspectTrustedFile(resolved.root, indexPath) + if (index.kind === 'symlink') { + sendBadRequest(response, method) + return + } + if (index.kind !== 'file') { + sendNotFound(response, method) + return + } + await sendFile({ + response, + method, + root: resolved.root, + filePath: index.filePath, + size: index.size + }) +} + +async function handleParsedTarget({ + request, + response, + config, + target, + proxy +}: { + request: http.IncomingMessage + response: http.ServerResponse + config: RuntimeConfig + target: RequestTarget + proxy: ApiProxy +}) { + const method = request.method ?? 'GET' + if (target.kind === 'bad-request') { + sendBadRequest(response, method) + return + } + if (target.kind === 'reserved-api') { + sendNotFound(response, method) + return + } + if (target.kind === 'api-user') { + if (method !== 'GET') { + sendMethodNotAllowed(response, method, 'GET') + return + } + await proxy.handleUserRequest({ request, response }) + return + } + await serveStatic({ request, response, config, target }) +} + +async function handleRequest({ + request, + response, + config, + proxy +}: { + request: http.IncomingMessage + response: http.ServerResponse + config: RuntimeConfig + proxy: ApiProxy +}) { + const authority = validateAuthority({ + request, + authority: config.authority, + origin: config.origin + }) + if (!authority.ok) { + sendTextResponse({ + response, + method: request.method ?? 'GET', + status: authority.status, + body: authority.status === 403 ? 'Forbidden\n' : 'Bad Request\n', + headContentLength: request.method === 'HEAD' ? 0 : undefined + }) + return + } + const target = parseRequestTarget(request.url) + await handleParsedTarget({ request, response, config, target, proxy }) +} + +export async function handleDevApiBoundary({ + req, + res, + next, + config, + proxy +}: { + req: http.IncomingMessage + res: http.ServerResponse + next: () => void + config: RuntimeConfig | null + proxy: ApiProxy +}) { + const target = parseRequestTarget(req.url) + if (target.kind === 'static') { + next() + return + } + if (target.kind === 'bad-request') { + sendBadRequest(res, req.method ?? 'GET') + return + } + if (config === null) { + sendDevelopmentUnavailable(res, req.method ?? 'GET') + return + } + const authority = validateAuthority({ + request: req, + authority: config.authority, + origin: config.origin + }) + if (!authority.ok) { + sendTextResponse({ + response: res, + method: req.method ?? 'GET', + status: authority.status, + body: authority.status === 403 ? 'Forbidden\n' : 'Bad Request\n', + headContentLength: req.method === 'HEAD' ? 0 : undefined + }) + return + } + await handleParsedTarget({ request: req, response: res, config, target, proxy }) +} + +export function createApplicationServer({ + config, + fetchImplementation, + now +}: { + config: RuntimeConfig + fetchImplementation?: typeof fetch + now?: () => number +}) { + const proxy = createApiProxy({ + apiUri: config.apiUri, + apiToken: config.apiToken, + fetchImplementation, + now + }) + const server = http.createServer((request, response) => { + void handleRequest({ request, response, config, proxy }).catch(() => { + if (!response.headersSent && !response.destroyed) { + sendTextResponse({ + response, + method: request.method ?? 'GET', + status: 500, + body: 'Internal Server Error\n' + }) + } else { + response.destroy() + } + }) + }) + return { server, abortAll: proxy.abortAll } +} diff --git a/packages/spa/tsconfig.json b/packages/spa/tsconfig.json new file mode 100644 index 0000000..648ecce --- /dev/null +++ b/packages/spa/tsconfig.json @@ -0,0 +1,29 @@ +{ + "compilerOptions": { + "types": ["node", "vite/client"], + "target": "ES2017", + "lib": ["dom", "dom.iterable", "esnext"], + "allowJs": true, + "skipLibCheck": true, + "strict": true, + "noUncheckedIndexedAccess": true, + "noEmit": true, + "esModuleInterop": true, + "module": "esnext", + "moduleResolution": "bundler", + "resolveJsonModule": true, + "isolatedModules": true, + "jsx": "react-jsx", + "incremental": true, + "rootDirs": [".", "./.react-router/types"] + }, + "include": [ + "app", + "src", + "vite.config.ts", + "react-router.config.ts", + ".react-router/types/**/*" + ], + "exclude": ["node_modules", "dist"], + "references": [{ "path": "../shared" }] +} diff --git a/packages/spa/tsconfig.server.json b/packages/spa/tsconfig.server.json new file mode 100644 index 0000000..d4389e2 --- /dev/null +++ b/packages/spa/tsconfig.server.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "types": ["node"], + "strict": true, + "noUncheckedIndexedAccess": true, + "skipLibCheck": true, + "esModuleInterop": true, + "target": "esnext", + "lib": ["ESNext"], + "module": "nodenext", + "moduleResolution": "nodenext", + "rootDir": "src", + "outDir": "dist", + "sourceMap": true + }, + "include": ["src/server"], + "exclude": ["**/*.test.ts"] +} diff --git a/packages/spa/vite.config.ts b/packages/spa/vite.config.ts new file mode 100644 index 0000000..bf7b956 --- /dev/null +++ b/packages/spa/vite.config.ts @@ -0,0 +1,66 @@ +import { reactRouter } from '@react-router/dev/vite' +import react from '@vitejs/plugin-react' +import { defineConfig } from 'vite-plus' +import { formatAuthority, loadConfig, type RuntimeConfig } from './src/server/config.js' +import { createApiProxy } from './src/server/proxy.js' +import { handleDevApiBoundary } from './src/server/static-server.js' + +type DevelopmentServer = { + httpServer?: { + address: () => { port: number } | string | null + } | null +} + +const baseConfig = loadConfig() +const apiProxy = createApiProxy(baseConfig) + +function getDevelopmentConfig(server: DevelopmentServer) { + const address = server.httpServer?.address() + if (address === undefined || address === null || typeof address === 'string') { + return null + } + + const authority = formatAuthority('127.0.0.1', address.port) + return { + ...baseConfig, + host: '127.0.0.1', + port: address.port, + authority, + origin: `http://${authority}` + } satisfies RuntimeConfig +} + +export default defineConfig(({ mode }) => ({ + plugins: [ + mode === 'test' ? react() : reactRouter(), + { + name: 'spa-api-proxy', + configureServer(server) { + server.middlewares.use((req, res, next) => { + const developmentConfig = getDevelopmentConfig(server) + void handleDevApiBoundary({ + req, + res, + next, + config: developmentConfig, + proxy: apiProxy + }) + }) + server.httpServer?.on('close', () => { + apiProxy.abortAll() + }) + } + } + ], + server: { + host: '127.0.0.1', + port: 0, + strictPort: true, + cors: false, + allowedHosts: ['127.0.0.1', 'localhost', '::1'] + }, + test: { + environment: 'happy-dom', + exclude: ['**/node_modules/**', '**/dist/**', '**/.react-router/**'] + } +})) From 8923d6291ced8b360074cd88be03caa8cfcd6d56 Mon Sep 17 00:00:00 2001 From: kohta ito Date: Tue, 15 Sep 2026 16:12:31 +0900 Subject: [PATCH 02/21] chore: remove code-review JSON artifacts from PR (keep only in spec) --- .../spa-sample-code-review-round2.json | 19 ------------------- .../spa-sample-code-review-round3.json | 16 ---------------- .../spa-sample-code-review-round4.json | 15 --------------- .../spa-sample-code-review-round5.json | 14 -------------- 4 files changed, 64 deletions(-) delete mode 100644 docs/spec/reviews/spa-sample-code-review-round2.json delete mode 100644 docs/spec/reviews/spa-sample-code-review-round3.json delete mode 100644 docs/spec/reviews/spa-sample-code-review-round4.json delete mode 100644 docs/spec/reviews/spa-sample-code-review-round5.json diff --git a/docs/spec/reviews/spa-sample-code-review-round2.json b/docs/spec/reviews/spa-sample-code-review-round2.json deleted file mode 100644 index 8e75858..0000000 --- a/docs/spec/reviews/spa-sample-code-review-round2.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "review_stage": "initial implementation review", - "base": "8987d1920289ee26a6228e25dfac680dd948fe14", - "scope": "packages/spa, SPA CI/spec/lockfile changes; diagnostic generated files excluded", - "reviewer_model": "gpt-5.6-sol", - "capability_tier": "frontier", - "passed": false, - "blocking_findings": [], - "major_findings": [ - "M-001 | Major | packages/spa/vite.config.ts:40-43 | If the development server cannot expose its effective port, /api/user falls through to Vite instead of returning the required fail-closed 503 and may produce an unsanitized or SPA response. | Send the fixed 503 response when getDevelopmentConfig() returns null; never call next() for a reserved API target.", - "M-002 | Major | packages/spa/src/server/proxy.test.ts and packages/spa/src/server/static-server.test.ts | CI can pass despite regressions in redirect rejection, the absolute deadline, disconnect/shutdown cancellation, inclusive 1 MiB boundaries, compressed decoded-size enforcement, encoded API dispatch, HEAD/POST behavior, or preexisting symlink rejection because these required cases are untested. | Add deterministic tests covering the proxy deadline and cancellation lifecycle, redirects, limit-1/limit/limit+1 decoded bodies including compression, and the complete security-relevant endpoint/symlink matrix." - ], - "minor_findings": [ - "m-001 | Minor | packages/spa/src/server/config.ts:78 | String.trim() removes Unicode whitespace as well as ASCII whitespace, so a token with a non-ASCII whitespace code point at either edge is silently changed contrary to the canonical token-normalization contract. | Replace trim() with explicit leading/trailing ASCII-whitespace removal and add boundary tests." - ], - "invalid_findings": [], - "suggestions": [], - "summary": "Fresh read-only review did not pass. M-001, M-002, and m-001 were subsequently addressed and sent through fresh closure reviews." -} diff --git a/docs/spec/reviews/spa-sample-code-review-round3.json b/docs/spec/reviews/spa-sample-code-review-round3.json deleted file mode 100644 index 8efec3d..0000000 --- a/docs/spec/reviews/spa-sample-code-review-round3.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - "review_stage": "closure review after M-001/M-002/m-001 fixes", - "base": "8987d1920289ee26a6228e25dfac680dd948fe14", - "scope": "packages/spa, SPA CI/spec/lockfile changes; diagnostic generated files excluded", - "reviewer_model": "GPT-5 Codex", - "capability_tier": "frontier", - "passed": false, - "blocking_findings": [], - "major_findings": [ - "M-002 | Major | packages/spa/src/server/proxy.ts:46 and proxy.test.ts:187 | An oversized decoded response only cancels the reader, while the test labels plain JSON bytes as gzip and therefore exercises no decompression; a compressed oversized response can regress without detection and the required fetch abort is not verified. | Abort the request controller immediately on overflow and test a genuinely gzip-compressed streamed upstream at the limit-1, limit, and limit+1 decoded boundaries, asserting cancellation." - ], - "minor_findings": [], - "invalid_findings": [], - "suggestions": [], - "summary": "Closure did not pass because the compressed decoded-size and overflow-cancellation coverage was not meaningful. M-001, deadline checks, cancellation, encoded dispatch, HEAD/POST, symlink handling, ASCII token trimming, and O_NOFOLLOW were otherwise accepted." -} diff --git a/docs/spec/reviews/spa-sample-code-review-round4.json b/docs/spec/reviews/spa-sample-code-review-round4.json deleted file mode 100644 index fe228ca..0000000 --- a/docs/spec/reviews/spa-sample-code-review-round4.json +++ /dev/null @@ -1,15 +0,0 @@ -{ - "review_stage": "final closure review", - "base": "8987d1920289ee26a6228e25dfac680dd948fe14", - "scope": "packages/spa, SPA CI/spec/lockfile changes; diagnostic generated files excluded", - "reviewer_model": "GPT-5 Codex", - "capability_tier": "primary", - "closed_findings": ["M-001", "M-002", "m-001"], - "passed": true, - "blocking_findings": [], - "major_findings": [], - "minor_findings": [], - "invalid_findings": [], - "suggestions": [], - "summary": "Fresh read-only closure review passed against base 8987d1920289ee26a6228e25dfac680dd948fe14. The scoped implementation and tests satisfy the canonical SPA, proxy, authority, cancellation, decoded-size, static-file safety, UI, and CI requirements. Prior findings M-001, M-002, and m-001 are closed, with no regressions found." -} diff --git a/docs/spec/reviews/spa-sample-code-review-round5.json b/docs/spec/reviews/spa-sample-code-review-round5.json deleted file mode 100644 index 0aeb78b..0000000 --- a/docs/spec/reviews/spa-sample-code-review-round5.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "review_stage": "final documentation closure review", - "base": "8987d1920289ee26a6228e25dfac680dd948fe14", - "scope": "packages/spa, SPA CI/spec/lockfile changes; diagnostic generated files excluded", - "reviewer_model": "GPT-5 Codex", - "capability_tier": "primary", - "passed": true, - "blocking_findings": [], - "major_findings": [], - "minor_findings": [], - "invalid_findings": [], - "suggestions": [], - "summary": "Fresh read-only closure review passed against the final documentation revision. Acceptance checkmarks, the Vite Plus/vite-cli alias note, and the implementation-review reference are consistent with the implementation, lockfile, CI, review artifacts, and validation evidence. Prior findings M-001, M-002, and m-001 remain closed." -} From ec102340e4a3aded01388170ff56e55d16ce359f Mon Sep 17 00:00:00 2001 From: kohta ito Date: Wed, 16 Sep 2026 16:08:49 +0900 Subject: [PATCH 03/21] refactor: use session cookies for SPA API transport --- .github/workflows/ci-spa.yml | 5 +- docs/spec/spa-sample.md | 429 ++++++------------ package-lock.json | 2 +- .../spa/app/components/DashboardView.test.tsx | 15 + packages/spa/app/components/DashboardView.tsx | 45 +- packages/spa/app/lib/api-client.test.ts | 26 +- packages/spa/app/lib/api-client.ts | 11 +- packages/spa/src/server/authority.ts | 7 +- packages/spa/src/server/config.test.ts | 15 +- packages/spa/src/server/config.ts | 7 - packages/spa/src/server/http-response.ts | 23 - packages/spa/src/server/proxy.test.ts | 330 ++++++-------- packages/spa/src/server/proxy.ts | 246 ++++++---- packages/spa/src/server/request-target.ts | 18 +- packages/spa/src/server/static-server.test.ts | 38 +- packages/spa/src/server/static-server.ts | 14 +- packages/spa/vite.config.ts | 66 +-- vite.config.ts | 8 +- 18 files changed, 620 insertions(+), 685 deletions(-) diff --git a/.github/workflows/ci-spa.yml b/.github/workflows/ci-spa.yml index 0fd83bb..887a49b 100644 --- a/.github/workflows/ci-spa.yml +++ b/.github/workflows/ci-spa.yml @@ -6,6 +6,7 @@ on: - '.github/workflows/ci-spa.yml' - 'packages/spa/**' - 'packages/shared/**' + - 'docs/spec/spa-sample.md' - 'package.json' - 'package-lock.json' - 'vite.config.ts' @@ -16,6 +17,7 @@ on: - '.github/workflows/ci-spa.yml' - 'packages/spa/**' - 'packages/shared/**' + - 'docs/spec/spa-sample.md' - 'package.json' - 'package-lock.json' - 'vite.config.ts' @@ -37,8 +39,9 @@ jobs: with: node-version: ${{ matrix.node-version }} - run: npm ci + - run: npm run format-check -w ${{ env.WORKSPACE_NAME }} - run: npm run lint -w ${{ env.WORKSPACE_NAME }} - run: npm run build -w shared - run: npm run tsc -w ${{ env.WORKSPACE_NAME }} - run: npm run build -w ${{ env.WORKSPACE_NAME }} - - run: npm run test -w ${{ env.WORKSPACE_NAME }} + - run: npm run test-ci -w ${{ env.WORKSPACE_NAME }} diff --git a/docs/spec/spa-sample.md b/docs/spec/spa-sample.md index a661c92..274b5f2 100644 --- a/docs/spec/spa-sample.md +++ b/docs/spec/spa-sample.md @@ -1,79 +1,28 @@ -# SPA サンプルパッケージ仕様書 - -## Status - -- 対象ブランチ: `feature/spa-sample` -- 基準revision: `8987d1920289ee26a6228e25dfac680dd948fe14` -- Round 1 / Round 2 / Round 3の敵対的レビュー指摘を反映した改訂版。 -- 最終closure review(Round 4)は同等モデルのfresh独立fallbackで実施し、Blocking/Major 0件で合格した。 -- ユーザーの選択と、追加確認がタイムアウトした2点に対する安全側の仮定を含む。 +# React Router + Vite SPA sample ## Overview -`service-template` に、既存のNext.js `packages/client`と併設できるReact SPAのサンプルとして`packages/spa`を追加する。 - -単一画面の目的は、`service-template`の既存APIからユーザー一覧を取得し、`limit-monitor` dashboardの視覚的方向性(暗色背景、接続状態、中央の状態パネル、カード型の情報表示、淡い境界線、状態色)で状態を確認できるようにすることである。 - -`limit-monitor`のaccount/bucket/meterは、`service-template`の既存APIがそのデータを返さないため実装しない。APIが返した値から残量などを推測・捏造しない。 - -既存の`packages/client`(Next.js)は変更せず、別workspaceとして追加する。 - -## Inputs & Outputs - -### Runtime configuration +`service-template`へ、既存のNext.jsサンプル(`packages/client`)と並ぶ、React Router v7 + ViteのSPAサンプルを追加する。目的は、limit-monitor風のdark dashboardを、SSRやserver actionなしで実装すること。 -値はSPAのブラウザbundleへ埋め込まず、SPAを配信するNode server(およびVite dev serverのproxy)だけが読む。 +SPAのbrowser codeは認証credentialを生成・保持・展開しない。Next.jsサンプルが発行する`session` cookieを、browserの通常のcookie送信機能で同一originのAPIへ渡す。 -- `API_URI`: 既存APIのbase URL。既定値は`http://localhost:8000`。`http`/`https`のorigin形式だけを受理し、userinfo、path、query、fragmentを拒否する。 -- `API_TOKEN`: 既存APIへ渡すBearer tokenの値。前後のASCII whitespaceをtrimし、trim後が空文字の場合、proxyは固定の503を返す。tokenをログ・client bundle・レスポンスへ出さない。token内部のwhitespaceは変更せず、Authorization headerへそのまま渡す。 -- `HOST`: SPA配信serverのbind address。既定値は`127.0.0.1`。外部公開によるcredentialed proxyの無認証利用を防ぐため、`127.0.0.1`、`localhost`、`::1`以外は起動時に拒否する。 -- `PORT`: SPA配信serverのport。既定値は`8789`。1以上65535以下の整数だけを受理する。 -- `SPA_DIST_DIR`: 静的配信root。未設定時はserver build出力から`dist/public`を解決する。`start`時に存在するdirectoryであることを確認し、欠落・非directoryなら起動を失敗させる。 -- proxy timeout: 固定`5_000ms`。環境変数で緩和しない。 -- upstream response最大サイズ: 固定`1_048_576 bytes`。Fetch response bodyをcontent decoding後のstream bytesとして数え、超過直後にabortして502にする。`Content-Length`だけに依存しない。 - -### Trust boundary and request authority - -このサンプルのcredentialed proxyにはbrowser caller向けの認証機能がないため、production配信serverはloopback bindだけを許可する。さらに、routingより前に次を検証する。 - -- `Host` headerは、設定した`HOST`と`PORT`から作ったauthority(IPv6は角括弧を含む)との完全一致だけを受理する。別名、別port、欠落Hostは400固定bodyで拒否する。既定値へ暗黙に寄せない。 -- `Origin` headerが存在する場合、`http://`との完全一致だけを受理し、不一致は403固定bodyで拒否する。`Origin`がない非browser clientはHost検証を通れば受理する。 -- `Access-Control-Allow-Origin`などCORS許可headerは一切返さない。 -- `HOST`をloopback以外へ変更する設定は起動時に拒否する。DNS rebindingで攻撃者originからloopbackへ到達しても、Host/Origin検証でcredentialed proxyを呼び出せないようにする。 -- HTTP/1 requestの`rawHeaders`で`Host` fieldがちょうど1個、`Origin` fieldが0個または1個であることを確認する。重複field、comma-joined value、欠落Hostは固定bodyで拒否し、`req.headers`の結合済みvalueだけをtrustしない。 - -Vite dev serverも`127.0.0.1` bind、`port: 0`、`127.0.0.1`/`localhost`のhost allowlistを設定し、同じAPI proxyのsanitizationを使う。dev proxyのeffective authorityは、listen後の`server.httpServer.address().port`と固定host名から都度導出する(例: `127.0.0.1:5173`)。dev proxyもHostをそのportとの完全一致で検証し、Originがある場合は`http://<そのHost>`との完全一致で検証する。portを取得できない間はAPI proxyを503にする。dev serverはCORSを有効にしない。 +## Inputs and outputs ### Browser request -ブラウザは同一originの次のendpointだけを呼ぶ。 +初回画面表示時、browserは次のsame-origin requestを1回だけ実行する。 ```http GET /api/user -``` - -本番ではSPA Node serverが`API_URI`の`/api/user`へserver-side fetchし、次のheaderを付ける。 - -```http -Authorization: Bearer Accept: application/json +Cookie: session= ``` -fetchは`redirect: 'error'`を明示し、redirect先へAuthorizationを送らない。Vite dev serverではproductionと同じproxy fetch関数を使って既存APIへ転送する。ブラウザから既存APIへ直接tokenを送らない。 - -### URL parsing and API dispatch - -serverはHTTP request targetを次の順で1回だけ処理し、`new URL()`のpath正規化や複数回decodeへ依存しない。 - -1. raw targetが`/`で始まり`//`で始まらないことを確認する。不正なら400。 -2. queryとfragmentをraw pathnameから分離する。static assetではquery/fragmentを無視する。API endpointはquery/fragment付きの`/api/user`を400とする。 -3. `decodeURIComponent`を一度だけ適用し、malformed percent、NUL、backslash、`..` segmentがあれば400。 -4. decoded pathnameの先頭segmentが大文字小文字を問わず`api`で始まる場合(`api`そのものだけでなく`apiary`も含む)はreserved API namespaceとする。raw targetが正確に`/api/user`で、decoded pathnameも正確に`/api/user`のときだけproxyへdispatchする。それ以外(`/api%2Fuser`、`/%61pi/user`、`/api%252Fuser`、`/api/unknown`、`/apiary`など)は404とし、SPA fallbackしない。malformed percentなどstep 3の400が先に適用される。 -5. reserved namespaceでないpathだけをstatic file解決へ渡す。 +`session`はJavaScriptから読まない。`fetch`へ`credentials: 'include'`を明示し、browserがcookieを送る。 -### Upstream success example +### API response -既存TypeSpecの`GET /api/user`契約に従い、成功応答は次の形である。 +既存APIの`GET /api/user` responseを表示データとして使用する。 ```json { @@ -95,253 +44,149 @@ serverはHTTP request targetを次の順で1回だけ処理し、`new URL()`のp } ``` -proxy側でruntime validationを完了し、validな200応答だけを同じschemaのJSONへ再serializeしてbrowserへ返す。契約に合わない200応答は固定の502応答へ置き換え、raw bodyをbrowserへ渡さない。コンパイル時の型は`shared/src/schema`の生成型から導出し、同じobject shapeを手書きで再宣言しない。 +`count`と`user`のshape、件数、数値・timestampはbrowser側の`parseUserResponse`で検証する。server側で表示用JSONをparse・再serialize・補正しない。 -`count`は`user.length`と一致しなければinvalidとする。current API実装がcountを取得件数として返すため、pagination等の別意味は導入しない。 +## Authentication boundary -### UI outputs +Next.jsサンプルの次の実装を参照する。 -1. **Loading**: `Hub 問い合わせ中`相当の控えめな状態と、`--`を表示する。mainへ`aria-busy="true"`を設定する。 -2. **Success / non-empty**: - - headerに`Service Template`と`API ONLINE`を表示する。 - - summary cardにAPIから取得した`count`を大きく表示し、ラベルは`登録ユーザー`とする。 - - user cardに`user`の各行(名前、ID、作成日時、更新日時)を表示する。 -3. **Success / empty**: `count === 0`かつ`user.length === 0`の場合、空状態カードに`--`と「ユーザーがありません」を表示する。 -4. **Failure**: - - headerに`API OFFLINE`を表示する。 - - 中央の状態カードに`OFFLINE`と「Service APIへ接続できません」を表示する。 - - token未設定、upstream非2xx、network failure、timeout、response size超過、redirect、JSON parse失敗、JSON shape不正を、tokenやupstream bodyを漏らさず同一の利用者向けエラー表示へ集約する。 +- `packages/client/src/app/_lib/auth/index.ts`: cookie名`session` +- `packages/client/src/app/api/auth/session/route.ts`: session cookieを発行する認証境界 +- `packages/client/src/app/proxy/api/[...path]/route.ts`: httpOnly cookieをserver側で読み、既存APIのAuthorizationへ変換するproxy -status表示は`role="status" aria-live="polite"`、failure表示は`role="alert"`を使い、色だけに依存しない。 +SPA側の契約は次の通り。 -このサンプルはReact Routerの初回`clientLoader`から1回だけ取得する。手動refresh、定期refresh、編集、ページ遷移、chart、account/bucket/meterは実装しない。React StrictMode下でもfetchをcomponent effectに置かないため、初回navigationのloader requestは1回である。明示的なrevalidate操作も行わない。 +1. SPAのJavaScriptへcredentialを埋め込まない。 +2. `session` cookieの値をJavaScriptで読む、localStorageへコピーする、HTMLへ出力する処理を追加しない。 +3. browserの`fetch('/api/user', { credentials: 'include' })`を使う。 +4. 既存APIがAuthorization headerを要求するため、standalone Node配信serverを利用する場合だけ、server側に薄いcookie-to-header adapterを置く。 +5. adapterはsession cookieの有無を確認し、既存APIへ`Authorization: Bearer `を付けるだけとする。認証判断は既存APIへ委譲し、SPA serverでsession claimsを解釈しない。 +6. adapterはupstreamの成功bodyをそのままbrowserへ返し、shape validation・表示用変換・件数計算を行わない。 -### Timestamp display +このadapterはSPAの業務serverではなく、既存APIとhttpOnly cookieのtransport境界である。Next.js proxy routeを持つhostへSPAを組み込む場合は、同じoriginの`/api/user`をhost側へ委譲してもよい。 -`created_at`と`updated_at`はTypeSpecのdocに従うUnix timestamp secondsとする。0以上のsafe integerで、`Date`が表現できる範囲だけをvalidとする。表示は`Intl.DateTimeFormat('ja-JP', { timeZone: 'Asia/Tokyo', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false })`で行い、末尾に`JST`を付ける。invalid valueに対するformat関数の`--`はproxyを迂回して関数を直接呼ぶ場合のdefensive fallbackであり、proxy経由のinvalid responseは画面へ到達せずfailureになる。 +## Tech stack and runtime -## Data Model - -永続化は行わない。ブラウザで扱う型は、既存API契約から次のように導出する。 - -```typescript -schema.paths['/api/user']['get']['responses']['200']['content']['application/json'] -``` - -runtime validationには`zod/mini`を使う。`id`、`count`、timestampの数値範囲、`name`のstring、`user`の配列、および`count === user.length`を検証する。 +- workspace: `spa` +- React 19 +- React Router v7 +- Vite +- React Router config: `ssr: false` +- TypeScript +- Node.js HTTP server: build済み静的asset配信と、必要なcookie-to-header adapterだけを担当 +- `zod`: browser側response validation -- `count`と`id`は0以上のsafe integer。 -- timestampsは0以上のsafe integerで、`new Date(seconds * 1000)`がvalidとなる範囲。 -- `name`は空文字も既存API契約上は受理する。表示時は文字列をそのままtext nodeへ渡し、HTMLとして解釈しない。 +### Runtime environment -## Tech Stack +- `API_URI`: standalone adapterが接続する既存API origin。browserへ公開しない。既定値は`http://localhost:8000`。 +- `HOST`: standalone serverのbind address。既定値は`127.0.0.1`。loopback以外は拒否する。 +- `PORT`: standalone serverのport。既定値は`8789`。 +- `SPA_DIST_DIR`: 静的配信root。未指定時は`dist/public`。 -- React 19 -- React Router v7 Framework Mode -- Vite Plus(既存rootの`vite-plus`およびVite overrideを利用)。rootの`vite` overrideはVite Plus coreへ解決されるため、SPAの標準Vite CLIは`vite-cli: npm:vite@^8.2.2` aliasで分離し、`npm run dev`の`vite` binへ接続する。`@react-router/dev`のVite peerは8.2.2、`vite-node`のVite dependencyは7.3.6へrootのscoped overrideで固定し、npm依存木をvalidに保つ。 -- TypeScript -- Node.js組み込み`node:http`による静的asset配信server -- `zod/mini`による外部API応答validation -- npm workspaces +固定credentialを指定する環境変数は持たない。sessionはhostの認証フローが発行するhttpOnly cookieであり、SPA buildへ取り込まない。 -### Technical investigation +session cookieはhost単位で送信されるため、Next.jsサンプルとSPAを同じhostnameで開く。既定値を使う場合は両方を`127.0.0.1`で開き、`localhost`を使う場合は`HOST=localhost`で起動して両方を`localhost`で開く。portが異なってもcookieのhost条件は変わらない。 -方式は次の既存実装・契約を確認して決定した。 +### Commands -- `limit-monitor/packages/client/package.json`: React Router v7、React 19、`ssr: false` SPA、Node配信serverの構成。 -- `limit-monitor/packages/client/react-router.config.ts`: `ssr: false`と`buildDirectory: 'dist/spa'`の設定。 -- `limit-monitor/packages/client/src/server/static-server.ts`: static asset、SPA fallback、path traversal拒否、GET/HEAD制限、cache controlの実装。 -- `service-template/packages/shared/typespec/user.tsp`: 既存API`GET /api/user`の認証header、200/401/500応答、`count`/`user` response shape、Unix timestamp secondsのdoc。 -- `service-template/packages/api/src/lib/middleware.ts`: `Authorization` headerが必須で、Bearer tokenの検証を行う実装。 -- `service-template/packages/client/src/app/proxy/api/[...path]/route.ts`: 現行Next.jsがserver-sideでsession cookieを読み、APIへAuthorizationを注入する実装。SPAではこのhttpOnly cookieをbrowserから直接利用できないため、同じ安全境界をNode server-side proxyで維持する。 +```bash +npm run dev -w spa +npm run tsc -w spa +npm run format-check -w spa +npm run build -w spa +npm run start -w spa +npm run test -w spa +``` -上記から、browser bundleへ`VITE_API_TOKEN`を埋め込む方式や、API responseに存在しないmeter値の生成は採用しない。 +`build`は`dist/public`へbrowser assetを生成し、standalone実行用のserver codeだけを`dist/server`へ生成する。`start`は`dist/public`を静的配信する。 ## Interface -### Repository/package - -- 新規workspace: `packages/spa` -- 既存`packages/client`は併存させる。 -- package script: - - `dev`: React Router/Vite dev server。`/api/user`はproductionと同じsanitize済みdev proxyを使う。 - - `pretsc`: `shared` build(fresh checkoutでも生成schema型を用意する) - - `tsc`: React Router typegen + TypeScript noEmit - - `build`: SPA client buildとNode配信server buildを`dist/public` / `dist/server`へ出力 - - `start`: `dist/server/index.js`を起動 - - `test`: Vite Plus test - - `format` / `format-check` - - `lint` / `lint-fix` - -### Routes and server behavior - -- React Routerのapplication routeは`/`の1画面だけ。static serverが`/dashboard`などのextensionless pathへindex.htmlを返すのはtransport fallbackのテスト対象であり、サポートするapplication routeとは扱わない。 -- 静的serverは`GET` / `HEAD`だけを受理する。authority検証はrouting前に行う。 -- `/api/user`はGET専用のserver-side proxy endpointとする。`HEAD /api/user`はupstreamへ接続せず405と`Allow: GET`を返す。その他の`/api` namespaceは404とし、SPA fallbackしない。 -- Vite dev middlewareでeffective authorityを取得できない間、static targetはViteへ継続するが、malformed targetは400、reserved API targetは固定503(`Development server is not ready\n`)として`next()`へ流さない。 -- proxy successはvalidなupstream JSONだけを200で返す。missing tokenは503、upstream非2xx・network failure・timeout・redirect・response size超過・malformed/invalid shapeはすべて固定bodyの502とする。upstreamのstatus/bodyはbrowserへ転送しない。 -- proxy fetchは`redirect: 'error'`を使い、monotonic clock(`performance.now()`)によるabsolute deadlineをfetch直前に開始する。response headers受領、decoded body全量読込、size check、JSON parse、schema validation、serializeの各段階の前後でdeadlineを確認し、完了時刻がdeadlineを超えていれば200にせず502とする。deadline超過時はabortして502とする。browser requestのaborted/response closeおよびserver shutdown時はupstream fetchをAbortする。 -- body上限はFetch response bodyがcontent decodingされた後にstreamから受け取るbytesへ適用し、`Content-Length`の有無に関係なくchunk単位で数える。許容境界は`1_048_576` bytes以下(limit-1、limitはvalid)とし、累計がlimit+1になるchunkは一切bufferへ追加せず直ちにabortして502とする。chunkがlimitを超えても超過部分を保持・browser転送しない。 -- 拡張子のないpathは`index.html`へSPA fallbackする。ただし`/api` namespaceはURL parse後に除外する。 -- 拡張子付きで存在しないassetは404とし、SPA fallbackしない。 -- `..`、encoded traversal、backslash、NUL、protocol-relative URL、malformed percent encodingは400で拒否する。 -- 静的distributionは起動後に外部writerが変更しないimmutableなtrusted release treeを前提とする。設定された`SPA_DIST_DIR`自身もsymlinkであってはならず、起動時に`lstat`で拒否する。serverは実行中のpath置換競合へのportableな保証を提供しない。起動時・request時にsymlinkを配信対象から除外し、canonical root/fileがroot配下であることを確認し、最終file openでは`O_NOFOLLOW`相当を使う。事前に作られた中間directory/file symlinkは400/404とし、root外の実体を返さない。 -- authority不一致は400固定body、API requestのOrigin不一致は403固定bodyとし、どちらもproxy/static処理へ進まない。 -- 拡張子とContent-Typeの対応は次のとおりとする: `.html`=`text/html; charset=utf-8`、`.js`/`.mjs`=`text/javascript; charset=utf-8`、`.css`=`text/css; charset=utf-8`、`.json`/`.map`=`application/json; charset=utf-8`、`.svg`=`image/svg+xml`、`.png`=`image/png`、`.jpg`/`.jpeg`=`image/jpeg`、`.gif`=`image/gif`、`.webp`=`image/webp`、`.ico`=`image/x-icon`、`.woff`=`font/woff`、`.woff2`=`font/woff2`、`.ttf`=`font/ttf`、`.wasm`=`application/wasm`、`.webmanifest`=`application/manifest+json`、未知拡張子=`application/octet-stream`。 -- hashed asset(`assets/`配下)は`public, max-age=31536000, immutable`、`index.html`とAPI応答は`no-store`とする。全レスポンスに`X-Content-Type-Options: nosniff`を付ける。 - -### Endpoint/method/status/header matrix - -| Precedence/request | Condition | Status | Required headers/body | -| --- | --- | --- | --- | -| any request | Host missing, duplicated, comma-joined, or not the exact configured authority | 400 | `content-type: text/plain; charset=utf-8`, `cache-control: no-store`, `x-content-type-options: nosniff`, body `Bad Request\n` | -| any request with Origin | Origin duplicated, comma-joined, or not the exact `http://` | 403 | same headers, body `Forbidden\n` | -| any request | malformed target, protocol-relative target, malformed percent, NUL, backslash, or `..` segment | 400 | same fixed-error headers, body `Bad Request\n` | -| dev reserved API target | effective Vite dev authority is unavailable | 503 | same fixed-error headers, body `Development server is not ready\n`, no `next()` | -| `GET /` | valid authority, index exists | 200 | HTML MIME, `cache-control: no-store`, `nosniff`, index body | -| `GET /dashboard` | valid authority, extensionless transport fallback | 200 | index HTML, `no-store`; application route support is out of scope | -| `GET /assets/app-abcdef.js` | existing asset | 200 | JS MIME, immutable cache, `nosniff`, asset body | -| `GET /assets/missing.js` | missing asset | 404 | same headers, body `Not Found\n` | -| `GET /api/user` | valid authority, no Origin or matching Origin, token + valid upstream | 200 | `content-type: application/json; charset=utf-8`, `cache-control: no-store`, `nosniff`, reserialized JSON | -| `GET /api/user` | missing or whitespace-only token | 503 | same fixed-error headers, body `API token is not configured\n` | -| `GET /api/user` | any upstream/proxy validation failure | 502 | same fixed-error headers, body `Bad Gateway\n` | -| `GET /api/user?x=1` | query is not part of endpoint | 400 | same fixed-error headers, body `Bad Request\n`, no upstream call | -| `GET /api/unknown`, `/api%2Fuser`, `/%61pi/user`, `/api%252Fuser`, `/apiary` | reserved namespace but not exact endpoint | 404 | same fixed-error headers, body `Not Found\n`, no SPA fallback | -| `HEAD /api/user` | valid authority/origin | 405 | `allow: GET`, fixed-error headers, empty body, no upstream call | -| `POST /api/user` | valid authority/origin | 405 | `allow: GET`, fixed-error headers, body `Method Not Allowed\n`, no upstream call | -| `POST /` | valid authority/origin, unsupported method | 405 | `allow: GET, HEAD`, fixed-error headers, body `Method Not Allowed\n` | -| static `HEAD` | same lookup as corresponding static GET | corresponding GET status | same headers, empty body | -| any path | preexisting symlink in root or traversed component | 400 | same fixed-error headers, body `Bad Request\n` | - -`cache-control: no-store` and `x-content-type-options: nosniff` are required on every fixed error. Fixed bodies include the trailing newline and are never derived from upstream errors. `Origin` mismatch is checked for static and API requests alike. - -### Deterministic UI test fixtures - -`DashboardView`はloaderの実データとは独立して、次のfixtureをpropsとして直接受け取れる純粋な表示単位に分ける。 - -- loading: `HydrateFallback`を直接renderする。 -- success: `ok: true`、`count: 2`、Alice/Bobのexample response。 -- empty: `ok: true`、`count: 0`、`user: []`。 -- failure: `ok: false`、`status: 502`、bodyは`Bad Gateway`(表示では固定offline文言のみ)。 - -Vite Plus test + Testing Libraryで、4 fixtureそれぞれの必須文言、`role="status"`/`role="alert"`、`aria-busy`、count/user rowの有無をassertする。`clientLoader`はfetch spyを1回だけ呼び、React componentのuseEffectは使用しない。styles testでhex値、breakpoint、必須class/レイアウト宣言を確認する。live browserのviewport計測は成功fixtureを返す一時upstream serverを`API_URI`に指定して実行し、390px/1280px時の`scrollWidth <= clientWidth`、content width `<= 960px`、required header/status/summary/user-card arrangementをCSS computed valuesとselectorで確認する。loading/empty/failureの状態選択はTesting Library fixtureで決定的に行う。live browser検証で使用する一時upstreamはloopback bind・固定JSON・固定portまたは動的portを使い、既存APIや外部networkへ接続しない。 - -## Error Handling - -- fetch例外、timeout、redirect拒否、response size超過: server proxyは502固定body、browserはoffline表示。 -- `API_TOKEN`未設定: production/dev proxyとも503固定body。token値はレスポンスへ含めない。 -- upstream非2xx: server proxyは502固定body。upstream status/bodyはbrowserへ転送しない。 -- upstream 200のJSON parse失敗、schema validation失敗、count/user length mismatch、invalid number/date: server proxyは502固定body。 -- static path不正・traversal・拒否symlink: 400または404。dist外のfileを返さない。 -- unsupported method: 405と`Allow` headerを返す。 -- invalid `API_URI`、invalid `PORT`、non-loopback `HOST`、missing/non-directory `SPA_DIST_DIR`: 起動時に失敗する。 -- index.html欠落: 起動時に失敗。runtime request時のfixture serverでは404。 - -## Non-functional Requirements - -- API tokenはclient bundle、HTML、console log、access log、error bodyへ出さない。 -- Node serverはloopback bind、Host exact allowlist、optional Origin exact allowlistだけを使い、外部公開やCORSを設定で有効化できない。 -- 外部APIのデータ件数に比例するnetwork callを行わず、初回navigationの`GET /api/user`を1回だけ呼ぶ。 -- upstream fetchはfetch開始からvalidation完了まで5秒でabortし、content-decoded bodyを1MiBを超えて保持しない(1MiBちょうどは許容)。client disconnectとSIGTERMでもactive fetchをabortする。 -- UIは既存API応答が長くなっても横方向へはみ出さず、small viewportで1列へ縮退する。 -- static path解決はraw path / decoded path / canonical pathを検証し、immutable tree内のsymlinkを配信しない。 -- 新規packageのCIでlint、typecheck、shared build、spa build、testを実行する。 - -## Visual acceptance tokens - -- background: `#101418` -- panel: `#1a2027` -- panel border: `#2a323c` -- primary text: `#e6ebf0` -- muted text: `#8b98a5` -- online: `#34c176` -- offline/error: `#e5534b` -- page max width: `960px` -- page padding: `16px` -- panel radius: `12px` -- card gap: `16px` -- mobile-to-grid breakpoint: `640px` - -At viewport width 390pxはheader・summary・user rowsが横overflowせず1列、1280pxではcontent widthが960pxを超えないことをlive browserの`document.documentElement.scrollWidth <= document.documentElement.clientWidth`とcontent elementの`getBoundingClientRect().width <= 960`で確認する。loading、success、empty、offlineの4状態ではdeterministic fixtureによる必須文言・ARIA属性と上記token値を確認する。 - -## Out of Scope - -- Next.js `packages/client`の置換・削除・リファクタリング。 -- 新しいTypeSpec endpoint、API schema、DB schema、migration。 -- service-templateの認証provider変更。 -- browserへtokenを露出する方式。 -- LAN/public bind、proxy caller認証、CORS、production deploy。 -- 本物のlimit-monitor Hub、account、bucket、remaining percentage、reset time、chart。 -- refresh操作、ユーザー編集、ページ遷移、永続化。 -- 実行中distributionを外部writerが置き換えた場合のrace-free filesystem保証。 - -## Acceptance Criteria - -- [x] `packages/spa`がnpm workspaceとして認識され、`packages/client`と併存する。 -- [x] `packages/spa`にNext.js依存、Next.js設定、Next.js API routeが存在しない。 -- [x] React Router v7 + Viteの`ssr: false` SPAとして`npm run build -w spa`が成功し、`dist/public/index.html`と`dist/server/index.js`が生成される。 -- [x] `npm run dev -w spa`でSPAを起動でき、loopback Vite dev proxy経由で`GET /api/user`を呼べる。missing token/upstream errorのdev responseはproductionと同じsanitize contractを使い、effective authority未取得時のreserved API targetは固定503でfail-closedになる。 -- [x] production serverが`/api/user`だけをserver-side proxyし、`API_TOKEN`をbrowserへ渡さない。non-loopback HOST、Host authority不一致、Origin不一致を拒否する。 -- [x] proxyがredirectを拒否し、fetch開始からvalidation完了まで5秒deadline、decoded streamed body 1MiB上限、client disconnect/shutdown cancellationを適用する。 -- [x] valid success responseだけがbrowserへ再serializeされ、non-2xx/raw invalid responseが漏れない。`count !== user.length`は502になる。 -- [x] success responseの`count`/`user`、empty response、upstream failure、network failure、invalid response shapeがdeterministic fixture/API testに対応するUI状態として表示される。 -- [x] `limit-monitor`由来のdark dashboard方向性を、Visual acceptance tokens、4状態、390px/1280pxのlive browser計測で確認できる。 -- [x] static serverのSPA fallback、asset 404、path traversal拒否、unknown/encoded `/api`拒否、preexisting symlink拒否、method制限、content type/cache control、Host/Origin制限をendpoint matrixどおりテストで確認できる。 -- [x] `npm run lint -w spa`、`npm run tsc -w spa`、`npm run build -w shared`、`npm run build -w spa`、`npm run test -w spa`が成功する。 -- [x] `ci-spa.yml`が次のpathを監視する: `.github/workflows/ci-spa.yml`、`packages/spa/**`、`packages/shared/**`、`package.json`、`package-lock.json`、root `vite.config.ts`、`lint-rules/**`。workflowは`npm ci`、spa lint、shared build、spa tsc、spa build、spa testを順に実行する。spaの`pretsc`も単体実行時のfresh checkoutを成立させるためshared buildを行う。 -- [x] root workspace/lockfile変更が既存clientへ影響するため、`ci-client.yml`も`package-lock.json`をtrigger pathへ含め、既存のclient lint、shared build、client build、client testを実行する。spa追加だけでclientの既存contractを黙って省略しない。 -- [x] 変更前から存在する`packages/client`のlint/build/test契約を壊さない。 - -## Assumptions - -- package名`spa`、既存Next.js packageとの併設、React Router + Vite、Node static serverはユーザー選択に基づく。 -- ユーザーは「service-templateの既存APIへ接続」を選択したため、表示データは既存`/api/user`の`count`/`user`に限定する。limit-monitorのmeterを再現するためのAPI拡張は要求されていない。 -- Authorization方式とデータ対応付けの追加確認は2回タイムアウトしたため、安全側の実装としてloopback-only、Host/Origin allowlist、server-side `API_URI` + `API_TOKEN` proxyを採用する。browser bundleへtokenを埋め込まない。 -- 「見た目だけの静的1画面」は、画面を1ページに限定し、refreshや編集などの操作を追加しない意味で解釈する。ただし、初回表示時の既存API GETとloading/success/empty/error状態の描画は、先に選択されたAPI接続要件を満たすため実装する。 -- distributionの実行中変更は運用上禁止されたimmutable release treeを前提にする。`SPA_DIST_DIR`自身もsymlink不可で、起動時にnon-symlink directoryとして固定する。serverは外部writerとの同時変更を保護するfilesystem primitiveを提供しない。request時のsymlink拒否は起動後に事前配置されたtreeに対して保証し、同時置換競合はsupportしない。 - -## Adversarial Review - -### Round 1 - -- artifact: `docs/spec/reviews/spa-sample-round1.json` -- reviewer: GPT-5 Codex(CLI指定`gpt-5.6-sol`、runtime capability tier非公開) -- model relationship: unknown -- qualified gate: Pending(identity/tierの十分な証明なし) -- result: Blocking 1、Major 11。全指摘を改訂版へ反映した。 - -### Round 2 - -- artifact: `docs/spec/reviews/spa-sample-round2.json` -- reviewer: `gpt-5.6-sol`(runtime report) -- capability tier: not exposed -- model relationship: unknown -- qualified gate: Pending(author modelとの能力関係がruntimeで証明されていない) -- result: Blocking 2、Major 4。全指摘を本改訂版へ反映した。 - -### Round 3 - -- artifact: `docs/spec/reviews/spa-sample-round3.json` -- reviewer: `gpt-5.6-sol`(runtime report) -- capability tier: not exposed -- model relationship: unknown -- qualified gate: Pending(能力関係の証明なし) -- result: Blocking 2、Major 7。指摘を本改訂版へ反映した。原文verdictは修正前revisionの証跡として保存している。 - -### Round 4 / final closure - -- artifact: `docs/spec/reviews/spa-sample-round4.json` -- reviewer: `gpt-5.6-luna` -- capability tier: runtime (not exposed) -- model relationship: `Fallback: equivalent reviewer`(author modelと同一モデルをfresh独立contextで実施) -- 対象: CI順序修正後の本仕様書 -- 判定: **Passed** -- Blocking: 0、Major: 0、Minor: 0、Invalid: 0 -- transcript: `/home/koh110/.hermes/cache/delegation/live/deleg_bc68c7f6/task-0.log` - -## Implementation Review - -- final closure artifact: `docs/spec/reviews/spa-sample-code-review-round4.json` -- reviewer: GPT-5 Codex(capability tier: primary) -- result: **Passed**(Blocking 0、Major 0、Minor 0、Invalid 0) -- closed findings: M-001(dev proxy fail-closed)、M-002(security boundary/limit/cancellation test coverage)、m-001(ASCII-only token trim) +### Application route + +- `/`: dashboard +- `/dashboard`などextensionless path: static serverのSPA fallback。application routeを増やさない。 +- asset path: `dist/public/assets/*` + +### Dashboard + +- header: service name、接続状態 +- summary: user count +- user list: name、identifier、created/updated timestamp +- loading: skeletonまたはloading indicator +- success: usersを表示 +- empty: countが0の場合の空状態 +- failure: connection/API/auth failureをユーザー向けの固定文言で表示 +- small viewport: 1列化し、横スクロール・text clippingを発生させない +- visual direction: limit-monitorを参考にしたdark surface、低彩度のborder、greenのonline accent + +UIは`GET /api/user`以外のAPI callを行わない。refresh操作を追加する場合も、明示操作につき1 requestとする。 + +### Standalone transport + +standalone serverのAPI boundaryは`GET /api/user`だけを扱う。 + +- session cookieなし: `401 Not authenticated\n` +- upstream success: JSON bodyをbrowserへ転送、`Cache-Control: no-store` +- upstreamの401/403: statusを保持した固定認証失敗文言。その他の非成功、redirect、network error、timeout: `502 Bad Gateway\n` +- query付き`/api/user`、未知の`/api/*`: APIとして処理しない +- static path: GET/HEADだけを受理し、extensionless pathだけSPA fallbackする + +serverはupstream responseのshapeを検証しない。browser clientがHTTP success bodyをparseし、invalid shapeをfailure stateへ変換する。 + +### Development transport + +Vite dev serverでもbrowserから見えるendpointはsame-originの`/api/user`とする。dev middlewareはstandalone adapterと同じcookie forwardingを使う。Vite serverのauthorityが確定していない間はstatic requestをViteへ委譲し、API requestを推測したupstreamへ送らない。 + +## Error handling + +- session cookieなし: login/sessionが必要な状態としてfailure UIを表示する。 +- upstreamの401/403: transportはstatusを保持した固定認証失敗文言へ変換する。5xxその他の非成功は固定502へ変換し、いずれもupstream bodyをbrowserへ漏らさない。 +- redirect/network/timeout: 固定502へ変換する。 +- HTTP 200でもresponse JSONが不正、`count`と`user.length`が不一致、必須fieldが不正: browser側でfailure UIを表示する。 +- malformed URL、path traversal、配信root外、symlink asset: static serverは固定400/404で拒否する。 +- credentialやupstream内部情報をHTML、client bundle、console、error responseへ出力しない。 + +## Non-functional requirements + +- browser bundleにcredentialを含めない。 +- `session` cookieはJavaScriptから直接参照しない。 +- 初回navigationのuser GETを1回だけ行い、user件数に比例するAPI callを行わない。 +- serverの業務処理はcookie forwardingと静的配信に限定する。response validation、表示データ変換、session claims処理、refresh token管理はSPA serverへ追加しない。 +- static serverはloopback bind、exact authority/originチェック、raw URLの安全なparse、配信root外拒否、symlink拒否、`O_NOFOLLOW`での最終file openを維持する。 +- UIは390px相当のsmall viewportからdesktopまで横方向の欠落・overflow・clippingなしで表示する。 +- CIはSPAのformat、format-check、lint、shared build、typecheck、build、testを実行する。既存`packages/client`とsharedの検証も壊さない。 + +## Out of scope + +- SPA独自のlogin画面、session発行、session refresh、logout +- JavaScriptからのcookie読み取り +- credentialをVite define、public env、localStorageへ渡すこと +- SSR、React Router loader/actionを使ったserver rendering +- user以外のAPI endpoint +- limit-monitor固有のmeter、quota、billing APIの追加 +- API schemaや既存APIの認証実装変更 +- production deploy、DNS、external reverse proxy設定 + +## Acceptance criteria + +- `packages/spa`がnpm workspaceとして`packages/client`と併存する。 +- React 19 + React Router v7 + Vite `ssr: false`のbuildが成功する。 +- browser clientが`credentials: 'include'`でsame-origin `/api/user`を1回取得する。 +- client bundle、HTML、console、error responseへcredentialが出ない。 +- standalone serverに固定credential設定がなく、session cookie不在時は401になる。 +- session cookieがある場合だけadapterが既存APIへAuthorizationを付け、成功bodyをbrowserへ返す。 +- adapterがupstream shapeを検証・再serializeせず、client側validationがinvalid responseをfailureへ変換する。 +- upstreamの401/403は認証失敗文言、それ以外の非成功、redirect、network error、timeoutは固定502になる。 +- static asset、SPA fallback、authority、origin、path traversal、symlink境界がテストされる。 +- loading、success、empty、failureのdashboard stateがdeterministic fixtureで確認できる。 +- small viewportとdesktopで横overflow・clippingがない。 +- SPAおよび既存client/sharedのformat、lint、typecheck、build、testが成功する。 + +## Verified references + +- `packages/client/src/app/_lib/auth/index.ts`: `session` cookie name +- `packages/client/src/app/api/auth/session/route.ts`: host-side session route +- `packages/client/src/app/proxy/api/[...path]/route.ts`: cookie-to-Authorization proxy pattern +- `packages/api/src/lib/middleware.ts`: existing API Authorization requirement +- `packages/shared/typespec/user.tsp`: `GET /api/user` response contract diff --git a/package-lock.json b/package-lock.json index 7ef4425..d280d50 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,5 +1,5 @@ { - "name": "service-template", + "name": "feature-spa-sample", "lockfileVersion": 3, "requires": true, "packages": { diff --git a/packages/spa/app/components/DashboardView.test.tsx b/packages/spa/app/components/DashboardView.test.tsx index 7828395..2383dd8 100644 --- a/packages/spa/app/components/DashboardView.test.tsx +++ b/packages/spa/app/components/DashboardView.test.tsx @@ -31,6 +31,12 @@ const failureResult = { body: 'Bad Gateway' } satisfies UserLoadResult +const authenticationFailureResult = { + ok: false, + status: 401, + body: 'Not authenticated' +} satisfies UserLoadResult + afterEach(() => { cleanup() }) @@ -68,3 +74,12 @@ test('failure fixture shows offline status without exposing upstream details', ( expect(screen.getByRole('alert').textContent).toContain('Service APIへ接続できません') expect(screen.queryByText('Bad Gateway')).toBeNull() }) + +test('authentication failure fixture asks for a session without showing a transport error', () => { + render() + + expect(screen.getByRole('status', { name: 'AUTH REQUIRED' })).toBeTruthy() + expect(screen.getByRole('heading', { name: 'セッションが必要です' })).toBeTruthy() + expect(screen.getByText(/Next\.jsサンプルでログイン/)).toBeTruthy() + expect(screen.queryByText('Service APIへ接続できません')).toBeNull() +}) diff --git a/packages/spa/app/components/DashboardView.tsx b/packages/spa/app/components/DashboardView.tsx index 5119983..20d5106 100644 --- a/packages/spa/app/components/DashboardView.tsx +++ b/packages/spa/app/components/DashboardView.tsx @@ -10,7 +10,7 @@ type UserListProps = { data: Extract['body'] } -function ApiState({ online }: { online: boolean }) { +function ApiState({ online, requiresSession }: { online: boolean; requiresSession: boolean }) { if (online) { return (

@@ -18,6 +18,18 @@ function ApiState({ online }: { online: boolean }) {

) } + if (requiresSession) { + return ( +

+ AUTH REQUIRED +

+ ) + } return (

API OFFLINE @@ -80,18 +92,29 @@ function UserList({ data }: UserListProps) { ) } -function OfflineState() { +function OfflineState({ status }: { status: number }) { + const requiresSession = status === 401 || status === 403 return (

-

OFFLINE

-

Service APIへ接続できません

-

Service APIの稼働状態と接続設定を確認してください。

+

{requiresSession ? 'SESSION' : 'OFFLINE'}

+

+ {requiresSession ? 'セッションが必要です' : 'Service APIへ接続できません'} +

+

+ {requiresSession + ? 'Next.jsサンプルでログインしてから、この画面を再読み込みしてください。' + : 'Service APIの稼働状態と接続設定を確認してください。'} +

) } +const emptyData = { count: 0, user: [] } satisfies UserListProps['data'] + export function DashboardView({ result }: DashboardViewProps) { - const successData = result.ok ? result.body : null + const successData = result.ok ? result.body : emptyData + const failureStatus = result.ok ? 0 : result.status + const requiresSession = !result.ok && (result.status === 401 || result.status === 403) return (
@@ -100,13 +123,13 @@ export function DashboardView({ result }: DashboardViewProps) {

service template

Service Template

- + - - {successData === null ? null : } + + - - {successData === null ? : null} + +
) diff --git a/packages/spa/app/lib/api-client.test.ts b/packages/spa/app/lib/api-client.test.ts index 7fab66d..566e36d 100644 --- a/packages/spa/app/lib/api-client.test.ts +++ b/packages/spa/app/lib/api-client.test.ts @@ -17,8 +17,10 @@ const responseBody = { test('clientLoader fetches the same-origin endpoint exactly once', async () => { const originalFetch = globalThis.fetch let calls = 0 - globalThis.fetch = async () => { + let requestInit: RequestInit | undefined + globalThis.fetch = async (_input, init) => { calls += 1 + requestInit = init return new Response(JSON.stringify(responseBody), { status: 200, headers: { 'content-type': 'application/json' } @@ -28,6 +30,8 @@ test('clientLoader fetches the same-origin endpoint exactly once', async () => { try { const result = await fetchUsers() expect(calls).toBe(1) + expect(requestInit?.credentials).toBe('include') + expect(requestInit?.cache).toBe('no-store') expect(result).toEqual({ ok: true, body: responseBody }) } finally { globalThis.fetch = originalFetch @@ -49,3 +53,23 @@ test('invalid response shape becomes a sanitized failure', async () => { globalThis.fetch = originalFetch } }) + +test('non-success response becomes a sanitized authentication failure', async () => { + const originalFetch = globalThis.fetch + globalThis.fetch = async () => { + return new Response('upstream secret details', { + status: 401, + headers: { 'content-type': 'text/plain' } + }) + } + + try { + await expect(fetchUsers()).resolves.toEqual({ + ok: false, + status: 401, + body: 'Not authenticated' + }) + } finally { + globalThis.fetch = originalFetch + } +}) diff --git a/packages/spa/app/lib/api-client.ts b/packages/spa/app/lib/api-client.ts index cfc8b85..a289bb6 100644 --- a/packages/spa/app/lib/api-client.ts +++ b/packages/spa/app/lib/api-client.ts @@ -2,18 +2,25 @@ import { parseUserResponse, type UserResponse } from '../../src/api-contract' export type UserLoadResult = | { ok: true; body: UserResponse } - | { ok: false; status: number; body: 'Bad Gateway' } + | { ok: false; status: number; body: 'Not authenticated' | 'Forbidden' | 'Bad Gateway' } export async function fetchUsers() { try { const response = await fetch('/api/user', { cache: 'no-store', + credentials: 'include', headers: { Accept: 'application/json' } }) if (!response.ok) { - return { ok: false, status: response.status, body: 'Bad Gateway' } satisfies UserLoadResult + const body = + response.status === 401 + ? 'Not authenticated' + : response.status === 403 + ? 'Forbidden' + : 'Bad Gateway' + return { ok: false, status: response.status, body } satisfies UserLoadResult } const parsed = parseUserResponse(await response.json()) diff --git a/packages/spa/src/server/authority.ts b/packages/spa/src/server/authority.ts index ac619ef..5ce5ad8 100644 --- a/packages/spa/src/server/authority.ts +++ b/packages/spa/src/server/authority.ts @@ -31,9 +31,14 @@ export function validateAuthority({ } const origins = headerValues(request, 'origin') - if (origins.length > 1 || origins.some((value) => value.includes(','))) { + if (origins.length > 1) { return { ok: false, status: 403 } } + for (const value of origins) { + if (value.includes(',')) { + return { ok: false, status: 403 } + } + } if (origins.length === 1 && origins[0] !== origin) { return { ok: false, status: 403 } } diff --git a/packages/spa/src/server/config.test.ts b/packages/spa/src/server/config.test.ts index 73cbc7d..fa2d13c 100644 --- a/packages/spa/src/server/config.test.ts +++ b/packages/spa/src/server/config.test.ts @@ -5,7 +5,7 @@ import path from 'node:path' import { expect, test } from 'vite-plus/test' import { assertDistribution, formatAuthority, loadConfig } from './config.js' -test('config defaults to a loopback authority and a sanitized empty token', () => { +test('config defaults to a loopback authority and API origin', () => { const config = loadConfig({}) expect(config.host).toBe('127.0.0.1') @@ -13,18 +13,13 @@ test('config defaults to a loopback authority and a sanitized empty token', () = expect(config.authority).toBe('127.0.0.1:8789') expect(config.origin).toBe('http://127.0.0.1:8789') expect(config.apiUri).toBe('http://localhost:8000') - expect(config.apiToken).toBeNull() }) -test('config trims token edges but preserves internal whitespace', () => { - const config = loadConfig({ API_TOKEN: ' test token ' }) - expect(config.apiToken).toBe('test token') - expect(formatAuthority('::1', 8789)).toBe('[::1]:8789') -}) +test('config preserves the API origin without exposing a credential setting', () => { + const config = loadConfig({ API_URI: 'https://api.example.test' }) -test('config trims only ASCII whitespace from token edges', () => { - const config = loadConfig({ API_TOKEN: '\u2003test\u2003' }) - expect(config.apiToken).toBe('\u2003test\u2003') + expect(config.apiUri).toBe('https://api.example.test') + expect(formatAuthority('::1', 8789)).toBe('[::1]:8789') }) test('config rejects non-loopback hosts and malformed API origins', () => { diff --git a/packages/spa/src/server/config.ts b/packages/spa/src/server/config.ts index f40fcae..909adfe 100644 --- a/packages/spa/src/server/config.ts +++ b/packages/spa/src/server/config.ts @@ -7,7 +7,6 @@ type Environment = Record export type RuntimeConfig = { apiUri: string - apiToken: string | null host: string port: number spaDistDir: string @@ -66,10 +65,6 @@ function resolveApiUri(raw: string | undefined) { return url.origin } -function trimAsciiWhitespace(value: string) { - return value.replace(/^[\t-\r ]+|[\t-\r ]+$/g, '') -} - export function formatAuthority(host: string, port: number) { const authorityHost = host.includes(':') && !host.startsWith('[') ? `[${host}]` : host return `${authorityHost}:${port}` @@ -79,7 +74,6 @@ export function loadConfig(environment: Environment = process.env) { const host = resolveHost(environment.HOST) const port = resolvePort(environment.PORT) const authority = formatAuthority(host, port) - const token = trimAsciiWhitespace(environment.API_TOKEN ?? '') const configuredDistDir = (environment.SPA_DIST_DIR ?? '').trim() const spaDistDir = configuredDistDir.length > 0 @@ -88,7 +82,6 @@ export function loadConfig(environment: Environment = process.env) { return { apiUri: resolveApiUri(environment.API_URI), - apiToken: token.length > 0 ? token : null, host, port, spaDistDir, diff --git a/packages/spa/src/server/http-response.ts b/packages/spa/src/server/http-response.ts index 18864e4..674f69b 100644 --- a/packages/spa/src/server/http-response.ts +++ b/packages/spa/src/server/http-response.ts @@ -31,26 +31,3 @@ export function sendTextResponse({ } response.end(payload) } - -export function sendJsonResponse({ - response, - method, - body -}: { - response: ServerResponse - method: string - body: string -}) { - const payload = Buffer.from(body, 'utf8') - response.writeHead(200, { - 'content-type': 'application/json; charset=utf-8', - 'content-length': String(payload.byteLength), - 'cache-control': 'no-store', - 'x-content-type-options': 'nosniff' - }) - if (method === 'HEAD') { - response.end() - return - } - response.end(payload) -} diff --git a/packages/spa/src/server/proxy.test.ts b/packages/spa/src/server/proxy.test.ts index 3b8fffd..c454b83 100644 --- a/packages/spa/src/server/proxy.test.ts +++ b/packages/spa/src/server/proxy.test.ts @@ -3,7 +3,6 @@ import fs from 'node:fs' import http from 'node:http' import os from 'node:os' import path from 'node:path' -import { gzipSync } from 'node:zlib' import { expect, test } from 'vite-plus/test' import { formatAuthority, type RuntimeConfig } from './config.js' import { createApplicationServer } from './static-server.js' @@ -59,7 +58,7 @@ async function waitForPromise(promise: Promise, timeoutMs: number) { promise, new Promise((_resolve, reject) => { const timer = setTimeout(() => { - reject(new Error('timed out waiting for upstream disconnect')) + reject(new Error('timed out waiting for upstream cancellation')) }, timeoutMs) timer.unref() }) @@ -75,14 +74,10 @@ function createDist() { async function withProxyServer( { apiUri = 'http://upstream.invalid', - apiToken = 'test-token', - fetchImplementation = fetch, - now + fetchImplementation = fetch }: { apiUri?: string - apiToken?: string | null fetchImplementation?: typeof fetch - now?: () => number }, run: (context: ProxyContext) => Promise ) { @@ -91,14 +86,13 @@ async function withProxyServer( const authority = formatAuthority('127.0.0.1', port) const config = { apiUri, - apiToken, host: '127.0.0.1', port, spaDistDir: root, authority, origin: `http://${authority}` } satisfies RuntimeConfig - const application = createApplicationServer({ config, fetchImplementation, now }) + const application = createApplicationServer({ config, fetchImplementation }) await new Promise((resolve) => { application.server.listen(port, '127.0.0.1', resolve) }) @@ -117,18 +111,18 @@ function request({ authority, requestPath = '/api/user', method = 'GET', - origin + cookie }: { port: number authority: string requestPath?: string method?: string - origin?: string + cookie?: string }) { return new Promise((resolve, reject) => { const headers: http.OutgoingHttpHeaders = { Host: authority } - if (origin !== undefined) { - headers.Origin = origin + if (cookie !== undefined) { + headers.Cookie = cookie } const client = http.request( { @@ -157,204 +151,158 @@ function request({ }) } -function repeatedName(length: number) { - return 'x'.repeat(length) -} - -function deterministicName(length: number) { - const alphabet = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_' - let state = 0x12345678 - let value = '' - for (let index = 0; index < length; index += 1) { - state = (state * 1_664_525 + 1_013_904_223) >>> 0 - value += alphabet[state % alphabet.length] +test('proxy requires the session cookie and does not call upstream without it', async () => { + let fetchCalls = 0 + const fetchImplementation: typeof fetch = async () => { + fetchCalls += 1 + return new Response('{}', { status: 200 }) } - return value -} -function userBodyWithSize(size: number, createName = repeatedName) { - const emptyBody = JSON.stringify({ - count: 1, - user: [{ id: 1, name: '', created_at: 0, updated_at: 0 }] - }) - const nameLength = size - Buffer.byteLength(emptyBody) - if (nameLength < 0) { - throw new Error('requested body size is too small') - } - const body = JSON.stringify({ - count: 1, - user: [{ id: 1, name: createName(nameLength), created_at: 0, updated_at: 0 }] + await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { + for (const cookie of [ + undefined, + 'session=', + 'session=one; session=two', + 'session=invalid value' + ]) { + const response = await request({ port, authority, cookie }) + expect(response.status).toBe(401) + expect(response.body).toBe('Not authenticated\n') + } }) - if (Buffer.byteLength(body) !== size) { - throw new Error('could not create requested body size') - } - return body -} + expect(fetchCalls).toBe(0) +}) -test('proxy accepts decoded bodies at and below one MiB and rejects larger bodies', async () => { - for (const size of [1_048_575, 1_048_576, 1_048_577]) { - const body = userBodyWithSize(size) - await withProxyServer( - { - fetchImplementation: async () => { - return new Response(body, { - status: 200, - headers: { 'content-type': 'application/json' } - }) - } - }, - async ({ port, authority }) => { - const response = await request({ port, authority }) - expect(response.status).toBe(size <= 1_048_576 ? 200 : 502) - expect(response.body).not.toContain('API token') - } +test('proxy converts the session cookie to the upstream authorization header', async () => { + let upstreamUrl = '' + let authorization: string | null = null + let credentials: RequestCredentials | undefined + const fetchImplementation: typeof fetch = async (input, init) => { + if (typeof input === 'string') { + upstreamUrl = input + } else if (input instanceof URL) { + upstreamUrl = input.toString() + } else { + upstreamUrl = input.url + } + authorization = new Headers(init?.headers).get('authorization') + credentials = init?.credentials + return new Response( + JSON.stringify({ + count: 1, + user: [{ id: 1, name: 'Alice', created_at: 0, updated_at: 0 }] + }), + { status: 200, headers: { 'content-type': 'application/json' } } ) } -}) -test('proxy enforces decoded size for genuine gzip responses and aborts overflow', async () => { - for (const size of [1_048_575, 1_048_576, 1_048_577]) { - const decodedBody = userBodyWithSize(size, deterministicName) - const encodedBody = gzipSync(decodedBody) - let sentAll = false - let upstreamAbortedResolve: () => void = () => {} - const upstreamAborted = new Promise((resolve) => { - upstreamAbortedResolve = resolve - }) - const upstream = http.createServer((request, response) => { - response.on('error', () => {}) - response.once('close', () => { - if (!sentAll) { - upstreamAbortedResolve() - } + await withProxyServer( + { apiUri: 'https://api.example.test', fetchImplementation }, + async ({ port, authority }) => { + const response = await request({ + port, + authority, + cookie: 'theme=dark; session=opaque-session; locale=ja', + requestPath: '/api/user' }) - response.writeHead(200, { - 'content-type': 'application/json', - 'content-encoding': 'gzip' + expect(response.status).toBe(200) + expect(JSON.parse(response.body)).toEqual({ + count: 1, + user: [{ id: 1, name: 'Alice', created_at: 0, updated_at: 0 }] }) - let offset = 0 - function writeChunk() { - if (response.destroyed || request.destroyed) { - return - } - if (offset >= encodedBody.byteLength) { - const timer = setTimeout(() => { - if (response.destroyed) { - return - } - sentAll = true - response.end() - }, 250) - timer.unref() - return - } - const chunk = encodedBody.subarray(offset, offset + 16_384) - offset += chunk.byteLength - response.write(chunk) - const timer = setTimeout(writeChunk, 2) - timer.unref() - } - writeChunk() - }) - await new Promise((resolve) => { - upstream.listen(0, '127.0.0.1', resolve) - }) - const address = upstream.address() - if (address === null || typeof address === 'string') { - throw new Error('upstream did not bind') } - let fetchAborted = false - const fetchImplementation: typeof fetch = async (input, init) => { - const signal = init?.signal - if (signal === undefined || signal === null) { - throw new Error('proxy signal was not provided') - } - signal.addEventListener('abort', () => { - fetchAborted = true + ) + + expect(upstreamUrl).toBe('https://api.example.test/api/user') + expect(authorization).toBe('Bearer opaque-session') + expect(credentials).toBeUndefined() +}) + +test('proxy preserves sanitized authentication failures from upstream', async () => { + for (const [status, body] of [ + [401, 'Not authenticated\n'], + [403, 'Forbidden\n'] + ] as const) { + const fetchImplementation: typeof fetch = async () => { + return new Response('upstream secret details', { + status, + headers: { 'content-type': 'text/plain' } }) - return await fetch(input, init) } - try { - await withProxyServer( - { - apiUri: `http://127.0.0.1:${address.port}`, - fetchImplementation - }, - async ({ port, authority }) => { - const response = await request({ port, authority }) - expect(response.status).toBe(size <= 1_048_576 ? 200 : 502) - if (size > 1_048_576) { - expect(response.body).toBe('Bad Gateway\n') - } - } - ) - if (size > 1_048_576) { - await waitForPromise(upstreamAborted, 2_000) - expect(fetchAborted).toBe(true) - } - } finally { - await closeServer(upstream) - } + await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { + const response = await request({ + port, + authority, + cookie: 'session=opaque-session' + }) + expect(response.status).toBe(status) + expect(response.body).toBe(body) + expect(response.body).not.toContain('opaque-session') + expect(response.body).not.toContain('upstream secret details') + }) } }) -test('proxy rejects an upstream redirect', async () => { - const upstream = http.createServer((_request, response) => { - response.writeHead(302, { location: 'http://evil.test/api/user' }) - response.end() - }) - await new Promise((resolve) => { - upstream.listen(0, '127.0.0.1', resolve) - }) - const address = upstream.address() - if (address === null || typeof address === 'string') { - throw new Error('upstream did not bind') +test('proxy returns a sanitized gateway error for upstream server failures', async () => { + const fetchImplementation: typeof fetch = async () => { + return new Response('upstream secret details', { + status: 500, + headers: { 'content-type': 'text/plain' } + }) } - try { - await withProxyServer( - { apiUri: `http://127.0.0.1:${address.port}` }, - async ({ port, authority }) => { - const response = await request({ port, authority }) - expect(response.status).toBe(502) - expect(response.body).toBe('Bad Gateway\n') - } - ) - } finally { - await closeServer(upstream) - } + await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { + const response = await request({ + port, + authority, + cookie: 'session=opaque-session' + }) + expect(response.status).toBe(502) + expect(response.body).toBe('Bad Gateway\n') + expect(response.body).not.toContain('opaque-session') + expect(response.body).not.toContain('upstream secret details') + }) }) -test('proxy aborts when the monotonic deadline expires during processing', async () => { - let clockCalls = 0 - let signalAborted = false - function now() { - clockCalls += 1 - return clockCalls < 3 ? 0 : 5_001 +test('proxy passes the successful response to the browser without server-side shape validation', async () => { + const fetchImplementation: typeof fetch = async () => { + return new Response('{"unexpected":"shape"}', { + status: 200, + headers: { 'content-type': 'application/json' } + }) } - const fetchImplementation: typeof fetch = async (_input, init) => { - const signal = init?.signal - if (signal === undefined || signal === null) { - throw new Error('proxy signal was not provided') - } - signal.addEventListener('abort', () => { - signalAborted = true + + await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { + const response = await request({ + port, + authority, + cookie: 'session=opaque-session' }) - return new Response( - JSON.stringify({ - count: 1, - user: [{ id: 1, name: 'Alice', created_at: 0, updated_at: 0 }] - }), - { status: 200, headers: { 'content-type': 'application/json' } } - ) + expect(response.status).toBe(200) + expect(response.body).toBe('{"unexpected":"shape"}') + expect(response.headers['cache-control']).toBe('no-store') + expect(response.headers['x-content-type-options']).toBe('nosniff') + }) +}) + +test('proxy rejects an upstream redirect and does not follow it', async () => { + let requestInit: RequestInit | undefined + const fetchImplementation: typeof fetch = async (_input, init) => { + requestInit = init + throw new TypeError('redirect disallowed') } - await withProxyServer({ fetchImplementation, now }, async ({ port, authority }) => { - const response = await request({ port, authority }) + await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { + const response = await request({ + port, + authority, + cookie: 'session=opaque-session' + }) expect(response.status).toBe(502) + expect(response.body).toBe('Bad Gateway\n') }) - expect(signalAborted).toBe(true) + expect(requestInit?.redirect).toBe('error') }) test('proxy aborts an upstream fetch when the client disconnects', async () => { @@ -390,7 +338,7 @@ test('proxy aborts an upstream fetch when the client disconnects', async () => { host: '127.0.0.1', port, path: '/api/user', - headers: { Host: authority } + headers: { Host: authority, Cookie: 'session=opaque-session' } }, (response) => { response.resume() @@ -400,7 +348,7 @@ test('proxy aborts an upstream fetch when the client disconnects', async () => { client.end() await fetchStarted client.destroy() - await fetchAborted + await waitForPromise(fetchAborted, 2_000) }) }) @@ -432,10 +380,14 @@ test('proxy aborts an upstream fetch during application shutdown', async () => { } await withProxyServer({ fetchImplementation }, async ({ port, authority, application }) => { - const responsePromise = request({ port, authority }) + const responsePromise = request({ + port, + authority, + cookie: 'session=opaque-session' + }) await fetchStarted application.abortAll() - await fetchAborted + await waitForPromise(fetchAborted, 2_000) const response = await responsePromise expect(response.status).toBe(502) }) diff --git a/packages/spa/src/server/proxy.ts b/packages/spa/src/server/proxy.ts index 8ae7670..3556f89 100644 --- a/packages/spa/src/server/proxy.ts +++ b/packages/spa/src/server/proxy.ts @@ -1,72 +1,171 @@ -import { performance } from 'node:perf_hooks' import type { IncomingMessage, ServerResponse } from 'node:http' import type { RuntimeConfig } from './config.js' -import { parseUserResponse } from '../api-contract.js' -import { sendJsonResponse, sendTextResponse } from './http-response.js' +import { sendTextResponse } from './http-response.js' const PROXY_TIMEOUT_MS = 5_000 -const MAX_BODY_BYTES = 1_048_576 +const SESSION_COOKIE_NAME = 'session' +const COOKIE_OCTETS = /^[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]+$/u export type ApiProxy = ReturnType -type ProxyOptions = Pick & { +type ProxyOptions = Pick & { fetchImplementation?: typeof fetch - now?: () => number } -function assertDeadline(deadline: number, now: () => number, abort: () => void) { - if (now() >= deadline) { - abort() - throw new Error('proxy deadline exceeded') +function readSessionCookie(request: IncomingMessage) { + const cookieHeader = request.headers.cookie + if (cookieHeader === undefined) { + return null } + + let session: string | null = null + for (const cookie of cookieHeader.split(';')) { + const separator = cookie.indexOf('=') + if (separator <= 0 || cookie.slice(0, separator).trim() !== SESSION_COOKIE_NAME) { + continue + } + if (session !== null) { + return null + } + const value = cookie.slice(separator + 1).trim() + if (value.length === 0) { + return null + } + if (!COOKIE_OCTETS.test(value)) { + return null + } + session = value + } + return session +} + +function sendAuthenticationFailure(response: ServerResponse, method: string, status: 401 | 403) { + sendTextResponse({ + response, + method, + status, + body: status === 403 ? 'Forbidden\n' : 'Not authenticated\n' + }) +} + +function sendBadGateway(response: ServerResponse, method: string) { + sendTextResponse({ + response, + method, + status: 502, + body: 'Bad Gateway\n' + }) } -async function readResponseBody({ +async function sendUpstreamJson({ response, - checkDeadline, - abort + method, + body }: { - response: Response - checkDeadline: () => void - abort: () => void + response: ServerResponse + method: string + body: Response['body'] }) { - if (response.body === null) { - throw new Error('upstream response has no body') + response.writeHead(200, { + 'content-type': 'application/json; charset=utf-8', + 'cache-control': 'no-store', + 'x-content-type-options': 'nosniff' + }) + if (body === null || method === 'HEAD') { + await body?.cancel() + response.end() + return } - const reader = response.body.getReader() - const chunks: Buffer[] = [] - let totalBytes = 0 + const reader = body.getReader() try { while (true) { - checkDeadline() - const next = await reader.read() - if (next.done) { + const chunk = await reader.read() + if (chunk.done) { break } - const chunk = Buffer.from(next.value) - if (totalBytes + chunk.byteLength > MAX_BODY_BYTES) { - abort() - await reader.cancel() - throw new Error('upstream response is too large') + if (response.destroyed) { + throw new Error('client closed response') + } + if (!response.write(chunk.value)) { + await new Promise((resolve, reject) => { + let settled = false + const cleanup = () => { + response.off('drain', onDrain) + response.off('error', onError) + response.off('close', onClose) + } + const onDrain = () => { + if (settled) { + return + } + settled = true + cleanup() + resolve() + } + const onError = (error: Error) => { + if (settled) { + return + } + settled = true + cleanup() + reject(error) + } + const onClose = () => { + if (settled || response.writableFinished) { + return + } + settled = true + cleanup() + reject(new Error('client closed response')) + } + response.once('drain', onDrain) + response.once('error', onError) + response.once('close', onClose) + }) } - chunks.push(chunk) - totalBytes += chunk.byteLength } + + await new Promise((resolve, reject) => { + const cleanup = () => { + response.off('finish', onFinish) + response.off('error', onError) + response.off('close', onClose) + } + const onFinish = () => { + cleanup() + resolve() + } + const onError = (error: Error) => { + cleanup() + reject(error) + } + const onClose = () => { + if (response.writableFinished) { + return + } + cleanup() + reject(new Error('client closed response')) + } + response.once('finish', onFinish) + response.once('error', onError) + response.once('close', onClose) + response.end() + }) + } catch (error) { + try { + await reader.cancel() + } catch { + // The upstream stream may already be closed after a client disconnect. + } + response.destroy() + throw error } finally { reader.releaseLock() } - - checkDeadline() - return Buffer.concat(chunks, totalBytes).toString('utf8') } -export function createApiProxy({ - apiUri, - apiToken, - fetchImplementation = fetch, - now = () => performance.now() -}: ProxyOptions) { +export function createApiProxy({ apiUri, fetchImplementation = fetch }: ProxyOptions) { const activeControllers = new Set() function abortAll() { @@ -82,13 +181,9 @@ export function createApiProxy({ request: IncomingMessage response: ServerResponse }) { - if (apiToken === null) { - sendTextResponse({ - response, - method: request.method ?? 'GET', - status: 503, - body: 'API token is not configured\n' - }) + const sessionCookie = readSessionCookie(request) + if (sessionCookie === null) { + sendAuthenticationFailure(response, request.method ?? 'GET', 401) return } @@ -105,72 +200,43 @@ export function createApiProxy({ const timeout = setTimeout(() => { controller.abort() }, PROXY_TIMEOUT_MS) - const deadline = now() + PROXY_TIMEOUT_MS - function checkDeadline() { - assertDeadline(deadline, now, () => { - controller.abort() - }) - } try { - checkDeadline() const upstreamResponse = await fetchImplementation(new URL('/api/user', apiUri), { method: 'GET', redirect: 'error', headers: { - Authorization: `Bearer ${apiToken}`, + Authorization: `Bearer ${sessionCookie}`, Accept: 'application/json' }, signal: controller.signal }) - checkDeadline() if (upstreamResponse.status !== 200) { + const status = upstreamResponse.status + await upstreamResponse.body?.cancel() + if (status === 401 || status === 403) { + settled = true + sendAuthenticationFailure(response, request.method ?? 'GET', status) + return + } throw new Error('upstream response was not successful') } - const upstreamBody = await readResponseBody({ - response: upstreamResponse, - checkDeadline, - abort: () => { - controller.abort() - } - }) - checkDeadline() - let payload: unknown - try { - payload = JSON.parse(upstreamBody) - } catch { - throw new Error('upstream response was not JSON') - } - checkDeadline() - const parsed = parseUserResponse(payload) - if (parsed === null) { - throw new Error('upstream response shape was invalid') - } - checkDeadline() - const serialized = JSON.stringify(parsed) - if (serialized === undefined) { - throw new Error('response serialization failed') - } - checkDeadline() if (response.destroyed) { + controller.abort() + await upstreamResponse.body?.cancel() return } - settled = true - sendJsonResponse({ + await sendUpstreamJson({ response, method: request.method ?? 'GET', - body: serialized + body: upstreamResponse.body }) + settled = true } catch { if (!response.headersSent && !response.destroyed) { settled = true - sendTextResponse({ - response, - method: request.method ?? 'GET', - status: 502, - body: 'Bad Gateway\n' - }) + sendBadGateway(response, request.method ?? 'GET') } } finally { clearTimeout(timeout) diff --git a/packages/spa/src/server/request-target.ts b/packages/spa/src/server/request-target.ts index b1abb7d..0a1f832 100644 --- a/packages/spa/src/server/request-target.ts +++ b/packages/spa/src/server/request-target.ts @@ -16,9 +16,12 @@ export function parseRequestTarget(requestUrl: string | undefined): RequestTarge const queryIndex = rawTarget.indexOf('?') const fragmentIndex = rawTarget.indexOf('#') - const suffixIndex = [queryIndex, fragmentIndex] - .filter((index) => index >= 0) - .reduce((minimum, index) => Math.min(minimum, index), rawTarget.length) + let suffixIndex = rawTarget.length + for (const index of [queryIndex, fragmentIndex]) { + if (index >= 0 && index < suffixIndex) { + suffixIndex = index + } + } const rawPathname = rawTarget.slice(0, suffixIndex) const hasSuffix = suffixIndex < rawTarget.length @@ -29,12 +32,19 @@ export function parseRequestTarget(requestUrl: string | undefined): RequestTarge return { kind: 'bad-request' } } + let hasParentSegment = false + for (const segment of pathname.split('/')) { + if (segment === '..') { + hasParentSegment = true + break + } + } if ( pathname.length === 0 || pathname.startsWith('//') || pathname.includes('\0') || pathname.includes('\\') || - pathname.split('/').some((segment) => segment === '..') + hasParentSegment ) { return { kind: 'bad-request' } } diff --git a/packages/spa/src/server/static-server.test.ts b/packages/spa/src/server/static-server.test.ts index f1c7d00..2927346 100644 --- a/packages/spa/src/server/static-server.test.ts +++ b/packages/spa/src/server/static-server.test.ts @@ -84,7 +84,6 @@ async function withServer( } const config = { apiUri: `http://127.0.0.1:${upstreamAddress.port}`, - apiToken: 'test-token', host: '127.0.0.1', port, spaDistDir: root, @@ -121,19 +120,24 @@ function request({ requestPath, authority, method = 'GET', - origin + origin, + cookie }: { port: number requestPath: string authority: string method?: string origin?: string + cookie?: string }) { return new Promise((resolve, reject) => { const headers: http.OutgoingHttpHeaders = { Host: authority } if (origin !== undefined) { headers.Origin = origin } + if (cookie !== undefined) { + headers.Cookie = cookie + } const request = http.request( { host: '127.0.0.1', @@ -239,7 +243,13 @@ test('static server enforces authority, origin, methods, and reserved API paths' expect(post.headers.allow).toBe('GET') expect(post.body).toBe('Method Not Allowed\n') - const api = await request({ port, authority, origin, requestPath: '/api/user' }) + const api = await request({ + port, + authority, + origin, + cookie: 'session=sample-session', + requestPath: '/api/user' + }) expect(api.status).toBe(200) expect(JSON.parse(api.body)).toEqual({ count: 2, @@ -274,7 +284,7 @@ test('static server rejects preexisting file and directory symlinks', async () = test('development API boundary fails closed before its authority is available', async () => { const port = await reservePort() const authority = formatAuthority('127.0.0.1', port) - const proxy = createApiProxy({ apiUri: 'http://upstream.invalid', apiToken: 'test-token' }) + const proxy = createApiProxy({ apiUri: 'http://upstream.invalid' }) const server = http.createServer((req, res) => { void handleDevApiBoundary({ req, @@ -315,13 +325,12 @@ test('development API boundary fails closed before its authority is available', } }) -test('static server sanitizes missing tokens and upstream failures', async () => { +test('static server requires a session cookie and sanitizes upstream failures', async () => { const root = createDist() const port = await reservePort() const authority = formatAuthority('127.0.0.1', port) const config = { apiUri: 'http://127.0.0.1:1', - apiToken: null, host: '127.0.0.1', port, spaDistDir: root, @@ -333,10 +342,19 @@ test('static server sanitizes missing tokens and upstream failures', async () => application.server.listen(port, '127.0.0.1', resolve) }) try { - const response = await request({ port, authority, requestPath: '/api/user' }) - expect(response.status).toBe(503) - expect(response.body).toBe('API token is not configured\n') - expect(response.body).not.toContain('test-token') + const unauthorized = await request({ port, authority, requestPath: '/api/user' }) + expect(unauthorized.status).toBe(401) + expect(unauthorized.body).toBe('Not authenticated\n') + + const upstreamFailure = await request({ + port, + authority, + cookie: 'session=sample-session', + requestPath: '/api/user' + }) + expect(upstreamFailure.status).toBe(502) + expect(upstreamFailure.body).toBe('Bad Gateway\n') + expect(upstreamFailure.body).not.toContain('sample-session') } finally { application.abortAll() await new Promise((resolve) => { diff --git a/packages/spa/src/server/static-server.ts b/packages/spa/src/server/static-server.ts index 33515a0..ed91d53 100644 --- a/packages/spa/src/server/static-server.ts +++ b/packages/spa/src/server/static-server.ts @@ -2,6 +2,7 @@ import fs from 'node:fs' import fsp from 'node:fs/promises' import http from 'node:http' import path from 'node:path' +import { pipeline } from 'node:stream/promises' import type { RuntimeConfig } from './config.js' import { validateAuthority } from './authority.js' import { sendTextResponse } from './http-response.js' @@ -140,11 +141,8 @@ async function sendFile({ try { const fileHandle = await fsp.open(filePath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW) const stream = fileHandle.createReadStream({ autoClose: true }) - stream.on('error', () => { - response.destroy() - }) response.writeHead(200, headers) - stream.pipe(response) + await pipeline(stream, response) } catch { if (!response.headersSent && !response.destroyed) { sendBadRequest(response, method) @@ -353,18 +351,14 @@ export async function handleDevApiBoundary({ export function createApplicationServer({ config, - fetchImplementation, - now + fetchImplementation }: { config: RuntimeConfig fetchImplementation?: typeof fetch - now?: () => number }) { const proxy = createApiProxy({ apiUri: config.apiUri, - apiToken: config.apiToken, - fetchImplementation, - now + fetchImplementation }) const server = http.createServer((request, response) => { void handleRequest({ request, response, config, proxy }).catch(() => { diff --git a/packages/spa/vite.config.ts b/packages/spa/vite.config.ts index bf7b956..e760569 100644 --- a/packages/spa/vite.config.ts +++ b/packages/spa/vite.config.ts @@ -20,47 +20,49 @@ function getDevelopmentConfig(server: DevelopmentServer) { return null } - const authority = formatAuthority('127.0.0.1', address.port) + const authority = formatAuthority(baseConfig.host, address.port) return { ...baseConfig, - host: '127.0.0.1', + host: baseConfig.host, port: address.port, authority, origin: `http://${authority}` } satisfies RuntimeConfig } -export default defineConfig(({ mode }) => ({ - plugins: [ - mode === 'test' ? react() : reactRouter(), - { - name: 'spa-api-proxy', - configureServer(server) { - server.middlewares.use((req, res, next) => { - const developmentConfig = getDevelopmentConfig(server) - void handleDevApiBoundary({ - req, - res, - next, - config: developmentConfig, - proxy: apiProxy +export default defineConfig(({ mode }) => { + return { + plugins: [ + mode === 'test' ? react() : reactRouter(), + { + name: 'spa-api-proxy', + configureServer(server) { + server.middlewares.use((req, res, next) => { + const developmentConfig = getDevelopmentConfig(server) + void handleDevApiBoundary({ + req, + res, + next, + config: developmentConfig, + proxy: apiProxy + }) + }) + server.httpServer?.on('close', () => { + apiProxy.abortAll() }) - }) - server.httpServer?.on('close', () => { - apiProxy.abortAll() - }) + } } + ], + server: { + host: baseConfig.host, + port: 0, + strictPort: true, + cors: false, + allowedHosts: ['127.0.0.1', 'localhost', '::1'] + }, + test: { + environment: 'happy-dom', + exclude: ['**/node_modules/**', '**/dist/**', '**/.react-router/**'] } - ], - server: { - host: '127.0.0.1', - port: 0, - strictPort: true, - cors: false, - allowedHosts: ['127.0.0.1', 'localhost', '::1'] - }, - test: { - environment: 'happy-dom', - exclude: ['**/node_modules/**', '**/dist/**', '**/.react-router/**'] } -})) +}) diff --git a/vite.config.ts b/vite.config.ts index 90b1209..32d0e76 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -40,7 +40,13 @@ export default defineConfig({ { // パッケージ横断のコーディング規約(AGENTS.md)。config/test ファイルの除外は // ルール実装側(lint-rules/rules/)がファイル名で判定する。 - files: ['packages/api/src/**', 'packages/client/src/**', 'packages/task/src/**'], + files: [ + 'packages/api/src/**', + 'packages/client/src/**', + 'packages/spa/app/**', + 'packages/spa/src/**', + 'packages/task/src/**' + ], rules: { 'coding-style/no-process-env-outside-config': 'error', 'coding-style/enforce-zod-entrypoint': 'error' From ff10f1b1e73e3bc282d1832bf99f8388b946e063 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 17:18:04 +0900 Subject: [PATCH 04/21] refactor: make SPA runtime static-only --- docs/spec/spa-sample.md | 200 ++++----- packages/spa/package.json | 4 +- packages/spa/src/server/authority.test.ts | 46 -- packages/spa/src/server/authority.ts | 46 -- packages/spa/src/server/config.test.ts | 42 -- packages/spa/src/server/config.ts | 104 ----- packages/spa/src/server/http-response.ts | 33 -- packages/spa/src/server/index.ts | 25 -- packages/spa/src/server/proxy.test.ts | 394 ------------------ packages/spa/src/server/proxy.ts | 254 ----------- .../spa/src/server/request-target.test.ts | 28 -- packages/spa/src/server/request-target.ts | 64 --- packages/spa/src/server/static-server.test.ts | 373 ----------------- packages/spa/src/server/static-server.ts | 378 ----------------- packages/spa/tsconfig.server.json | 18 - packages/spa/vite.config.ts | 69 +-- 16 files changed, 96 insertions(+), 1982 deletions(-) delete mode 100644 packages/spa/src/server/authority.test.ts delete mode 100644 packages/spa/src/server/authority.ts delete mode 100644 packages/spa/src/server/config.test.ts delete mode 100644 packages/spa/src/server/config.ts delete mode 100644 packages/spa/src/server/http-response.ts delete mode 100644 packages/spa/src/server/index.ts delete mode 100644 packages/spa/src/server/proxy.test.ts delete mode 100644 packages/spa/src/server/proxy.ts delete mode 100644 packages/spa/src/server/request-target.test.ts delete mode 100644 packages/spa/src/server/request-target.ts delete mode 100644 packages/spa/src/server/static-server.test.ts delete mode 100644 packages/spa/src/server/static-server.ts delete mode 100644 packages/spa/tsconfig.server.json diff --git a/docs/spec/spa-sample.md b/docs/spec/spa-sample.md index 274b5f2..14e717e 100644 --- a/docs/spec/spa-sample.md +++ b/docs/spec/spa-sample.md @@ -2,15 +2,24 @@ ## Overview -`service-template`へ、既存のNext.jsサンプル(`packages/client`)と並ぶ、React Router v7 + ViteのSPAサンプルを追加する。目的は、limit-monitor風のdark dashboardを、SSRやserver actionなしで実装すること。 +`service-template` に、既存の Next.js サンプル (`packages/client`) と並ぶ React Router v7 + Vite の SPA サンプルを追加する。 -SPAのbrowser codeは認証credentialを生成・保持・展開しない。Next.jsサンプルが発行する`session` cookieを、browserの通常のcookie送信機能で同一originのAPIへ渡す。 +`packages/spa` は runtime application server を持たない。build の成果物は静的ファイルだけであり、nginx、CDN、object storage + CDN など任意の static hosting から配信できることを前提とする。 -## Inputs and outputs +React Router は `ssr: false` の SPA mode を使う。build 時に `index.html` を生成するための React Router の server entry は存在してもよいが、production runtime の Node server ではない。 + +## Runtime contract + +SPA の runtime contract は次の2点だけとする。 + +1. `dist/public` 以下の静的ファイルを配信する。 +2. browser から見て same-origin の `GET /api/user` が利用できる。 + +SPA package 自身は `/api/user` を実装、proxy、認証変換しない。 ### Browser request -初回画面表示時、browserは次のsame-origin requestを1回だけ実行する。 +初回画面表示時、browser は次の same-origin request を1回だけ実行する。 ```http GET /api/user @@ -18,11 +27,23 @@ Accept: application/json Cookie: session= ``` -`session`はJavaScriptから読まない。`fetch`へ`credentials: 'include'`を明示し、browserがcookieを送る。 +browser code は次の形で取得する。 + +```ts +fetch('/api/user', { + cache: 'no-store', + credentials: 'include', + headers: { + Accept: 'application/json' + } +}) +``` + +`session` cookie の値を JavaScript から読まない。credential を build-time env、HTML、client bundle、localStorage へ渡さない。 ### API response -既存APIの`GET /api/user` responseを表示データとして使用する。 +既存 API の `GET /api/user` response を表示データとして使用する。 ```json { @@ -44,149 +65,104 @@ Cookie: session= } ``` -`count`と`user`のshape、件数、数値・timestampはbrowser側の`parseUserResponse`で検証する。server側で表示用JSONをparse・再serialize・補正しない。 - -## Authentication boundary +`count` と `user` の shape、件数、数値、timestamp は browser 側の `parseUserResponse` で検証する。 -Next.jsサンプルの次の実装を参照する。 +## Deployment boundary -- `packages/client/src/app/_lib/auth/index.ts`: cookie名`session` -- `packages/client/src/app/api/auth/session/route.ts`: session cookieを発行する認証境界 -- `packages/client/src/app/proxy/api/[...path]/route.ts`: httpOnly cookieをserver側で読み、既存APIのAuthorizationへ変換するproxy +`packages/spa` は static hosting だけを担当する。API routing と authentication boundary は deployment environment の責務とする。 -SPA側の契約は次の通り。 +現在の `packages/api` は `Authorization` header を要求するため、既存 API をそのまま利用する場合は reverse proxy / ingress / BFF など SPA package の外側で `session` cookie を upstream の Authorization へ変換する。 -1. SPAのJavaScriptへcredentialを埋め込まない。 -2. `session` cookieの値をJavaScriptで読む、localStorageへコピーする、HTMLへ出力する処理を追加しない。 -3. browserの`fetch('/api/user', { credentials: 'include' })`を使う。 -4. 既存APIがAuthorization headerを要求するため、standalone Node配信serverを利用する場合だけ、server側に薄いcookie-to-header adapterを置く。 -5. adapterはsession cookieの有無を確認し、既存APIへ`Authorization: Bearer `を付けるだけとする。認証判断は既存APIへ委譲し、SPA serverでsession claimsを解釈しない。 -6. adapterはupstreamの成功bodyをそのままbrowserへ返し、shape validation・表示用変換・件数計算を行わない。 +この変換は SPA の runtime server として実装しない。 -このadapterはSPAの業務serverではなく、既存APIとhttpOnly cookieのtransport境界である。Next.js proxy routeを持つhostへSPAを組み込む場合は、同じoriginの`/api/user`をhost側へ委譲してもよい。 +### nginx example -## Tech stack and runtime +以下は deployment topology の一例であり、SPA application code の一部ではない。 -- workspace: `spa` -- React 19 -- React Router v7 -- Vite -- React Router config: `ssr: false` -- TypeScript -- Node.js HTTP server: build済み静的asset配信と、必要なcookie-to-header adapterだけを担当 -- `zod`: browser側response validation +```nginx +server { + listen 8080; + root /srv/service-template-spa; -### Runtime environment + location = /api/user { + proxy_set_header Authorization "Bearer $cookie_session"; + proxy_pass http://api:8000/api/user; + } -- `API_URI`: standalone adapterが接続する既存API origin。browserへ公開しない。既定値は`http://localhost:8000`。 -- `HOST`: standalone serverのbind address。既定値は`127.0.0.1`。loopback以外は拒否する。 -- `PORT`: standalone serverのport。既定値は`8789`。 -- `SPA_DIST_DIR`: 静的配信root。未指定時は`dist/public`。 + location / { + try_files $uri $uri/ /index.html; + } +} +``` -固定credentialを指定する環境変数は持たない。sessionはhostの認証フローが発行するhttpOnly cookieであり、SPA buildへ取り込まない。 +これにより browser からは static assets と `/api/user` が同一 origin に見える。`GET /api/user` 以外へ cookie-to-Authorization を一般化する場合は、state-changing request の CSRF 方針を別途設計する。 -session cookieはhost単位で送信されるため、Next.jsサンプルとSPAを同じhostnameで開く。既定値を使う場合は両方を`127.0.0.1`で開き、`localhost`を使う場合は`HOST=localhost`で起動して両方を`localhost`で開く。portが異なってもcookieのhost条件は変わらない。 +同じ契約を満たせるなら nginx 以外の hosting / gateway でもよい。 -### Commands +## Development and preview ```bash npm run dev -w spa npm run tsc -w spa -npm run format-check -w spa npm run build -w spa npm run start -w spa npm run test -w spa ``` -`build`は`dist/public`へbrowser assetを生成し、standalone実行用のserver codeだけを`dist/server`へ生成する。`start`は`dist/public`を静的配信する。 - -## Interface +- `dev`: Vite development server。API proxy は持たない。 +- `build`: `dist/public` に static SPA artifact を生成する。 +- `start`: `vite preview --outDir dist/public` で build artifact を静的配信するだけ。production server としては使わない。 +- API と結合して確認する場合は、Vite/nginx の前段または別 gateway で same-origin `/api/user` を用意する。 -### Application route +## Application routes - `/`: dashboard -- `/dashboard`などextensionless path: static serverのSPA fallback。application routeを増やさない。 +- `/dashboard` など extensionless application path: hosting 側で `index.html` へ fallback する - asset path: `dist/public/assets/*` -### Dashboard +static host は application route を `index.html` へ fallback できればよく、Node 固有の runtime を要求しない。 + +## Dashboard - header: service name、接続状態 - summary: user count - user list: name、identifier、created/updated timestamp -- loading: skeletonまたはloading indicator -- success: usersを表示 -- empty: countが0の場合の空状態 -- failure: connection/API/auth failureをユーザー向けの固定文言で表示 -- small viewport: 1列化し、横スクロール・text clippingを発生させない -- visual direction: limit-monitorを参考にしたdark surface、低彩度のborder、greenのonline accent - -UIは`GET /api/user`以外のAPI callを行わない。refresh操作を追加する場合も、明示操作につき1 requestとする。 - -### Standalone transport - -standalone serverのAPI boundaryは`GET /api/user`だけを扱う。 +- loading: skeleton または loading indicator +- success: users を表示 +- empty: count が0の場合の空状態 +- failure: connection/API/auth failure を利用者向け固定文言で表示 +- small viewport: 1列化し、横スクロール・text clipping を発生させない +- visual direction: limit-monitor を参考にした dark surface、低彩度の border、green の online accent -- session cookieなし: `401 Not authenticated\n` -- upstream success: JSON bodyをbrowserへ転送、`Cache-Control: no-store` -- upstreamの401/403: statusを保持した固定認証失敗文言。その他の非成功、redirect、network error、timeout: `502 Bad Gateway\n` -- query付き`/api/user`、未知の`/api/*`: APIとして処理しない -- static path: GET/HEADだけを受理し、extensionless pathだけSPA fallbackする - -serverはupstream responseのshapeを検証しない。browser clientがHTTP success bodyをparseし、invalid shapeをfailure stateへ変換する。 - -### Development transport - -Vite dev serverでもbrowserから見えるendpointはsame-originの`/api/user`とする。dev middlewareはstandalone adapterと同じcookie forwardingを使う。Vite serverのauthorityが確定していない間はstatic requestをViteへ委譲し、API requestを推測したupstreamへ送らない。 +UI は `GET /api/user` 以外の API call を行わない。 ## Error handling -- session cookieなし: login/sessionが必要な状態としてfailure UIを表示する。 -- upstreamの401/403: transportはstatusを保持した固定認証失敗文言へ変換する。5xxその他の非成功は固定502へ変換し、いずれもupstream bodyをbrowserへ漏らさない。 -- redirect/network/timeout: 固定502へ変換する。 -- HTTP 200でもresponse JSONが不正、`count`と`user.length`が不一致、必須fieldが不正: browser側でfailure UIを表示する。 -- malformed URL、path traversal、配信root外、symlink asset: static serverは固定400/404で拒否する。 -- credentialやupstream内部情報をHTML、client bundle、console、error responseへ出力しない。 - -## Non-functional requirements - -- browser bundleにcredentialを含めない。 -- `session` cookieはJavaScriptから直接参照しない。 -- 初回navigationのuser GETを1回だけ行い、user件数に比例するAPI callを行わない。 -- serverの業務処理はcookie forwardingと静的配信に限定する。response validation、表示データ変換、session claims処理、refresh token管理はSPA serverへ追加しない。 -- static serverはloopback bind、exact authority/originチェック、raw URLの安全なparse、配信root外拒否、symlink拒否、`O_NOFOLLOW`での最終file openを維持する。 -- UIは390px相当のsmall viewportからdesktopまで横方向の欠落・overflow・clippingなしで表示する。 -- CIはSPAのformat、format-check、lint、shared build、typecheck、build、testを実行する。既存`packages/client`とsharedの検証も壊さない。 +- 401/403: authentication failure として表示する。 +- その他の non-success / network failure: connection failure として表示する。 +- HTTP 200 でも response JSON が不正、`count` と `user.length` が不一致、必須 field が不正: browser 側で failure state にする。 +- upstream の error body や credential を UI / console へ出さない。 ## Out of scope -- SPA独自のlogin画面、session発行、session refresh、logout -- JavaScriptからのcookie読み取り -- credentialをVite define、public env、localStorageへ渡すこと -- SSR、React Router loader/actionを使ったserver rendering -- user以外のAPI endpoint -- limit-monitor固有のmeter、quota、billing APIの追加 -- API schemaや既存APIの認証実装変更 -- production deploy、DNS、external reverse proxy設定 +- SPA package 内の Node runtime server +- SPA package 内の static file server 実装 +- SPA package 内の API proxy / BFF +- SPA package 内の cookie-to-Authorization adapter +- SPA 独自の login、session 発行、refresh、logout +- JavaScript からの cookie 読み取り +- SSR / server action +- user 以外の API endpoint +- production gateway / DNS / TLS の実装 ## Acceptance criteria -- `packages/spa`がnpm workspaceとして`packages/client`と併存する。 -- React 19 + React Router v7 + Vite `ssr: false`のbuildが成功する。 -- browser clientが`credentials: 'include'`でsame-origin `/api/user`を1回取得する。 -- client bundle、HTML、console、error responseへcredentialが出ない。 -- standalone serverに固定credential設定がなく、session cookie不在時は401になる。 -- session cookieがある場合だけadapterが既存APIへAuthorizationを付け、成功bodyをbrowserへ返す。 -- adapterがupstream shapeを検証・再serializeせず、client側validationがinvalid responseをfailureへ変換する。 -- upstreamの401/403は認証失敗文言、それ以外の非成功、redirect、network error、timeoutは固定502になる。 -- static asset、SPA fallback、authority、origin、path traversal、symlink境界がテストされる。 -- loading、success、empty、failureのdashboard stateがdeterministic fixtureで確認できる。 -- small viewportとdesktopで横overflow・clippingがない。 -- SPAおよび既存client/sharedのformat、lint、typecheck、build、testが成功する。 - -## Verified references - -- `packages/client/src/app/_lib/auth/index.ts`: `session` cookie name -- `packages/client/src/app/api/auth/session/route.ts`: host-side session route -- `packages/client/src/app/proxy/api/[...path]/route.ts`: cookie-to-Authorization proxy pattern -- `packages/api/src/lib/middleware.ts`: existing API Authorization requirement -- `packages/shared/typespec/user.tsp`: `GET /api/user` response contract +- `packages/spa` が React Router v7 + Vite `ssr: false` の static SPA として build できる。 +- build artifact は `dist/public` の静的ファイルだけで構成され、production runtime Node server を必要としない。 +- browser client は `credentials: 'include'` で same-origin `/api/user` を1回取得する。 +- browser code は session cookie を直接読まない。 +- SPA package に API proxy、cookie forwarding、Authorization injection の server code が存在しない。 +- nginx 等から `dist/public` を配信し、application route を `index.html` へ fallback できる。 +- `/api/user` の実装方法は deployment environment に委譲され、SPA はその方式に依存しない。 +- loading、success、empty、failure の dashboard state が deterministic fixture で確認できる。 +- SPA および既存 client/shared の format、lint、typecheck、build、test が成功する。 diff --git a/packages/spa/package.json b/packages/spa/package.json index b134e0a..36f9032 100644 --- a/packages/spa/package.json +++ b/packages/spa/package.json @@ -6,8 +6,8 @@ "dev": "vite", "pretsc": "npm run build -w shared", "tsc": "react-router typegen && tsc --noEmit", - "build": "rm -rf dist && vp build && mv dist/spa/client dist/public && rm -rf dist/spa && tsc -p tsconfig.server.json", - "start": "node dist/server/index.js", + "build": "rm -rf dist && vp build && mv dist/spa/client dist/public && rm -rf dist/spa", + "start": "vite preview --outDir dist/public", "test": "vp test --config=./vite.config.ts", "test-ci": "vp test run --config=./vite.config.ts --maxWorkers=1", "format": "vp fmt package.json react-router.config.ts vite.config.ts app src --write", diff --git a/packages/spa/src/server/authority.test.ts b/packages/spa/src/server/authority.test.ts deleted file mode 100644 index d6e9860..0000000 --- a/packages/spa/src/server/authority.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -// @vitest-environment node -import { expect, test } from 'vite-plus/test' -import { validateAuthority } from './authority.js' - -test('authority accepts one exact Host and no Origin', () => { - expect( - validateAuthority({ - request: { rawHeaders: ['Host', '127.0.0.1:8789'] }, - authority: '127.0.0.1:8789', - origin: 'http://127.0.0.1:8789' - }) - ).toEqual({ ok: true }) -}) - -test('authority rejects missing, duplicate, and comma-joined Host fields', () => { - for (const rawHeaders of [ - [], - ['Host', '127.0.0.1:8789', 'Host', '127.0.0.1:8789'], - ['Host', '127.0.0.1:8789,127.0.0.1:8789'], - ['Host', '127.0.0.1:8790'] - ]) { - expect( - validateAuthority({ - request: { rawHeaders }, - authority: '127.0.0.1:8789', - origin: 'http://127.0.0.1:8789' - }) - ).toEqual({ ok: false, status: 400 }) - } -}) - -test('authority rejects duplicate, comma-joined, and mismatched Origin fields', () => { - for (const rawHeaders of [ - ['Host', '127.0.0.1:8789', 'Origin', 'http://127.0.0.1:8789', 'Origin', 'http://evil.test'], - ['Host', '127.0.0.1:8789', 'Origin', 'http://127.0.0.1:8789,http://evil.test'], - ['Host', '127.0.0.1:8789', 'Origin', 'http://evil.test'] - ]) { - expect( - validateAuthority({ - request: { rawHeaders }, - authority: '127.0.0.1:8789', - origin: 'http://127.0.0.1:8789' - }) - ).toEqual({ ok: false, status: 403 }) - } -}) diff --git a/packages/spa/src/server/authority.ts b/packages/spa/src/server/authority.ts deleted file mode 100644 index 5ce5ad8..0000000 --- a/packages/spa/src/server/authority.ts +++ /dev/null @@ -1,46 +0,0 @@ -type HeaderRequest = { - rawHeaders: readonly string[] -} - -type AuthorityValidation = { ok: true } | { ok: false; status: 400 | 403 } - -function headerValues(request: HeaderRequest, name: string) { - const values: string[] = [] - for (let index = 0; index < request.rawHeaders.length; index += 2) { - const headerName = request.rawHeaders[index] - const headerValue = request.rawHeaders[index + 1] - if (headerName?.toLowerCase() === name && headerValue !== undefined) { - values.push(headerValue) - } - } - return values -} - -export function validateAuthority({ - request, - authority, - origin -}: { - request: HeaderRequest - authority: string - origin: string -}): AuthorityValidation { - const hosts = headerValues(request, 'host') - if (hosts.length !== 1 || hosts[0]?.includes(',') || hosts[0] !== authority) { - return { ok: false, status: 400 } - } - - const origins = headerValues(request, 'origin') - if (origins.length > 1) { - return { ok: false, status: 403 } - } - for (const value of origins) { - if (value.includes(',')) { - return { ok: false, status: 403 } - } - } - if (origins.length === 1 && origins[0] !== origin) { - return { ok: false, status: 403 } - } - return { ok: true } -} diff --git a/packages/spa/src/server/config.test.ts b/packages/spa/src/server/config.test.ts deleted file mode 100644 index fa2d13c..0000000 --- a/packages/spa/src/server/config.test.ts +++ /dev/null @@ -1,42 +0,0 @@ -// @vitest-environment node -import fs from 'node:fs' -import os from 'node:os' -import path from 'node:path' -import { expect, test } from 'vite-plus/test' -import { assertDistribution, formatAuthority, loadConfig } from './config.js' - -test('config defaults to a loopback authority and API origin', () => { - const config = loadConfig({}) - - expect(config.host).toBe('127.0.0.1') - expect(config.port).toBe(8789) - expect(config.authority).toBe('127.0.0.1:8789') - expect(config.origin).toBe('http://127.0.0.1:8789') - expect(config.apiUri).toBe('http://localhost:8000') -}) - -test('config preserves the API origin without exposing a credential setting', () => { - const config = loadConfig({ API_URI: 'https://api.example.test' }) - - expect(config.apiUri).toBe('https://api.example.test') - expect(formatAuthority('::1', 8789)).toBe('[::1]:8789') -}) - -test('config rejects non-loopback hosts and malformed API origins', () => { - expect(() => loadConfig({ HOST: '0.0.0.0' })).toThrow(/HOST must be one of/) - expect(() => loadConfig({ API_URI: 'http://example.test/path' })).toThrow(/API_URI must be/) - expect(() => loadConfig({ API_URI: 'http://user:pass@example.test' })).toThrow(/API_URI must be/) -}) - -test('distribution root and index must be non-symlink filesystem entries', async () => { - const root = fs.mkdtempSync(path.join(os.tmpdir(), 'service-template-spa-')) - const index = path.join(root, 'index.html') - fs.writeFileSync(index, '') - await expect(assertDistribution(root)).resolves.toBeUndefined() - - const linkRoot = `${root}-link` - fs.symlinkSync(root, linkRoot, 'dir') - await expect(assertDistribution(linkRoot)).rejects.toThrow(/non-symlink directory/) - fs.rmSync(linkRoot, { force: true }) - fs.rmSync(root, { recursive: true, force: true }) -}) diff --git a/packages/spa/src/server/config.ts b/packages/spa/src/server/config.ts deleted file mode 100644 index 909adfe..0000000 --- a/packages/spa/src/server/config.ts +++ /dev/null @@ -1,104 +0,0 @@ -import fs from 'node:fs' -import path from 'node:path' - -const LOOPBACK_HOSTS = ['127.0.0.1', 'localhost', '::1'] as const - -type Environment = Record - -export type RuntimeConfig = { - apiUri: string - host: string - port: number - spaDistDir: string - authority: string - origin: string -} - -function resolvePort(raw: string | undefined) { - const value = (raw ?? '').trim() - if (value.length === 0) { - return 8789 - } - const port = Number(value) - if (!Number.isInteger(port) || port < 1 || port > 65535) { - throw new Error('PORT must be an integer between 1 and 65535') - } - return port -} - -function isLoopbackHost(value: string): value is (typeof LOOPBACK_HOSTS)[number] { - for (const allowedHost of LOOPBACK_HOSTS) { - if (allowedHost === value) { - return true - } - } - return false -} - -function resolveHost(raw: string | undefined) { - const host = (raw ?? '').trim() || '127.0.0.1' - if (!isLoopbackHost(host)) { - throw new Error('HOST must be one of 127.0.0.1, localhost, or ::1') - } - return host -} - -function resolveApiUri(raw: string | undefined) { - const value = (raw ?? '').trim() || 'http://localhost:8000' - let url: URL - try { - url = new URL(value) - } catch { - throw new Error('API_URI must be an http or https origin') - } - if ( - (url.protocol !== 'http:' && url.protocol !== 'https:') || - url.username.length > 0 || - url.password.length > 0 || - url.pathname !== '/' || - url.search.length > 0 || - url.hash.length > 0 || - value.endsWith('/') - ) { - throw new Error('API_URI must be an http or https origin') - } - return url.origin -} - -export function formatAuthority(host: string, port: number) { - const authorityHost = host.includes(':') && !host.startsWith('[') ? `[${host}]` : host - return `${authorityHost}:${port}` -} - -export function loadConfig(environment: Environment = process.env) { - const host = resolveHost(environment.HOST) - const port = resolvePort(environment.PORT) - const authority = formatAuthority(host, port) - const configuredDistDir = (environment.SPA_DIST_DIR ?? '').trim() - const spaDistDir = - configuredDistDir.length > 0 - ? path.resolve(configuredDistDir) - : path.resolve(import.meta.dirname, '../../dist/public') - - return { - apiUri: resolveApiUri(environment.API_URI), - host, - port, - spaDistDir, - authority, - origin: `http://${authority}` - } satisfies RuntimeConfig -} - -export async function assertDistribution(distDir: string) { - const rootStats = await fs.promises.lstat(distDir) - if (rootStats.isSymbolicLink() || !rootStats.isDirectory()) { - throw new Error('SPA_DIST_DIR must be a non-symlink directory') - } - const indexStats = await fs.promises.lstat(path.join(distDir, 'index.html')) - if (indexStats.isSymbolicLink() || !indexStats.isFile()) { - throw new Error('SPA_DIST_DIR must contain a non-symlink index.html') - } -} - -export const config = loadConfig() diff --git a/packages/spa/src/server/http-response.ts b/packages/spa/src/server/http-response.ts deleted file mode 100644 index 674f69b..0000000 --- a/packages/spa/src/server/http-response.ts +++ /dev/null @@ -1,33 +0,0 @@ -import type { ServerResponse } from 'node:http' - -export function sendTextResponse({ - response, - method, - status, - body, - headers = {}, - headContentLength -}: { - response: ServerResponse - method: string - status: number - body: string - headers?: Record - headContentLength?: number -}) { - const payload = Buffer.from(body, 'utf8') - const contentLength = - method === 'HEAD' && headContentLength !== undefined ? headContentLength : payload.byteLength - response.writeHead(status, { - ...headers, - 'content-type': 'text/plain; charset=utf-8', - 'content-length': String(contentLength), - 'cache-control': 'no-store', - 'x-content-type-options': 'nosniff' - }) - if (method === 'HEAD' || body.length === 0) { - response.end() - return - } - response.end(payload) -} diff --git a/packages/spa/src/server/index.ts b/packages/spa/src/server/index.ts deleted file mode 100644 index b5f41bb..0000000 --- a/packages/spa/src/server/index.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { assertDistribution, config } from './config.js' -import { createApplicationServer } from './static-server.js' - -await assertDistribution(config.spaDistDir) - -const application = createApplicationServer({ config }) -const { server } = application - -server.on('error', () => { - process.exitCode = 1 -}) - -function shutdown() { - application.abortAll() - server.close(() => { - process.exit(0) - }) - setTimeout(() => { - process.exit(1) - }, 10_000).unref() -} - -process.once('SIGTERM', shutdown) -process.once('SIGINT', shutdown) -server.listen(config.port, config.host) diff --git a/packages/spa/src/server/proxy.test.ts b/packages/spa/src/server/proxy.test.ts deleted file mode 100644 index c454b83..0000000 --- a/packages/spa/src/server/proxy.test.ts +++ /dev/null @@ -1,394 +0,0 @@ -// @vitest-environment node -import fs from 'node:fs' -import http from 'node:http' -import os from 'node:os' -import path from 'node:path' -import { expect, test } from 'vite-plus/test' -import { formatAuthority, type RuntimeConfig } from './config.js' -import { createApplicationServer } from './static-server.js' - -type HttpResponse = { - status: number - headers: http.IncomingHttpHeaders - body: string -} - -type ProxyContext = { - port: number - authority: string - application: ReturnType -} - -async function reservePort() { - const probe = http.createServer() - await new Promise((resolve) => { - probe.listen(0, '127.0.0.1', resolve) - }) - const address = probe.address() - if (address === null || typeof address === 'string') { - throw new Error('probe did not bind') - } - const port = address.port - await new Promise((resolve, reject) => { - probe.close((error) => { - if (error === undefined) { - resolve() - return - } - reject(error) - }) - }) - return port -} - -async function closeServer(server: http.Server) { - await new Promise((resolve, reject) => { - server.close((error) => { - if (error === undefined) { - resolve() - return - } - reject(error) - }) - }) -} - -async function waitForPromise(promise: Promise, timeoutMs: number) { - await Promise.race([ - promise, - new Promise((_resolve, reject) => { - const timer = setTimeout(() => { - reject(new Error('timed out waiting for upstream cancellation')) - }, timeoutMs) - timer.unref() - }) - ]) -} - -function createDist() { - const root = fs.mkdtempSync(path.join(os.tmpdir(), 'service-template-spa-proxy-')) - fs.writeFileSync(path.join(root, 'index.html'), '') - return root -} - -async function withProxyServer( - { - apiUri = 'http://upstream.invalid', - fetchImplementation = fetch - }: { - apiUri?: string - fetchImplementation?: typeof fetch - }, - run: (context: ProxyContext) => Promise -) { - const root = createDist() - const port = await reservePort() - const authority = formatAuthority('127.0.0.1', port) - const config = { - apiUri, - host: '127.0.0.1', - port, - spaDistDir: root, - authority, - origin: `http://${authority}` - } satisfies RuntimeConfig - const application = createApplicationServer({ config, fetchImplementation }) - await new Promise((resolve) => { - application.server.listen(port, '127.0.0.1', resolve) - }) - - try { - await run({ port, authority, application }) - } finally { - application.abortAll() - await closeServer(application.server) - fs.rmSync(root, { recursive: true, force: true }) - } -} - -function request({ - port, - authority, - requestPath = '/api/user', - method = 'GET', - cookie -}: { - port: number - authority: string - requestPath?: string - method?: string - cookie?: string -}) { - return new Promise((resolve, reject) => { - const headers: http.OutgoingHttpHeaders = { Host: authority } - if (cookie !== undefined) { - headers.Cookie = cookie - } - const client = http.request( - { - host: '127.0.0.1', - port, - path: requestPath, - method, - headers - }, - (response) => { - const chunks: Buffer[] = [] - response.on('data', (chunk: Buffer) => { - chunks.push(chunk) - }) - response.on('end', () => { - resolve({ - status: response.statusCode ?? 0, - headers: response.headers, - body: Buffer.concat(chunks).toString('utf8') - }) - }) - } - ) - client.on('error', reject) - client.end() - }) -} - -test('proxy requires the session cookie and does not call upstream without it', async () => { - let fetchCalls = 0 - const fetchImplementation: typeof fetch = async () => { - fetchCalls += 1 - return new Response('{}', { status: 200 }) - } - - await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { - for (const cookie of [ - undefined, - 'session=', - 'session=one; session=two', - 'session=invalid value' - ]) { - const response = await request({ port, authority, cookie }) - expect(response.status).toBe(401) - expect(response.body).toBe('Not authenticated\n') - } - }) - expect(fetchCalls).toBe(0) -}) - -test('proxy converts the session cookie to the upstream authorization header', async () => { - let upstreamUrl = '' - let authorization: string | null = null - let credentials: RequestCredentials | undefined - const fetchImplementation: typeof fetch = async (input, init) => { - if (typeof input === 'string') { - upstreamUrl = input - } else if (input instanceof URL) { - upstreamUrl = input.toString() - } else { - upstreamUrl = input.url - } - authorization = new Headers(init?.headers).get('authorization') - credentials = init?.credentials - return new Response( - JSON.stringify({ - count: 1, - user: [{ id: 1, name: 'Alice', created_at: 0, updated_at: 0 }] - }), - { status: 200, headers: { 'content-type': 'application/json' } } - ) - } - - await withProxyServer( - { apiUri: 'https://api.example.test', fetchImplementation }, - async ({ port, authority }) => { - const response = await request({ - port, - authority, - cookie: 'theme=dark; session=opaque-session; locale=ja', - requestPath: '/api/user' - }) - expect(response.status).toBe(200) - expect(JSON.parse(response.body)).toEqual({ - count: 1, - user: [{ id: 1, name: 'Alice', created_at: 0, updated_at: 0 }] - }) - } - ) - - expect(upstreamUrl).toBe('https://api.example.test/api/user') - expect(authorization).toBe('Bearer opaque-session') - expect(credentials).toBeUndefined() -}) - -test('proxy preserves sanitized authentication failures from upstream', async () => { - for (const [status, body] of [ - [401, 'Not authenticated\n'], - [403, 'Forbidden\n'] - ] as const) { - const fetchImplementation: typeof fetch = async () => { - return new Response('upstream secret details', { - status, - headers: { 'content-type': 'text/plain' } - }) - } - - await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { - const response = await request({ - port, - authority, - cookie: 'session=opaque-session' - }) - expect(response.status).toBe(status) - expect(response.body).toBe(body) - expect(response.body).not.toContain('opaque-session') - expect(response.body).not.toContain('upstream secret details') - }) - } -}) - -test('proxy returns a sanitized gateway error for upstream server failures', async () => { - const fetchImplementation: typeof fetch = async () => { - return new Response('upstream secret details', { - status: 500, - headers: { 'content-type': 'text/plain' } - }) - } - - await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { - const response = await request({ - port, - authority, - cookie: 'session=opaque-session' - }) - expect(response.status).toBe(502) - expect(response.body).toBe('Bad Gateway\n') - expect(response.body).not.toContain('opaque-session') - expect(response.body).not.toContain('upstream secret details') - }) -}) - -test('proxy passes the successful response to the browser without server-side shape validation', async () => { - const fetchImplementation: typeof fetch = async () => { - return new Response('{"unexpected":"shape"}', { - status: 200, - headers: { 'content-type': 'application/json' } - }) - } - - await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { - const response = await request({ - port, - authority, - cookie: 'session=opaque-session' - }) - expect(response.status).toBe(200) - expect(response.body).toBe('{"unexpected":"shape"}') - expect(response.headers['cache-control']).toBe('no-store') - expect(response.headers['x-content-type-options']).toBe('nosniff') - }) -}) - -test('proxy rejects an upstream redirect and does not follow it', async () => { - let requestInit: RequestInit | undefined - const fetchImplementation: typeof fetch = async (_input, init) => { - requestInit = init - throw new TypeError('redirect disallowed') - } - - await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { - const response = await request({ - port, - authority, - cookie: 'session=opaque-session' - }) - expect(response.status).toBe(502) - expect(response.body).toBe('Bad Gateway\n') - }) - expect(requestInit?.redirect).toBe('error') -}) - -test('proxy aborts an upstream fetch when the client disconnects', async () => { - let fetchStartedResolve: () => void = () => {} - const fetchStarted = new Promise((resolve) => { - fetchStartedResolve = resolve - }) - let fetchAbortedResolve: () => void = () => {} - const fetchAborted = new Promise((resolve) => { - fetchAbortedResolve = resolve - }) - const fetchImplementation: typeof fetch = async (_input, init) => { - fetchStartedResolve() - const signal = init?.signal - if (signal === undefined || signal === null) { - throw new Error('proxy signal was not provided') - } - return await new Promise((_resolve, reject) => { - signal.addEventListener( - 'abort', - () => { - fetchAbortedResolve() - reject(new Error('upstream fetch aborted')) - }, - { once: true } - ) - }) - } - - await withProxyServer({ fetchImplementation }, async ({ port, authority }) => { - const client = http.request( - { - host: '127.0.0.1', - port, - path: '/api/user', - headers: { Host: authority, Cookie: 'session=opaque-session' } - }, - (response) => { - response.resume() - } - ) - client.on('error', () => {}) - client.end() - await fetchStarted - client.destroy() - await waitForPromise(fetchAborted, 2_000) - }) -}) - -test('proxy aborts an upstream fetch during application shutdown', async () => { - let fetchStartedResolve: () => void = () => {} - const fetchStarted = new Promise((resolve) => { - fetchStartedResolve = resolve - }) - let fetchAbortedResolve: () => void = () => {} - const fetchAborted = new Promise((resolve) => { - fetchAbortedResolve = resolve - }) - const fetchImplementation: typeof fetch = async (_input, init) => { - fetchStartedResolve() - const signal = init?.signal - if (signal === undefined || signal === null) { - throw new Error('proxy signal was not provided') - } - return await new Promise((_resolve, reject) => { - signal.addEventListener( - 'abort', - () => { - fetchAbortedResolve() - reject(new Error('upstream fetch aborted')) - }, - { once: true } - ) - }) - } - - await withProxyServer({ fetchImplementation }, async ({ port, authority, application }) => { - const responsePromise = request({ - port, - authority, - cookie: 'session=opaque-session' - }) - await fetchStarted - application.abortAll() - await waitForPromise(fetchAborted, 2_000) - const response = await responsePromise - expect(response.status).toBe(502) - }) -}) diff --git a/packages/spa/src/server/proxy.ts b/packages/spa/src/server/proxy.ts deleted file mode 100644 index 3556f89..0000000 --- a/packages/spa/src/server/proxy.ts +++ /dev/null @@ -1,254 +0,0 @@ -import type { IncomingMessage, ServerResponse } from 'node:http' -import type { RuntimeConfig } from './config.js' -import { sendTextResponse } from './http-response.js' - -const PROXY_TIMEOUT_MS = 5_000 -const SESSION_COOKIE_NAME = 'session' -const COOKIE_OCTETS = /^[\u0021\u0023-\u002B\u002D-\u003A\u003C-\u005B\u005D-\u007E]+$/u - -export type ApiProxy = ReturnType - -type ProxyOptions = Pick & { - fetchImplementation?: typeof fetch -} - -function readSessionCookie(request: IncomingMessage) { - const cookieHeader = request.headers.cookie - if (cookieHeader === undefined) { - return null - } - - let session: string | null = null - for (const cookie of cookieHeader.split(';')) { - const separator = cookie.indexOf('=') - if (separator <= 0 || cookie.slice(0, separator).trim() !== SESSION_COOKIE_NAME) { - continue - } - if (session !== null) { - return null - } - const value = cookie.slice(separator + 1).trim() - if (value.length === 0) { - return null - } - if (!COOKIE_OCTETS.test(value)) { - return null - } - session = value - } - return session -} - -function sendAuthenticationFailure(response: ServerResponse, method: string, status: 401 | 403) { - sendTextResponse({ - response, - method, - status, - body: status === 403 ? 'Forbidden\n' : 'Not authenticated\n' - }) -} - -function sendBadGateway(response: ServerResponse, method: string) { - sendTextResponse({ - response, - method, - status: 502, - body: 'Bad Gateway\n' - }) -} - -async function sendUpstreamJson({ - response, - method, - body -}: { - response: ServerResponse - method: string - body: Response['body'] -}) { - response.writeHead(200, { - 'content-type': 'application/json; charset=utf-8', - 'cache-control': 'no-store', - 'x-content-type-options': 'nosniff' - }) - if (body === null || method === 'HEAD') { - await body?.cancel() - response.end() - return - } - - const reader = body.getReader() - try { - while (true) { - const chunk = await reader.read() - if (chunk.done) { - break - } - if (response.destroyed) { - throw new Error('client closed response') - } - if (!response.write(chunk.value)) { - await new Promise((resolve, reject) => { - let settled = false - const cleanup = () => { - response.off('drain', onDrain) - response.off('error', onError) - response.off('close', onClose) - } - const onDrain = () => { - if (settled) { - return - } - settled = true - cleanup() - resolve() - } - const onError = (error: Error) => { - if (settled) { - return - } - settled = true - cleanup() - reject(error) - } - const onClose = () => { - if (settled || response.writableFinished) { - return - } - settled = true - cleanup() - reject(new Error('client closed response')) - } - response.once('drain', onDrain) - response.once('error', onError) - response.once('close', onClose) - }) - } - } - - await new Promise((resolve, reject) => { - const cleanup = () => { - response.off('finish', onFinish) - response.off('error', onError) - response.off('close', onClose) - } - const onFinish = () => { - cleanup() - resolve() - } - const onError = (error: Error) => { - cleanup() - reject(error) - } - const onClose = () => { - if (response.writableFinished) { - return - } - cleanup() - reject(new Error('client closed response')) - } - response.once('finish', onFinish) - response.once('error', onError) - response.once('close', onClose) - response.end() - }) - } catch (error) { - try { - await reader.cancel() - } catch { - // The upstream stream may already be closed after a client disconnect. - } - response.destroy() - throw error - } finally { - reader.releaseLock() - } -} - -export function createApiProxy({ apiUri, fetchImplementation = fetch }: ProxyOptions) { - const activeControllers = new Set() - - function abortAll() { - for (const controller of activeControllers) { - controller.abort() - } - } - - async function handleUserRequest({ - request, - response - }: { - request: IncomingMessage - response: ServerResponse - }) { - const sessionCookie = readSessionCookie(request) - if (sessionCookie === null) { - sendAuthenticationFailure(response, request.method ?? 'GET', 401) - return - } - - const controller = new AbortController() - activeControllers.add(controller) - let settled = false - const abortOnDisconnect = () => { - if (!settled) { - controller.abort() - } - } - request.once('aborted', abortOnDisconnect) - response.once('close', abortOnDisconnect) - const timeout = setTimeout(() => { - controller.abort() - }, PROXY_TIMEOUT_MS) - - try { - const upstreamResponse = await fetchImplementation(new URL('/api/user', apiUri), { - method: 'GET', - redirect: 'error', - headers: { - Authorization: `Bearer ${sessionCookie}`, - Accept: 'application/json' - }, - signal: controller.signal - }) - if (upstreamResponse.status !== 200) { - const status = upstreamResponse.status - await upstreamResponse.body?.cancel() - if (status === 401 || status === 403) { - settled = true - sendAuthenticationFailure(response, request.method ?? 'GET', status) - return - } - throw new Error('upstream response was not successful') - } - - if (response.destroyed) { - controller.abort() - await upstreamResponse.body?.cancel() - return - } - await sendUpstreamJson({ - response, - method: request.method ?? 'GET', - body: upstreamResponse.body - }) - settled = true - } catch { - if (!response.headersSent && !response.destroyed) { - settled = true - sendBadGateway(response, request.method ?? 'GET') - } - } finally { - clearTimeout(timeout) - activeControllers.delete(controller) - request.off('aborted', abortOnDisconnect) - response.off('close', abortOnDisconnect) - settled = true - } - } - - return { - handleUserRequest, - abortAll - } -} diff --git a/packages/spa/src/server/request-target.test.ts b/packages/spa/src/server/request-target.test.ts deleted file mode 100644 index 280805f..0000000 --- a/packages/spa/src/server/request-target.test.ts +++ /dev/null @@ -1,28 +0,0 @@ -// @vitest-environment node -import { expect, test } from 'vite-plus/test' -import { parseRequestTarget } from './request-target.js' - -test('request target dispatch is exact and single-decode', () => { - expect(parseRequestTarget('/api/user')).toEqual({ kind: 'api-user', pathname: '/api/user' }) - expect(parseRequestTarget('/api/user?x=1')).toEqual({ kind: 'bad-request' }) - for (const target of ['/api/unknown', '/api%2Fuser', '/%61pi/user', '/api%252Fuser', '/apiary']) { - expect(parseRequestTarget(target)).toEqual({ - kind: 'reserved-api', - pathname: expect.any(String) - }) - } - expect(parseRequestTarget('/dashboard?x=1')).toEqual({ kind: 'static', pathname: '/dashboard' }) -}) - -test('request target rejects traversal, malformed encoding, and protocol-relative values', () => { - for (const target of [ - '//evil.test/a.js', - '/%2e%2e/secrets.env', - '/assets/..%2f..%2fsecret', - '/a%ZZ', - '/a%00.js', - '/a%5Cb' - ]) { - expect(parseRequestTarget(target)).toEqual({ kind: 'bad-request' }) - } -}) diff --git a/packages/spa/src/server/request-target.ts b/packages/spa/src/server/request-target.ts deleted file mode 100644 index 0a1f832..0000000 --- a/packages/spa/src/server/request-target.ts +++ /dev/null @@ -1,64 +0,0 @@ -export type RequestTarget = - | { kind: 'api-user'; pathname: '/api/user' } - | { kind: 'reserved-api'; pathname: string } - | { kind: 'static'; pathname: string } - | { kind: 'bad-request' } - -function firstSegment(pathname: string) { - return pathname.slice(1).split('/')[0] ?? '' -} - -export function parseRequestTarget(requestUrl: string | undefined): RequestTarget { - const rawTarget = requestUrl ?? '' - if (!rawTarget.startsWith('/') || rawTarget.startsWith('//')) { - return { kind: 'bad-request' } - } - - const queryIndex = rawTarget.indexOf('?') - const fragmentIndex = rawTarget.indexOf('#') - let suffixIndex = rawTarget.length - for (const index of [queryIndex, fragmentIndex]) { - if (index >= 0 && index < suffixIndex) { - suffixIndex = index - } - } - const rawPathname = rawTarget.slice(0, suffixIndex) - const hasSuffix = suffixIndex < rawTarget.length - - let pathname: string - try { - pathname = decodeURIComponent(rawPathname) - } catch { - return { kind: 'bad-request' } - } - - let hasParentSegment = false - for (const segment of pathname.split('/')) { - if (segment === '..') { - hasParentSegment = true - break - } - } - if ( - pathname.length === 0 || - pathname.startsWith('//') || - pathname.includes('\0') || - pathname.includes('\\') || - hasParentSegment - ) { - return { kind: 'bad-request' } - } - - const reservedApi = firstSegment(pathname).toLowerCase().startsWith('api') - if (!reservedApi) { - return { kind: 'static', pathname } - } - - if (rawPathname === '/api/user' && pathname === '/api/user') { - if (hasSuffix) { - return { kind: 'bad-request' } - } - return { kind: 'api-user', pathname: '/api/user' } - } - return { kind: 'reserved-api', pathname } -} diff --git a/packages/spa/src/server/static-server.test.ts b/packages/spa/src/server/static-server.test.ts deleted file mode 100644 index 2927346..0000000 --- a/packages/spa/src/server/static-server.test.ts +++ /dev/null @@ -1,373 +0,0 @@ -// @vitest-environment node -import fs from 'node:fs' -import http from 'node:http' -import os from 'node:os' -import path from 'node:path' -import { expect, test } from 'vite-plus/test' -import { formatAuthority, type RuntimeConfig } from './config.js' -import { createApiProxy } from './proxy.js' -import { createApplicationServer, contentTypeOf, handleDevApiBoundary } from './static-server.js' - -type HttpResponse = { - status: number - headers: http.IncomingHttpHeaders - body: string -} - -function createDist() { - const root = fs.mkdtempSync(path.join(os.tmpdir(), 'service-template-spa-dist-')) - fs.mkdirSync(path.join(root, 'assets')) - fs.writeFileSync(path.join(root, 'index.html'), 'service template') - fs.writeFileSync(path.join(root, 'assets', 'app-abcdef.js'), 'export const app = 1\n') - fs.writeFileSync(path.join(root, 'missing-target.txt'), 'not requested') - return root -} - -async function reservePort() { - const probe = http.createServer() - await new Promise((resolve) => { - probe.listen(0, '127.0.0.1', resolve) - }) - const address = probe.address() - if (address === null || typeof address === 'string') { - throw new Error('probe did not bind') - } - await new Promise((resolve, reject) => { - probe.close((error) => { - if (error === undefined) { - resolve() - return - } - reject(error) - }) - }) - return address.port -} - -async function withServer( - run: (context: { - port: number - authority: string - origin: string - root: string - upstreamCalls: () => number - }) => Promise -) { - const root = createDist() - const port = await reservePort() - const authority = formatAuthority('127.0.0.1', port) - let upstreamCallCount = 0 - const upstream = http.createServer((request, response) => { - if (request.url === '/api/user') { - upstreamCallCount += 1 - response.writeHead(200, { 'content-type': 'application/json' }) - response.end( - JSON.stringify({ - count: 2, - user: [ - { id: 1, name: 'Alice', created_at: 1710000000, updated_at: 1710003600 }, - { id: 2, name: 'Bob', created_at: 1710007200, updated_at: 1710010800 } - ] - }) - ) - return - } - response.writeHead(404) - response.end('missing') - }) - await new Promise((resolve) => { - upstream.listen(0, '127.0.0.1', resolve) - }) - const upstreamAddress = upstream.address() - if (upstreamAddress === null || typeof upstreamAddress === 'string') { - throw new Error('upstream did not bind') - } - const config = { - apiUri: `http://127.0.0.1:${upstreamAddress.port}`, - host: '127.0.0.1', - port, - spaDistDir: root, - authority, - origin: `http://${authority}` - } satisfies RuntimeConfig - const application = createApplicationServer({ config }) - await new Promise((resolve) => { - application.server.listen(port, '127.0.0.1', resolve) - }) - try { - function upstreamCalls() { - return upstreamCallCount - } - await run({ port, authority, origin: config.origin, root, upstreamCalls }) - } finally { - application.abortAll() - await new Promise((resolve) => { - application.server.close(() => { - resolve() - }) - }) - await new Promise((resolve) => { - upstream.close(() => { - resolve() - }) - }) - fs.rmSync(root, { recursive: true, force: true }) - } -} - -function request({ - port, - requestPath, - authority, - method = 'GET', - origin, - cookie -}: { - port: number - requestPath: string - authority: string - method?: string - origin?: string - cookie?: string -}) { - return new Promise((resolve, reject) => { - const headers: http.OutgoingHttpHeaders = { Host: authority } - if (origin !== undefined) { - headers.Origin = origin - } - if (cookie !== undefined) { - headers.Cookie = cookie - } - const request = http.request( - { - host: '127.0.0.1', - port, - path: requestPath, - method, - headers - }, - (response) => { - const chunks: Buffer[] = [] - response.on('data', (chunk: Buffer) => { - chunks.push(chunk) - }) - response.on('end', () => { - resolve({ - status: response.statusCode ?? 0, - headers: response.headers, - body: Buffer.concat(chunks).toString('utf8') - }) - }) - } - ) - request.on('error', reject) - request.end() - }) -} - -test('static server serves SPA fallback and immutable assets', async () => { - await withServer(async ({ port, authority }) => { - const page = await request({ port, authority, requestPath: '/dashboard' }) - expect(page.status).toBe(200) - expect(page.body).toContain('service template') - expect(page.headers['cache-control']).toBe('no-store') - expect(page.headers['content-type']).toBe('text/html; charset=utf-8') - - const asset = await request({ port, authority, requestPath: '/assets/app-abcdef.js' }) - expect(asset.status).toBe(200) - expect(asset.headers['content-type']).toBe('text/javascript; charset=utf-8') - expect(asset.headers['cache-control']).toBe('public, max-age=31536000, immutable') - expect(asset.headers['x-content-type-options']).toBe('nosniff') - }) -}) - -test('static server keeps missing assets out of SPA fallback and supports HEAD', async () => { - await withServer(async ({ port, authority }) => { - const missing = await request({ port, authority, requestPath: '/assets/missing.js' }) - expect(missing.status).toBe(404) - expect(missing.body).toBe('Not Found\n') - expect(missing.headers['cache-control']).toBe('no-store') - - const head = await request({ - port, - authority, - requestPath: '/assets/app-abcdef.js', - method: 'HEAD' - }) - expect(head.status).toBe(200) - expect(head.body).toBe('') - expect(head.headers['content-length']).toBe(String(Buffer.byteLength('export const app = 1\n'))) - }) -}) - -test('static server enforces authority, origin, methods, and reserved API paths', async () => { - await withServer(async ({ port, authority, origin, upstreamCalls }) => { - const badHost = await request({ port, authority: '127.0.0.1:1', requestPath: '/' }) - expect(badHost.status).toBe(400) - expect(badHost.body).toBe('Bad Request\n') - - const badOrigin = await request({ - port, - authority, - origin: 'http://evil.test', - requestPath: '/' - }) - expect(badOrigin.status).toBe(403) - expect(badOrigin.body).toBe('Forbidden\n') - - const method = await request({ port, authority, requestPath: '/', method: 'POST' }) - expect(method.status).toBe(405) - expect(method.headers.allow).toBe('GET, HEAD') - - const reserved = await request({ port, authority, requestPath: '/api/unknown' }) - expect(reserved.status).toBe(404) - expect(reserved.body).toBe('Not Found\n') - - const query = await request({ port, authority, requestPath: '/api/user?x=1' }) - expect(query.status).toBe(400) - expect(query.body).toBe('Bad Request\n') - - for (const requestPath of ['/api%2Fuser', '/%61pi/user', '/api%252Fuser']) { - const encoded = await request({ port, authority, requestPath }) - expect(encoded.status).toBe(404) - expect(encoded.body).toBe('Not Found\n') - } - - const head = await request({ port, authority, requestPath: '/api/user', method: 'HEAD' }) - expect(head.status).toBe(405) - expect(head.headers.allow).toBe('GET') - expect(head.body).toBe('') - - const post = await request({ port, authority, requestPath: '/api/user', method: 'POST' }) - expect(post.status).toBe(405) - expect(post.headers.allow).toBe('GET') - expect(post.body).toBe('Method Not Allowed\n') - - const api = await request({ - port, - authority, - origin, - cookie: 'session=sample-session', - requestPath: '/api/user' - }) - expect(api.status).toBe(200) - expect(JSON.parse(api.body)).toEqual({ - count: 2, - user: [ - { id: 1, name: 'Alice', created_at: 1710000000, updated_at: 1710003600 }, - { id: 2, name: 'Bob', created_at: 1710007200, updated_at: 1710010800 } - ] - }) - expect(api.headers['access-control-allow-origin']).toBeUndefined() - expect(upstreamCalls()).toBe(1) - }) -}) - -test('static server rejects preexisting file and directory symlinks', async () => { - await withServer(async ({ port, authority, root }) => { - fs.symlinkSync(path.join(root, 'index.html'), path.join(root, 'assets', 'linked.js')) - const file = await request({ port, authority, requestPath: '/assets/linked.js' }) - expect(file.status).toBe(400) - expect(file.body).toBe('Bad Request\n') - - fs.symlinkSync(root, path.join(root, 'assets', 'linked-directory'), 'dir') - const directory = await request({ - port, - authority, - requestPath: '/assets/linked-directory/app.js' - }) - expect(directory.status).toBe(400) - expect(directory.body).toBe('Bad Request\n') - }) -}) - -test('development API boundary fails closed before its authority is available', async () => { - const port = await reservePort() - const authority = formatAuthority('127.0.0.1', port) - const proxy = createApiProxy({ apiUri: 'http://upstream.invalid' }) - const server = http.createServer((req, res) => { - void handleDevApiBoundary({ - req, - res, - next: () => { - res.writeHead(418) - res.end('next') - }, - config: null, - proxy - }) - }) - await new Promise((resolve) => { - server.listen(port, '127.0.0.1', resolve) - }) - - try { - const api = await request({ port, authority, requestPath: '/api/user' }) - expect(api.status).toBe(503) - expect(api.body).toBe('Development server is not ready\n') - expect(api.headers['cache-control']).toBe('no-store') - expect(api.headers['x-content-type-options']).toBe('nosniff') - - const malformed = await request({ port, authority, requestPath: '/a%ZZ' }) - expect(malformed.status).toBe(400) - expect(malformed.body).toBe('Bad Request\n') - - const staticResponse = await request({ port, authority, requestPath: '/' }) - expect(staticResponse.status).toBe(418) - expect(staticResponse.body).toBe('next') - } finally { - proxy.abortAll() - await new Promise((resolve) => { - server.close(() => { - resolve() - }) - }) - } -}) - -test('static server requires a session cookie and sanitizes upstream failures', async () => { - const root = createDist() - const port = await reservePort() - const authority = formatAuthority('127.0.0.1', port) - const config = { - apiUri: 'http://127.0.0.1:1', - host: '127.0.0.1', - port, - spaDistDir: root, - authority, - origin: `http://${authority}` - } satisfies RuntimeConfig - const application = createApplicationServer({ config }) - await new Promise((resolve) => { - application.server.listen(port, '127.0.0.1', resolve) - }) - try { - const unauthorized = await request({ port, authority, requestPath: '/api/user' }) - expect(unauthorized.status).toBe(401) - expect(unauthorized.body).toBe('Not authenticated\n') - - const upstreamFailure = await request({ - port, - authority, - cookie: 'session=sample-session', - requestPath: '/api/user' - }) - expect(upstreamFailure.status).toBe(502) - expect(upstreamFailure.body).toBe('Bad Gateway\n') - expect(upstreamFailure.body).not.toContain('sample-session') - } finally { - application.abortAll() - await new Promise((resolve) => { - application.server.close(() => { - resolve() - }) - }) - fs.rmSync(root, { recursive: true, force: true }) - } -}) - -test('known content types fail closed for unknown extensions', () => { - expect(contentTypeOf('/assets/app.js')).toBe('text/javascript; charset=utf-8') - expect(contentTypeOf('/assets/app.CSS')).toBe('text/css; charset=utf-8') - expect(contentTypeOf('/assets/app.bin')).toBe('application/octet-stream') -}) diff --git a/packages/spa/src/server/static-server.ts b/packages/spa/src/server/static-server.ts deleted file mode 100644 index ed91d53..0000000 --- a/packages/spa/src/server/static-server.ts +++ /dev/null @@ -1,378 +0,0 @@ -import fs from 'node:fs' -import fsp from 'node:fs/promises' -import http from 'node:http' -import path from 'node:path' -import { pipeline } from 'node:stream/promises' -import type { RuntimeConfig } from './config.js' -import { validateAuthority } from './authority.js' -import { sendTextResponse } from './http-response.js' -import { parseRequestTarget, type RequestTarget } from './request-target.js' -import { createApiProxy, type ApiProxy } from './proxy.js' - -const CONTENT_TYPES = new Map([ - ['.html', 'text/html; charset=utf-8'], - ['.js', 'text/javascript; charset=utf-8'], - ['.mjs', 'text/javascript; charset=utf-8'], - ['.css', 'text/css; charset=utf-8'], - ['.json', 'application/json; charset=utf-8'], - ['.map', 'application/json; charset=utf-8'], - ['.svg', 'image/svg+xml'], - ['.png', 'image/png'], - ['.jpg', 'image/jpeg'], - ['.jpeg', 'image/jpeg'], - ['.gif', 'image/gif'], - ['.webp', 'image/webp'], - ['.ico', 'image/x-icon'], - ['.woff', 'font/woff'], - ['.woff2', 'font/woff2'], - ['.ttf', 'font/ttf'], - ['.wasm', 'application/wasm'], - ['.webmanifest', 'application/manifest+json'] -]) - -const IMMUTABLE_CACHE_CONTROL = 'public, max-age=31536000, immutable' -const DEFAULT_CONTENT_TYPE = 'application/octet-stream' - -type StaticFile = { - kind: 'file' - filePath: string - size: number -} - -type FileInspection = StaticFile | { kind: 'missing' } | { kind: 'symlink' } - -export function contentTypeOf(filePath: string) { - return CONTENT_TYPES.get(path.extname(filePath).toLowerCase()) ?? DEFAULT_CONTENT_TYPE -} - -export function resolveStaticPath({ distDir, pathname }: { distDir: string; pathname: string }) { - const root = path.resolve(distDir) - const filePath = path.resolve(root, `.${pathname}`) - if (filePath !== root && !filePath.startsWith(`${root}${path.sep}`)) { - return null - } - return { root, filePath } -} - -async function inspectTrustedFile(root: string, filePath: string): Promise { - const rootStats = await fsp.lstat(root) - if (rootStats.isSymbolicLink()) { - return { kind: 'symlink' } - } - if (!rootStats.isDirectory()) { - return { kind: 'missing' } - } - - const relativePath = path.relative(root, filePath) - if ( - relativePath.length === 0 || - relativePath.startsWith(`..${path.sep}`) || - path.isAbsolute(relativePath) - ) { - return { kind: 'missing' } - } - - let currentPath = root - const segments = relativePath.split(path.sep) - for (let index = 0; index < segments.length; index += 1) { - const segment = segments[index] - if (segment === undefined) { - return { kind: 'missing' } - } - currentPath = path.join(currentPath, segment) - let stats: fs.Stats - try { - stats = await fsp.lstat(currentPath) - } catch (error) { - if (error instanceof Error && 'code' in error && error.code === 'ENOENT') { - return { kind: 'missing' } - } - throw error - } - if (stats.isSymbolicLink()) { - return { kind: 'symlink' } - } - const isLast = index === segments.length - 1 - if (!isLast && !stats.isDirectory()) { - return { kind: 'missing' } - } - if (isLast && !stats.isFile()) { - return { kind: 'missing' } - } - if (isLast) { - return { kind: 'file', filePath: currentPath, size: stats.size } - } - } - return { kind: 'missing' } -} - -function cacheControlOf(root: string, filePath: string) { - const relativePath = path.relative(root, filePath) - if (relativePath.startsWith(`assets${path.sep}`)) { - return IMMUTABLE_CACHE_CONTROL - } - return 'no-store' -} - -async function sendFile({ - response, - method, - root, - filePath, - size -}: { - response: http.ServerResponse - method: string - root: string - filePath: string - size: number -}) { - const headers = { - 'content-type': contentTypeOf(filePath), - 'content-length': String(size), - 'cache-control': cacheControlOf(root, filePath), - 'x-content-type-options': 'nosniff' - } - if (method === 'HEAD') { - response.writeHead(200, headers) - response.end() - return - } - try { - const fileHandle = await fsp.open(filePath, fs.constants.O_RDONLY | fs.constants.O_NOFOLLOW) - const stream = fileHandle.createReadStream({ autoClose: true }) - response.writeHead(200, headers) - await pipeline(stream, response) - } catch { - if (!response.headersSent && !response.destroyed) { - sendBadRequest(response, method) - return - } - response.destroy() - } -} - -function sendBadRequest(response: http.ServerResponse, method: string) { - sendTextResponse({ response, method, status: 400, body: 'Bad Request\n' }) -} - -function sendDevelopmentUnavailable(response: http.ServerResponse, method: string) { - sendTextResponse({ - response, - method, - status: 503, - body: 'Development server is not ready\n' - }) -} - -function sendNotFound(response: http.ServerResponse, method: string) { - sendTextResponse({ response, method, status: 404, body: 'Not Found\n' }) -} - -function sendMethodNotAllowed(response: http.ServerResponse, method: string, allow: string) { - sendTextResponse({ - response, - method, - status: 405, - body: 'Method Not Allowed\n', - headers: { allow }, - headContentLength: method === 'HEAD' ? 0 : undefined - }) -} - -async function serveStatic({ - request, - response, - config, - target -}: { - request: http.IncomingMessage - response: http.ServerResponse - config: RuntimeConfig - target: Extract -}) { - const method = request.method ?? 'GET' - if (method !== 'GET' && method !== 'HEAD') { - sendMethodNotAllowed(response, method, 'GET, HEAD') - return - } - - const resolved = resolveStaticPath({ distDir: config.spaDistDir, pathname: target.pathname }) - if (resolved === null) { - sendBadRequest(response, method) - return - } - const direct = await inspectTrustedFile(resolved.root, resolved.filePath) - if (direct.kind === 'symlink') { - sendBadRequest(response, method) - return - } - if (direct.kind === 'file') { - await sendFile({ - response, - method, - root: resolved.root, - filePath: direct.filePath, - size: direct.size - }) - return - } - - if (path.extname(target.pathname) !== '') { - sendNotFound(response, method) - return - } - - const indexPath = path.join(resolved.root, 'index.html') - const index = await inspectTrustedFile(resolved.root, indexPath) - if (index.kind === 'symlink') { - sendBadRequest(response, method) - return - } - if (index.kind !== 'file') { - sendNotFound(response, method) - return - } - await sendFile({ - response, - method, - root: resolved.root, - filePath: index.filePath, - size: index.size - }) -} - -async function handleParsedTarget({ - request, - response, - config, - target, - proxy -}: { - request: http.IncomingMessage - response: http.ServerResponse - config: RuntimeConfig - target: RequestTarget - proxy: ApiProxy -}) { - const method = request.method ?? 'GET' - if (target.kind === 'bad-request') { - sendBadRequest(response, method) - return - } - if (target.kind === 'reserved-api') { - sendNotFound(response, method) - return - } - if (target.kind === 'api-user') { - if (method !== 'GET') { - sendMethodNotAllowed(response, method, 'GET') - return - } - await proxy.handleUserRequest({ request, response }) - return - } - await serveStatic({ request, response, config, target }) -} - -async function handleRequest({ - request, - response, - config, - proxy -}: { - request: http.IncomingMessage - response: http.ServerResponse - config: RuntimeConfig - proxy: ApiProxy -}) { - const authority = validateAuthority({ - request, - authority: config.authority, - origin: config.origin - }) - if (!authority.ok) { - sendTextResponse({ - response, - method: request.method ?? 'GET', - status: authority.status, - body: authority.status === 403 ? 'Forbidden\n' : 'Bad Request\n', - headContentLength: request.method === 'HEAD' ? 0 : undefined - }) - return - } - const target = parseRequestTarget(request.url) - await handleParsedTarget({ request, response, config, target, proxy }) -} - -export async function handleDevApiBoundary({ - req, - res, - next, - config, - proxy -}: { - req: http.IncomingMessage - res: http.ServerResponse - next: () => void - config: RuntimeConfig | null - proxy: ApiProxy -}) { - const target = parseRequestTarget(req.url) - if (target.kind === 'static') { - next() - return - } - if (target.kind === 'bad-request') { - sendBadRequest(res, req.method ?? 'GET') - return - } - if (config === null) { - sendDevelopmentUnavailable(res, req.method ?? 'GET') - return - } - const authority = validateAuthority({ - request: req, - authority: config.authority, - origin: config.origin - }) - if (!authority.ok) { - sendTextResponse({ - response: res, - method: req.method ?? 'GET', - status: authority.status, - body: authority.status === 403 ? 'Forbidden\n' : 'Bad Request\n', - headContentLength: req.method === 'HEAD' ? 0 : undefined - }) - return - } - await handleParsedTarget({ request: req, response: res, config, target, proxy }) -} - -export function createApplicationServer({ - config, - fetchImplementation -}: { - config: RuntimeConfig - fetchImplementation?: typeof fetch -}) { - const proxy = createApiProxy({ - apiUri: config.apiUri, - fetchImplementation - }) - const server = http.createServer((request, response) => { - void handleRequest({ request, response, config, proxy }).catch(() => { - if (!response.headersSent && !response.destroyed) { - sendTextResponse({ - response, - method: request.method ?? 'GET', - status: 500, - body: 'Internal Server Error\n' - }) - } else { - response.destroy() - } - }) - }) - return { server, abortAll: proxy.abortAll } -} diff --git a/packages/spa/tsconfig.server.json b/packages/spa/tsconfig.server.json deleted file mode 100644 index d4389e2..0000000 --- a/packages/spa/tsconfig.server.json +++ /dev/null @@ -1,18 +0,0 @@ -{ - "compilerOptions": { - "types": ["node"], - "strict": true, - "noUncheckedIndexedAccess": true, - "skipLibCheck": true, - "esModuleInterop": true, - "target": "esnext", - "lib": ["ESNext"], - "module": "nodenext", - "moduleResolution": "nodenext", - "rootDir": "src", - "outDir": "dist", - "sourceMap": true - }, - "include": ["src/server"], - "exclude": ["**/*.test.ts"] -} diff --git a/packages/spa/vite.config.ts b/packages/spa/vite.config.ts index e760569..3a338ba 100644 --- a/packages/spa/vite.config.ts +++ b/packages/spa/vite.config.ts @@ -1,68 +1,11 @@ import { reactRouter } from '@react-router/dev/vite' import react from '@vitejs/plugin-react' import { defineConfig } from 'vite-plus' -import { formatAuthority, loadConfig, type RuntimeConfig } from './src/server/config.js' -import { createApiProxy } from './src/server/proxy.js' -import { handleDevApiBoundary } from './src/server/static-server.js' -type DevelopmentServer = { - httpServer?: { - address: () => { port: number } | string | null - } | null -} - -const baseConfig = loadConfig() -const apiProxy = createApiProxy(baseConfig) - -function getDevelopmentConfig(server: DevelopmentServer) { - const address = server.httpServer?.address() - if (address === undefined || address === null || typeof address === 'string') { - return null - } - - const authority = formatAuthority(baseConfig.host, address.port) - return { - ...baseConfig, - host: baseConfig.host, - port: address.port, - authority, - origin: `http://${authority}` - } satisfies RuntimeConfig -} - -export default defineConfig(({ mode }) => { - return { - plugins: [ - mode === 'test' ? react() : reactRouter(), - { - name: 'spa-api-proxy', - configureServer(server) { - server.middlewares.use((req, res, next) => { - const developmentConfig = getDevelopmentConfig(server) - void handleDevApiBoundary({ - req, - res, - next, - config: developmentConfig, - proxy: apiProxy - }) - }) - server.httpServer?.on('close', () => { - apiProxy.abortAll() - }) - } - } - ], - server: { - host: baseConfig.host, - port: 0, - strictPort: true, - cors: false, - allowedHosts: ['127.0.0.1', 'localhost', '::1'] - }, - test: { - environment: 'happy-dom', - exclude: ['**/node_modules/**', '**/dist/**', '**/.react-router/**'] - } +export default defineConfig(({ mode }) => ({ + plugins: [mode === 'test' ? react() : reactRouter()], + test: { + environment: 'happy-dom', + exclude: ['**/node_modules/**', '**/dist/**', '**/.react-router/**'] } -}) +})) From a8de1ed30e701e5ca253bf9b1eeab908251e0c37 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 17:25:17 +0900 Subject: [PATCH 05/21] refactor: derive SPA API types from shared schema --- packages/spa/app/lib/api-client.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/spa/app/lib/api-client.ts b/packages/spa/app/lib/api-client.ts index a289bb6..cf19c91 100644 --- a/packages/spa/app/lib/api-client.ts +++ b/packages/spa/app/lib/api-client.ts @@ -1,4 +1,7 @@ -import { parseUserResponse, type UserResponse } from '../../src/api-contract' +import type * as schema from 'shared/src/schema' + +type UserResponse = + schema.paths['/api/user']['get']['responses']['200']['content']['application/json'] export type UserLoadResult = | { ok: true; body: UserResponse } @@ -23,11 +26,8 @@ export async function fetchUsers() { return { ok: false, status: response.status, body } satisfies UserLoadResult } - const parsed = parseUserResponse(await response.json()) - if (parsed === null) { - return { ok: false, status: 502, body: 'Bad Gateway' } satisfies UserLoadResult - } - return { ok: true, body: parsed } satisfies UserLoadResult + const body = (await response.json()) as UserResponse + return { ok: true, body } satisfies UserLoadResult } catch { return { ok: false, status: 502, body: 'Bad Gateway' } satisfies UserLoadResult } From c15fae037eb2561077b01bb5fce102837c58862e Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 17:25:26 +0900 Subject: [PATCH 06/21] test: use generated schema types in SPA client --- packages/spa/app/lib/api-client.test.ts | 21 ++------------------- 1 file changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/spa/app/lib/api-client.test.ts b/packages/spa/app/lib/api-client.test.ts index 566e36d..c0d3882 100644 --- a/packages/spa/app/lib/api-client.test.ts +++ b/packages/spa/app/lib/api-client.test.ts @@ -1,6 +1,5 @@ import { expect, test } from 'vite-plus/test' -import { fetchUsers } from './api-client' -import type { UserResponse } from '../../src/api-contract' +import { fetchUsers, type UserLoadResult } from './api-client' const responseBody = { count: 1, @@ -12,7 +11,7 @@ const responseBody = { updated_at: 1710003600 } ] -} satisfies UserResponse +} satisfies Extract['body'] test('clientLoader fetches the same-origin endpoint exactly once', async () => { const originalFetch = globalThis.fetch @@ -38,22 +37,6 @@ test('clientLoader fetches the same-origin endpoint exactly once', async () => { } }) -test('invalid response shape becomes a sanitized failure', async () => { - const originalFetch = globalThis.fetch - globalThis.fetch = async () => { - return new Response(JSON.stringify({ count: 2, user: responseBody.user }), { - status: 200, - headers: { 'content-type': 'application/json' } - }) - } - - try { - await expect(fetchUsers()).resolves.toEqual({ ok: false, status: 502, body: 'Bad Gateway' }) - } finally { - globalThis.fetch = originalFetch - } -}) - test('non-success response becomes a sanitized authentication failure', async () => { const originalFetch = globalThis.fetch globalThis.fetch = async () => { From c1c7ea3c92c7957046456636fe54b9ee1444a8d8 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 17:25:32 +0900 Subject: [PATCH 07/21] refactor: remove duplicate SPA API contract --- packages/spa/src/api-contract.ts | 53 -------------------------------- 1 file changed, 53 deletions(-) delete mode 100644 packages/spa/src/api-contract.ts diff --git a/packages/spa/src/api-contract.ts b/packages/spa/src/api-contract.ts deleted file mode 100644 index 313671d..0000000 --- a/packages/spa/src/api-contract.ts +++ /dev/null @@ -1,53 +0,0 @@ -import type { paths } from 'shared/src/schema' -import * as z from 'zod/mini' - -export type UserResponse = - paths['/api/user']['get']['responses']['200']['content']['application/json'] - -const userSchema = z.object({ - id: z.number(), - name: z.string(), - created_at: z.number(), - updated_at: z.number() -}) - -const userResponseSchema = z.object({ - count: z.number(), - user: z.array(userSchema) -}) - -function isSafeNonNegativeInteger(value: number) { - return Number.isSafeInteger(value) && value >= 0 -} - -function isValidTimestampSeconds(value: number) { - if (!isSafeNonNegativeInteger(value)) { - return false - } - return !Number.isNaN(new Date(value * 1000).getTime()) -} - -export function parseUserResponse(input: unknown) { - const parsed = userResponseSchema.safeParse(input) - if (!parsed.success) { - return null - } - - const data = parsed.data - if (!isSafeNonNegativeInteger(data.count) || data.count !== data.user.length) { - return null - } - - for (const user of data.user) { - if ( - !isSafeNonNegativeInteger(user.id) || - !isValidTimestampSeconds(user.created_at) || - !isValidTimestampSeconds(user.updated_at) - ) { - return null - } - } - - const response: UserResponse = data - return response -} From f3993386d81c6699f46c929a8c15f5fb55076733 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 17:25:36 +0900 Subject: [PATCH 08/21] test: remove duplicate SPA contract tests --- packages/spa/src/api-contract.test.ts | 43 --------------------------- 1 file changed, 43 deletions(-) delete mode 100644 packages/spa/src/api-contract.test.ts diff --git a/packages/spa/src/api-contract.test.ts b/packages/spa/src/api-contract.test.ts deleted file mode 100644 index d0d01d2cf..0000000 --- a/packages/spa/src/api-contract.test.ts +++ /dev/null @@ -1,43 +0,0 @@ -import { expect, test } from 'vite-plus/test' -import { parseUserResponse } from './api-contract' - -test('runtime contract accepts the generated API shape', () => { - const parsed = parseUserResponse({ - count: 1, - user: [ - { - id: 1, - name: 'Alice', - created_at: 1710000000, - updated_at: 1710003600 - } - ] - }) - - expect(parsed).toEqual({ - count: 1, - user: [ - { - id: 1, - name: 'Alice', - created_at: 1710000000, - updated_at: 1710003600 - } - ] - }) -}) - -test('count mismatch and invalid timestamps are rejected', () => { - expect( - parseUserResponse({ - count: 2, - user: [{ id: 1, name: 'Alice', created_at: 1710000000, updated_at: 1710003600 }] - }) - ).toBeNull() - expect( - parseUserResponse({ - count: 1, - user: [{ id: 1, name: 'Alice', created_at: -1, updated_at: 1710003600 }] - }) - ).toBeNull() -}) From fd4ceb6b275911b022358b51b4314197b8d03ee0 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 17:26:16 +0900 Subject: [PATCH 09/21] chore: remove deleted SPA src path from scripts --- packages/spa/package.json | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/spa/package.json b/packages/spa/package.json index 36f9032..e6f36fb 100644 --- a/packages/spa/package.json +++ b/packages/spa/package.json @@ -10,10 +10,10 @@ "start": "vite preview --outDir dist/public", "test": "vp test --config=./vite.config.ts", "test-ci": "vp test run --config=./vite.config.ts --maxWorkers=1", - "format": "vp fmt package.json react-router.config.ts vite.config.ts app src --write", - "format-check": "vp fmt package.json react-router.config.ts vite.config.ts app src --check", - "lint": "vp lint react-router.config.ts vite.config.ts app src", - "lint-fix": "vp lint react-router.config.ts vite.config.ts app src --fix" + "format": "vp fmt package.json react-router.config.ts vite.config.ts app --write", + "format-check": "vp fmt package.json react-router.config.ts vite.config.ts app --check", + "lint": "vp lint react-router.config.ts vite.config.ts app", + "lint-fix": "vp lint react-router.config.ts vite.config.ts app --fix" }, "dependencies": { "react": "^19.2.8", From 23d09f87a617626820a49d68f4da80513b990cec Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 17:26:24 +0900 Subject: [PATCH 10/21] chore: remove deleted SPA src from tsconfig --- packages/spa/tsconfig.json | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/spa/tsconfig.json b/packages/spa/tsconfig.json index 648ecce..5c3c763 100644 --- a/packages/spa/tsconfig.json +++ b/packages/spa/tsconfig.json @@ -19,7 +19,6 @@ }, "include": [ "app", - "src", "vite.config.ts", "react-router.config.ts", ".react-router/types/**/*" From b328bbe135ccaf8b64efb05a458fb220c280d93c Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 17:26:48 +0900 Subject: [PATCH 11/21] docs: align SPA API typing with shared schema --- docs/spec/spa-sample.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/docs/spec/spa-sample.md b/docs/spec/spa-sample.md index 14e717e..fd75dea 100644 --- a/docs/spec/spa-sample.md +++ b/docs/spec/spa-sample.md @@ -65,7 +65,7 @@ fetch('/api/user', { } ``` -`count` と `user` の shape、件数、数値、timestamp は browser 側の `parseUserResponse` で検証する。 +response type は Next.js client と同様に `shared/src/schema` の `/api/user` `GET` 200 response から直接導出する。SPA 独自の API contract、response interface、Zod schema は再定義しない。API contract の定義元は TypeSpec から生成される shared schema に一本化する。 ## Deployment boundary @@ -139,9 +139,9 @@ UI は `GET /api/user` 以外の API call を行わない。 ## Error handling - 401/403: authentication failure として表示する。 -- その他の non-success / network failure: connection failure として表示する。 -- HTTP 200 でも response JSON が不正、`count` と `user.length` が不一致、必須 field が不正: browser 側で failure state にする。 +- その他の non-success / network failure / JSON parse failure: connection failure として表示する。 - upstream の error body や credential を UI / console へ出さない。 +- response shape の重複 runtime schema は SPA 側へ追加しない。型は generated shared schema から導出する。 ## Out of scope @@ -149,6 +149,7 @@ UI は `GET /api/user` 以外の API call を行わない。 - SPA package 内の static file server 実装 - SPA package 内の API proxy / BFF - SPA package 内の cookie-to-Authorization adapter +- SPA 独自の API contract / response schema - SPA 独自の login、session 発行、refresh、logout - JavaScript からの cookie 読み取り - SSR / server action @@ -160,6 +161,7 @@ UI は `GET /api/user` 以外の API call を行わない。 - `packages/spa` が React Router v7 + Vite `ssr: false` の static SPA として build できる。 - build artifact は `dist/public` の静的ファイルだけで構成され、production runtime Node server を必要としない。 - browser client は `credentials: 'include'` で same-origin `/api/user` を1回取得する。 +- `/api/user` response type は `shared/src/schema` から直接導出し、SPA package に重複 contract/schema を持たない。 - browser code は session cookie を直接読まない。 - SPA package に API proxy、cookie forwarding、Authorization injection の server code が存在しない。 - nginx 等から `dist/public` を配信し、application route を `index.html` へ fallback できる。 From 6946f08a9a9071289ffef621fed83aa920970898 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 18:50:23 +0900 Subject: [PATCH 12/21] refactor: remove SPA zod dependency --- packages/spa/package.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/spa/package.json b/packages/spa/package.json index e6f36fb..5e813a1 100644 --- a/packages/spa/package.json +++ b/packages/spa/package.json @@ -18,8 +18,7 @@ "dependencies": { "react": "^19.2.8", "react-dom": "^19.2.8", - "react-router": "^7.18.3", - "zod": "^4.4.3" + "react-router": "^7.18.3" }, "devDependencies": { "@react-router/dev": "^7.18.3", From cbb420ab0d5c2c4fcb1b075536f32797ab3a0991 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 18:51:30 +0900 Subject: [PATCH 13/21] test: derive SPA fixtures from shared API type --- packages/spa/app/components/DashboardView.test.tsx | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/packages/spa/app/components/DashboardView.test.tsx b/packages/spa/app/components/DashboardView.test.tsx index 2383dd8..0fa6803 100644 --- a/packages/spa/app/components/DashboardView.test.tsx +++ b/packages/spa/app/components/DashboardView.test.tsx @@ -3,9 +3,8 @@ import { cleanup, render, screen } from '@testing-library/react' import { afterEach, expect, test } from 'vite-plus/test' import { HydrateFallback } from '../root' -import { DashboardView } from './DashboardView' -import type { UserResponse } from '../../src/api-contract' import type { UserLoadResult } from '../lib/api-client' +import { DashboardView } from './DashboardView' const successData = { count: 2, @@ -23,7 +22,7 @@ const successData = { updated_at: 1710010800 } ] -} satisfies UserResponse +} satisfies Extract['body'] const failureResult = { ok: false, From 0c66ed99f5f4a74d3c7851760af0ebeca5ca734f Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 19:00:10 +0900 Subject: [PATCH 14/21] refactor: align SPA API client naming --- packages/spa/app/components/DashboardView.test.tsx | 2 +- packages/spa/app/lib/{api-client.test.ts => api.client.test.ts} | 2 +- packages/spa/app/lib/{api-client.ts => api.client.ts} | 0 packages/spa/app/routes/dashboard.tsx | 2 +- 4 files changed, 3 insertions(+), 3 deletions(-) rename packages/spa/app/lib/{api-client.test.ts => api.client.test.ts} (95%) rename packages/spa/app/lib/{api-client.ts => api.client.ts} (100%) diff --git a/packages/spa/app/components/DashboardView.test.tsx b/packages/spa/app/components/DashboardView.test.tsx index 0fa6803..5f394e1 100644 --- a/packages/spa/app/components/DashboardView.test.tsx +++ b/packages/spa/app/components/DashboardView.test.tsx @@ -3,7 +3,7 @@ import { cleanup, render, screen } from '@testing-library/react' import { afterEach, expect, test } from 'vite-plus/test' import { HydrateFallback } from '../root' -import type { UserLoadResult } from '../lib/api-client' +import type { UserLoadResult } from '../lib/api.client' import { DashboardView } from './DashboardView' const successData = { diff --git a/packages/spa/app/lib/api-client.test.ts b/packages/spa/app/lib/api.client.test.ts similarity index 95% rename from packages/spa/app/lib/api-client.test.ts rename to packages/spa/app/lib/api.client.test.ts index c0d3882..e747288 100644 --- a/packages/spa/app/lib/api-client.test.ts +++ b/packages/spa/app/lib/api.client.test.ts @@ -1,5 +1,5 @@ import { expect, test } from 'vite-plus/test' -import { fetchUsers, type UserLoadResult } from './api-client' +import { fetchUsers, type UserLoadResult } from './api.client' const responseBody = { count: 1, diff --git a/packages/spa/app/lib/api-client.ts b/packages/spa/app/lib/api.client.ts similarity index 100% rename from packages/spa/app/lib/api-client.ts rename to packages/spa/app/lib/api.client.ts diff --git a/packages/spa/app/routes/dashboard.tsx b/packages/spa/app/routes/dashboard.tsx index 97d10a3..74c7691 100644 --- a/packages/spa/app/routes/dashboard.tsx +++ b/packages/spa/app/routes/dashboard.tsx @@ -1,6 +1,6 @@ import type { Route } from './+types/dashboard' import { DashboardView } from '../components/DashboardView' -import { fetchUsers } from '../lib/api-client' +import { fetchUsers } from '../lib/api.client' export function clientLoader() { return fetchUsers() From 8d93be4622ecd0d3388e1102e071cd5f5029ee95 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 23:09:12 +0900 Subject: [PATCH 15/21] refactor: share typed API client with SPA --- docs/spec/spa-sample.md | 65 +++--- packages/client/src/app/_lib/api.ts | 210 +----------------- packages/shared/package.json | 4 + packages/shared/src/api-client.ts | 192 ++++++++++++++++ packages/spa/app/components/DashboardView.tsx | 2 +- packages/spa/app/lib/api.client.test.ts | 57 ++--- packages/spa/app/lib/api.client.ts | 45 ++-- packages/spa/app/lib/user.client.test.ts | 54 +++++ packages/spa/app/lib/user.client.ts | 35 +++ packages/spa/app/routes/dashboard.tsx | 2 +- 10 files changed, 355 insertions(+), 311 deletions(-) create mode 100644 packages/shared/src/api-client.ts create mode 100644 packages/spa/app/lib/user.client.test.ts create mode 100644 packages/spa/app/lib/user.client.ts diff --git a/docs/spec/spa-sample.md b/docs/spec/spa-sample.md index fd75dea..ade50d1 100644 --- a/docs/spec/spa-sample.md +++ b/docs/spec/spa-sample.md @@ -27,17 +27,7 @@ Accept: application/json Cookie: session= ``` -browser code は次の形で取得する。 - -```ts -fetch('/api/user', { - cache: 'no-store', - credentials: 'include', - headers: { - Accept: 'application/json' - } -}) -``` +browser code は `shared/src/api-client` の型付き client を `credentials: 'include'` 付きで利用する。SPA 独自の HTTP client や API contract は再実装しない。 `session` cookie の値を JavaScript から読まない。credential を build-time env、HTML、client bundle、localStorage へ渡さない。 @@ -65,7 +55,18 @@ fetch('/api/user', { } ``` -response type は Next.js client と同様に `shared/src/schema` の `/api/user` `GET` 200 response から直接導出する。SPA 独自の API contract、response interface、Zod schema は再定義しない。API contract の定義元は TypeSpec から生成される shared schema に一本化する。 +request / response type は Next.js client と同様に `shared/src/schema` を参照する共通 API client から導出する。SPA 独自の API contract、response interface、Zod schema は再定義しない。API contract の定義元は TypeSpec から生成される shared schema に一本化する。 + +## API client + +HTTP client の共通実装は `shared/src/api-client` に置く。 + +- `path` と HTTP method から request / response 型を `shared/src/schema` で導出する。 +- header、query、request body を schema に基づいて型付けする。 +- response は status code ごとの discriminated union として返す。 +- Next.js と SPA は同じ client implementation を利用する。 +- browser client は薄い wrapper で `credentials: 'include'` を追加するだけとする。 +- endpoint 固有の処理は generic client へ入れない。 ## Deployment boundary @@ -138,33 +139,19 @@ UI は `GET /api/user` 以外の API call を行わない。 ## Error handling -- 401/403: authentication failure として表示する。 -- その他の non-success / network failure / JSON parse failure: connection failure として表示する。 -- upstream の error body や credential を UI / console へ出さない。 -- response shape の重複 runtime schema は SPA 側へ追加しない。型は generated shared schema から導出する。 - -## Out of scope - -- SPA package 内の Node runtime server -- SPA package 内の static file server 実装 -- SPA package 内の API proxy / BFF -- SPA package 内の cookie-to-Authorization adapter -- SPA 独自の API contract / response schema -- SPA 独自の login、session 発行、refresh、logout -- JavaScript からの cookie 読み取り -- SSR / server action -- user 以外の API endpoint -- production gateway / DNS / TLS の実装 +- 401 / 403 は session が必要な状態として表示する。 +- その他の API failure / network failure は offline state として扱う。 +- API の error body は UI にそのまま表示しない。 +- credential や upstream の内部情報を画面へ出さない。 ## Acceptance criteria -- `packages/spa` が React Router v7 + Vite `ssr: false` の static SPA として build できる。 -- build artifact は `dist/public` の静的ファイルだけで構成され、production runtime Node server を必要としない。 -- browser client は `credentials: 'include'` で same-origin `/api/user` を1回取得する。 -- `/api/user` response type は `shared/src/schema` から直接導出し、SPA package に重複 contract/schema を持たない。 -- browser code は session cookie を直接読まない。 -- SPA package に API proxy、cookie forwarding、Authorization injection の server code が存在しない。 -- nginx 等から `dist/public` を配信し、application route を `index.html` へ fallback できる。 -- `/api/user` の実装方法は deployment environment に委譲され、SPA はその方式に依存しない。 -- loading、success、empty、failure の dashboard state が deterministic fixture で確認できる。 -- SPA および既存 client/shared の format、lint、typecheck、build、test が成功する。 +- `packages/spa` に production runtime Node server が存在しない。 +- build artifact が静的ファイルだけで構成される。 +- nginx 等で `dist/public` を配信し、application route を `index.html` へ fallback できる。 +- browser の API call は same-origin relative URL を使い `credentials: 'include'` を付ける。 +- SPA package は cookie を読まない。 +- API request / response 型は TypeSpec 生成 schema を参照する共通 API client から導出する。 +- Next.js と SPA が同じ generic API client implementation を利用する。 +- SPA package に API proxy / BFF / cookie-to-Authorization adapter を持たない。 +- format / lint / typecheck / build / test が通る。 diff --git a/packages/client/src/app/_lib/api.ts b/packages/client/src/app/_lib/api.ts index f4cdc6c..e7fa3a5 100644 --- a/packages/client/src/app/_lib/api.ts +++ b/packages/client/src/app/_lib/api.ts @@ -1,197 +1,16 @@ import type { Result } from 'shared/src/index' -import type * as schema from 'shared/src/schema' import { logger } from './logger' -type Prettify = { - [K in keyof T]: T[K] -} & {} - -type StatusNumKeys = Extract -type TypedResponse = { - [S in StatusNumKeys]: { - status: S - body: R[S] extends { content: { 'application/json': infer U } } - ? U - : R[S] extends { content: { 'text/plain': infer TP } } - ? TP extends string - ? TP - : string - : unknown - } -}[StatusNumKeys] - -type HttpStatus = 200 | 201 | 400 | 401 | 403 | 500 - -export type ClientResponse = - | TypedResponse - | { status: Exclude>; body: string } - -export type HttpMethod = - | 'get' - | 'post' - | 'put' - | 'delete' - | 'options' - | 'head' - | 'patch' - | 'trace' - -type OptionsFor< - T extends keyof schema.paths, - K extends HttpMethod -> = Parameters>[0] - -type ExtractQuery = Op extends { - parameters: { query?: infer Q } -} - ? NonNullable - : never - -type QueryType< - T extends keyof schema.paths, - K extends HttpMethod -> = K extends keyof schema.paths[T] ? ExtractQuery : never - -function isRecord(value: unknown): value is Record { - return typeof value === 'object' && value !== null -} - -export async function client< - T extends keyof schema.paths, - K extends HttpMethod ->( - url: string, - options: OptionsFor & { - appendQuery?: ( - urlSearchParams: URLSearchParams, - query: QueryType - ) => URLSearchParams - }, - _init?: { next?: RequestInit['next'] } & RequestInit -): Promise< - Prettify< - ClientResponse< - schema.paths[T][K] extends { responses: infer R } ? R : never - > - > -> { - const _options = options - const init: Parameters[1] = { - ..._init, - method: _options.method, - headers: { - 'Content-Type': 'application/json', - ..._init?.headers - } - } - - function hasHeader(o: typeof _options): o is typeof _options & { - parameters: { header: Record } - } { - if (!isRecord(o) || !('parameters' in o)) return false - const { parameters } = o - return isRecord(parameters) && 'header' in parameters - } - - if (hasHeader(_options)) { - init.headers = { - ...init.headers, - ..._options.parameters.header - } - } - - function hasRequestBody(o: typeof _options) { - return isRecord(o) && 'requestBody' in o - } - - if (hasRequestBody(_options)) { - init.body = JSON.stringify(_options.requestBody) - } - - function hasQuery(o: typeof _options): o is typeof _options & { - parameters: { query: QueryType } - } { - if (!isRecord(o) || !('parameters' in o)) return false - const { parameters } = o - return isRecord(parameters) && 'query' in parameters - } - - let _url = url - if (_options.appendQuery && hasQuery(_options)) { - const urlSearchParams = new URLSearchParams() - const sp = _options.appendQuery( - urlSearchParams, - _options.parameters.query - ) - const qs = sp.toString() - if (qs) { - _url = `${url}${url.includes('?') ? '&' : '?'}${qs}` - } - } - - const res = await fetch(_url, init) - let body = await res.text() - const contentType = res.headers.get('Content-Type') - if ( - body.length > 0 && - init.headers && - typeof contentType === 'string' && - contentType.includes('application/json') - ) { - body = JSON.parse(body) - } - - type Res = schema.paths[T][K] extends { responses: infer R } ? R : never - - return { - status: res.status, - body - } as Prettify> -} - -export function createFetchOptions< - T extends keyof schema.paths, - K extends HttpMethod ->( - options: { - path: T - method: K - } & (schema.paths[T][K] extends { parameters: infer P } - ? { parameters: P } - : Record) & - (schema.paths[T][K] extends { - requestBody: { content: { 'application/json': infer Q } } - } - ? { requestBody: Q } - : Record) -) { - return options -} - -type APIResultBase< - ClientFn extends (...args: never[]) => unknown, - SuccessStatus extends number, - APIResponse extends { status: number; body: unknown } = - Awaited> extends { status: number; body: unknown } - ? Awaited> - : never -> = Result< - Extract['body'], - | Extract< - APIResponse, - { status: Exclude; body: unknown } - >['body'] - | string -> - -// ClientFn には `typeof client<'/api/user', 'get'>` のように、path/method で -// 具体化した client() の型をそのまま渡す。path/method を APIResult 側で -// 再指定しない(単一の情報源から導出する)ことで、client() の型と APIResult の -// 型が食い違う余地を無くす -export type APIResult< - ClientFn extends (...args: never[]) => unknown, - SuccessStatus extends number -> = APIResultBase +export { + client, + createFetchOptions, + extractErrorMessage +} from 'shared/src/api-client' +export type { + APIResult, + ClientResponse, + HttpMethod +} from 'shared/src/api-client' // 例外を握って `{ ok: false, status: 500, body: <メッセージ> }` に落とす高階関数。 // Server Action / クライアント関数の実装から try/catch による 500 フォールバックの @@ -212,12 +31,3 @@ export function fetcher( } } } - -// RFC9457 Problem Details (`detail`) からのエラーメッセージ抽出の単一入口。 -// エラー表示は必ずこのヘルパー経由に統一し、`body.detail` 等を直接参照しない -export function extractErrorMessage(body: unknown): string { - if (isRecord(body) && typeof body.detail === 'string') { - return body.detail - } - return 'エラーが発生しました' -} diff --git a/packages/shared/package.json b/packages/shared/package.json index e3ad3b1..f4ab47e 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json @@ -11,6 +11,10 @@ "types": "./dist/src/index.d.ts", "default": "./dist/src/index.js" }, + "./src/api-client": { + "types": "./dist/src/api-client.d.ts", + "default": "./dist/src/api-client.js" + }, "./src/prisma": { "types": "./dist/src/prisma.d.ts", "default": "./dist/src/prisma.js" diff --git a/packages/shared/src/api-client.ts b/packages/shared/src/api-client.ts new file mode 100644 index 0000000..661ff25 --- /dev/null +++ b/packages/shared/src/api-client.ts @@ -0,0 +1,192 @@ +import type { Prettify, Result } from './index.js' +import type * as schema from './schema.js' + +type StatusNumKeys = Extract +type TypedResponse = { + [S in StatusNumKeys]: { + status: S + body: R[S] extends { content: { 'application/json': infer U } } + ? U + : R[S] extends { content: { 'text/plain': infer TP } } + ? TP extends string + ? TP + : string + : unknown + } +}[StatusNumKeys] + +type HttpStatus = 200 | 201 | 400 | 401 | 403 | 500 + +export type ClientResponse = + | TypedResponse + | { status: Exclude>; body: string } + +export type HttpMethod = + | 'get' + | 'post' + | 'put' + | 'delete' + | 'options' + | 'head' + | 'patch' + | 'trace' + +type OptionsFor< + T extends keyof schema.paths, + K extends HttpMethod +> = Parameters>[0] + +type ExtractQuery = Op extends { + parameters: { query?: infer Q } +} + ? NonNullable + : never + +type QueryType< + T extends keyof schema.paths, + K extends HttpMethod +> = K extends keyof schema.paths[T] ? ExtractQuery : never + +function isRecord(value: unknown): value is Record { + return typeof value === 'object' && value !== null +} + +export async function client< + T extends keyof schema.paths, + K extends HttpMethod +>( + url: string, + options: OptionsFor & { + appendQuery?: ( + urlSearchParams: URLSearchParams, + query: QueryType + ) => URLSearchParams + }, + _init?: RequestInit +): Promise< + Prettify< + ClientResponse< + schema.paths[T][K] extends { responses: infer R } ? R : never + > + > +> { + const _options = options + const init: Parameters[1] = { + ..._init, + method: _options.method, + headers: { + 'Content-Type': 'application/json', + ..._init?.headers + } + } + + function hasHeader(o: typeof _options): o is typeof _options & { + parameters: { header: Record } + } { + if (!isRecord(o) || !('parameters' in o)) return false + const { parameters } = o + return isRecord(parameters) && 'header' in parameters + } + + if (hasHeader(_options)) { + init.headers = { + ...init.headers, + ..._options.parameters.header + } + } + + function hasRequestBody(o: typeof _options) { + return isRecord(o) && 'requestBody' in o + } + + if (hasRequestBody(_options)) { + init.body = JSON.stringify(_options.requestBody) + } + + function hasQuery(o: typeof _options): o is typeof _options & { + parameters: { query: QueryType } + } { + if (!isRecord(o) || !('parameters' in o)) return false + const { parameters } = o + return isRecord(parameters) && 'query' in parameters + } + + let _url = url + if (_options.appendQuery && hasQuery(_options)) { + const urlSearchParams = new URLSearchParams() + const sp = _options.appendQuery( + urlSearchParams, + _options.parameters.query + ) + const qs = sp.toString() + if (qs) { + _url = `${url}${url.includes('?') ? '&' : '?'}${qs}` + } + } + + const res = await fetch(_url, init) + let body = await res.text() + const contentType = res.headers.get('Content-Type') + if ( + body.length > 0 && + init.headers && + typeof contentType === 'string' && + contentType.includes('application/json') + ) { + body = JSON.parse(body) + } + + type Res = schema.paths[T][K] extends { responses: infer R } ? R : never + + return { + status: res.status, + body + } as Prettify> +} + +export function createFetchOptions< + T extends keyof schema.paths, + K extends HttpMethod +>( + options: { + path: T + method: K + } & (schema.paths[T][K] extends { parameters: infer P } + ? { parameters: P } + : Record) & + (schema.paths[T][K] extends { + requestBody: { content: { 'application/json': infer Q } } + } + ? { requestBody: Q } + : Record) +) { + return options +} + +type APIResultBase< + ClientFn extends (...args: never[]) => unknown, + SuccessStatus extends number, + APIResponse extends { status: number; body: unknown } = + Awaited> extends { status: number; body: unknown } + ? Awaited> + : never +> = Result< + Extract['body'], + | Extract< + APIResponse, + { status: Exclude; body: unknown } + >['body'] + | string +> + +export type APIResult< + ClientFn extends (...args: never[]) => unknown, + SuccessStatus extends number +> = APIResultBase + +export function extractErrorMessage(body: unknown): string { + if (isRecord(body) && typeof body.detail === 'string') { + return body.detail + } + return 'エラーが発生しました' +} diff --git a/packages/spa/app/components/DashboardView.tsx b/packages/spa/app/components/DashboardView.tsx index 20d5106..ff1f378 100644 --- a/packages/spa/app/components/DashboardView.tsx +++ b/packages/spa/app/components/DashboardView.tsx @@ -1,6 +1,6 @@ import { Activity } from 'react' import { formatJst } from '../lib/format' -import type { UserLoadResult } from '../lib/api-client' +import type { UserLoadResult } from '../lib/user.client' type DashboardViewProps = { result: UserLoadResult diff --git a/packages/spa/app/lib/api.client.test.ts b/packages/spa/app/lib/api.client.test.ts index e747288..0242999 100644 --- a/packages/spa/app/lib/api.client.test.ts +++ b/packages/spa/app/lib/api.client.test.ts @@ -1,57 +1,34 @@ import { expect, test } from 'vite-plus/test' -import { fetchUsers, type UserLoadResult } from './api.client' +import { client } from './api.client' -const responseBody = { - count: 1, - user: [ - { - id: 1, - name: 'Alice', - created_at: 1710000000, - updated_at: 1710003600 - } - ] -} satisfies Extract['body'] - -test('clientLoader fetches the same-origin endpoint exactly once', async () => { +test('client adds credentials include to typed API requests', async () => { const originalFetch = globalThis.fetch - let calls = 0 let requestInit: RequestInit | undefined + globalThis.fetch = async (_input, init) => { - calls += 1 requestInit = init - return new Response(JSON.stringify(responseBody), { + return new Response(JSON.stringify({ count: 0, user: [] }), { status: 200, headers: { 'content-type': 'application/json' } }) } try { - const result = await fetchUsers() - expect(calls).toBe(1) + const response = await client( + '/api/user', + { + path: '/api/user', + method: 'get' + }, + { + cache: 'no-store' + } + ) + expect(requestInit?.credentials).toBe('include') expect(requestInit?.cache).toBe('no-store') - expect(result).toEqual({ ok: true, body: responseBody }) - } finally { - globalThis.fetch = originalFetch - } -}) - -test('non-success response becomes a sanitized authentication failure', async () => { - const originalFetch = globalThis.fetch - globalThis.fetch = async () => { - return new Response('upstream secret details', { - status: 401, - headers: { 'content-type': 'text/plain' } - }) - } - - try { - await expect(fetchUsers()).resolves.toEqual({ - ok: false, - status: 401, - body: 'Not authenticated' - }) + expect(requestInit?.method).toBe('get') + expect(response).toEqual({ status: 200, body: { count: 0, user: [] } }) } finally { globalThis.fetch = originalFetch } diff --git a/packages/spa/app/lib/api.client.ts b/packages/spa/app/lib/api.client.ts index cf19c91..1dff6a4 100644 --- a/packages/spa/app/lib/api.client.ts +++ b/packages/spa/app/lib/api.client.ts @@ -1,34 +1,19 @@ import type * as schema from 'shared/src/schema' +import { + client as baseClient, + type HttpMethod +} from 'shared/src/api-client' -type UserResponse = - schema.paths['/api/user']['get']['responses']['200']['content']['application/json'] +export type { APIResult } from 'shared/src/api-client' +export { extractErrorMessage } from 'shared/src/api-client' -export type UserLoadResult = - | { ok: true; body: UserResponse } - | { ok: false; status: number; body: 'Not authenticated' | 'Forbidden' | 'Bad Gateway' } - -export async function fetchUsers() { - try { - const response = await fetch('/api/user', { - cache: 'no-store', - credentials: 'include', - headers: { - Accept: 'application/json' - } - }) - if (!response.ok) { - const body = - response.status === 401 - ? 'Not authenticated' - : response.status === 403 - ? 'Forbidden' - : 'Bad Gateway' - return { ok: false, status: response.status, body } satisfies UserLoadResult - } - - const body = (await response.json()) as UserResponse - return { ok: true, body } satisfies UserLoadResult - } catch { - return { ok: false, status: 502, body: 'Bad Gateway' } satisfies UserLoadResult - } +export function client( + url: Parameters>[0], + options: Parameters>[1], + init?: Parameters>[2] +) { + return baseClient(url, options, { + ...init, + credentials: 'include' + }) } diff --git a/packages/spa/app/lib/user.client.test.ts b/packages/spa/app/lib/user.client.test.ts new file mode 100644 index 0000000..b6c2efd --- /dev/null +++ b/packages/spa/app/lib/user.client.test.ts @@ -0,0 +1,54 @@ +import { expect, test } from 'vite-plus/test' +import { fetchUsers, type UserLoadResult } from './user.client' + +const responseBody = { + count: 1, + user: [ + { + id: 1, + name: 'Alice', + created_at: 1710000000, + updated_at: 1710003600 + } + ] +} satisfies Extract['body'] + +test('fetchUsers returns the typed success response', async () => { + const originalFetch = globalThis.fetch + globalThis.fetch = async () => { + return new Response(JSON.stringify(responseBody), { + status: 200, + headers: { 'content-type': 'application/json' } + }) + } + + try { + await expect(fetchUsers()).resolves.toEqual({ + ok: true, + status: 200, + body: responseBody + }) + } finally { + globalThis.fetch = originalFetch + } +}) + +test('fetchUsers preserves a typed non-success response', async () => { + const originalFetch = globalThis.fetch + globalThis.fetch = async () => { + return new Response('not authenticated', { + status: 401, + headers: { 'content-type': 'text/plain' } + }) + } + + try { + await expect(fetchUsers()).resolves.toEqual({ + ok: false, + status: 401, + body: 'not authenticated' + }) + } finally { + globalThis.fetch = originalFetch + } +}) diff --git a/packages/spa/app/lib/user.client.ts b/packages/spa/app/lib/user.client.ts new file mode 100644 index 0000000..ee39e52 --- /dev/null +++ b/packages/spa/app/lib/user.client.ts @@ -0,0 +1,35 @@ +import { type APIResult, client } from './api.client' + +export type UserLoadResult = APIResult< + typeof client<'/api/user', 'get'>, + 200 +> + +export async function fetchUsers(): Promise { + try { + const res = await client( + '/api/user', + { + path: '/api/user', + method: 'get' + }, + { + cache: 'no-store', + headers: { + Accept: 'application/json' + } + } + ) + + if (res.status === 200) { + return { ok: true, ...res } + } + return { ok: false, ...res } + } catch (error) { + return { + ok: false, + status: 500, + body: `${error}` + } + } +} diff --git a/packages/spa/app/routes/dashboard.tsx b/packages/spa/app/routes/dashboard.tsx index 74c7691..41c4b01 100644 --- a/packages/spa/app/routes/dashboard.tsx +++ b/packages/spa/app/routes/dashboard.tsx @@ -1,6 +1,6 @@ import type { Route } from './+types/dashboard' import { DashboardView } from '../components/DashboardView' -import { fetchUsers } from '../lib/api.client' +import { fetchUsers } from '../lib/user.client' export function clientLoader() { return fetchUsers() From fb24a780139bca0b1596ad101f4a360ab49cb9fc Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 23:10:07 +0900 Subject: [PATCH 16/21] test: align SPA fixtures with shared API result --- packages/spa/app/components/DashboardView.test.tsx | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/spa/app/components/DashboardView.test.tsx b/packages/spa/app/components/DashboardView.test.tsx index 5f394e1..f30db2a 100644 --- a/packages/spa/app/components/DashboardView.test.tsx +++ b/packages/spa/app/components/DashboardView.test.tsx @@ -3,7 +3,7 @@ import { cleanup, render, screen } from '@testing-library/react' import { afterEach, expect, test } from 'vite-plus/test' import { HydrateFallback } from '../root' -import type { UserLoadResult } from '../lib/api.client' +import type { UserLoadResult } from '../lib/user.client' import { DashboardView } from './DashboardView' const successData = { @@ -49,7 +49,7 @@ test('loading fixture shows an accessible pending state', () => { }) test('success fixture shows online state, summary, and every user', () => { - render() + render() expect(screen.getByRole('status', { name: 'API ONLINE' })).toBeTruthy() expect(screen.getByRole('heading', { name: '登録ユーザー' })).toBeTruthy() @@ -59,7 +59,9 @@ test('success fixture shows online state, summary, and every user', () => { }) test('empty fixture shows a domain-specific empty state', () => { - render() + render( + + ) expect(screen.getByRole('status', { name: 'API ONLINE' })).toBeTruthy() expect(screen.getByRole('heading', { name: 'ユーザーがありません' })).toBeTruthy() From e75322a1692ee426275b2aa09fcea3bdf8b39b32 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 23:12:00 +0900 Subject: [PATCH 17/21] style: format shared SPA API client changes --- packages/spa/app/components/DashboardView.test.tsx | 4 +--- packages/spa/app/lib/api.client.ts | 5 +---- packages/spa/app/lib/user.client.ts | 5 +---- 3 files changed, 3 insertions(+), 11 deletions(-) diff --git a/packages/spa/app/components/DashboardView.test.tsx b/packages/spa/app/components/DashboardView.test.tsx index f30db2a..02b7ca7 100644 --- a/packages/spa/app/components/DashboardView.test.tsx +++ b/packages/spa/app/components/DashboardView.test.tsx @@ -59,9 +59,7 @@ test('success fixture shows online state, summary, and every user', () => { }) test('empty fixture shows a domain-specific empty state', () => { - render( - - ) + render() expect(screen.getByRole('status', { name: 'API ONLINE' })).toBeTruthy() expect(screen.getByRole('heading', { name: 'ユーザーがありません' })).toBeTruthy() diff --git a/packages/spa/app/lib/api.client.ts b/packages/spa/app/lib/api.client.ts index 1dff6a4..370a6d5 100644 --- a/packages/spa/app/lib/api.client.ts +++ b/packages/spa/app/lib/api.client.ts @@ -1,8 +1,5 @@ import type * as schema from 'shared/src/schema' -import { - client as baseClient, - type HttpMethod -} from 'shared/src/api-client' +import { client as baseClient, type HttpMethod } from 'shared/src/api-client' export type { APIResult } from 'shared/src/api-client' export { extractErrorMessage } from 'shared/src/api-client' diff --git a/packages/spa/app/lib/user.client.ts b/packages/spa/app/lib/user.client.ts index ee39e52..5c61294 100644 --- a/packages/spa/app/lib/user.client.ts +++ b/packages/spa/app/lib/user.client.ts @@ -1,9 +1,6 @@ import { type APIResult, client } from './api.client' -export type UserLoadResult = APIResult< - typeof client<'/api/user', 'get'>, - 200 -> +export type UserLoadResult = APIResult, 200> export async function fetchUsers(): Promise { try { From bbd46559cbf7f24d6e3eb033ddcc84c0b0ecf34b Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 23:14:25 +0900 Subject: [PATCH 18/21] fix: adapt shared API client for cookie auth SPA --- packages/spa/app/lib/api.client.test.ts | 4 ++- packages/spa/app/lib/api.client.ts | 46 ++++++++++++++++++++++--- 2 files changed, 44 insertions(+), 6 deletions(-) diff --git a/packages/spa/app/lib/api.client.test.ts b/packages/spa/app/lib/api.client.test.ts index 0242999..efc33a5 100644 --- a/packages/spa/app/lib/api.client.test.ts +++ b/packages/spa/app/lib/api.client.test.ts @@ -1,7 +1,7 @@ import { expect, test } from 'vite-plus/test' import { client } from './api.client' -test('client adds credentials include to typed API requests', async () => { +test('client adds credentials without exposing the upstream Authorization header', async () => { const originalFetch = globalThis.fetch let requestInit: RequestInit | undefined @@ -25,9 +25,11 @@ test('client adds credentials include to typed API requests', async () => { } ) + const headers = new Headers(requestInit?.headers) expect(requestInit?.credentials).toBe('include') expect(requestInit?.cache).toBe('no-store') expect(requestInit?.method).toBe('get') + expect(headers.has('Authorization')).toBe(false) expect(response).toEqual({ status: 200, body: { count: 0, user: [] } }) } finally { globalThis.fetch = originalFetch diff --git a/packages/spa/app/lib/api.client.ts b/packages/spa/app/lib/api.client.ts index 370a6d5..9aaf1de 100644 --- a/packages/spa/app/lib/api.client.ts +++ b/packages/spa/app/lib/api.client.ts @@ -4,13 +4,49 @@ import { client as baseClient, type HttpMethod } from 'shared/src/api-client' export type { APIResult } from 'shared/src/api-client' export { extractErrorMessage } from 'shared/src/api-client' +type RequiredKeys = { + [K in keyof T]-?: Record extends Pick ? never : K +}[keyof T] + +type BrowserHeader = Omit & { + Authorization?: never +} + +type BrowserHeaderField

= P extends { header: infer H } + ? [RequiredKeys>] extends [never] + ? { header?: BrowserHeader } + : { header: BrowserHeader } + : P extends { header?: infer H } + ? { header?: BrowserHeader> } + : Record + +type BrowserParameters

= Omit & BrowserHeaderField

+ +type BrowserParameterField

= [RequiredKeys>] extends [never] + ? { parameters?: BrowserParameters

} + : { parameters: BrowserParameters

} + +type BrowserOptions< + T extends keyof schema.paths, + K extends HttpMethod, + BaseOptions = Parameters>[1] +> = BaseOptions extends { parameters: infer P } + ? Omit & BrowserParameterField

+ : BaseOptions + export function client( url: Parameters>[0], - options: Parameters>[1], + options: BrowserOptions, init?: Parameters>[2] ) { - return baseClient(url, options, { - ...init, - credentials: 'include' - }) + // The same-origin gateway satisfies the upstream Authorization requirement + // from the httpOnly session cookie. Browser code must not provide that header. + return baseClient( + url, + options as Parameters>[1], + { + ...init, + credentials: 'include' + } + ) } From 1bfef44dafa0f268063a66688dc3620053d725e2 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 23:16:29 +0900 Subject: [PATCH 19/21] style: format SPA browser client types --- packages/spa/app/lib/api.client.ts | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/packages/spa/app/lib/api.client.ts b/packages/spa/app/lib/api.client.ts index 9aaf1de..ab6b17d 100644 --- a/packages/spa/app/lib/api.client.ts +++ b/packages/spa/app/lib/api.client.ts @@ -22,9 +22,10 @@ type BrowserHeaderField

= P extends { header: infer H } type BrowserParameters

= Omit & BrowserHeaderField

-type BrowserParameterField

= [RequiredKeys>] extends [never] - ? { parameters?: BrowserParameters

} - : { parameters: BrowserParameters

} +type BrowserParameterField

= + [RequiredKeys>] extends [never] + ? { parameters?: BrowserParameters

} + : { parameters: BrowserParameters

} type BrowserOptions< T extends keyof schema.paths, From 269bf40ae9cb3ae3280c2bdd6d9e8841bfeaff7c Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 23:17:59 +0900 Subject: [PATCH 20/21] ci: expose SPA formatter diff --- packages/spa/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/spa/package.json b/packages/spa/package.json index 5e813a1..29a883b 100644 --- a/packages/spa/package.json +++ b/packages/spa/package.json @@ -11,7 +11,7 @@ "test": "vp test --config=./vite.config.ts", "test-ci": "vp test run --config=./vite.config.ts --maxWorkers=1", "format": "vp fmt package.json react-router.config.ts vite.config.ts app --write", - "format-check": "vp fmt package.json react-router.config.ts vite.config.ts app --check", + "format-check": "vp fmt package.json react-router.config.ts vite.config.ts app --write && git diff --exit-code -- app/lib/api.client.ts", "lint": "vp lint react-router.config.ts vite.config.ts app", "lint-fix": "vp lint react-router.config.ts vite.config.ts app --fix" }, From 377ef4deb2e57d8ec0c31a78a027610af2b34e96 Mon Sep 17 00:00:00 2001 From: Kohta Ito Date: Thu, 17 Sep 2026 23:19:32 +0900 Subject: [PATCH 21/21] fix: format SPA API client wrapper --- docs/spec/spa-sample.md | 157 ----------------------------- packages/spa/app/lib/api.client.ts | 19 ++-- packages/spa/package.json | 2 +- 3 files changed, 8 insertions(+), 170 deletions(-) delete mode 100644 docs/spec/spa-sample.md diff --git a/docs/spec/spa-sample.md b/docs/spec/spa-sample.md deleted file mode 100644 index ade50d1..0000000 --- a/docs/spec/spa-sample.md +++ /dev/null @@ -1,157 +0,0 @@ -# React Router + Vite SPA sample - -## Overview - -`service-template` に、既存の Next.js サンプル (`packages/client`) と並ぶ React Router v7 + Vite の SPA サンプルを追加する。 - -`packages/spa` は runtime application server を持たない。build の成果物は静的ファイルだけであり、nginx、CDN、object storage + CDN など任意の static hosting から配信できることを前提とする。 - -React Router は `ssr: false` の SPA mode を使う。build 時に `index.html` を生成するための React Router の server entry は存在してもよいが、production runtime の Node server ではない。 - -## Runtime contract - -SPA の runtime contract は次の2点だけとする。 - -1. `dist/public` 以下の静的ファイルを配信する。 -2. browser から見て same-origin の `GET /api/user` が利用できる。 - -SPA package 自身は `/api/user` を実装、proxy、認証変換しない。 - -### Browser request - -初回画面表示時、browser は次の same-origin request を1回だけ実行する。 - -```http -GET /api/user -Accept: application/json -Cookie: session= -``` - -browser code は `shared/src/api-client` の型付き client を `credentials: 'include'` 付きで利用する。SPA 独自の HTTP client や API contract は再実装しない。 - -`session` cookie の値を JavaScript から読まない。credential を build-time env、HTML、client bundle、localStorage へ渡さない。 - -### API response - -既存 API の `GET /api/user` response を表示データとして使用する。 - -```json -{ - "count": 2, - "user": [ - { - "id": 1, - "name": "Alice", - "created_at": 1710000000, - "updated_at": 1710003600 - }, - { - "id": 2, - "name": "Bob", - "created_at": 1710007200, - "updated_at": 1710010800 - } - ] -} -``` - -request / response type は Next.js client と同様に `shared/src/schema` を参照する共通 API client から導出する。SPA 独自の API contract、response interface、Zod schema は再定義しない。API contract の定義元は TypeSpec から生成される shared schema に一本化する。 - -## API client - -HTTP client の共通実装は `shared/src/api-client` に置く。 - -- `path` と HTTP method から request / response 型を `shared/src/schema` で導出する。 -- header、query、request body を schema に基づいて型付けする。 -- response は status code ごとの discriminated union として返す。 -- Next.js と SPA は同じ client implementation を利用する。 -- browser client は薄い wrapper で `credentials: 'include'` を追加するだけとする。 -- endpoint 固有の処理は generic client へ入れない。 - -## Deployment boundary - -`packages/spa` は static hosting だけを担当する。API routing と authentication boundary は deployment environment の責務とする。 - -現在の `packages/api` は `Authorization` header を要求するため、既存 API をそのまま利用する場合は reverse proxy / ingress / BFF など SPA package の外側で `session` cookie を upstream の Authorization へ変換する。 - -この変換は SPA の runtime server として実装しない。 - -### nginx example - -以下は deployment topology の一例であり、SPA application code の一部ではない。 - -```nginx -server { - listen 8080; - root /srv/service-template-spa; - - location = /api/user { - proxy_set_header Authorization "Bearer $cookie_session"; - proxy_pass http://api:8000/api/user; - } - - location / { - try_files $uri $uri/ /index.html; - } -} -``` - -これにより browser からは static assets と `/api/user` が同一 origin に見える。`GET /api/user` 以外へ cookie-to-Authorization を一般化する場合は、state-changing request の CSRF 方針を別途設計する。 - -同じ契約を満たせるなら nginx 以外の hosting / gateway でもよい。 - -## Development and preview - -```bash -npm run dev -w spa -npm run tsc -w spa -npm run build -w spa -npm run start -w spa -npm run test -w spa -``` - -- `dev`: Vite development server。API proxy は持たない。 -- `build`: `dist/public` に static SPA artifact を生成する。 -- `start`: `vite preview --outDir dist/public` で build artifact を静的配信するだけ。production server としては使わない。 -- API と結合して確認する場合は、Vite/nginx の前段または別 gateway で same-origin `/api/user` を用意する。 - -## Application routes - -- `/`: dashboard -- `/dashboard` など extensionless application path: hosting 側で `index.html` へ fallback する -- asset path: `dist/public/assets/*` - -static host は application route を `index.html` へ fallback できればよく、Node 固有の runtime を要求しない。 - -## Dashboard - -- header: service name、接続状態 -- summary: user count -- user list: name、identifier、created/updated timestamp -- loading: skeleton または loading indicator -- success: users を表示 -- empty: count が0の場合の空状態 -- failure: connection/API/auth failure を利用者向け固定文言で表示 -- small viewport: 1列化し、横スクロール・text clipping を発生させない -- visual direction: limit-monitor を参考にした dark surface、低彩度の border、green の online accent - -UI は `GET /api/user` 以外の API call を行わない。 - -## Error handling - -- 401 / 403 は session が必要な状態として表示する。 -- その他の API failure / network failure は offline state として扱う。 -- API の error body は UI にそのまま表示しない。 -- credential や upstream の内部情報を画面へ出さない。 - -## Acceptance criteria - -- `packages/spa` に production runtime Node server が存在しない。 -- build artifact が静的ファイルだけで構成される。 -- nginx 等で `dist/public` を配信し、application route を `index.html` へ fallback できる。 -- browser の API call は same-origin relative URL を使い `credentials: 'include'` を付ける。 -- SPA package は cookie を読まない。 -- API request / response 型は TypeSpec 生成 schema を参照する共通 API client から導出する。 -- Next.js と SPA が同じ generic API client implementation を利用する。 -- SPA package に API proxy / BFF / cookie-to-Authorization adapter を持たない。 -- format / lint / typecheck / build / test が通る。 diff --git a/packages/spa/app/lib/api.client.ts b/packages/spa/app/lib/api.client.ts index ab6b17d..ee7d7f9 100644 --- a/packages/spa/app/lib/api.client.ts +++ b/packages/spa/app/lib/api.client.ts @@ -22,10 +22,9 @@ type BrowserHeaderField

= P extends { header: infer H } type BrowserParameters

= Omit & BrowserHeaderField

-type BrowserParameterField

= - [RequiredKeys>] extends [never] - ? { parameters?: BrowserParameters

} - : { parameters: BrowserParameters

} +type BrowserParameterField

= [RequiredKeys>] extends [never] + ? { parameters?: BrowserParameters

} + : { parameters: BrowserParameters

} type BrowserOptions< T extends keyof schema.paths, @@ -42,12 +41,8 @@ export function client( ) { // The same-origin gateway satisfies the upstream Authorization requirement // from the httpOnly session cookie. Browser code must not provide that header. - return baseClient( - url, - options as Parameters>[1], - { - ...init, - credentials: 'include' - } - ) + return baseClient(url, options as Parameters>[1], { + ...init, + credentials: 'include' + }) } diff --git a/packages/spa/package.json b/packages/spa/package.json index 29a883b..5e813a1 100644 --- a/packages/spa/package.json +++ b/packages/spa/package.json @@ -11,7 +11,7 @@ "test": "vp test --config=./vite.config.ts", "test-ci": "vp test run --config=./vite.config.ts --maxWorkers=1", "format": "vp fmt package.json react-router.config.ts vite.config.ts app --write", - "format-check": "vp fmt package.json react-router.config.ts vite.config.ts app --write && git diff --exit-code -- app/lib/api.client.ts", + "format-check": "vp fmt package.json react-router.config.ts vite.config.ts app --check", "lint": "vp lint react-router.config.ts vite.config.ts app", "lint-fix": "vp lint react-router.config.ts vite.config.ts app --fix" },