diff --git a/.dockerignore b/.dockerignore index 5c3e986f..2a8bad56 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,4 +1,9 @@ -node_modules -.nuxt -.output -data \ No newline at end of file +**/node_modules +**/dist +ui/dts +.env +data +dev/logs +test-results +playwright-report +.git diff --git a/.github/workflows/pull-requests.yml b/.github/workflows/pull-requests.yml index 39b50581..06d5265d 100644 --- a/.github/workflows/pull-requests.yml +++ b/.github/workflows/pull-requests.yml @@ -4,6 +4,12 @@ name: Check pull requests on: pull_request +# a new push to the pull request cancels the checks of the previous one; master and tags +# never cancel (no concurrency group there) +concurrency: + group: ${{ github.workflow }}-${{ github.event.pull_request.number }} + cancel-in-progress: true + jobs: quality: - uses: ./.github/workflows/reuse-quality.yml \ No newline at end of file + uses: ./.github/workflows/reuse-quality.yml diff --git a/.github/workflows/reuse-quality.yml b/.github/workflows/reuse-quality.yml index 0219123f..1f16aa64 100644 --- a/.github/workflows/reuse-quality.yml +++ b/.github/workflows/reuse-quality.yml @@ -1,10 +1,16 @@ name: Quality checks +# The full gate: static checks and builds in one job, then the whole test suite (unit, api, +# e2e) in a second job that reuses the generated types and the UI build as an artifact. +# Used by pull requests and releases; the pre-push hook only +# runs a light subset (dev/pre-push.sh). No shards: the suite takes a few minutes on one +# worker, less than the setup a second runner would pay again. + on: workflow_call: jobs: - quality: + static: runs-on: ubuntu-latest steps: - name: Checkout git repository @@ -12,7 +18,7 @@ jobs: - uses: actions/setup-node@v5 with: - node-version: 24 + node-version-file: .nvmrc cache: 'npm' - name: Install dependencies @@ -24,47 +30,119 @@ jobs: - name: Build types run: npm run build-types + - name: Build UI (generates the ui/dts files vue-tsc needs) + run: npm -w ui run build + - name: Type check run: npm run check-types - - name: Build UI - run: npm -w ui run build + - name: Audit + run: npm audit --omit=dev --audit-level=critical + + # the API imports the generated .type modules and serves ui/dist/index.html at startup + - name: Upload generated types and UI build + uses: actions/upload-artifact@v4 + with: + name: build + include-hidden-files: true + path: | + api/**/.type/ + worker/**/.type/ + ui/dist/ + ui/dts/ + retention-days: 1 + + tests: + needs: static + runs-on: ubuntu-latest + steps: + - name: Checkout git repository + uses: actions/checkout@v5 + + - uses: actions/setup-node@v5 + with: + node-version-file: .nvmrc + cache: 'npm' + + - name: Install dependencies + run: npm ci + + - name: Download generated types and UI build + uses: actions/download-artifact@v4 + with: + name: build + + # only the browser binaries are cached, keyed on the playwright version; never test state + - name: Read the Playwright version + id: playwright + run: echo "version=$(node -p "require('@playwright/test/package.json').version")" >> "$GITHUB_OUTPUT" + + - name: Cache the Playwright browser + id: playwright-cache + uses: actions/cache@v4 + with: + path: ~/.cache/ms-playwright + key: playwright-${{ runner.os }}-${{ steps.playwright.outputs.version }} + + - name: Install the Playwright browser + if: steps.playwright-cache.outputs.cache-hit != 'true' + run: npx playwright install --with-deps chromium + + - name: Install the Playwright browser system dependencies + if: steps.playwright-cache.outputs.cache-hit == 'true' + run: npx playwright install-deps chromium - name: Init .env - run: ./dev/init-env.sh + run: ./node_modules/.bin/df-dev init-env # local bin only: a bare npx would fetch an unrelated "df-dev" from the registry if the dependency were missing - name: Use localhost as DEV_HOST in CI run: sed -i 's/^DEV_HOST=.*/DEV_HOST=localhost/' .env - - name: Start docker compose services - run: docker compose --profile dev up -d --wait + - name: Start the core docker compose services (optional ones stay off, like a default dev env) + run: docker compose up -d --wait + # logs in dev/logs, uploaded on failure - name: Start dev API - run: npx dotenv -- npm run dev-api & + run: mkdir -p dev/logs && NODE_CONFIG="$(./node_modules/.bin/df-dev absent-config)" ./node_modules/.bin/dotenv -- npm -w api run dev > dev/logs/api.log 2>&1 & - name: Start dev worker - run: npx dotenv -- npm run dev-worker & + run: NODE_CONFIG="$(./node_modules/.bin/df-dev absent-config)" ./node_modules/.bin/dotenv -- npm -w worker run dev > dev/logs/worker.log 2>&1 & - - name: Wait for dev API to be ready + - name: Start dev UI + run: ./node_modules/.bin/dotenv -- npm -w ui run dev > dev/logs/ui.log 2>&1 & + + - name: Wait for the dev API, worker and UI to be ready run: | set -a; source .env; set +a for i in {1..30}; do - curl -sf "http://localhost:${DEV_API_PORT}/api/v1/_ping" && exit 0 + if curl -sf "http://localhost:${DEV_API_PORT}/api/v1/_ping" >/dev/null \ + && curl -sf "http://localhost:${DEV_WORKER_OBSERVER_PORT}/metrics" >/dev/null \ + && curl -sf "http://localhost:${DEV_UI_PORT}/processings/" >/dev/null; then + exit 0 + fi sleep 2 done - echo "dev API did not become ready" >&2 + echo "dev API, worker or UI did not become ready" >&2 + tail -n 50 dev/logs/*.log exit 1 - name: Run tests - run: npm run test-unit && npm run test-api + run: npm test - - name: Audit - run: npm audit --omit=dev --audit-level=critical + - name: Upload test results on failure + if: failure() + uses: actions/upload-artifact@v4 + with: + name: test-results + path: | + test-results/ + dev/logs/ + retention-days: 7 - name: Docker compose logs on failure if: failure() - run: docker compose --profile dev logs + run: docker compose --profile '*' logs - name: Stop docker compose services if: always() - run: docker compose --profile dev down + run: docker compose --profile '*' down diff --git a/.gitignore b/.gitignore index 4490df16..b405ce28 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,18 @@ -data/ -dev/logs/ +# dependencies and generated code node_modules/ -**/config/local-* -.config/ .type/ + +# local environment and data .env -playwright-report/ +**/config/local-* +data/ +dev/logs/ + +# test output test-results/ +playwright-report/ + +# agent working files +docs/superpowers/ +.superpowers/ +.playwright-mcp/ diff --git a/.husky/commit-msg b/.husky/commit-msg index dab272da..da994831 100755 --- a/.husky/commit-msg +++ b/.husky/commit-msg @@ -1 +1 @@ -npx --no-install commitlint --edit "" +npx --no -- commitlint --edit "$1" diff --git a/.husky/pre-push b/.husky/pre-push index 53e984fe..dd2d75c2 100755 --- a/.husky/pre-push +++ b/.husky/pre-push @@ -1 +1 @@ -npm run quality +bash dev/pre-push.sh diff --git a/.zellij.kdl b/.zellij.kdl index c8895f74..8f935810 100644 --- a/.zellij.kdl +++ b/.zellij.kdl @@ -1,32 +1,23 @@ +// Dev environment of processings, see @data-fair/lib-dev. Agents: npx --no df-dev status | logs | restart layout { - pane { - split_direction "vertical" - pane name="processings" borderless=true { - command "${DEV_SHELL}" - args "-ic" "nvm use > /dev/null 2>&1 && bash" - } - pane name="deps" { - command "${DEV_SHELL}" - args "-ic" "npm run dev-deps" - } + pane split_direction="vertical" { + pane name="processings" borderless=true + pane name="status" command="./node_modules/.bin/df-status" { + args "--start-deps" } - pane { - split_direction "vertical" - pane name="ui" { - command "${DEV_SHELL}" - args "-ic" "nvm use > /dev/null 2>&1 && npm run dev-ui" - } - pane name="api" { - command "${DEV_SHELL}" - args "-ic" "nvm use > /dev/null 2>&1 && npm run dev-api" - } - pane name="worker" { - command "${DEV_SHELL}" - args "-ic" "nvm use > /dev/null 2>&1 && npm run dev-worker" - } + } + pane split_direction="vertical" { + pane name="ui" command="bash" { + args "-c" "cd ui && FORCE_COLOR=1 NODE_CONFIG_DIR=../api/config/ exec ../node_modules/.bin/df-mem-cap vite --port $DEV_UI_PORT" } - pane size=1 borderless=true { - command "bash" - args "-ic" "echo -n -e \"Dev server available at \\e[1;96mhttp://${DEV_HOST}:${NGINX_PORT1}/processings\\033[0m\"" + pane name="api" command="bash" { + args "-c" "./node_modules/.bin/df-dev wait-deps && export NODE_CONFIG=$(./node_modules/.bin/df-dev absent-config) && cd api && FORCE_COLOR=1 NODE_ENV=development DEBUG=upgrade exec ../node_modules/.bin/nodemon -e js,ts,json index.ts" } + pane name="worker" command="bash" { + args "-c" "./node_modules/.bin/df-dev wait-deps && export NODE_CONFIG=$(./node_modules/.bin/df-dev absent-config) && cd worker && FORCE_COLOR=1 NODE_ENV=development DEBUG='worker,upgrade*' exec ../node_modules/.bin/nodemon -e js,ts,json index.ts" + } + } + pane name="url" size=1 borderless=true command="bash" { + args "-c" "echo -n -e \"Dev server available at \\e[1;96mhttp://$DEV_HOST:$NGINX_PORT/processings/dev\\e[0m\"; exec sleep infinity" + } } diff --git a/AGENTS.md b/AGENTS.md index 11be9935..8a2a6227 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -13,49 +13,38 @@ running `data-fair` instance. The project is a monorepo with four workspaces: ## Dev environment -The dev environment is managed by **zellij** (terminal multiplexer) and **docker compose**. -**Never start, stop, or restart dev processes yourself** — the user manages them through -zellij panes (`npm run dev-zellij`). +The user starts the dev environment of a checkout with `npm run dev-zellij` (zellij >= 0.44, session named after the checkout directory). Agents never start or kill the session, and act on processes and containers only through `df-dev`: + +```bash +npx --no df-dev status # containers (health, memory), panes (running / exited + code, readiness), dev processes memory +npx --no df-dev logs api -n 100 # last lines of a pane: api, worker, ui +npx --no df-dev restart worker # Ctrl+C, rerun, wait for its readiness URL +npx --no df-dev up events # optional container (compose profile), then restart api and worker +``` + +- Read the logs before restarting: nodemon (api, worker) and vite (ui) already reload on file changes. Restart only a pane that exited, hangs, or needs new env. +- If `restart` answers "not ready", report to the user with the logs instead of retrying. +- Never use `docker compose restart`, `kill` or `zellij action` directly, nor `npm ci` / `npm install` while the env runs. +- Always `npx --no df-dev`: without `--no`, npx would download an unrelated public package if the dependency were missing. +- Optional containers: `events` (notifications; when absent the api and worker run with `privateEventsUrl: ""`), `openapi-viewer` (API docs) and `maildev` (catches the mails of simple-directory and of the worker's transport, plugins' `sendMail`). The user can start them with the env: `npm run dev-zellij -- --services events,openapi-viewer`. The dev environment also serves as the test environment: the Playwright test suite hits the running dev API, dev worker and dev UI. There is no separate test server. Each git worktree gets its own `.env` (random ports + `.localhost` subdomain) so -multiple worktrees coexist without port collisions. Use the worktree scripts: +multiple worktrees coexist without port collisions. From the main checkout: ```bash -./dev/worktree.sh feat-xyz # create ../processings_feat-xyz with a fresh .env -./dev/delete-worktree.sh feat-xyz # tear down docker compose and remove the worktree +npx --no df-worktree feat-xyz # ../processings_feat-xyz: npm ci + df-dev setup (.env, types, UI build) +npx --no df-worktree-delete feat-xyz # containers, volumes, zellij session, then the worktree ``` -### Checking status - -```bash -bash dev/status.sh -``` - -Shows the health of all services (nginx, dev API, dev UI, dev worker, simple-directory, -data-fair upstream, events, openapi-viewer, mongo, elasticsearch) and lists log files -with sizes and timestamps. - -### Log files - -All dev processes write to `dev/logs/`: -- `dev-api.log` — API server -- `dev-worker.log` — worker process -- `dev-ui.log` — UI dev server (Vite) -- `docker-compose.log` — all docker compose services - -### Troubleshooting - -1. Run `bash dev/status.sh` to identify which services are down -2. Read the relevant log file in `dev/logs/` for error details -3. Report findings to the user — do not attempt to fix infrastructure issues yourself +Branch names: letters, digits, `.`, `_`, `-`, at most 60 characters, no `/`. ### Port assignments Port numbers and the `DEV_HOST` subdomain live in `.env` (gitignored, generated by -`dev/init-env.sh`). Do not modify port assignments by hand. +`npx --no df-dev setup` from `dev/dev.json`). Do not modify port assignments by hand. ### Test users @@ -83,26 +72,49 @@ These endpoints are used by the Playwright support helpers in `tests/support/axi ### Testing ```bash -npm test # all tests +npm test # all tests (no --max-failures: one flake must not hide the rest) npm run test-unit # unit tests only npm run test-api # API tests only +npm run test-api-fast # API tests, stop at the first failure (iteration) npm run test-e2e # e2e tests only npx playwright test path/to/file # specific file ``` +The run writes per-test durations to `dev/logs/test-timings.json`, and keeps a trace and a +screenshot of each failing test in `test-results/` (`npx playwright show-trace `). +Timeout: 30 s per test, hooks included; specs that run plugins through the worker call +`test.slow()` instead of raising it. `clean()` fails, naming the runs, when the worker is +still busy after 10 s: the culprit is the test that left them. + +e2e specs log in through the simple-directory API (`tests/fixtures/login.ts`, one login per +user and worker, renewed after 10 min) and turn off lib-vue's keepalive with a future +`sd-keepalive` localStorage timestamp, so no page ever rotates the shared exchange token. + Tests are organized under `tests/features//.{unit,api,e2e}.spec.ts`. -The `state-setup` project pings `/api/v1/test-env/pending-tasks` and tails the dev API -and worker logs into the test reporter output. +The `state-setup` project pings `/api/v1/test-env/pending-tasks` and seeds the data-fair API +key of the worker. Pure logic goes to unit specs; api specs cover the HTTP contract and the +worker; e2e specs only cover user flows and what only a browser can check. The `e2e` project depends on `e2e-warmup` (`tests/e2e-warmup.ts`), which walks the list -and edit routes once before the specs run. Vite discovers dependencies lazily in dev: the -first page mounting the vjsf form or an action menu makes it re-optimize and force a full -page reload, which breaks whatever assertion was in flight. Running an e2e spec alone -still goes through the warmup, so a cold Vite cache costs a few seconds once instead of a -random timeout failure. - -The full test suite is long — when iterating on changes always run only the related -test cases. The full suite runs on `git push` via husky. +and edit routes once before the specs run, so a cold Vite transforms them first. Dependency +discovery is off: a blank page there with a module named in the console means a commonjs +dependency is missing from `optimizeDeps.include` in `ui/vite.config.ts` (use the exact import +specifier). Running an e2e spec alone still goes through the warmup. + +When iterating on changes always run only the related test cases. + +Quality gates: + +| When | Where | What | +|---|---|---| +| commit | `.husky/pre-commit` | `npm run lint` | +| push | `.husky/pre-push` → `dev/pre-push.sh` | type check, all unit tests, the `@smoke` api/e2e set, and the api/e2e spec files changed since `origin/master` | +| pull request | `pull-requests.yml` → `reuse-quality.yml` | lint, builds, type check, audit, then the whole unit/api/e2e suite (1 retry) | +| release tag | `releases.yml` → `reuse-quality.yml` | the same, before building the images | + +`npm run quality` still runs the whole gate locally. A test joins the `@smoke` set +(`test('...', { tag: '@smoke' }, ...)`) only if it is fast and covers a core flow (create, +permissions, run, edit form); check its duration in `dev/logs/test-timings.json`. ### Linting & Type Checking diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 81a910a8..2d8c741c 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -4,59 +4,40 @@ - A Javascript/Typescript IDE with [Vue.js](https://vuejs.org/) and [ESLint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) support. - A recent [Docker](https://docs.docker.com/engine/install/) installation. -- [Node.js v20+](https://nodejs.org/) +- [Node.js](https://nodejs.org/) v24, the major in `.nvmrc` ## Install dependencies -1) Install npm dependencies for all workspaces : - ```sh -npm i +npm ci +npx --no df-dev setup # .env with free ports (kept if it exists, --force to redraw), types, UI build +docker compose pull # at first and then once in a while ``` -2) Pull images at first and then once in a while : +## Start the development environment ```sh -docker compose pull +npm run dev-zellij # core containers + ui, api, worker +npm run dev-zellij -- --services events,openapi-viewer # with the optional containers ``` -3) Then run the containers : +This opens a [zellij](https://zellij.dev/) (>= 0.44) session named after the checkout directory, or attaches to it if it runs. Start it from a shell on the `.nvmrc` Node version. The dev URL is in the footer. From another terminal: `npx --no df-dev status`, `npx --no df-dev logs `, `npx --no df-dev restart `, `npx --no df-dev up `. -```sh -npm run dev-deps -``` +## Stop the development environment -*Stop the containers with this command :* +Quit zellij, then: ```sh npm run stop-dev-deps ``` -## Working on @data-fair/processings/api - -The API is a small [Express](https://expressjs.com) server. -Run a development server (access it at http://localhost:8082/api/) : - -```sh -npm run dev-api -``` - -## Working on @data-fair/processings/ui +## Worktrees -The UI is a [Vue 3](https://vuejs.org/) project that uses [Vuetify 3](https://vuetifyjs.com/). -Run a development server (access it at http://localhost:3039/) : +Each checkout has its own `.env` with random ports, so you can run multiple worktrees side by side : ```sh -npm run dev-ui -``` - -## Working on @data-fair/processings/worker - -The worker is a small [Node.js](https://nodejs.org) process that runs periodically the processings. -Run a development process : - -```sh -npm run dev-worker +npx --no df-worktree feat-xyz # from the main checkout: ../processings_feat-xyz, installed and built +npx --no df-worktree-delete feat-xyz # its containers, volumes and zellij session, then the worktree ``` ## Working on types @@ -83,42 +64,3 @@ Run the test suite : ```sh npm run test ``` - ---- - -## All-in-one development - -You can run all services at once thanks to Zellij. - -
-First time instructions - -1) Install Rust's Cargo -```sh -curl https://sh.rustup.rs -sSf | sh -# choose 1 when prompted -``` -2) Install Zellij -```sh -cargo install --locked zellij -``` -3) Install NVM -```sh -curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/master/install.sh | bash -# in processings -nvm install -``` -
- -Run the Zellij command : - -```sh -npm run dev-zellij -``` - -Access the running services at https://localhost:5600/ - -*Tips :* -- Use Ctrl + Q to quit Zellij. It'll also stop the containers. -- Click on a panel, then use Ctrl + C then Esc to stop a terminal and regain access of the panel. -- The logs of the `dev-deps` panel are stored on the host in the `logs` directory. diff --git a/Dockerfile b/Dockerfile index 394db3a0..eba85daf 100644 --- a/Dockerfile +++ b/Dockerfile @@ -8,6 +8,8 @@ RUN apk upgrade --no-cache # the npm bundled with node lags behind on its own dependencies' security fixes, # it cannot be removed as lib-node-registry runs "npm rebuild" on plugins with native modules RUN npm install -g npm@11.21.0 && npm cache clean --force +# corepack and yarn are never used +RUN rm -rf /usr/local/lib/node_modules/corepack /usr/local/bin/corepack /opt/yarn-* /usr/local/bin/yarn /usr/local/bin/yarnpkg WORKDIR /app ENV NODE_ENV=production diff --git a/api/config/development.mjs b/api/config/development.mjs index 0958cc36..d3bf3de2 100644 --- a/api/config/development.mjs +++ b/api/config/development.mjs @@ -6,7 +6,7 @@ const registryPort = process.env.REGISTRY_PORT ?? '8085' const observerPort = parseInt(process.env.DEV_API_OBSERVER_PORT ?? '9092') export default { - cipherPassword: 'dev', + cipherPassword: 'dev-cipher-password-0123456789abcdef', dataDir: '../data/development', mongoUrl: `mongodb://localhost:${mongoPort}/data-fair-processings-development`, observer: { diff --git a/api/package.json b/api/package.json index b702de27..18f8439a 100644 --- a/api/package.json +++ b/api/package.json @@ -20,8 +20,8 @@ "@types/ws": "^8.5.12" }, "dependencies": { - "@data-fair/lib-express": "~1.28.1", - "@data-fair/lib-node": "~2.15.0", + "@data-fair/lib-express": "^1.31.0", + "@data-fair/lib-node": "^2.16.1", "@data-fair/lib-node-registry": "0.7.2", "@data-fair/lib-utils": "^1.13.1", "@data-fair/lib-validation": "^1.0.2", diff --git a/api/src/admin/router.ts b/api/src/admin/router.ts index 260525fa..2a034375 100644 --- a/api/src/admin/router.ts +++ b/api/src/admin/router.ts @@ -14,9 +14,14 @@ router.use(async (req, res, next) => { next() }) -let info = { version: process.env.NODE_ENV } +let info: Record = { version: process.env.NODE_ENV ?? 'development' } if (process.env.NODE_ENV === 'production') { - info = JSON.parse(await readFile(resolve(import.meta.dirname, '../../../BUILD.json'), 'utf8')) + try { + info = JSON.parse(await readFile(resolve(import.meta.dirname, '../../../BUILD.json'), 'utf8')) + } catch { + // BUILD.json is written by CI, an image built elsewhere must still start + info = { version: 'unknown (built without CI)' } + } } router.get('/info', (req, res) => { res.send(info) diff --git a/api/src/processings/operations.ts b/api/src/processings/operations.ts new file mode 100644 index 00000000..23ffb74a --- /dev/null +++ b/api/src/processings/operations.ts @@ -0,0 +1,19 @@ +// operations.ts — pure functions only +// must not import #mongo, #config, or store state + +import type { Processing } from '#types' +import { httpError } from '@data-fair/lib-utils/http-errors.js' + +/** + * `lib-express/error-handler.js` collapses every AxiosRequestError to 500, so + * we translate registry failures into user-facing French messages at the + * boundary. 403/404 keep their status (the UI relies on them to show its + * "plugin broken" banner); anything else is a registry outage → 502. + */ +export const translateRegistryError = (err: any, processing: Pick) => { + const status = err?.status ?? err?.statusCode + const ownerLabel = processing.owner.name ?? processing.owner.id + if (status === 403) return httpError(403, `Le compte ${ownerLabel} n'a pas accès au plugin ${processing.plugin}.`) + if (status === 404) return httpError(404, `Le plugin ${processing.plugin} est introuvable dans le registre.`) + return httpError(502, 'Le registre des plugins est temporairement indisponible.') +} diff --git a/api/src/processings/router.ts b/api/src/processings/router.ts index 912dfa46..76f4d9a9 100644 --- a/api/src/processings/router.ts +++ b/api/src/processings/router.ts @@ -27,6 +27,7 @@ import { resolvedSchema as processingSchema } from '#types/processing/index.ts' import getApiDoc from '../misc/utils/api-docs.ts' import findUtils from '../misc/utils/find.ts' import permissions from '../misc/utils/permissions.ts' +import { translateRegistryError } from './operations.ts' const router = Router() export default router @@ -59,20 +60,6 @@ const registryAccount = (owner: Processing['owner']) => ({ ...(owner.department ? { department: owner.department } : {}) }) -/** - * `lib-express/error-handler.js` collapses every AxiosRequestError to 500, so - * we translate registry failures into user-facing French messages at the - * boundary. 403/404 keep their status (the UI relies on them to show its - * "plugin broken" banner); anything else is a registry outage → 502. - */ -const translateRegistryError = (err: any, processing: Pick) => { - const status = err?.status ?? err?.statusCode - const ownerLabel = processing.owner.name ?? processing.owner.id - if (status === 403) return httpError(403, `Le compte ${ownerLabel} n'a pas accès au plugin ${processing.plugin}.`) - if (status === 404) return httpError(404, `Le plugin ${processing.plugin} est introuvable dans le registre.`) - return httpError(502, 'Le registre des plugins est temporairement indisponible.') -} - async function ensurePluginAndReadSchema (processing: Pick) { const account = registryAccount(processing.owner) // `processing.plugin` is the registry artefact id, passed through as-is. @@ -144,8 +131,6 @@ const sendProcessingEvent = ( topicAction: string, sessionState?: SessionStateAuthenticated ) => { - if (!config.privateEventsUrl && !config.secretKeys.events) return - eventsQueue.pushEvent({ title: `Le traitement ${processing.title} ${actionText}`, topic: { key: `processings:processing-${topicAction}:${processing._id}` }, @@ -468,9 +453,7 @@ router.patch('/:id', async (req, res) => { await mongo.processings.updateOne({ _id: req.params.id }, patch) await mongo.runs.updateMany({ 'processing._id': processing._id }, { $set: { permissions: patchedProcessing.permissions || [] } }) await applyProcessing(mongo, patchedProcessing) - if (config.privateEventsUrl && config.secretKeys.events) { - sendProcessingEvent(patchedProcessing, 'a été modifié', 'patch', sessionState) - } + sendProcessingEvent(patchedProcessing, 'a été modifié', 'patch', sessionState) res.status(200).json(cleanProcessing(patchedProcessing, sessionState)) }) diff --git a/api/src/server.ts b/api/src/server.ts index f0401db6..5540eeca 100644 --- a/api/src/server.ts +++ b/api/src/server.ts @@ -5,7 +5,7 @@ import { session, assertAuthenticated } from '@data-fair/lib-express/index.js' import * as wsServer from '@data-fair/lib-express/ws-server.js' import * as wsEmitter from '@data-fair/lib-node/ws-emitter.js' import eventsQueue from '@data-fair/lib-node/events-queue.js' -import { startObserver, stopObserver, internalError } from '@data-fair/lib-node/observer.js' +import { startObserver, stopObserver } from '@data-fair/lib-node/observer.js' import { createHttpTerminator } from 'http-terminator' import { exec as execCallback } from 'child_process' import { promisify } from 'util' @@ -33,13 +33,8 @@ export const start = async () => { session.init(config.privateDirectoryUrl) await mongo.init() await locks.start(mongo.db) - if (config.privateEventsUrl) { - if (!config.secretKeys.events) { - internalError('processings', 'Missing secretKeys.events in config') - } else { - await eventsQueue.start({ eventsUrl: config.privateEventsUrl, eventsSecret: config.secretKeys.events }) - } - } + // without the events service (optional) the queue is inactive and pushEvent is a no-op + await eventsQueue.start({ eventsUrl: config.privateEventsUrl, eventsSecret: config.secretKeys.events }) await wsServer.start(server, mongo.db, async (channel, sessionState) => { assertAuthenticated(sessionState) diff --git a/dev/delete-worktree.sh b/dev/delete-worktree.sh deleted file mode 100755 index 3a4db0f8..00000000 --- a/dev/delete-worktree.sh +++ /dev/null @@ -1,29 +0,0 @@ -#!/bin/bash - -BRANCH_NAME=$1 - -if [ -z "$BRANCH_NAME" ]; then - echo "Error: Please provide a branch name." - echo "Usage: ./dev/delete-worktree.sh feat-xyz" - exit 1 -fi - -REPO_NAME=$(basename "$PWD") -TARGET_DIR="../${REPO_NAME}_${BRANCH_NAME}" - -if [ ! -d "$TARGET_DIR" ]; then - echo "Error: Worktree directory $TARGET_DIR does not exist." - exit 1 -fi - -echo "Stopping docker compose services in $TARGET_DIR" -cd "$TARGET_DIR" -docker compose --profile dev down - -echo "Removing git worktree at $TARGET_DIR" -cd "$OLDPWD" -git worktree remove "$TARGET_DIR" - -echo "-----------------------------------------------" -echo "✅ Worktree $BRANCH_NAME deleted!" -echo "-----------------------------------------------" diff --git a/dev/dev.json b/dev/dev.json new file mode 100644 index 00000000..774a05f4 --- /dev/null +++ b/dev/dev.json @@ -0,0 +1,36 @@ +{ + "ports": [ + "NGINX_PORT", + "DEV_API_PORT", + "DEV_UI_PORT", + "DEV_UI_HMR_PORT", + "DEV_API_OBSERVER_PORT", + "DEV_WORKER_OBSERVER_PORT", + "MONGO_PORT", + "ES_PORT", + "SD_PORT", + "EVENTS_PORT", + "OAV_PORT", + "DF_PORT", + "REGISTRY_PORT", + "MAILDEV_UI_PORT", + "MAILDEV_SMTP_PORT" + ], + "panes": { + "api": { + "ready": "http://localhost:${DEV_API_PORT}/api/v1/_ping" + }, + "ui": { + "ready": "http://localhost:${DEV_UI_PORT}/processings/" + }, + "worker": { + "ready": "http://localhost:${DEV_WORKER_OBSERVER_PORT}/metrics" + } + }, + "url": "http://${DEV_HOST}:${NGINX_PORT}/processings/dev", + "optional": { + "events": { + "privateEventsUrl": "" + } + } +} diff --git a/dev/init-env.sh b/dev/init-env.sh deleted file mode 100755 index 6ae3aa37..00000000 --- a/dev/init-env.sh +++ /dev/null @@ -1,34 +0,0 @@ -#!/bin/bash - -RANDOM_NB=$((1024 + RANDOM % 48000)) -echo "Use random base port $RANDOM_NB" - -BRANCH=$(git rev-parse --abbrev-ref HEAD 2>/dev/null | sed 's/[^a-zA-Z0-9-]/-/g') -DEV_HOST="${BRANCH:-df}.localhost" - -cat < ".env" -DEV_HOST=${DEV_HOST} - -NGINX_PORT1=$((RANDOM_NB)) -NGINX_PORT2=$((RANDOM_NB + 1)) - -DEV_API_PORT=$((RANDOM_NB + 10)) -DEV_UI_PORT=$((RANDOM_NB + 11)) -DEV_WORKER_PORT=$((RANDOM_NB + 12)) -DEV_API_OBSERVER_PORT=$((RANDOM_NB + 13)) -DEV_WORKER_OBSERVER_PORT=$((RANDOM_NB + 14)) -DEV_UI_HMR_PORT=$((RANDOM_NB + 15)) - -MONGO_PORT=$((RANDOM_NB + 20)) -ES_PORT=$((RANDOM_NB + 21)) - -SD_PORT=$((RANDOM_NB + 30)) -EVENTS_PORT=$((RANDOM_NB + 31)) -OAV_PORT=$((RANDOM_NB + 32)) -DF_PORT=$((RANDOM_NB + 33)) -REGISTRY_PORT=$((RANDOM_NB + 34)) - -# all dev services listen on the loopback, the SSRF protection of the default http agents -# would refuse them (cf @data-fair/lib-node http-agents) -SSRF_PUBLIC_IPS=127.0.0.1,::1 -EOF diff --git a/dev/pre-push.sh b/dev/pre-push.sh new file mode 100755 index 00000000..3a635d91 --- /dev/null +++ b/dev/pre-push.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash +# The light pre-push gate, run by .husky/pre-push (lint already ran on pre-commit). The full +# gate (static checks + the whole unit/api/e2e suite) runs on pull requests and releases +# (no nightly: the suite is small); `npm run quality` still runs it locally on demand. +# +# api/e2e tests need the dev env up (npx --no df-dev status). +set -euo pipefail +cd "$(dirname "$0")/.." + +npm run check-types + +npx playwright test --project=unit --max-failures=1 + +# the smoke set: a few api/e2e tests over the core flows, tagged @smoke +npx playwright test --project=api --project=e2e --grep @smoke --max-failures=1 + +# plus every api/e2e spec file this push adds or modifies. Only the spec files themselves: +# these tests reach the code over HTTP, so an import graph (--only-changed) would not tie +# them to the api/src, worker/src or ui/src files they exercise. +base=$(git merge-base HEAD origin/master 2>/dev/null || true) +if [ -n "$base" ]; then + mapfile -t changed < <(git diff --name-only --diff-filter=d "$base" HEAD -- 'tests/**/*.api.spec.ts' 'tests/**/*.e2e.spec.ts') + if [ ${#changed[@]} -gt 0 ]; then + echo "changed api/e2e spec files: ${changed[*]}" + npx playwright test --project=api --project=e2e --max-failures=1 "${changed[@]}" + fi +fi diff --git a/dev/resources/nginx.conf.template b/dev/resources/nginx.conf.template index 11e093bd..5e21e774 100644 --- a/dev/resources/nginx.conf.template +++ b/dev/resources/nginx.conf.template @@ -1,32 +1,53 @@ -# nginx configuration file for processings development and test environment +# Dev reverse proxy of the data-fair stack. This head is identical in every service repo +# (data-fair-service skill, references/nginx.md) and mirrors the production ingress-nginx config, +# minus the shared cache and gzip. The nginx image entrypoint substitutes the env vars and +# includes the result in the http block. + +# websocket support (realtime channels, Vite HMR): upgrade only the requests that ask for it +map $http_upgrade $connection_upgrade { + default upgrade; + '' close; +} +proxy_http_version 1.1; +proxy_set_header Upgrade $http_upgrade; +proxy_set_header Connection $connection_upgrade; + +# Transmit host, protocol and user ip, we use it for routing, rate limiting, etc. +proxy_set_header Host $http_host; +proxy_set_header X-Forwarded-Host $http_host; +proxy_set_header X-Forwarded-Proto $scheme; +proxy_set_header X-Forwarded-For $remote_addr; +proxy_set_header X-Real-IP $remote_addr; +proxy_set_header X-Client-IP $remote_addr; +# the relay secret proves a forwarded client IP to the ingress; services never see it +proxy_set_header X-Trusted-Forwarder ""; +proxy_set_header X-Forwarded-Path $request_uri; +# Headers data-fair uses for better private caching +proxy_set_header X-Private-If-Modified-Since $http_if_modified_since; +proxy_set_header X-Private-If-None-Match $http_if_none_match; +# range requests support (pmtiles) +proxy_set_header Range $http_range; + +# accept some occasional long queries +proxy_read_timeout 600s; +# body size limits are implemented by services themselves +client_max_body_size 0; +# direct streaming of uploads +proxy_request_buffering off; +# direct streaming of downloads, enabled on-demand by services using x-accel-buffering header +proxy_buffering off; +# allow large response headers (setCookies with large session token) +proxy_buffer_size 32k; +proxy_buffers 4 32k; + +# No server or location below sets proxy_set_header: it would drop every header above. server { - listen ${NGINX_PORT1}; + listen ${NGINX_PORT}; server_name ${DEV_HOST}; - # Transmit host, protocol and user ip, we use it for routing, rate limiting, etc. - proxy_set_header Host $http_host; - proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - proxy_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Forwarded-Host $http_host; - proxy_set_header X-Real-IP $remote_addr; - proxy_set_header X-Client-IP $remote_addr; - - # web socket support - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "Upgrade"; - - # accept some occasional long queries + HMR long poll from the Vite dev server - proxy_read_timeout 86400; - # body size limits are implemented by services themselves - client_max_body_size 0; - # direct streaming of uploads - proxy_request_buffering off; - # direct streaming of downloads - proxy_buffering off; - # allow large response headers (setCookies with large session token) - proxy_buffer_size 32k; - proxy_buffers 4 32k; + # add the trailing slash to the service prefixes + rewrite ^(/processings|/simple-directory|/data-fair|/events|/registry|/openapi-viewer)$ $1/ redirect; location = / { return 302 /processings/; @@ -36,42 +57,43 @@ server { return 302 /processings/dev; } - # API routes served by API server + # API routes served by the API server location /processings/api/ { proxy_pass http://localhost:${DEV_API_PORT}; } - # ui-config served by API + # ui-config served by the API server location ~ /processings/(.*)-ui-config.js { proxy_pass http://localhost:${DEV_API_PORT}; } - # UI served by Vite dev server + # UI served by the Vite dev server, long timeout for the HMR websocket location /processings/ { + proxy_read_timeout 86400s; proxy_pass http://localhost:${DEV_UI_PORT}; } location /simple-directory/ { - proxy_pass http://localhost:${SD_PORT}/simple-directory/; + proxy_pass http://localhost:${SD_PORT}; } + # data-fair API without its prefix, like prod location /data-fair/ { - proxy_pass http://localhost:${DF_PORT}/data-fair/; - } - - location /openapi-viewer/ { - proxy_pass http://localhost:${OAV_PORT}/; + rewrite ^/data-fair/(.*) /$1 break; + proxy_pass http://localhost:${DF_PORT}; } location /events/ { - proxy_pass http://localhost:${EVENTS_PORT}/; + proxy_pass http://localhost:${EVENTS_PORT}; } - # No URI on proxy_pass: nginx forwards the original encoded request URI as-is + # no URI on proxy_pass: the original encoded request URI goes through as-is, # so artefact ids like @data-fair%2Fprocessing-hello-world keep their %2F - # all the way to the express :name route. Registry expects the /registry - # prefix in the URL itself (PUBLIC_URL=...registry). location /registry/ { proxy_pass http://localhost:${REGISTRY_PORT}; } + + location /openapi-viewer/ { + proxy_pass http://localhost:${OAV_PORT}; + } } diff --git a/dev/status.sh b/dev/status.sh deleted file mode 100755 index ef47fd36..00000000 --- a/dev/status.sh +++ /dev/null @@ -1,100 +0,0 @@ -#!/usr/bin/env bash -# Check the status of all dev environment services. -# Read-only — never starts, stops, or restarts anything. -# Safe to run from sandbox (only needs curl and .env). - -set -euo pipefail - -SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" -PROJECT_DIR="$(dirname "$SCRIPT_DIR")" - -# Load port configuration -if [ -f "$PROJECT_DIR/.env" ]; then - set -a - source "$PROJECT_DIR/.env" - set +a -else - echo "ERROR: .env file not found at $PROJECT_DIR/.env" - exit 1 -fi - -NGINX1="http://${DEV_HOST}:${NGINX_PORT1}" - -# Colors (disabled if not a terminal) -if [ -t 1 ]; then - GREEN='\033[0;32m' - RED='\033[0;31m' - YELLOW='\033[0;33m' - BOLD='\033[1m' - RESET='\033[0m' -else - GREEN='' RED='' YELLOW='' BOLD='' RESET='' -fi - -check_http() { - local name="$1" url="$2" - local http_code - http_code=$(curl -s -L --max-time 2 -o /dev/null -w "%{http_code}" "$url" 2>&1) || http_code="000" - if [ "$http_code" = "000" ]; then - printf "${RED}%-20s DOWN %s (connection refused)${RESET}\n" "$name" "$url" - elif [ "$http_code" -ge 200 ] && [ "$http_code" -lt 400 ]; then - printf "${GREEN}%-20s UP %s${RESET}\n" "$name" "$url" - else - printf "${YELLOW}%-20s ERROR %s (HTTP %s)${RESET}\n" "$name" "$url" "$http_code" - fi -} - -check_tcp() { - local name="$1" host="$2" port="$3" - if (echo > /dev/tcp/"$host"/"$port") 2>/dev/null; then - printf "${GREEN}%-20s UP %s:%s${RESET}\n" "$name" "$host" "$port" - else - printf "${RED}%-20s DOWN %s:%s${RESET}\n" "$name" "$host" "$port" - fi -} - -echo -e "${BOLD}Dev environment status${RESET}" -echo "" - -# --- Nginx (gateway to everything) --- -echo -e "${BOLD}Nginx proxy:${RESET}" -check_http "nginx (port1)" "$NGINX1" -check_tcp "nginx (port2)" "localhost" "${NGINX_PORT2}" -echo "" - -# --- Dev processes --- -echo -e "${BOLD}Dev processes:${RESET}" -check_http "dev-api" "http://localhost:${DEV_API_PORT}/api/v1/_ping" -check_http "dev-ui" "http://localhost:${DEV_UI_PORT}" -check_tcp "dev-worker-observer" "localhost" "${DEV_WORKER_OBSERVER_PORT}" -echo "" - -# --- Docker compose services --- -echo -e "${BOLD}Docker compose services:${RESET}" -check_http "simple-directory" "${NGINX1}/simple-directory/" -check_http "data-fair" "${NGINX1}/data-fair/" -check_http "events" "${NGINX1}/events/" -check_http "openapi-viewer" "${NGINX1}/openapi-viewer/" -check_tcp "mongo" "localhost" "${MONGO_PORT}" -check_tcp "elasticsearch" "localhost" "${ES_PORT}" -echo "" - -# --- Docker compose status (if docker/podman available) --- -if command -v docker &> /dev/null && docker compose version &> /dev/null; then - echo -e "${BOLD}Container details:${RESET}" - (cd "$PROJECT_DIR" && docker compose ps --format "table {{.Name}}\t{{.Status}}\t{{.Ports}}" 2>/dev/null) || echo "(docker compose not available)" - echo "" -fi - -# --- Log files --- -echo -e "${BOLD}Log files:${RESET}" -found_logs=false -for log in "$PROJECT_DIR"/dev/logs/*.log; do - [ -f "$log" ] || continue - found_logs=true - name=$(basename "$log") - size=$(wc -c < "$log" 2>/dev/null || echo 0) - mod=$(date -r "$log" "+%H:%M:%S" 2>/dev/null || echo "unknown") - printf " %-25s %6s bytes (last modified: %s)\n" "$name" "$size" "$mod" -done -$found_logs || echo " (no log files found)" diff --git a/dev/worktree.sh b/dev/worktree.sh deleted file mode 100755 index 4ac8e08c..00000000 --- a/dev/worktree.sh +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash - -BRANCH_NAME=$1 - -if [ -z "$BRANCH_NAME" ]; then - echo "Error: Please provide a branch name." - echo "Usage: ./dev/worktree.sh feat-xyz" - exit 1 -fi - -SOURCE_BRANCH=$(git branch --show-current) -REPO_NAME=$(basename "$PWD") -TARGET_DIR="../${REPO_NAME}_${BRANCH_NAME}" - -echo "Creating worktree at $TARGET_DIR from branch $SOURCE_BRANCH" -git worktree add -b "$BRANCH_NAME" "$TARGET_DIR" $SOURCE_BRANCH - -cd $TARGET_DIR - -if [ -d "$OLDPWD/.claude" ]; then - echo "Copy local Claude settings" - mkdir -p .claude - for f in "$OLDPWD/.claude"/*.json; do - [ -f "$f" ] && cp "$f" .claude/ - done -fi - -echo "Create .env file" -./dev/init-env.sh - -echo "npm ci" -npm ci - -echo "npm run build-types" -npm run build-types - -echo "npm -w ui run build" -npm -w ui run build - -echo "-----------------------------------------------" -echo "✅ Setup Complete!" -echo "Location: $TARGET_DIR" -echo "Branch: $BRANCH_NAME" -echo "-----------------------------------------------" -echo "Next step:" -echo " cd $TARGET_DIR" -echo "" diff --git a/docker-compose.yml b/docker-compose.yml index 6532823c..07d561b3 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -4,21 +4,18 @@ services: # reverse proxy for the whole environment ##### nginx: - profiles: - - dev image: nginx:1.29.4-alpine network_mode: host environment: - DEV_HOST=${DEV_HOST} - - NGINX_PORT1=${NGINX_PORT1} - - NGINX_PORT2=${NGINX_PORT2} + - NGINX_PORT=${NGINX_PORT} - DEV_API_PORT=${DEV_API_PORT} - DEV_UI_PORT=${DEV_UI_PORT} - SD_PORT=${SD_PORT} - DF_PORT=${DF_PORT} - EVENTS_PORT=${EVENTS_PORT} - - OAV_PORT=${OAV_PORT} - REGISTRY_PORT=${REGISTRY_PORT} + - OAV_PORT=${OAV_PORT} volumes: - ./dev/resources/nginx.conf.template:/etc/nginx/templates/default.conf.template:ro @@ -27,93 +24,107 @@ services: ##### simple-directory: - profiles: - - dev - image: ghcr.io/data-fair/simple-directory:8 + image: ghcr.io/data-fair/simple-directory:master network_mode: host depends_on: - - mongo + mongo: + condition: service_healthy environment: - - DEBUG=session - PORT=${SD_PORT} + - PUBLIC_URL=http://${DEV_HOST}:${NGINX_PORT}/simple-directory + - MONGO_URL=mongodb://localhost:${MONGO_PORT}/simple-directory + - OBSERVER_ACTIVE=false + - CIPHER_PASSWORD=dev-cipher-password-0123456789abcdef + - STORAGE_TYPE=file + - ADMINS=["test_superadmin@test.com","superadmin@test.com","alban.mouton@koumoul.com"] - CONTACT=contact@test.com - - ADMINS=["superadmin@test.com","test_superadmin@test.com"] - - PUBLIC_URL=http://${DEV_HOST}:${NGINX_PORT1}/simple-directory # in dev simple-directory only notifies this service, directly (the shared identities router refuses calls through the proxy) - IDENTITIES_WEBHOOKS=[{"base":"http://localhost:${DEV_API_PORT}/api/identities","key":"secret-identities"}] - - MAILDEV_ACTIVE=true - - MONGO_URL=mongodb://localhost:${MONGO_PORT}/simple-directory - - STORAGE_TYPE=file - - AUTHRATELIMIT_ATTEMPTS=500 - - AUTHRATELIMIT_DURATION=30 - - OBSERVER_ACTIVE=false - - MANAGE_PARTNERS=true + # tests log in through the API many times per minute + - AUTHRATELIMIT_ATTEMPTS=200 + - AUTHRATELIMIT_DURATION=1 - MANAGE_DEPARTMENTS=true - - CIPHER_PASSWORD=dev + - MANAGE_PARTNERS=true + - MANAGE_SITES=true + - SECRET_SITES=secret-sites + - SECRET_EVENTS=secret-events + - SECRET_SENDMAILS=secret-sendmails + - MAILDEV_ACTIVE=true + - MAILDEV_URL=http://localhost:${MAILDEV_UI_PORT} + - MAILS_TRANSPORT={"host":"localhost","port":${MAILDEV_SMTP_PORT},"ignoreTLS":true} + # per recipient, stored in mongo: repeated test runs would stop the mails silently + - MAILSRATELIMIT_POINTS=100000 volumes: - ./dev/resources/users.json:/app/data/users.json - ./dev/resources/organizations.json:/app/data/organizations.json + healthcheck: + test: ["CMD", "nc", "-z", "localhost", "${SD_PORT}"] + interval: 2s + timeout: 2s + retries: 60 data-fair: - profiles: - - dev - image: ghcr.io/data-fair/data-fair:6 + image: ghcr.io/data-fair/data-fair:master + # it can start before its dependencies answer restart: on-failure:10 network_mode: host depends_on: mongo: - condition: service_started + condition: service_healthy elasticsearch: condition: service_healthy environment: - PORT=${DF_PORT} + - PUBLIC_URL=http://${DEV_HOST}:${NGINX_PORT}/data-fair + - WS_PUBLIC_URL=ws://${DEV_HOST}:${NGINX_PORT}/data-fair + - DIRECTORY_URL=http://${DEV_HOST}:${NGINX_PORT}/simple-directory + - PRIVATE_DIRECTORY_URL=http://localhost:${SD_PORT} + - PRIVATE_EVENTS_URL=http://localhost:${EVENTS_PORT} - MONGO_URL=mongodb://localhost:${MONGO_PORT}/data-fair - ES_HOST=http://localhost:${ES_PORT} - - DIRECTORY_URL=http://${DEV_HOST}:${NGINX_PORT1}/simple-directory - - PRIVATE_EVENTS_URL=http://localhost:${EVENTS_PORT} - - PRIVATE_DIRECTORY_URL=http://localhost:${SD_PORT} - - PUBLIC_URL=http://${DEV_HOST}:${NGINX_PORT1}/data-fair - - WS_PUBLIC_URL=ws://${DEV_HOST}:${NGINX_PORT1}/data-fair + # single node: with replicas the cluster stays yellow and /ping answers 500 + - ES_NB_REPLICAS=0 - OBSERVER_ACTIVE=false - - PRIVATE_PROCESSINGS_URL=http://localhost:${DEV_API_PORT} + # default: 3 koumoul.com remote services fetched at boot, extensions would call production + - REMOTE_SERVICES=[] + - CACHE_PUBLIC_MAX_AGE=1 + # one IP for every test and the portal SSR: the per-IP / per-user limits answer 429 + - DEFAULT_LIMITS_API_RATE_ANONYMOUS_NB=100000 + - DEFAULT_LIMITS_API_RATE_USER_NB=100000 + - DEFAULT_LIMITS_API_RATE_ANONYMOUS_COMPUTE_MS=0 + - DEFAULT_LIMITS_API_RATE_USER_COMPUTE_MS=0 + - DEFAULT_LIMITS_API_RATE_ANONYMOUS_BANDWIDTH_DYNAMIC=100000000 + - DEFAULT_LIMITS_API_RATE_USER_BANDWIDTH_DYNAMIC=100000000 + - WORKER_BASE_CONCURRENCY=1 + # tile cache capped collection, 2 GB by default + - CACHE_MONGO_SIZE=200 - SECRET_EVENTS=secret-events - - EXTRA_ADMIN_NAV_ITEMS=[{"id":"processingsAdminDoc","href":"http://${DEV_HOST}:${NGINX_PORT1}/openapi-viewer?urlType=processingsAdmin","icon":"mdi-cog-transfer-outline","title":"API Traitements périodiques"}] - - OPENAPI_VIEWER_URL=http://${DEV_HOST}:${NGINX_PORT1}/openapi-viewer/ + - PRIVATE_PROCESSINGS_URL=http://localhost:${DEV_API_PORT} + - EXTRA_ADMIN_NAV_ITEMS=[{"id":"processingsAdminDoc","href":"http://${DEV_HOST}:${NGINX_PORT}/openapi-viewer?urlType=processingsAdmin","icon":"mdi-cog-transfer-outline","title":"API Traitements périodiques"}] + - OPENAPI_VIEWER_URL=http://${DEV_HOST}:${NGINX_PORT}/openapi-viewer/ - OPENAPI_VIEWER_V2=true - - ##### - # optional services - ##### + volumes: + # the image declares an anonymous /data: datasets files would vanish on recreate while mongo keeps them + - data-fair-data:/data events: profiles: - - dev + - events image: ghcr.io/data-fair/events:main network_mode: host + depends_on: + - mongo environment: - PORT=${EVENTS_PORT} + - PRIVATE_DIRECTORY_URL=http://localhost:${SD_PORT} - MONGO_URL=mongodb://localhost:${MONGO_PORT}/data-fair-events - - PRIVATE_DIRECTORY_URL=http://${DEV_HOST}:${NGINX_PORT1}/simple-directory + - OBSERVER_ACTIVE=false - SECRET_IDENTITIES=secret-identities - SECRET_EVENTS=secret-events - SECRET_SENDMAILS=secret-sendmails - - OBSERVER_ACTIVE=false - openapi-viewer: - profiles: - - dev - image: ghcr.io/data-fair/openapi-viewer:master - network_mode: host - environment: - - PORT=${OAV_PORT} - - USE_SIMPLE_DIRECTORY=true - - ALLOWED_URLS={"processings":"http://${DEV_HOST}:${NGINX_PORT1}/processings/api/v1/api-docs.json","processingsId":"http://${DEV_HOST}:${NGINX_PORT1}/processings/api/v1/processings/{id}/api-docs.json","processingsAdmin":"http://${DEV_HOST}:${NGINX_PORT1}/processings/api/v1/admin/api-docs.json"} - - # registry-side dev container — same domain as processings under /registry - # so the UI can hit it directly with the SimpleDirectory session cookie. + # same domain as processings under /registry so the UI can hit it directly with the simple-directory session cookie registry: - profiles: - - dev image: ghcr.io/data-fair/registry:main network_mode: host depends_on: @@ -121,94 +132,97 @@ services: - simple-directory environment: - PORT=${REGISTRY_PORT} - - MONGO_URL=mongodb://localhost:${MONGO_PORT}/data-fair-registry + - PUBLIC_URL=http://${DEV_HOST}:${NGINX_PORT}/registry - PRIVATE_DIRECTORY_URL=http://localhost:${SD_PORT} - - PUBLIC_URL=http://${DEV_HOST}:${NGINX_PORT1}/registry - - SECRET_INTERNAL_SERVICES=secret-registry-internal - - CIPHER_PASSWORD=1234567890123456789012345678901234567890 - - API_KEYS_SALT=1234567890123456789012345678901234567890 + - MONGO_URL=mongodb://localhost:${MONGO_PORT}/data-fair-registry - OBSERVER_ACTIVE=false + - CIPHER_PASSWORD=dev-cipher-password-0123456789abcdef + - API_KEYS_SALT=dev-api-keys-salt-0123456789abcdef01 + - SECRET_INTERNAL_SERVICES=secret-registry-internal - FILES_STORAGE=fs - # /tmp is world-writable in the registry image; the container runs as - # uid 1000 ("node") and can't write to a docker-managed volume on /app/data - # without an init step. Tarballs are throwaway in dev/test so we just keep - # them inside the container and drop the named volume. + # the container runs as uid 1000 and cannot write to a docker-managed volume on /app/data; tarballs are throwaway in dev - DATA_DIR=/tmp/registry-data + ##### + # tools + ##### + + openapi-viewer: + profiles: + - openapi-viewer + image: ghcr.io/data-fair/openapi-viewer:master + network_mode: host + environment: + - PORT=${OAV_PORT} + - USE_SIMPLE_DIRECTORY=true + - ALLOWED_URLS={"processings":"http://${DEV_HOST}:${NGINX_PORT}/processings/api/v1/api-docs.json","processingsId":"http://${DEV_HOST}:${NGINX_PORT}/processings/api/v1/processings/{id}/api-docs.json","processingsAdmin":"http://${DEV_HOST}:${NGINX_PORT}/processings/api/v1/admin/api-docs.json"} + + # catches the mails of simple-directory and of the worker's own transport (plugins' sendMail) + maildev: + profiles: + - maildev + image: maildev/maildev:2.1.0 + ports: + - ${MAILDEV_UI_PORT}:1080 + - ${MAILDEV_SMTP_PORT}:1025 + # https://github.com/maildev/maildev/issues/484 + healthcheck: + test: 'wget -O - http://127.0.0.1:$${MAILDEV_WEB_PORT}$${MAILDEV_BASE_PATHNAME}/healthz || exit 1' + ##### # db and search engine ##### elasticsearch: - profiles: - - dev - image: ghcr.io/data-fair/elasticsearch:7.x + image: ghcr.io/data-fair/elasticsearch:8.19.9 ports: - ${ES_PORT}:9200 environment: - discovery.type=single-node - xpack.security.enabled=false - - ES_HEAP_SIZE=128m - - "ES_JAVA_OPTS=-Xms128m -Xmx128m -server" + - ingest.geoip.downloader.enabled=false + # features the services never use, skipped to lighten the boot + - xpack.ml.enabled=false + - xpack.watcher.enabled=false + - stack.templates.enabled=false + - cluster.deprecation_indexing.enabled=false + # heap starts at 64m and grows up to 512m (pre-touching a fixed 512m cost ~360m per idle stack) + - ES_JAVA_OPTS=-Xms64m -Xmx512m volumes: - elasticsearch-data:/usr/share/elasticsearch/data healthcheck: test: ["CMD", "curl", "-f", "http://localhost:9200"] - start_period: 10s - timeout: 5s - interval: 2s - retries: 50 + # 2 s probes while starting (df-dev wait-deps gives up after 3 min), then one per minute + interval: 60s + timeout: 10s + retries: 3 + start_period: 3m + start_interval: 2s + mem_limit: 2g + # no swap: an idle ES got 1.7 GB swapped out + memswap_limit: 2g + # halves the boot CPU burst (ES sizes its thread pools, GC and JIT threads to the quota) + cpus: 2 mongo: - profiles: - - dev - image: mongo:4.2 + # production version; later 8.0 patches refuse Ubuntu 7.0 kernels (https://jira.mongodb.org/browse/SERVER-136848) + image: mongo:8.0.17 ports: - ${MONGO_PORT}:27017 + # wiredTiger takes half the machine's RAM by default + command: ["--wiredTigerCacheSizeGB", "0.25"] volumes: - mongo-data:/data/db - - ##### - # Api and worker in docker mode - ##### - - main: - build: - context: . - dockerfile: Dockerfile - target: main - args: - NODE_ENV: development - depends_on: - - data-fair - profiles: - - testImages - image: datafair/processings/main:dev - network_mode: host - environment: - - NODE_ENV=development - volumes: - - processings-data:/app/data - - worker: - build: - context: . - dockerfile: Dockerfile - target: worker - args: - NODE_ENV: development - depends_on: - - data-fair - profiles: - - testImages - image: datafair/processings/worker:dev - network_mode: host - environment: - - NODE_ENV=development - volumes: - - processings-data:/app/data + healthcheck: + test: ["CMD", "mongosh", "--quiet", "--eval", "db.runCommand({ ping: 1 }).ok"] + # 2 s probes while starting, then one per minute: a mongosh probe costs ~1.3 s of CPU + interval: 60s + timeout: 10s + retries: 3 + start_period: 3m + start_interval: 2s volumes: elasticsearch-data: mongo-data: - processings-data: + data-fair-data: diff --git a/docs/architecture/v6-registry-integration.md b/docs/architecture/v6-registry-integration.md index 5088d74d..6dadd621 100644 --- a/docs/architecture/v6-registry-integration.md +++ b/docs/architecture/v6-registry-integration.md @@ -261,7 +261,7 @@ registry: - PORT=${REGISTRY_PORT} - MONGO_URL=mongodb://localhost:${MONGO_PORT}/data-fair-registry - PRIVATE_DIRECTORY_URL=http://localhost:${SD_PORT} - - PUBLIC_URL=http://${DEV_HOST}:${NGINX_PORT1}/registry + - PUBLIC_URL=http://${DEV_HOST}:${NGINX_PORT}/registry - SECRET_INTERNAL_SERVICES=secret-registry-internal - OBSERVER_ACTIVE=false - STORAGE_TYPE=fs diff --git a/eslint.config.mjs b/eslint.config.mjs index 97a5088e..187ca837 100644 --- a/eslint.config.mjs +++ b/eslint.config.mjs @@ -2,7 +2,7 @@ import neostandard from 'neostandard' import dfLibRecommended from '@data-fair/lib-utils/eslint/recommended.js' export default [ - { ignores: ['ui/*', '**/.type/', 'data/'] }, + { ignores: ['ui/', '**/.type/', 'data/'] }, ...dfLibRecommended, ...neostandard({ ts: true }) ] diff --git a/package-lock.json b/package-lock.json index 0086224f..84acf8ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,25 +15,26 @@ "shared" ], "dependencies": { - "@data-fair/lib-types-builder": "^1.14.3" + "@data-fair/lib-types-builder": "^1.14.5" }, "devDependencies": { + "@commitlint/cli": "^21.2.3", "@commitlint/config-conventional": "^21.2.3", "@data-fair/lib-common-types": "^1.23.0", - "@data-fair/lib-node": "~2.15.0", - "@data-fair/lib-utils": "^1.13.1", + "@data-fair/lib-dev": "^0.1.0", + "@data-fair/lib-node": "^2.16.1", + "@data-fair/lib-utils": "^1.14.0", "@playwright/test": "^1.52.0", "@types/config": "^3.3.5", "@types/debug": "^4.1.12", - "commitlint": "^21.2.3", "dotenv": "^16.4.5", "dotenv-cli": "^7.4.4", - "eslint": "^9.35.0", - "eslint-plugin-vue": "^10.4.0", - "eslint-plugin-vuetify": "^2.7.2", + "eslint": "^10.12.0", + "eslint-plugin-vue": "^10.11.1", + "eslint-plugin-vuetify": "^2.7.3", "form-data": "^4.0.6", "husky": "^9.1.7", - "neostandard": "^0.12.2", + "neostandard": "^0.14.1", "nodemon": "^3.1.14", "tough-cookie": "^5.0.0", "typescript": "^6.0.3" @@ -44,8 +45,8 @@ }, "api": { "dependencies": { - "@data-fair/lib-express": "~1.28.1", - "@data-fair/lib-node": "~2.15.0", + "@data-fair/lib-express": "^1.31.0", + "@data-fair/lib-node": "^2.16.1", "@data-fair/lib-node-registry": "0.7.2", "@data-fair/lib-utils": "^1.13.1", "@data-fair/lib-validation": "^1.0.2", @@ -190,6 +191,28 @@ "integrity": "sha512-FWa0sPlqYGJgpTs6OxBRcL/AW4JT0OIO+W1ajerluoTVh8CV0B7XM1qsNCRgnkSCkRCgOICKHRQlY17jrsm0+Q==", "license": "(Apache-2.0 AND BSD-3-Clause)" }, + "node_modules/@cacheable/memory": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@cacheable/memory/-/memory-2.2.0.tgz", + "integrity": "sha512-CTLKqLItRCEixEAewD3/j9DB3/o96gpTPD4eJ1v+DGOlxZRZncRQkGYqqnAGCscYd6RNeXfGeiuCphsPtqyIfQ==", + "license": "MIT", + "dependencies": { + "@cacheable/utils": "^2.5.0", + "@keyv/bigmap": "^1.3.1", + "hookified": "^1.15.1", + "keyv": "^5.6.0" + } + }, + "node_modules/@cacheable/utils": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cacheable/utils/-/utils-2.5.0.tgz", + "integrity": "sha512-buipgOVDkkPXNR5+xBpDw7Zk2n1EvU7qBJCNUcL7rhQ//kfpOXPAvQ511Os0vpLYJ1pZnvudNytkQt2hst3wqA==", + "license": "MIT", + "dependencies": { + "hashery": "^1.5.1", + "keyv": "^5.6.0" + } + }, "node_modules/@commitlint/cli": { "version": "21.2.3", "resolved": "https://registry.npmjs.org/@commitlint/cli/-/cli-21.2.3.tgz", @@ -485,9 +508,9 @@ "license": "MIT" }, "node_modules/@data-fair/lib-common-types": { - "version": "1.24.0", - "resolved": "https://registry.npmjs.org/@data-fair/lib-common-types/-/lib-common-types-1.24.0.tgz", - "integrity": "sha512-RhK90AKeDqfE6gIb5WLZQAPnv0Zx9Q+gKulNIQTDyF8e/BrDwsrhHzYdu4YZ+WfhUbmlMEWhcDtBaG/LMNUeEQ==", + "version": "1.25.0", + "resolved": "https://registry.npmjs.org/@data-fair/lib-common-types/-/lib-common-types-1.25.0.tgz", + "integrity": "sha512-yeXxh8+F028v+z5Mp45Bg5yjAPaACbosNSRWa4bYwbNTo5Dhg/GPt17TNU1UtuxGCnGe+69z41GO5nctOi1udw==", "license": "MIT", "dependencies": { "@data-fair/lib-utils": "^1.6.1", @@ -503,13 +526,30 @@ } } }, + "node_modules/@data-fair/lib-dev": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/@data-fair/lib-dev/-/lib-dev-0.1.0.tgz", + "integrity": "sha512-jyhqdR7XM3eRhP0XoYB79WXC6f/sStA3kNkjw5qNyBfs57hprgL1hEE4XjoFekaqRQPyjH3G+EAFJ//VQ8uqfg==", + "dev": true, + "license": "MIT", + "dependencies": { + "commander": "^12.1.0" + }, + "bin": { + "df-dev": "cli.js", + "df-mem-cap": "mem-cap.sh", + "df-status": "status-pane.sh", + "df-worktree": "worktree.sh", + "df-worktree-delete": "worktree-delete.sh" + } + }, "node_modules/@data-fair/lib-express": { - "version": "1.28.1", - "resolved": "https://registry.npmjs.org/@data-fair/lib-express/-/lib-express-1.28.1.tgz", - "integrity": "sha512-WVNwEBOPJgwb/1Z/IIJ+Byl5/8mX3jBBTzXWb+c/TvYktkUXexNShyCtaCRy1zcYkAQqCuvGrQ1srg6ur5ohUw==", + "version": "1.31.0", + "resolved": "https://registry.npmjs.org/@data-fair/lib-express/-/lib-express-1.31.0.tgz", + "integrity": "sha512-yeUZ0v9iYezjsqQK2CXbX4+jajXMiMgG7w50xISJmWJb+CRQKgz4+MlITzUdHJQVPsRrXKduQ0YjRSvuwV+E2A==", "license": "MIT", "dependencies": { - "@data-fair/lib-common-types": "^1.7.1", + "@data-fair/lib-common-types": "^1.25.0", "cookie": "^0.7.2", "jsonwebtoken": "^9.0.2", "jwks-rsa": "^3.1.0", @@ -517,7 +557,7 @@ "serialize-javascript": "^7.0.0" }, "peerDependencies": { - "@data-fair/lib-node": "^2.15.0", + "@data-fair/lib-node": "^2.16.0", "express": "5", "ws": "8" }, @@ -546,12 +586,12 @@ } }, "node_modules/@data-fair/lib-node": { - "version": "2.15.0", - "resolved": "https://registry.npmjs.org/@data-fair/lib-node/-/lib-node-2.15.0.tgz", - "integrity": "sha512-eNnjYry7NxbViNCbADz76daKSW7/zxMffTvYMxtnnXbNbZcR6rCjq05BzxLZf8hYIoqgYTMfbBR6jUh5tu5HbA==", + "version": "2.16.1", + "resolved": "https://registry.npmjs.org/@data-fair/lib-node/-/lib-node-2.16.1.tgz", + "integrity": "sha512-Xwl1s6JHXGMNBWWNg3vTdh5/bjrwReRxSf2AgMtdPxxnQLVrBmAuy6oqORldjJbyCtGRqT10fGRFP7IDUx6NyA==", "license": "MIT", "dependencies": { - "@data-fair/lib-common-types": "^1.8.4", + "@data-fair/lib-common-types": "^1.25.0", "@data-fair/lib-utils": "^1.1.0", "@data-fair/lib-validation": "^1.0.0", "agentkeepalive": "^4.5.0", @@ -600,9 +640,9 @@ } }, "node_modules/@data-fair/lib-types-builder": { - "version": "1.14.4", - "resolved": "https://registry.npmjs.org/@data-fair/lib-types-builder/-/lib-types-builder-1.14.4.tgz", - "integrity": "sha512-uR6IbUvCyuOKsqMKtkrYojSBbq2MXxnZTqtfPYVAAnDVFEWICSuW4hnLPIS8JXNEuUsHj+A6yVFU24qhiLMdUQ==", + "version": "1.14.5", + "resolved": "https://registry.npmjs.org/@data-fair/lib-types-builder/-/lib-types-builder-1.14.5.tgz", + "integrity": "sha512-OQEBFA+ew0+1HvNVVbOvyogtf7CQUZATLfIEj+snbqDe0CjgAZDqfCK36bpDHmqsUKqEr43eOMtUYBITRNENUA==", "license": "MIT", "dependencies": { "@bcherny/json-schema-ref-parser": "^10.0.5-fork", @@ -709,40 +749,6 @@ "resolved": "shared", "link": true }, - "node_modules/@emnapi/core": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.10.0.tgz", - "integrity": "sha512-yq6OkJ4p82CAfPl0u9mQebQHKPJkY7WrIuk205cTYnYe+k2Z8YBh11FrbRG/H6ihirqcacOgl2BIO8oyMQLeXw==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.10.0.tgz", - "integrity": "sha512-ewvYlk86xUoGI0zQRNq/mC+16R1QeDlKQy21Ki3oSYXNgLb45GV1P6A0M+/s6nyCuNDqe5VpaY84BzXGwVbwFA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/wasi-threads": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", - "integrity": "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@eslint-community/eslint-utils": { "version": "4.10.1", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.10.1.tgz", @@ -783,120 +789,63 @@ } }, "node_modules/@eslint/config-array": { - "version": "0.21.2", - "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.21.2.tgz", - "integrity": "sha512-nJl2KGTlrf9GjLimgIru+V/mzgSK0ABCDQRvxw5BjURL7WfH5uoWmizbH7QB6MmnMBd8cIC9uceWnezL1VZWWw==", + "version": "0.23.5", + "resolved": "https://registry.npmjs.org/@eslint/config-array/-/config-array-0.23.5.tgz", + "integrity": "sha512-Y3kKLvC1dvTOT+oGlqNQ1XLqK6D1HU2YXPc52NmAlJZbMMWDzGYXMiPRJ8TYD39muD/OTjlZmNJ4ib7dvSrMBA==", "license": "Apache-2.0", "dependencies": { - "@eslint/object-schema": "^2.1.7", + "@eslint/object-schema": "^3.0.5", "debug": "^4.3.1", - "minimatch": "^3.1.5" + "minimatch": "^10.2.4" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/config-helpers": { - "version": "0.4.2", - "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.4.2.tgz", - "integrity": "sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw==", + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@eslint/config-helpers/-/config-helpers-0.7.0.tgz", + "integrity": "sha512-DObd/KKUsU+FaFv4PLxSRenpXfQWmPXXP3pPZ6/K1PCrMu2vQpMDMuQe/BqYeoLcz8ro0bVDF1RxOJgfVEdhUw==", "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0" + "@eslint/core": "^1.2.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/core": { - "version": "0.17.0", - "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.17.0.tgz", - "integrity": "sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ==", + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eslint/core/-/core-1.2.1.tgz", + "integrity": "sha512-MwcE1P+AZ4C6DWlpin/OmOA54mmIZ/+xZuJiQd4SyB29oAJjN30UW9wkKNptW2ctp4cEsvhlLY/CsQ1uoHDloQ==", "license": "Apache-2.0", "dependencies": { "@types/json-schema": "^7.0.15" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - } - }, - "node_modules/@eslint/eslintrc": { - "version": "3.3.7", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.3.7.tgz", - "integrity": "sha512-F42g89Qd5oAWtp0k0nnSrjziAKza7w8SVT4mStc18LZMaRb4J1HQAHLCalEtDCxrTuksx7NU9qsmeLwpOfPqWw==", - "license": "MIT", - "dependencies": { - "ajv": "^6.14.0", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.3.2", - "minimatch": "^3.1.5", - "strip-json-comments": "^3.1.1" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" - } - }, - "node_modules/@eslint/eslintrc/node_modules/ajv": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.15.0.tgz", - "integrity": "sha512-fgFx7Hfoq60ytK2c7DhnF8jIvzYgOMxfugjLOSMHjLIPgenqa7S7oaagATUq99mV6IYvN2tRmC0wnTYX6iPbMw==", - "license": "MIT", - "dependencies": { - "fast-deep-equal": "^3.1.1", - "fast-json-stable-stringify": "^2.0.0", - "json-schema-traverse": "^0.4.1", - "uri-js": "^4.2.2" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/epoberezkin" - } - }, - "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", - "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", - "license": "MIT" - }, - "node_modules/@eslint/js": { - "version": "9.39.5", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.39.5.tgz", - "integrity": "sha512-QywQuszQh77pIXCsq998c8hbhSTI/azTty1Z6N53dmAudKHhy573j3yvRLsX2BSp8YpLtoCEG8E9DJe+8zUh4A==", - "license": "MIT", - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://eslint.org/donate" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/object-schema": { - "version": "2.1.7", - "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-2.1.7.tgz", - "integrity": "sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA==", + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@eslint/object-schema/-/object-schema-3.0.5.tgz", + "integrity": "sha512-vqTaUEgxzm+YDSdElad6PiRoX4t8VGDjCtt05zn4nU810UIx/uNEV7/lZJ6KwFThKZOzOxzXy48da+No7HZaMw==", "license": "Apache-2.0", "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@eslint/plugin-kit": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz", - "integrity": "sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA==", + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/@eslint/plugin-kit/-/plugin-kit-0.7.3.tgz", + "integrity": "sha512-IkO+/KEUvwbVpiURZg+P7zF74z5Jxe0UgJxVni+RtoHQ6IZieXaO02kmadomap/q+l6bc/jdPGGqTjhuZnuz1Q==", "license": "Apache-2.0", "dependencies": { - "@eslint/core": "^0.17.0", + "@eslint/core": "^1.2.1", "levn": "^0.4.1" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" } }, "node_modules/@humanfs/core": { @@ -1741,6 +1690,28 @@ "debug": "^4.3.4" } }, + "node_modules/@keyv/bigmap": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@keyv/bigmap/-/bigmap-1.3.1.tgz", + "integrity": "sha512-WbzE9sdmQtKy8vrNPa9BRnwZh5UF4s1KTmSK0KUVLo3eff5BlQNNWDnFOouNpKfPKDnms9xynJjsMYjMaT/aFQ==", + "license": "MIT", + "dependencies": { + "hashery": "^1.4.0", + "hookified": "^1.15.0" + }, + "engines": { + "node": ">= 18" + }, + "peerDependencies": { + "keyv": "^5.6.0" + } + }, + "node_modules/@keyv/serialize": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@keyv/serialize/-/serialize-1.1.1.tgz", + "integrity": "sha512-dXn3FZhPv0US+7dtJsIi2R+c7qWYiReoEh5zUntWCf4oSpMNib8FDhSoed6m3QyZdx5hK7iLFkYk3rNxwt8vTA==", + "license": "MIT" + }, "node_modules/@koumoul/vjsf": { "version": "4.6.1", "resolved": "https://registry.npmjs.org/@koumoul/vjsf/-/vjsf-4.6.1.tgz", @@ -1808,28 +1779,6 @@ "sparse-bitfield": "^3.0.3" } }, - "node_modules/@napi-rs/wasm-runtime": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.2.5.tgz", - "integrity": "sha512-HshSvXzmBxNzqejd3k/KemgQ3hdREUYFRRrgxOZ+gPljDIsO2SDZrVZMd4Z/HsxudQbE62OVyVFE8z9BCurfjA==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@tybys/wasm-util": "^0.10.3" - }, - "engines": { - "node": "^20.19.0 || ^22.13.0 || >=23.5.0" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Brooooooklyn" - }, - "peerDependencies": { - "@emnapi/core": "^1.7.1 || ^2.0.0-alpha.4", - "@emnapi/runtime": "^1.7.1 || ^2.0.0-alpha.4" - } - }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -1865,16 +1814,6 @@ "node": ">= 8" } }, - "node_modules/@nolyfill/is-core-module": { - "version": "1.0.39", - "resolved": "https://registry.npmjs.org/@nolyfill/is-core-module/-/is-core-module-1.0.39.tgz", - "integrity": "sha512-nn5ozdjYQpUCZlWGuxcJY/KpxkWQs4DcbMCmKojjyrYDEAGy4Ce19NN4v5MduafTwJlbKc99UA8YhSVqq9yPZA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.4.0" - } - }, "node_modules/@opentelemetry/api": { "version": "1.9.1", "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.9.1.tgz", @@ -2518,34 +2457,24 @@ } }, "node_modules/@stylistic/eslint-plugin": { - "version": "2.11.0", - "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-2.11.0.tgz", - "integrity": "sha512-PNRHbydNG5EH8NK4c+izdJlxajIR6GxcUhzsYNRsn6Myep4dsZt0qFCz3rCPnkvgO5FYibDcMqgNHUT+zvjYZw==", + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/@stylistic/eslint-plugin/-/eslint-plugin-5.10.0.tgz", + "integrity": "sha512-nPK52ZHvot8Ju/0A4ucSX1dcPV2/1clx0kLcH5wDmrE4naKso7TUC/voUyU1O9OTKTrR6MYip6LP0ogEMQ9jPQ==", "dev": true, "license": "MIT", "dependencies": { - "@typescript-eslint/utils": "^8.13.0", - "eslint-visitor-keys": "^4.2.0", - "espree": "^10.3.0", + "@eslint-community/eslint-utils": "^4.9.1", + "@typescript-eslint/types": "^8.56.0", + "eslint-visitor-keys": "^4.2.1", + "espree": "^10.4.0", "estraverse": "^5.3.0", - "picomatch": "^4.0.2" + "picomatch": "^4.0.3" }, "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" }, "peerDependencies": { - "eslint": ">=8.40.0" - } - }, - "node_modules/@tybys/wasm-util": { - "version": "0.10.4", - "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.4.tgz", - "integrity": "sha512-W3c4gRigFS0T/Ma4qIYF3GDAc5AQdHb1yL5znJT1Zv1YaD9Kitx656wBjvr19qbiosmZT8lWDM5BEMynUqX65A==", - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "tslib": "^2.4.0" + "eslint": "^9.0.0 || ^10.0.0" } }, "node_modules/@types/body-parser": { @@ -2592,6 +2521,12 @@ "@types/ms": "*" } }, + "node_modules/@types/esrecurse": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/@types/esrecurse/-/esrecurse-4.3.1.tgz", + "integrity": "sha512-xJBAbDifo5hpffDBuHl0Y8ywswbiAp/Wi7Y/GtAgSlZyIABppyurxVueOPE8LUQOxdlgi6Zqce7uoEpqNTeiUw==", + "license": "MIT" + }, "node_modules/@types/estree": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", @@ -2962,42 +2897,6 @@ "typescript": ">=4.8.4 <6.1.0" } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", - "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.8" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/utils": { "version": "8.71.1", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.71.1.tgz", @@ -3051,395 +2950,52 @@ "url": "https://opencollective.com/eslint" } }, - "node_modules/@unrs/resolver-binding-android-arm-eabi": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm-eabi/-/resolver-binding-android-arm-eabi-1.12.2.tgz", - "integrity": "sha512-g5T90pqg1bo/7mytQx6F4iBNC0Wsh9cu+z9veDbFjc7HjpesJFWD7QMS0NGStXM075+7dJPPVvBbpZlnrdpi/w==", - "cpu": [ - "arm" - ], - "dev": true, + "node_modules/@vitejs/plugin-vue": { + "version": "6.0.9", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.9.tgz", + "integrity": "sha512-rD/MORlhaZMlXWW0rEn4FB4wMinWC0z/D7Ye160S5+Rs1mC8ZDAdcDp4SjKfUhG5t8q1ktcPVw4xuTkPRlzrSA==", "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "dependencies": { + "@rolldown/pluginutils": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", + "vue": "^3.2.25" + } }, - "node_modules/@unrs/resolver-binding-android-arm64": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-android-arm64/-/resolver-binding-android-arm64-1.12.2.tgz", - "integrity": "sha512-YGCRZv/9GLhwmz6mYDeTsm/92BAyR28l6c2ReweVW5pWgfsitWLY8upvfRlGdoyD8HjeTHSYJWyZGD4KJA/nFQ==", - "cpu": [ - "arm64" - ], - "dev": true, + "node_modules/@volar/language-core": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", + "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", "license": "MIT", - "optional": true, - "os": [ - "android" - ] + "dependencies": { + "@volar/source-map": "2.4.28" + } }, - "node_modules/@unrs/resolver-binding-darwin-arm64": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-1.12.2.tgz", - "integrity": "sha512-u9DiNT1auQMO20A9SyTuG3wUgQWB9Z7KjAg0uFuCDR1FsAY8A0CG2S6JpHS1xwm/w1G08bjXZDcyOCjv1WAm2w==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "node_modules/@volar/source-map": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", + "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", + "license": "MIT" }, - "node_modules/@unrs/resolver-binding-darwin-x64": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-1.12.2.tgz", - "integrity": "sha512-f7rPLi/T1HVKZu/u6t87lroib16n8vrSzcyxI7lg4BGO9UF26KhQL44sd9eOUgrTYhvRXtWOIZT5PejdPyJfUA==", - "cpu": [ - "x64" - ], - "dev": true, + "node_modules/@volar/typescript": { + "version": "2.4.28", + "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", + "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", "license": "MIT", - "optional": true, - "os": [ - "darwin" - ] + "dependencies": { + "@volar/language-core": "2.4.28", + "path-browserify": "^1.0.1", + "vscode-uri": "^3.0.8" + } }, - "node_modules/@unrs/resolver-binding-freebsd-x64": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-freebsd-x64/-/resolver-binding-freebsd-x64-1.12.2.tgz", - "integrity": "sha512-BpcOjWCJub6nRZUS2zA20pmLvjtqAtGejETaIyRLiZiQf++cbrjltLA5NN/xaXfqeOBOSlMFbemIl5/S5tljmg==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "freebsd" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-gnueabihf": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-gnueabihf/-/resolver-binding-linux-arm-gnueabihf-1.12.2.tgz", - "integrity": "sha512-vZTDvdSISZjJx66OzJqtsOhzifbqRjbmI1Mnu49fQDwog5GtDI4QidRiEAYbZCRj9C8YZEW+3ZjqsyS9GR4k2A==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm-musleabihf": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm-musleabihf/-/resolver-binding-linux-arm-musleabihf-1.12.2.tgz", - "integrity": "sha512-BiPI+IrIlwcW4nLLMM21+B1dFPzd55yAVgVGrdgDjNef+ch03GdxrcyaIz8X9SsQirh/kCQ7mviyWlMxdh2D7g==", - "cpu": [ - "arm" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-1.12.2.tgz", - "integrity": "sha512-zJc0H99FEPoFfSrNpa91HYfxzfAJCr502oxNK1cfdC9hlaFI43RT+JFCann9JUgZmLzzntChHyn13Sgn9ljHNg==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-arm64-musl": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-1.12.2.tgz", - "integrity": "sha512-KQ3Lki6l+Pz1k/eBipN41ES+YUK30beLGb9YqcB1O542cyLCNE6GaxrfcY3T6EezmGGk84wb5XyO9loTM9tkcA==", - "cpu": [ - "arm64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-loong64-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-gnu/-/resolver-binding-linux-loong64-gnu-1.12.2.tgz", - "integrity": "sha512-3SJGEh1DborhG6pyxvhPzCT4bbSIVihsvgJc13P1bHG7KLdNDaF9T3gsTwFc7Jw/5Y5/iWOjkEx7Zy0NvCGX3Q==", - "cpu": [ - "loong64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-loong64-musl": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-loong64-musl/-/resolver-binding-linux-loong64-musl-1.12.2.tgz", - "integrity": "sha512-jiuG/Obbel7uw1PwHNFfrkiKhLAF6mnyZ6aWlOAVN9WqKm8v0OFGnciJIHu8+CMvXLQ8AD51LPzAoUfT21D5Ew==", - "cpu": [ - "loong64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-ppc64-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-ppc64-gnu/-/resolver-binding-linux-ppc64-gnu-1.12.2.tgz", - "integrity": "sha512-q7xRvVpmcfeL+LlZg8Pbbo6QaTZwDU5BaGZbwfhkEsXJn3Was8xYfE0RBH266xZt0rM6B7i8xAYIvjthuUIWHg==", - "cpu": [ - "ppc64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-gnu/-/resolver-binding-linux-riscv64-gnu-1.12.2.tgz", - "integrity": "sha512-0CVdx6lcnT3Q9inOH8tsMIOJ6ImndllMjqJHg8RLVdB7Vq4SfkEXl9mCSsVNuNA4MCYycRicCUxPCabVHJRr6A==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-riscv64-musl": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-riscv64-musl/-/resolver-binding-linux-riscv64-musl-1.12.2.tgz", - "integrity": "sha512-iOwlRo9vnp6R6ohHQS11n0NnfdXx/omhkocmIfaPRpQhKZ+3BDMkkdRVh53qjkFkpPddf+FETA28NwGN7l5l+w==", - "cpu": [ - "riscv64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-s390x-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-s390x-gnu/-/resolver-binding-linux-s390x-gnu-1.12.2.tgz", - "integrity": "sha512-HYJtLfXq94q8iZNFT1lknx258wlkkWhZeUXJRqzKBBUJ00CvZ+N33zgbCqimLjsyw5Va6uUxhVa12mI+kaveEw==", - "cpu": [ - "s390x" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-gnu": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-1.12.2.tgz", - "integrity": "sha512-mPsUhunKKDih5O96Y6enDQyHc1SqBPlY1E/SfMWDM3EdJ95Z9CArPeCVwCCqbP45ljvivdEk8Fxn+SIb1rDAJQ==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "glibc" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-linux-x64-musl": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-1.12.2.tgz", - "integrity": "sha512-azrt6+5ydLd8Vt210AAFis/lZevSfPw93EJRIJG+xPu4WCJ8K0kppCTpMyLPcKT7H15M4Jnt2tMp5bOvCkRC6A==", - "cpu": [ - "x64" - ], - "dev": true, - "libc": [ - "musl" - ], - "license": "MIT", - "optional": true, - "os": [ - "linux" - ] - }, - "node_modules/@unrs/resolver-binding-openharmony-arm64": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-openharmony-arm64/-/resolver-binding-openharmony-arm64-1.12.2.tgz", - "integrity": "sha512-YZ9hP4O0X9PQb8eO980qmLNGH4zT3I9+SZTdt0Pr0YyuGQhYKoOZkV02VzrzyOZJ5xIJ3UFIenKkUkGg8GjgWQ==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "openharmony" - ] - }, - "node_modules/@unrs/resolver-binding-wasm32-wasi": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-1.12.2.tgz", - "integrity": "sha512-tYFDIkMxSflfEc/h92ZWNsZlHSwgimbNHSO3PL2JWQHfCuC2q316jMyYU9TIWZsFK2bQwyK5VAdYgn8ygPj69A==", - "cpu": [ - "wasm32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "dependencies": { - "@emnapi/core": "1.10.0", - "@emnapi/runtime": "1.10.0", - "@napi-rs/wasm-runtime": "^1.1.4" - }, - "engines": { - "node": ">=14.0.0" - } - }, - "node_modules/@unrs/resolver-binding-win32-arm64-msvc": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-1.12.2.tgz", - "integrity": "sha512-qzNyg3xL0VPQmCaUh+N5jSitce6k+uCBfMDesWRnlULOZaqUkaJ0ybdT+UqlAWJoQjuqfIU/0Ptx9bteN4D82g==", - "cpu": [ - "arm64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-ia32-msvc": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-1.12.2.tgz", - "integrity": "sha512-WD9sY00OfpHVGfsnHZoA8jVT+esS/Bg8z8jzxp5BnDCjjwsuKsPQrzswwpFy4J1AUJbXPRfkpcX0mXrzeXW79g==", - "cpu": [ - "ia32" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@unrs/resolver-binding-win32-x64-msvc": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/@unrs/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-1.12.2.tgz", - "integrity": "sha512-nAB74NfSNKknqQ1RrYj6uz8FcXEomu/MATJZxh/x+BArzN2U3JbOYC0APYzUIGhVY3m5hRxA8VPNdPBoG8txlA==", - "cpu": [ - "x64" - ], - "dev": true, - "license": "MIT", - "optional": true, - "os": [ - "win32" - ] - }, - "node_modules/@vitejs/plugin-vue": { - "version": "6.0.9", - "resolved": "https://registry.npmjs.org/@vitejs/plugin-vue/-/plugin-vue-6.0.9.tgz", - "integrity": "sha512-rD/MORlhaZMlXWW0rEn4FB4wMinWC0z/D7Ye160S5+Rs1mC8ZDAdcDp4SjKfUhG5t8q1ktcPVw4xuTkPRlzrSA==", - "license": "MIT", - "dependencies": { - "@rolldown/pluginutils": "^1.0.1" - }, - "engines": { - "node": "^20.19.0 || >=22.12.0" - }, - "peerDependencies": { - "vite": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0", - "vue": "^3.2.25" - } - }, - "node_modules/@volar/language-core": { - "version": "2.4.28", - "resolved": "https://registry.npmjs.org/@volar/language-core/-/language-core-2.4.28.tgz", - "integrity": "sha512-w4qhIJ8ZSitgLAkVay6AbcnC7gP3glYM3fYwKV3srj8m494E3xtrCv6E+bWviiK/8hs6e6t1ij1s2Endql7vzQ==", - "license": "MIT", - "dependencies": { - "@volar/source-map": "2.4.28" - } - }, - "node_modules/@volar/source-map": { - "version": "2.4.28", - "resolved": "https://registry.npmjs.org/@volar/source-map/-/source-map-2.4.28.tgz", - "integrity": "sha512-yX2BDBqJkRXfKw8my8VarTyjv48QwxdJtvRgUpNE5erCsgEUdI2DsLbpa+rOQVAJYshY99szEcRDmyHbF10ggQ==", - "license": "MIT" - }, - "node_modules/@volar/typescript": { - "version": "2.4.28", - "resolved": "https://registry.npmjs.org/@volar/typescript/-/typescript-2.4.28.tgz", - "integrity": "sha512-Ja6yvWrbis2QtN4ClAKreeUZPVYMARDYZl9LMEv1iQ1QdepB6wn0jTRxA9MftYmYa4DQ4k/DaSZpFPUfxl8giw==", - "license": "MIT", - "dependencies": { - "@volar/language-core": "2.4.28", - "path-browserify": "^1.0.1", - "vscode-uri": "^3.0.8" - } - }, - "node_modules/@vue-macros/common": { - "version": "3.1.4", - "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.4.tgz", - "integrity": "sha512-/5Fv+6DgIcM9ajY05ZmKBv+LMX1M9A0X+IUwDRVdt67ciw8OV9bvG2r34p3RiEadlsQybjhKPRKNXDC8Bp23cw==", + "node_modules/@vue-macros/common": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@vue-macros/common/-/common-3.1.4.tgz", + "integrity": "sha512-/5Fv+6DgIcM9ajY05ZmKBv+LMX1M9A0X+IUwDRVdt67ciw8OV9bvG2r34p3RiEadlsQybjhKPRKNXDC8Bp23cw==", "license": "MIT", "dependencies": { "@vue/compiler-sfc": "^3.5.22", @@ -3862,15 +3418,13 @@ } }, "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==", + "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", - "dependencies": { - "color-convert": "^2.0.1" - }, "engines": { - "node": ">=8" + "node": ">=12" }, "funding": { "url": "https://github.com/chalk/ansi-styles?sponsor=1" @@ -3926,144 +3480,6 @@ "url": "https://ko-fi.com/dangreen" } }, - "node_modules/array-buffer-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.2.tgz", - "integrity": "sha512-LHE+8BuR7RYGDKvnrmcuSq3tDcKv9OFEXQt/HpbZhY7V6h0zlUXutnAD82GiFx9rdieCMjkvtcsPqBwgUl1Iiw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "is-array-buffer": "^3.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array-includes": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.2.0.tgz", - "integrity": "sha512-VXY5eFRarnXcYxwBjJzPmEhH55+rmP79/+ueDhi0F+TuqfHCItagIHqxeUZrmgrOPa31QTh9H85DjX3FfJ0FTg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.2", - "es-object-atoms": "^1.1.2", - "es-shim-unscopables": "^1.1.0", - "is-string": "^1.1.1", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.findlast": { - "version": "1.2.5", - "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", - "integrity": "sha512-CVvd6FHg1Z3POpBLxO6E6zr+rSKEQ9L6rZHAaY7lLfhKsWYUBBOuMs0e9o24oopj6H+geRCX0YJ+TJLBK2eHyQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flat": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.3.3.tgz", - "integrity": "sha512-rwG/ja1neyLqCuGZ5YYrznA62D4mZXg0i1cIskIUKSiqF3Cje9/wXAls9B9s1Wa2fomMsIv8czB8jZcPmxCXFg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.flatmap": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/array.prototype.flatmap/-/array.prototype.flatmap-1.3.3.tgz", - "integrity": "sha512-Y7Wt51eKJSyi80hFrJCePGGNo5ktJCslFuboqJsbf57CCPcm5zztluPlc4/aD8sWsKvlwatezpV4U1efk8kpjg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/array.prototype.tosorted": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/array.prototype.tosorted/-/array.prototype.tosorted-1.1.4.tgz", - "integrity": "sha512-p6Fx8B7b7ZhL/gmUsAy0D15WhvDccw3mnGNbZpi3pmeJdxtWsj2jEaI4Y6oo3XiHfzuSgPwKc04MYt6KgvC/wA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.3", - "es-errors": "^1.3.0", - "es-shim-unscopables": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/arraybuffer.prototype.slice": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/arraybuffer.prototype.slice/-/arraybuffer.prototype.slice-1.0.4.tgz", - "integrity": "sha512-BNoCY6SXXPQ7gF2opIP4GBE+Xw7U+pHMYKuzjgCN3GwiaIR09UUeKfheyIry77QtrCBlC0KK0q5/TER/tYh3PQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.1", - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.5", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6", - "is-array-buffer": "^3.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/ast-kit": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/ast-kit/-/ast-kit-2.2.0.tgz", @@ -4097,38 +3513,12 @@ "url": "https://github.com/sponsors/sxzz" } }, - "node_modules/async-function": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/async-function/-/async-function-1.0.0.tgz", - "integrity": "sha512-hsU18Ae8CDTR6Kgu9DYf0EbCr/a5iGL0rytQDobUcdpYOKokk8LEjVphnXkDkgpi0wYVsqrXuP0bZxJaTqdgoA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", "license": "MIT" }, - "node_modules/available-typed-arrays": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", - "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "possible-typed-array-names": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/axios": { "version": "1.20.0", "resolved": "https://registry.npmjs.org/axios/-/axios-1.20.0.tgz", @@ -4168,10 +3558,13 @@ } }, "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==", - "license": "MIT" + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", + "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", + "license": "MIT", + "engines": { + "node": "18 || 20 || >=22" + } }, "node_modules/bare-events": { "version": "2.9.2", @@ -4326,13 +3719,15 @@ "license": "ISC" }, "node_modules/brace-expansion": { - "version": "1.1.21", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.21.tgz", - "integrity": "sha512-9zeA+KLZNNzglF2TPKRQEDyx6Yby7daAkuy8MiPzpXPsYDWi/DRM8jmwUDxokQjYqBpv5DgPiwD4h4ZZSy1Ujw==", + "version": "5.0.12", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", + "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^4.0.2" + }, + "engines": { + "node": "20 || >=22" } }, "node_modules/braces": { @@ -4371,6 +3766,19 @@ "node": ">= 0.8" } }, + "node_modules/cacheable": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/cacheable/-/cacheable-2.5.0.tgz", + "integrity": "sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==", + "license": "MIT", + "dependencies": { + "@cacheable/memory": "^2.2.0", + "@cacheable/utils": "^2.5.0", + "hookified": "^1.15.0", + "keyv": "^5.6.0", + "qified": "^0.10.1" + } + }, "node_modules/cacheable-lookup": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/cacheable-lookup/-/cacheable-lookup-7.0.0.tgz", @@ -4380,25 +3788,6 @@ "node": ">=14.16" } }, - "node_modules/call-bind": { - "version": "1.0.9", - "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.9.tgz", - "integrity": "sha512-a/hy+pNsFUTR+Iz8TCJvXudKVLAnz/DyeSUo10I5yvFDQJBFU2s9uqQpoSrJlroHUKoKqzg+epxyP9lqFdzfBQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind-apply-helpers": "^1.0.2", - "es-define-property": "^1.0.1", - "get-intrinsic": "^1.3.0", - "set-function-length": "^1.2.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/call-bind-apply-helpers": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", @@ -4438,27 +3827,12 @@ "version": "3.1.0", "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, "license": "MIT", "engines": { "node": ">=6" } }, - "node_modules/chalk": { - "version": "4.1.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", - "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", - "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/change-case": { "version": "5.4.4", "resolved": "https://registry.npmjs.org/change-case/-/change-case-5.4.4.tgz", @@ -4536,24 +3910,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "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==", - "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==", - "license": "MIT" - }, "node_modules/colorjs.io": { "version": "0.7.1", "resolved": "https://registry.npmjs.org/colorjs.io/-/colorjs.io-0.7.1.tgz", @@ -4585,39 +3941,6 @@ "node": ">=18" } }, - "node_modules/comment-parser": { - "version": "1.4.9", - "resolved": "https://registry.npmjs.org/comment-parser/-/comment-parser-1.4.9.tgz", - "integrity": "sha512-+2AvZKjJaNq9GQljm3tr0utwrig5BL+jgJGvz5rDpGKNIp+ojcRXWUwBbh/sGIi1QCprR6PsKFakub+w1v+4hQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 12.0.0" - } - }, - "node_modules/commitlint": { - "version": "21.2.3", - "resolved": "https://registry.npmjs.org/commitlint/-/commitlint-21.2.3.tgz", - "integrity": "sha512-rsPd9FevYj4VpapWvcYZGtO9WXBrc3Jy5leodXAfCmLFxhbW+Yx3Ew+5czqpk1Vw+uIQCA+PaGqzBtcixkBdqw==", - "dev": true, - "license": "MIT", - "dependencies": { - "@commitlint/cli": "^21.2.3", - "@commitlint/types": "^21.2.3" - }, - "bin": { - "commitlint": "cli.js" - }, - "engines": { - "node": ">=22.12.0" - } - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", - "license": "MIT" - }, "node_modules/confbox": { "version": "0.3.1", "resolved": "https://registry.npmjs.org/confbox/-/confbox-0.3.1.tgz", @@ -4831,60 +4154,6 @@ "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", "license": "MIT" }, - "node_modules/data-view-buffer": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.2.tgz", - "integrity": "sha512-EmKO5V3OLXh1rtK2wgXRansaK1/mtVdTUEiEI0W8RkvgT05kfxaH29PliLnpLP73yYO6142Q72QNa8Wx/A5CqQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/data-view-byte-length": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/data-view-byte-length/-/data-view-byte-length-1.0.2.tgz", - "integrity": "sha512-tuhGbE6CfTM9+5ANGf+oQb72Ky/0+s3xKUpHvShfiz2RxMFgFPjsXuRLBVMtvMs15awe45SRb83D6wH4ew6wlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/inspect-js" - } - }, - "node_modules/data-view-byte-offset": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/data-view-byte-offset/-/data-view-byte-offset-1.0.1.tgz", - "integrity": "sha512-BS8PfmtDGnrgYdOonGZQdLZslWIeCGFP9tpan0hi1Co2Zr2NKADsvGYA8XxuG/4UWgJ6Cjtv+YJnB6MM69QGlQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-data-view": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/dayjs": { "version": "1.11.23", "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.23.tgz", @@ -4914,42 +4183,6 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "license": "MIT" }, - "node_modules/define-data-property": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", - "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0", - "es-errors": "^1.3.0", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/define-properties": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", - "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.0.1", - "has-property-descriptors": "^1.0.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/delay": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/delay/-/delay-5.0.0.tgz", @@ -4995,19 +4228,6 @@ "node": ">=8" } }, - "node_modules/doctrine": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", - "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", - "dev": true, - "license": "Apache-2.0", - "dependencies": { - "esutils": "^2.0.2" - }, - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/dotenv": { "version": "16.6.1", "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.6.1.tgz", @@ -5138,94 +4358,6 @@ "is-arrayish": "^0.2.1" } }, - "node_modules/es-abstract": { - "version": "1.24.2", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.24.2.tgz", - "integrity": "sha512-2FpH9Q5i2RRwyEP1AylXe6nYLR5OhaJTZwmlcP0dL/+JCbgg7yyEo/sEK6HeGZRf3dFpWwThaRHVApXSkW3xeg==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-buffer-byte-length": "^1.0.2", - "arraybuffer.prototype.slice": "^1.0.4", - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "data-view-buffer": "^1.0.2", - "data-view-byte-length": "^1.0.2", - "data-view-byte-offset": "^1.0.1", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.1", - "es-set-tostringtag": "^2.1.0", - "es-to-primitive": "^1.3.0", - "function.prototype.name": "^1.1.8", - "get-intrinsic": "^1.3.0", - "get-proto": "^1.0.1", - "get-symbol-description": "^1.1.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "hasown": "^2.0.2", - "internal-slot": "^1.1.0", - "is-array-buffer": "^3.0.5", - "is-callable": "^1.2.7", - "is-data-view": "^1.0.2", - "is-negative-zero": "^2.0.3", - "is-regex": "^1.2.1", - "is-set": "^2.0.3", - "is-shared-array-buffer": "^1.0.4", - "is-string": "^1.1.1", - "is-typed-array": "^1.1.15", - "is-weakref": "^1.1.1", - "math-intrinsics": "^1.1.0", - "object-inspect": "^1.13.4", - "object-keys": "^1.1.1", - "object.assign": "^4.1.7", - "own-keys": "^1.0.1", - "regexp.prototype.flags": "^1.5.4", - "safe-array-concat": "^1.1.3", - "safe-push-apply": "^1.0.0", - "safe-regex-test": "^1.1.0", - "set-proto": "^1.0.0", - "stop-iteration-iterator": "^1.1.0", - "string.prototype.trim": "^1.2.10", - "string.prototype.trimend": "^1.0.9", - "string.prototype.trimstart": "^1.0.8", - "typed-array-buffer": "^1.0.3", - "typed-array-byte-length": "^1.0.3", - "typed-array-byte-offset": "^1.0.4", - "typed-array-length": "^1.0.7", - "unbox-primitive": "^1.1.0", - "which-typed-array": "^1.1.19" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/es-abstract-get": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/es-abstract-get/-/es-abstract-get-1.0.0.tgz", - "integrity": "sha512-6PMWXpdhshVvFp+FoWYs1EvG1Nj0tvk0dZM+XcK0xMEM1czRVcP6ohqPWHy6qPagSpC8j4+p89WXlT+xXJs/fg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.2", - "is-callable": "^1.2.7", - "object-inspect": "^1.13.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-define-property": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", @@ -5244,34 +4376,6 @@ "node": ">= 0.4" } }, - "node_modules/es-iterator-helpers": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.4.0.tgz", - "integrity": "sha512-c/A0P0oxkACDc+cKWw8evLXK83oBKgn0qPOqCYT4x9uolpCIJAcYvJC9QYKNDRPsTeGyCrQ326jrvgZWdCdK5Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.2", - "es-errors": "^1.3.0", - "es-set-tostringtag": "^2.1.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.3.0", - "globalthis": "^1.0.4", - "gopd": "^1.2.0", - "has-property-descriptors": "^1.0.2", - "has-proto": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "iterator.prototype": "^1.1.5", - "math-intrinsics": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/es-object-atoms": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", @@ -5299,40 +4403,6 @@ "node": ">= 0.4" } }, - "node_modules/es-shim-unscopables": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/es-shim-unscopables/-/es-shim-unscopables-1.1.0.tgz", - "integrity": "sha512-d9T8ucsEhh8Bi1woXCf+TIKDIROLG5WCkxg8geBCbvk22kzwC5G2OnXVMO6FUsvQlgUUXQ2itephWDLqDzbeCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/es-to-primitive": { - "version": "1.3.4", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.3.4.tgz", - "integrity": "sha512-yPDz7wqpg1/mmHLmS3tcfTfbw5f1eryXvyghYBffGdERwe+mV7ZcWzTR8LR17Kvqt3qfPurjlonmnq3MKXIOXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-abstract-get": "^1.0.0", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "is-callable": "^1.2.7", - "is-date-object": "^1.1.0", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/es-toolkit": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", @@ -5396,44 +4466,42 @@ } }, "node_modules/eslint": { - "version": "9.39.5", - "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.39.5.tgz", - "integrity": "sha512-DgZS62aPLXKlnxILS/AYCoRvHaZeXceIzlXPkkGGzJWSow1aEk0lbTlxUSlyjC8jcaKxAdOnTDz+o1JFSBsyjw==", - "deprecated": "This version is no longer supported. Please see https://eslint.org/version-support for other options.", + "version": "10.12.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-10.12.0.tgz", + "integrity": "sha512-npHjrHb2o4ehH3mE+YuxABR+0gyb0aVWCIolgJDArwCiHEIsonBm3ZKjel5b0U5+a+MbEvIyRCGCzD3eKKK2NA==", "license": "MIT", + "workspaces": [ + "packages/*" + ], "dependencies": { "@eslint-community/eslint-utils": "^4.8.0", - "@eslint-community/regexpp": "^4.12.1", - "@eslint/config-array": "^0.21.2", - "@eslint/config-helpers": "^0.4.2", - "@eslint/core": "^0.17.0", - "@eslint/eslintrc": "^3.3.6", - "@eslint/js": "9.39.5", - "@eslint/plugin-kit": "^0.4.1", + "@eslint-community/regexpp": "^4.12.2", + "@eslint/config-array": "^0.23.5", + "@eslint/config-helpers": "^0.7.0", + "@eslint/core": "^1.2.1", + "@eslint/plugin-kit": "^0.7.3", "@humanfs/node": "^0.16.6", "@humanwhocodes/module-importer": "^1.0.1", "@humanwhocodes/retry": "^0.4.2", "@types/estree": "^1.0.6", "ajv": "^6.14.0", - "chalk": "^4.0.0", "cross-spawn": "^7.0.6", "debug": "^4.3.2", "escape-string-regexp": "^4.0.0", - "eslint-scope": "^8.4.0", - "eslint-visitor-keys": "^4.2.1", - "espree": "^10.4.0", - "esquery": "^1.5.0", + "eslint-scope": "^9.1.2", + "eslint-visitor-keys": "^5.0.1", + "espree": "^11.2.0", + "esquery": "^1.7.0", "esutils": "^2.0.2", "fast-deep-equal": "^3.1.3", - "file-entry-cache": "^8.0.0", + "file-entry-cache": "11.1.5 || >11.1.6 <12", "find-up": "^5.0.0", "glob-parent": "^6.0.2", "ignore": "^5.2.0", "imurmurhash": "^0.1.4", "is-glob": "^4.0.0", "json-stable-stringify-without-jsonify": "^1.0.1", - "lodash.merge": "^4.6.2", - "minimatch": "^3.1.5", + "minimatch": "^10.2.5", "natural-compare": "^1.4.0", "optionator": "^0.9.3" }, @@ -5441,7 +4509,7 @@ "eslint": "bin/eslint.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://eslint.org/donate" @@ -5471,66 +4539,6 @@ "eslint": ">=6.0.0" } }, - "node_modules/eslint-import-context": { - "version": "0.1.9", - "resolved": "https://registry.npmjs.org/eslint-import-context/-/eslint-import-context-0.1.9.tgz", - "integrity": "sha512-K9Hb+yRaGAGUbwjhFNHvSmmkZs9+zbuoe3kFQ4V1wYjrepUFYM2dZAfNtjbbj3qsPfUfsA68Bx/ICWQMi+C8Eg==", - "dev": true, - "license": "MIT", - "dependencies": { - "get-tsconfig": "^4.10.1", - "stable-hash-x": "^0.2.0" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-import-context" - }, - "peerDependencies": { - "unrs-resolver": "^1.0.0" - }, - "peerDependenciesMeta": { - "unrs-resolver": { - "optional": true - } - } - }, - "node_modules/eslint-import-resolver-typescript": { - "version": "3.10.1", - "resolved": "https://registry.npmjs.org/eslint-import-resolver-typescript/-/eslint-import-resolver-typescript-3.10.1.tgz", - "integrity": "sha512-A1rHYb06zjMGAxdLSkN2fXPBwuSaQ0iO5M/hdyS0Ajj1VBaRp0sPD3dn1FhME3c/JluGFbwSxyCfqdSbtQLAHQ==", - "dev": true, - "license": "ISC", - "dependencies": { - "@nolyfill/is-core-module": "1.0.39", - "debug": "^4.4.0", - "get-tsconfig": "^4.10.0", - "is-bun-module": "^2.0.0", - "stable-hash": "^0.0.5", - "tinyglobby": "^0.2.13", - "unrs-resolver": "^1.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-import-resolver-typescript" - }, - "peerDependencies": { - "eslint": "*", - "eslint-plugin-import": "*", - "eslint-plugin-import-x": "*" - }, - "peerDependenciesMeta": { - "eslint-plugin-import": { - "optional": true - }, - "eslint-plugin-import-x": { - "optional": true - } - } - }, "node_modules/eslint-plugin-es-x": { "version": "7.8.0", "resolved": "https://registry.npmjs.org/eslint-plugin-es-x/-/eslint-plugin-es-x-7.8.0.tgz", @@ -5553,86 +4561,10 @@ "eslint": ">=8" } }, - "node_modules/eslint-plugin-import-x": { - "version": "4.17.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-import-x/-/eslint-plugin-import-x-4.17.1.tgz", - "integrity": "sha512-4cdstYkKCyjumM2Q9NSI03K8D2a9F4Ssz33K2lv2hQa4KmR9jPLwk3uWGtNvclfqBrPGfGuMBwsGMbe6dMRbfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "@typescript-eslint/types": "^8.56.0", - "comment-parser": "^1.4.1", - "debug": "^4.4.1", - "eslint-import-context": "^0.1.9", - "is-glob": "^4.0.3", - "minimatch": "^9.0.3 || ^10.1.2", - "semver": "^7.7.2", - "stable-hash-x": "^0.2.0", - "unrs-resolver": "^1.9.2" - }, - "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-import-x" - }, - "peerDependencies": { - "@typescript-eslint/utils": "^8.56.0", - "eslint": "^8.57.0 || ^9.0.0 || ^10.0.0", - "eslint-import-resolver-node": "*" - }, - "peerDependenciesMeta": { - "@typescript-eslint/utils": { - "optional": true - }, - "eslint-import-resolver-node": { - "optional": true - } - } - }, - "node_modules/eslint-plugin-import-x/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/eslint-plugin-import-x/node_modules/brace-expansion": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", - "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" - }, - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/eslint-plugin-import-x/node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.8" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/eslint-plugin-n": { - "version": "17.24.0", - "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-17.24.0.tgz", - "integrity": "sha512-/gC7/KAYmfNnPNOb3eu8vw+TdVnV0zhdQwexsw6FLXbhzroVj20vRn2qL8lDWDGnAQ2J8DhdfvXxX9EoxvERvw==", + "version": "18.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-n/-/eslint-plugin-n-18.4.1.tgz", + "integrity": "sha512-2sBReWOvCbzgkPri9M5SFmD5EbIwZLa1xz6B5RZsrI19WSFKpyx1sOMr+pdk8puCiXuEgCbErEHy1PuaUrc/4w==", "dev": true, "license": "MIT", "dependencies": { @@ -5643,17 +4575,27 @@ "globals": "^15.11.0", "globrex": "^0.1.2", "ignore": "^5.3.2", - "semver": "^7.6.3", - "ts-declaration-location": "^1.0.6" + "js-yaml": "^5.4.1", + "semver": "^7.6.3" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" }, "peerDependencies": { - "eslint": ">=8.23.0" + "eslint": ">=8.57.1", + "ts-declaration-location": "^1.0.6", + "typescript": ">=5.0.0" + }, + "peerDependenciesMeta": { + "ts-declaration-location": { + "optional": true + }, + "typescript": { + "optional": true + } } }, "node_modules/eslint-plugin-n/node_modules/globals": { @@ -5669,6 +4611,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/eslint-plugin-n/node_modules/js-yaml": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-5.4.3.tgz", + "integrity": "sha512-yzzNtgczwgoVHNigCyKTXcQJU4Y8t/ikU4UxXW0BvrLfHTGWZhsNcOT2s/a7vn81/4KqVnNmHjaUEPlvWnNwVw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/puzrin" + }, + { + "type": "github", + "url": "https://github.com/sponsors/nodeca" + } + ], + "license": "MIT", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.mjs" + } + }, "node_modules/eslint-plugin-promise": { "version": "7.3.0", "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-7.3.0.tgz", @@ -5688,49 +4653,6 @@ "eslint": "^7.0.0 || ^8.0.0 || ^9.0.0 || ^10.0.0" } }, - "node_modules/eslint-plugin-react": { - "version": "7.37.5", - "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.5.tgz", - "integrity": "sha512-Qteup0SqU15kdocexFNAJMvCJEfa2xUKNV4CC1xsVMrIIqEy3SQ/rqyxCWNzfrd3/ldy6HMlD2e0JDVpDg2qIA==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.8", - "array.prototype.findlast": "^1.2.5", - "array.prototype.flatmap": "^1.3.3", - "array.prototype.tosorted": "^1.1.4", - "doctrine": "^2.1.0", - "es-iterator-helpers": "^1.2.1", - "estraverse": "^5.3.0", - "hasown": "^2.0.2", - "jsx-ast-utils": "^2.4.1 || ^3.0.0", - "minimatch": "^3.1.2", - "object.entries": "^1.1.9", - "object.fromentries": "^2.0.8", - "object.values": "^1.2.1", - "prop-types": "^15.8.1", - "resolve": "^2.0.0-next.5", - "semver": "^6.3.1", - "string.prototype.matchall": "^4.0.12", - "string.prototype.repeat": "^1.0.0" - }, - "engines": { - "node": ">=4" - }, - "peerDependencies": { - "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7" - } - }, - "node_modules/eslint-plugin-react/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/eslint-plugin-vue": { "version": "10.11.1", "resolved": "https://registry.npmjs.org/eslint-plugin-vue/-/eslint-plugin-vue-10.11.1.tgz", @@ -5779,16 +4701,18 @@ } }, "node_modules/eslint-scope": { - "version": "8.4.0", - "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.4.0.tgz", - "integrity": "sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg==", + "version": "9.1.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-9.1.2.tgz", + "integrity": "sha512-xS90H51cKw0jltxmvmHy2Iai1LIqrfbw57b79w/J7MfvDfkIkFZ+kj6zC3BjtUwh150HsSSdxXZcsuv72miDFQ==", "license": "BSD-2-Clause", "dependencies": { + "@types/esrecurse": "^4.3.1", + "@types/estree": "^1.0.8", "esrecurse": "^4.3.0", "estraverse": "^5.2.0" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^20.19.0 || ^22.13.0 || >=24" }, "funding": { "url": "https://opencollective.com/eslint" @@ -5798,6 +4722,7 @@ "version": "4.2.1", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz", "integrity": "sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ==", + "dev": true, "license": "Apache-2.0", "engines": { "node": "^18.18.0 || ^20.9.0 || >=21.1.0" @@ -5822,6 +4747,35 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/eslint/node_modules/eslint-visitor-keys": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-5.0.1.tgz", + "integrity": "sha512-tD40eHxA35h0PEIZNeIjkHoDR4YjjJp34biM0mDvplBe//mB+IHCqHDGV7pxF+7MklTvighcCPPZC7ynWyjdTA==", + "license": "Apache-2.0", + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/espree": { + "version": "11.2.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-11.2.0.tgz", + "integrity": "sha512-7p3DrVEIopW1B1avAGLuCSh1jubc01H2JHc8B4qqGblmg5gI9yumBgACjWo4JlIc04ufug4xJ3SQI8HkS/Rgzw==", + "license": "BSD-2-Clause", + "dependencies": { + "acorn": "^8.16.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^5.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", @@ -5832,6 +4786,7 @@ "version": "10.4.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.4.0.tgz", "integrity": "sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ==", + "dev": true, "license": "BSD-2-Clause", "dependencies": { "acorn": "^8.15.0", @@ -6102,15 +5057,12 @@ } }, "node_modules/file-entry-cache": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", - "integrity": "sha512-XXTUwCvisa5oacNGRP9SfNtYBNAMi+RPwBFmblZEF7N7swHYQS6/Zfk7SRwx4D5j3CH211YNRco1DEMNVfZCnQ==", + "version": "11.1.5", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-11.1.5.tgz", + "integrity": "sha512-+PFTHITI08JIGhnNpGNI8T8inUpgZfk3GNEqfT9R2zZV2iFXg3CvqzSl/uEhs7TSGujYRELEANyDvS8Fj7+S7Q==", "license": "MIT", "dependencies": { - "flat-cache": "^4.0.0" - }, - "engines": { - "node": ">=16.0.0" + "flat-cache": "^6.1.23" } }, "node_modules/fill-range": { @@ -6163,16 +5115,14 @@ } }, "node_modules/flat-cache": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-4.0.1.tgz", - "integrity": "sha512-f7ccFPK3SXFHpx15UIGyRJ/FJQctuKZ0zVuN3frBo4HnK3cay9VEW0R6yPYFHC0AgqhukPzKjq22t5DmAyqGyw==", + "version": "6.1.23", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-6.1.23.tgz", + "integrity": "sha512-f++BY9pTk+983xK1FLzlLpmM0i0z+jHmx3QESGkURMXujQZz1k5wzwX6hjnQ8goaD0B+sYnDK1yZ6MTyZfUaqA==", "license": "MIT", "dependencies": { - "flatted": "^3.2.9", - "keyv": "^4.5.4" - }, - "engines": { - "node": ">=16" + "cacheable": "^2.5.0", + "flatted": "^3.4.2", + "hookified": "^1.15.0" } }, "node_modules/flatted": { @@ -6201,22 +5151,6 @@ } } }, - "node_modules/for-each": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.5.tgz", - "integrity": "sha512-dKx12eRCVIzqCxFGplyFKJMPvLEWgmNtUrpTiJIR5u97zEhRG8ySrtboPHZXx7daLxQVrl643cTzbab2tkQjxg==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-callable": "^1.2.7" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/form-data": { "version": "4.0.6", "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.6.tgz", @@ -6288,50 +5222,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/function.prototype.name": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/function.prototype.name/-/function.prototype.name-1.2.0.tgz", - "integrity": "sha512-jObKIik1P2QjPHP5nz5BaOtUlfgS0fWo8IUByNXkM+o+02sJOi94em77GwJKQSJ3gfPHdgzLNrHc1uokV4P/ew==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "es-define-property": "^1.0.1", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2", - "hasown": "^2.0.4", - "is-callable": "^1.2.7", - "is-document.all": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/functions-have-names": { - "version": "1.2.3", - "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz", - "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==", - "dev": true, - "license": "MIT", - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/generator-function": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/generator-function/-/generator-function-2.0.1.tgz", - "integrity": "sha512-SFdFmIJi+ybC0vjlHN0ZGVGHc3lgE0DxPAT0djjVg+kjOnSqclqmj0KQ7ykTOLP6YxoqOvuAODGdcHJn+43q3g==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/get-caller-file": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", @@ -6392,24 +5282,6 @@ "node": ">= 0.4" } }, - "node_modules/get-symbol-description": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", - "integrity": "sha512-w9UMqWwJxHNOvoNzSJ2oPF5wvYcvP7jUvYzhp67yEhTi17ZDBBC1z9pTdGuzjD+EFIqLSYRweZjqfiPzQ06Ebg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/get-tsconfig": { "version": "4.14.3", "resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.14.3.tgz", @@ -6452,9 +5324,10 @@ } }, "node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "version": "17.13.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-17.13.0.tgz", + "integrity": "sha512-RwMTC61u7hrG3ZJMkZQOK4JLJrKS8QtoTii63EmWvFXHqycY9FObBJQCbsLxSO8kjKhWE5kV1GC+Vb1g3RI0Zg==", + "dev": true, "license": "MIT", "engines": { "node": ">=18" @@ -6463,23 +5336,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/globalthis": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/globalthis/-/globalthis-1.0.4.tgz", - "integrity": "sha512-DpLKbNU4WylpxJykQujfCcwYWiV/Jhm50Goo0wrVILAv5jOr9d+H+UR3PhSCD2rCCEIg0uc+G+muBTwD54JhDQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.2.1", - "gopd": "^1.0.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/globrex": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/globrex/-/globrex-0.1.2.tgz", @@ -6505,19 +5361,6 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "license": "ISC" }, - "node_modules/has-bigints": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.1.0.tgz", - "integrity": "sha512-R3pbpkcIqv2Pm3dUwgjclDRVmWpTJW2DcMzcIhEXEx1oh/CEMObMm3KLmRJOdvhM7o4uQBnwr8pzRK2sJWIqfg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-flag": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", @@ -6527,35 +5370,6 @@ "node": ">=8" } }, - "node_modules/has-property-descriptors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", - "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-define-property": "^1.0.0" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/has-proto": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.2.0.tgz", - "integrity": "sha512-KIL7eQPfHQRC8+XluaIw7BHUwwqL19bQn4hzNgdr+1wXoU0KKj6rufu47lhY7KbJR2C6T6+PfyN0Ea7wkSS+qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/has-symbols": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", @@ -6583,6 +5397,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/hashery": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/hashery/-/hashery-1.5.1.tgz", + "integrity": "sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==", + "license": "MIT", + "dependencies": { + "hookified": "^1.15.0" + }, + "engines": { + "node": ">=20" + } + }, "node_modules/hasown": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", @@ -6601,6 +5427,12 @@ "integrity": "sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==", "license": "MIT" }, + "node_modules/hookified": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-1.15.1.tgz", + "integrity": "sha512-MvG/clsADq1GPM2KGo2nyfaWVyn9naPiXrqIe4jYjXNZQt238kWyOGrsyc/DmRAQ+Re6yeo6yX/yoNCG5KAEVg==", + "license": "MIT" + }, "node_modules/http-errors": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.1.tgz", @@ -6738,6 +5570,7 @@ "version": "3.3.1", "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.1.tgz", "integrity": "sha512-TR3KfrTZTYLPB6jUjfx6MF9WcWrHL9su5TObK4ZkYgBdWKPOFoSoQIdEuTuR82pmtxH2spWG9h6etwfr1pLBqQ==", + "dev": true, "license": "MIT", "dependencies": { "parent-module": "^1.0.0", @@ -6754,6 +5587,7 @@ "version": "4.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -6769,536 +5603,111 @@ } }, "node_modules/inherits": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", - "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", - "license": "ISC" - }, - "node_modules/ini": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", - "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", - "dev": true, - "license": "ISC", - "engines": { - "node": "^20.17.0 || >=22.9.0" - } - }, - "node_modules/internal-slot": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.1.0.tgz", - "integrity": "sha512-4gd7VpWNQNB4UKKCFFVcp1AVv+FMOgs9NKzjHKusc8jTMhd5eL1NqQqOpE0KzMds804/yHlglp3uxgluOqAPLw==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "hasown": "^2.0.2", - "side-channel": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/ipaddr.js": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.5.0.tgz", - "integrity": "sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==", - "license": "MIT", - "engines": { - "node": ">= 10" - } - }, - "node_modules/is-array-buffer": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.5.tgz", - "integrity": "sha512-DDfANUiiG2wC1qawP66qlTugJeL5HyzMpfr8lLK+jMQirGzNod0B12cFB/9q838Ru27sBwfw78/rdoU7RERz6A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", - "dev": true, - "license": "MIT" - }, - "node_modules/is-async-function": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-async-function/-/is-async-function-2.1.1.tgz", - "integrity": "sha512-9dgM/cZBnNvjzaMYHVoxxfPj2QXt22Ev7SuuPrs+xav0ukGB0S6d4ydZdEiM48kLx5kDV+QBPrpVnFyefL8kkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "async-function": "^1.0.0", - "call-bound": "^1.0.3", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bigint": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.1.0.tgz", - "integrity": "sha512-n4ZT37wG78iz03xPRKJrHTdZbe3IicyucEtdRsV5yglwc3GyUfbAfpSeD0FJ41NbUNSt5wbhqfp1fS+BgnvDFQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "has-bigints": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-binary-path": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", - "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", - "dev": true, - "license": "MIT", - "dependencies": { - "binary-extensions": "^2.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-boolean-object": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.2.2.tgz", - "integrity": "sha512-wa56o2/ElJMYqjCjGkXri7it5FbebW5usLw/nPmCMs5DeZ7eziSYZhSmPRn0txqeW4LnAmQQU7FgqLpsEFKM4A==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-bun-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-bun-module/-/is-bun-module-2.0.0.tgz", - "integrity": "sha512-gNCGbnnnnFAUGKeZ9PdbyeGYJqewpmc2aKHUEMO5nQPWU9lOmv7jcmQIv+qHD8fXW6W7qfuCwX4rY9LNRjXrkQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "semver": "^7.7.1" - } - }, - "node_modules/is-callable": { - "version": "1.2.7", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", - "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-core-module": { - "version": "2.17.0", - "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.17.0.tgz", - "integrity": "sha512-J/vG0zBCbIKOQFfufSwyXdMrsohyJIUNkrnmo6WZGzoM7tr/lsbfW5b2BvisL6zsyMzK9UxV9L6c7AoFbyXHOA==", - "dev": true, - "license": "MIT", - "dependencies": { - "hasown": "^2.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-data-view": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-data-view/-/is-data-view-1.0.2.tgz", - "integrity": "sha512-RKtWF8pGmS87i2D6gqQu/l7EYRlVdfzemCJN/P3UOs//x1QE7mfhvzHIApBTRf7axvT6DMGwSwBXYCT0nfB9xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "get-intrinsic": "^1.2.6", - "is-typed-array": "^1.1.13" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-date-object": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.1.0.tgz", - "integrity": "sha512-PwwhEakHVKTdRNVOw+/Gyh0+MzlCl4R6qKvkhuvLtPMggI1WAHt9sOwZxQLSGpUaDnrdyDsomoRgNnCfKNSXXg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-document.all": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/is-document.all/-/is-document.all-1.0.0.tgz", - "integrity": "sha512-+XSoyS05OdBbhFuELhgTCpFNHkpBOJqtsZfUFFpe5QTw+9Sjbh8zitxhQkYAo6wV7e1Vb8cAPvpCk9jGam/82g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-extglob": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", - "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-finalizationregistry": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-finalizationregistry/-/is-finalizationregistry-1.1.1.tgz", - "integrity": "sha512-1pC6N8qWJbWoPtEjgcL2xyhQOP491EQjeUo3qTKcmV8YSDDJrOepfG8pcC7h/QgnQHYSv0mJ3Z/ZWxmatVrysg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-generator-function": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.1.2.tgz", - "integrity": "sha512-upqt1SkGkODW9tsGNG5mtXTXtECizwtS2kA161M+gJPc1xdb/Ax629af6YrTwcOeQHbewrPNlE5Dx7kzvXTizA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "generator-function": "^2.0.0", - "get-proto": "^1.0.1", - "has-tostringtag": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-glob": { - "version": "4.0.3", - "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", - "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", - "license": "MIT", - "dependencies": { - "is-extglob": "^2.1.1" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/is-map": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz", - "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-negative-zero": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.3.tgz", - "integrity": "sha512-5KoIu2Ngpyek75jXodFvnafB6DJgr3u8uuK0LEZJjrU19DrMD3EVERaR8sjz8CCGgpZvxPl9SuE1GMVPFHx1mw==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-number": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", - "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", - "license": "MIT", - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/is-number-object": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.1.1.tgz", - "integrity": "sha512-lZhclumE1G6VYD8VHe35wFaIif+CTy5SJIi5+3y4psDgWu4wPDoBhF8NxUOinEc7pHgiTsT6MaBb92rKhhD+Xw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-plain-obj": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", - "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/is-regex": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.2.1.tgz", - "integrity": "sha512-MjYsKHO5O7mCsmRGxWcLWheFqN9DJ/2TmngvjKXihe6efViPqc274+Fx/4fYj/r03+ESvBdTXK0V6tA3rgez1g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2", - "hasown": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/is-retry-allowed": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", - "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", - "license": "MIT", - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "license": "ISC" }, - "node_modules/is-set": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz", - "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==", + "node_modules/ini": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-6.0.0.tgz", + "integrity": "sha512-IBTdIkzZNOpqm7q3dRqJvMaldXjDHWkEDfrwGEQTs5eaQMWV+djAhR+wahyNNMAa+qpbDUhBMVt4ZKNwpPm7xQ==", "dev": true, - "license": "MIT", + "license": "ISC", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": "^20.17.0 || >=22.9.0" } }, - "node_modules/is-shared-array-buffer": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.4.tgz", - "integrity": "sha512-ISWac8drv4ZGfwKl5slpHG9OwPNty4jOWPRIhBpxOoD+hqITiwuipOQ2bNthAzwA3B4fIjO4Nln74N0S9byq8A==", - "dev": true, + "node_modules/ipaddr.js": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.5.0.tgz", + "integrity": "sha512-aq+t5NAc+cS6rZQQVWC2x98CPqGtKKTMDd4Gaodv0wShnItdKg/51djkGJ1hqH+Oy0ivDftCbSLCQob8zso01w==", "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">= 10" } }, - "node_modules/is-string": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", - "integrity": "sha512-BtEeSsoaQjlSPBemMQIrY1MY0uM6vnS1g5fmufYOtnxLGUZM2178PKbhsk7Ffv58IX+ZtcvoGwccYsh0PglkAA==", + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true, + "license": "MIT" + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", "dev": true, "license": "MIT", "dependencies": { - "call-bound": "^1.0.3", - "has-tostringtag": "^1.0.2" + "binary-extensions": "^2.0.0" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=8" } }, - "node_modules/is-symbol": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.1.1.tgz", - "integrity": "sha512-9gGx6GTtCQM73BgmHQXfDmLtfjjTUDSyoxTCbp5WtoixAhfgsDirWIcVQ/IHpvI5Vgd5i/J5F7B9cN/WlVbC/w==", - "dev": true, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "has-symbols": "^1.1.0", - "safe-regex-test": "^1.1.0" - }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-typed-array": { - "version": "1.1.15", - "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.15.tgz", - "integrity": "sha512-p3EcsicXjit7SaskXHs1hA91QxgTw46Fv6EFKKGS5DRFLD8yKnohjF3hxoju94b/OcMZoQukzpPpBE9uLVKzgQ==", - "dev": true, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", "license": "MIT", "dependencies": { - "which-typed-array": "^1.1.16" + "is-extglob": "^2.1.1" }, "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.10.0" } }, - "node_modules/is-weakmap": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz", - "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==", - "dev": true, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", "license": "MIT", "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" + "node": ">=0.12.0" } }, - "node_modules/is-weakref": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.1.1.tgz", - "integrity": "sha512-6i9mGWSlqzNMEqpCp93KwRS1uUOodk2OJ6b+sq7ZPDSy2WuI5NFIxp/254TytR8ftefexkWn5xNiHUNpPOfSew==", + "node_modules/is-plain-obj": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz", + "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==", "dev": true, "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3" - }, "engines": { - "node": ">= 0.4" + "node": ">=12" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/is-weakset": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.4.tgz", - "integrity": "sha512-mfcwb6IzQyOKTs84CQMrOwW4gQcaTOAWJ0zzJCl2WSPDrWk/OzDaImWFH3djXhb24g4eudZfLRozAvPGw4d9hQ==", - "dev": true, + "node_modules/is-retry-allowed": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-2.2.0.tgz", + "integrity": "sha512-XVm7LOeLpTW4jV19QSH38vkswxoLud8sQ57YwJVTPWdiaI9I8keEhGFpBlslyVsgdQy4Opg8QOLb8YRgsyZiQg==", "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "get-intrinsic": "^1.2.6" - }, "engines": { - "node": ">= 0.4" + "node": ">=10" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/isarray": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", - "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", - "dev": true, - "license": "MIT" - }, "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", "license": "ISC" }, - "node_modules/iterator.prototype": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/iterator.prototype/-/iterator.prototype-1.1.5.tgz", - "integrity": "sha512-H0dkQoCa3b2VEeKQBOxFph+JAbcrQdE7KC0UkqwpLmv2EC4P41QXP+rqo9wYodACiG5/WM5s9oDApTU8utwj9g==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.6", - "get-proto": "^1.0.0", - "has-symbols": "^1.1.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/jiti": { "version": "2.6.1", "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz", @@ -7347,12 +5756,6 @@ "js-yaml": "bin/js-yaml.js" } }, - "node_modules/json-buffer": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", - "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", - "license": "MIT" - }, "node_modules/json-parse-even-better-errors": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", @@ -7488,22 +5891,6 @@ "npm": ">=6" } }, - "node_modules/jsx-ast-utils": { - "version": "3.3.5", - "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", - "integrity": "sha512-ZZow9HBI5O6EPgSJLUb8n2NKgmVWTwCvHGwFuJlMjvLFqlGG6pjirPhtdsseaLZjSibD8eegzmYpUZwoIlj2cQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "array-includes": "^3.1.6", - "array.prototype.flat": "^1.3.1", - "object.assign": "^4.1.4", - "object.values": "^1.1.6" - }, - "engines": { - "node": ">=4.0" - } - }, "node_modules/jwa": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/jwa/-/jwa-2.0.1.tgz", @@ -7551,12 +5938,12 @@ } }, "node_modules/keyv": { - "version": "4.5.4", - "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", - "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-5.6.0.tgz", + "integrity": "sha512-CYDD3SOtsHtyXeEORYRx2qBtpDJFjRTGXUtmNEMGyzYOKj1TE3tycdlho7kA1Ufx9OYWZzg52QFBGALTirzDSw==", "license": "MIT", "dependencies": { - "json-buffer": "3.0.1" + "@keyv/serialize": "^1.1.1" } }, "node_modules/levn": { @@ -7925,31 +6312,12 @@ "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==", "license": "MIT" }, - "node_modules/lodash.merge": { - "version": "4.6.2", - "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", - "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", - "license": "MIT" - }, "node_modules/lodash.once": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==", "license": "MIT" }, - "node_modules/loose-envify": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", - "integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "js-tokens": "^3.0.0 || ^4.0.0" - }, - "bin": { - "loose-envify": "cli.js" - } - }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -8115,15 +6483,18 @@ } }, "node_modules/minimatch": { - "version": "3.1.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", - "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", - "license": "ISC", + "version": "10.2.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", + "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", + "license": "BlueOak-1.0.0", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^5.0.8" }, "engines": { - "node": "*" + "node": "18 || 20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -8250,22 +6621,6 @@ "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" } }, - "node_modules/napi-postinstall": { - "version": "0.3.4", - "resolved": "https://registry.npmjs.org/napi-postinstall/-/napi-postinstall-0.3.4.tgz", - "integrity": "sha512-PHI5f1O0EP5xJ9gQmFGMS6IZcrVvTjpXjz7Na41gTE7eE2hK11lg04CECCYEEjdc17EV4DO+fkGEtt7TpTaTiQ==", - "dev": true, - "license": "MIT", - "bin": { - "napi-postinstall": "lib/cli.js" - }, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/napi-postinstall" - } - }, "node_modules/natural-compare": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", @@ -8302,83 +6657,116 @@ } }, "node_modules/neostandard": { - "version": "0.12.2", - "resolved": "https://registry.npmjs.org/neostandard/-/neostandard-0.12.2.tgz", - "integrity": "sha512-VZU8EZpSaNadp3rKEwBhVD1Kw8jE3AftQLkCyOaM7bWemL1LwsYRsBnAmXy2LjG9zO8t66qJdqB7ccwwORyrAg==", + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/neostandard/-/neostandard-0.14.1.tgz", + "integrity": "sha512-cEGi7ADMWJRTcdsZeDXCyA1ZeJLQPBq6HP9z9CE1ysu+CJOKYt59ADG0BT6ETonuF6xNXZbMiNc8S8prYys4aQ==", "dev": true, "license": "MIT", "dependencies": { "@humanwhocodes/gitignore-to-minimatch": "^1.0.2", - "@stylistic/eslint-plugin": "2.11.0", - "eslint-import-resolver-typescript": "^3.10.1", - "eslint-plugin-import-x": "^4.16.1", - "eslint-plugin-n": "^17.20.0", - "eslint-plugin-promise": "^7.2.1", - "eslint-plugin-react": "^7.37.5", - "find-up": "^5.0.0", - "globals": "^15.15.0", - "peowly": "^1.3.2", - "typescript-eslint": "^8.35.1" + "@stylistic/eslint-plugin": "5.10.0", + "eslint-plugin-n": "^18.2.2", + "eslint-plugin-promise": "^7.3.0", + "find-up": "^8.0.0", + "globals": "^17.9.0", + "peowly": "^2.0.1", + "typescript-eslint": "^8.56.0" }, "bin": { - "neostandard": "cli.mjs" + "neostandard": "cli.js" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": "^22.13.0 || >=24" }, "peerDependencies": { - "eslint": "^9.0.0" + "eslint": "^9.22.0 || ^10.0.0" } }, - "node_modules/neostandard/node_modules/globals": { - "version": "15.15.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-15.15.0.tgz", - "integrity": "sha512-7ACyT3wmyp3I61S4fG682L0VA2RGD9otkqGJIwNUMF1SWUombIIk+af1unuDYgMm082aHYwD+mzJvv9Iu8dsgg==", + "node_modules/neostandard/node_modules/find-up": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-8.0.0.tgz", + "integrity": "sha512-JGG8pvDi2C+JxidYdIwQDyS/CgcrIdh18cvgxcBge3wSHRQOrooMD3GlFBcmMJAN9M42SAZjDp5zv1dglJjwww==", "dev": true, "license": "MIT", + "dependencies": { + "locate-path": "^8.0.0", + "unicorn-magic": "^0.3.0" + }, "engines": { - "node": ">=18" + "node": ">=20" }, "funding": { "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/node-addon-api": { - "version": "7.1.1", - "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", - "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "node_modules/neostandard/node_modules/locate-path": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-8.0.0.tgz", + "integrity": "sha512-XT9ewWAC43tiAV7xDAPflMkG0qOPn2QjHqlgX8FOqmWa/rxnyYDulF9T0F7tRy1u+TVTmK/M//6VIOye+2zDXg==", + "dev": true, "license": "MIT", - "optional": true + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, - "node_modules/node-exports-info": { - "version": "1.6.2", - "resolved": "https://registry.npmjs.org/node-exports-info/-/node-exports-info-1.6.2.tgz", - "integrity": "sha512-kXs9Go0cah0qHVV2v389IXQLdLCeE1xfFtjOAF+iobu0OIoG1pje8At2vMHyaPMiPMnG/LWP50twML21eMcAag==", + "node_modules/neostandard/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", "dev": true, "license": "MIT", "dependencies": { - "array.prototype.flatmap": "^1.3.3", - "es-errors": "^1.3.0", - "object.entries": "^1.1.9", - "semver": "^6.3.1" + "yocto-queue": "^1.0.0" }, "engines": { - "node": ">= 0.4" + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" }, "funding": { - "url": "https://github.com/sponsors/ljharb" + "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/node-exports-info/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "node_modules/neostandard/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "license": "MIT", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/neostandard/node_modules/yocto-queue": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.2.2.tgz", + "integrity": "sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/node-addon-api": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-7.1.1.tgz", + "integrity": "sha512-5m3bsyrjFWE1xf7nz7YXdN4udnVtXK6/Yfgn5qnahL6bCkf2yKt4k3nuTKAtT4r3IG8JNR2ncsIMdZuAzJjHQQ==", + "license": "MIT", + "optional": true + }, "node_modules/node-fetch-native": { "version": "1.6.7", "resolved": "https://registry.npmjs.org/node-fetch-native/-/node-fetch-native-1.6.7.tgz", @@ -8406,44 +6794,21 @@ "ignore-by-default": "^1.0.1", "minimatch": "^10.2.1", "pstree.remy": "^1.1.8", - "semver": "^7.5.3", - "simple-update-notifier": "^2.0.0", - "supports-color": "^5.5.0", - "touch": "^3.1.0", - "undefsafe": "^2.0.5" - }, - "bin": { - "nodemon": "bin/nodemon.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/nodemon" - } - }, - "node_modules/nodemon/node_modules/balanced-match": { - "version": "4.0.4", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz", - "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==", - "dev": true, - "license": "MIT", - "engines": { - "node": "18 || 20 || >=22" - } - }, - "node_modules/nodemon/node_modules/brace-expansion": { - "version": "5.0.12", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.12.tgz", - "integrity": "sha512-YovQ3rzhaLMIrDjNDMkNS01tea93qhEhG5xy8f6+R0l+dw3Ki+5sCoIoI942iuLZTHWogWktgwVDhU09iNEimQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^4.0.2" + "semver": "^7.5.3", + "simple-update-notifier": "^2.0.0", + "supports-color": "^5.5.0", + "touch": "^3.1.0", + "undefsafe": "^2.0.5" + }, + "bin": { + "nodemon": "bin/nodemon.js" }, "engines": { - "node": "20 || >=22" + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/nodemon" } }, "node_modules/nodemon/node_modules/has-flag": { @@ -8456,22 +6821,6 @@ "node": ">=4" } }, - "node_modules/nodemon/node_modules/minimatch": { - "version": "10.2.6", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.6.tgz", - "integrity": "sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==", - "dev": true, - "license": "BlueOak-1.0.0", - "dependencies": { - "brace-expansion": "^5.0.8" - }, - "engines": { - "node": "18 || 20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/nodemon/node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -8514,16 +6863,6 @@ "url": "https://github.com/fb55/nth-check?sponsor=1" } }, - "node_modules/object-assign": { - "version": "4.1.1", - "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", - "integrity": "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "node_modules/object-inspect": { "version": "1.13.4", "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz", @@ -8536,91 +6875,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.assign": { - "version": "4.1.7", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", - "integrity": "sha512-nK28WOo+QIjBkDduTINE4JkF/UJJKyf2EJxvJKfblDpyg0Q+pkOHNTL0Qwy6NP6FhE/EnzV73BxxqcJaXY9anw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0", - "has-symbols": "^1.1.0", - "object-keys": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.entries": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/object.entries/-/object.entries-1.1.9.tgz", - "integrity": "sha512-8u/hfXFRBD1O0hPUjioLhoWFHRmt6tKA4/vZPyckBr18l1KE9uHrFaFaUi8MDRTpi4uak2goyPTSNJLXX2k2Hw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/object.fromentries": { - "version": "2.0.8", - "resolved": "https://registry.npmjs.org/object.fromentries/-/object.fromentries-2.0.8.tgz", - "integrity": "sha512-k6E21FzySsSK5a21KRADBd/NGneRegFO5pLHfdQLpRDETUNJueLXs3WCzyQ3tFRDYgbq3KHGXfTbi2bs8WQ6rQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.2", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/object.values": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.2.1.tgz", - "integrity": "sha512-gXah6aZrcUxjWg2zR2MwouP2eHlCBzdV4pygudehaKXSGW4v2AsRQUK+lwwXhii6KFZcunEnmSUoYp5CXibxtA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "call-bound": "^1.0.3", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/obug": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/obug/-/obug-2.2.1.tgz", @@ -8683,25 +6937,6 @@ "node": ">= 0.8.0" } }, - "node_modules/own-keys": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/own-keys/-/own-keys-1.0.2.tgz", - "integrity": "sha512-19YVAg7T+WTrxggPukVq7DjTv6+PJ867TmhCvBsYwmbFCsZd344rq2Ld1p0wo8f8Qrrhgp82c6FJRqdXWtSEhg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.4", - "get-intrinsic": "^1.3.0", - "object-keys": "^1.1.1", - "safe-push-apply": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/p-finally": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz", @@ -8772,6 +7007,7 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, "license": "MIT", "dependencies": { "callsites": "^3.0.0" @@ -8841,13 +7077,6 @@ "node": ">=8" } }, - "node_modules/path-parse": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", - "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", - "dev": true, - "license": "MIT" - }, "node_modules/path-to-regexp": { "version": "8.4.2", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.4.2.tgz", @@ -8865,14 +7094,14 @@ "license": "MIT" }, "node_modules/peowly": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/peowly/-/peowly-1.3.3.tgz", - "integrity": "sha512-5UmUtvuCv3KzBX2NuQw2uF28o0t8Eq4KkPRZfUCzJs+DiNVKw7OaYn29vNDgrt/Pggs23CPlSTqgzlhHJfpT0A==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/peowly/-/peowly-2.0.1.tgz", + "integrity": "sha512-T6hvS1bc/rXh4fA7jWOAteq5/c2kkz4QFRmGY9dER1ncqBDNwwWRD3h43ruiRr3YK5zHNqVrqfo2XUEqRo4gdQ==", "dev": true, "license": "MIT", "engines": { - "node": ">=18.6.0", - "typescript": ">=5.8" + "node": "^22.13.0 || >=24.0.0", + "typescript": ">=5.9" } }, "node_modules/perfect-debounce": { @@ -8939,16 +7168,6 @@ "node": ">=20" } }, - "node_modules/possible-typed-array-names": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.1.0.tgz", - "integrity": "sha512-/+5VFTchJDoVj3bhoqi6UeymcD00DAwb1nJwamzPvHEszJ4FpF6SNNbUbOS8yI56qHzdV8eK0qEfOSiodkTdxg==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - } - }, "node_modules/postcss": { "version": "8.5.29", "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.29.tgz", @@ -9029,18 +7248,6 @@ "node": "^16 || ^18 || >=20" } }, - "node_modules/prop-types": { - "version": "15.8.1", - "resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz", - "integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==", - "dev": true, - "license": "MIT", - "dependencies": { - "loose-envify": "^1.4.0", - "object-assign": "^4.1.1", - "react-is": "^16.13.1" - } - }, "node_modules/proxy-addr": { "version": "2.0.8", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.8.tgz", @@ -9092,6 +7299,24 @@ "node": ">=6" } }, + "node_modules/qified": { + "version": "0.10.1", + "resolved": "https://registry.npmjs.org/qified/-/qified-0.10.1.tgz", + "integrity": "sha512-+Owyggi9IxT1ePKGafcI87ubSmxol6smwJ+RAHDQlx9+9cPwFWDiKFFCPuWhr9ignlGpZ9vDQLw67N4dcTVFEA==", + "license": "MIT", + "dependencies": { + "hookified": "^2.1.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/qified/node_modules/hookified": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/hookified/-/hookified-2.2.0.tgz", + "integrity": "sha512-p/LgFzRN5FeoD3DLS6bkUapeye6E4SI6yJs6KetENd18S+FBthqYq2amJUWpt5z0EQwwHemidjY5OqJGEKm5uA==", + "license": "MIT" + }, "node_modules/qs": { "version": "6.16.0", "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", @@ -9172,13 +7397,6 @@ "node": ">= 0.10" } }, - "node_modules/react-is": { - "version": "16.13.1", - "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", - "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==", - "dev": true, - "license": "MIT" - }, "node_modules/readdirp": { "version": "3.6.0", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", @@ -9211,50 +7429,6 @@ "integrity": "sha512-D2E33ceRPga0NvTDhJmphEgJ7FUYF0v4lr1ki0csq06OdlxKfugGzN0dSkxM/NfqCxYELK4KcaTOUOjTV6Dcng==", "license": "MIT" }, - "node_modules/reflect.getprototypeof": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/reflect.getprototypeof/-/reflect.getprototypeof-1.0.10.tgz", - "integrity": "sha512-00o4I+DVrefhv+nX0ulyi3biSHCPDe+yLv5o/p6d/UVlirijB8E16FtfwSAi4g3tcqrQ4lRAqQSoFEZJehYEcw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-abstract": "^1.23.9", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0", - "get-intrinsic": "^1.2.7", - "get-proto": "^1.0.1", - "which-builtin-type": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/regexp.prototype.flags": { - "version": "1.5.4", - "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.4.tgz", - "integrity": "sha512-dYqgNSZbDwkaJ2ceRd9ojCGjBq+mOm9LmtXnAnEGyHhN/5R7iDW2TRw3h+o/jCFxus3P2LfWIIiwowAjANm7IA==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "define-properties": "^1.2.1", - "es-errors": "^1.3.0", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "set-function-name": "^2.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/require-from-string": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", @@ -9274,30 +7448,6 @@ "node": ">=0.10.5" } }, - "node_modules/resolve": { - "version": "2.0.0-next.7", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-2.0.0-next.7.tgz", - "integrity": "sha512-tqt+NBWwyaMgw3zDsnygx4CByWjQEJHOPMdslYhppaQSJUtL/D4JO9CcBBlhPoI8lz9oJIDXkwXfhF4aWqP8xQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "is-core-module": "^2.16.2", - "node-exports-info": "^1.6.0", - "object-keys": "^1.1.1", - "path-parse": "^1.0.7", - "supports-preserve-symlinks-flag": "^1.0.0" - }, - "bin": { - "resolve": "bin/resolve" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/resolve-from": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", @@ -9487,26 +7637,6 @@ "tslib": "^2.1.0" } }, - "node_modules/safe-array-concat": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.4.tgz", - "integrity": "sha512-wtZlHyOje6OZTGqAoaDKxFkgRtkF9CnHAVnCHKfuj200wAgL+bSJhdsCD2l0Qx/2ekEXjPWcyKkfGb5CPboslg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "get-intrinsic": "^1.3.0", - "has-symbols": "^1.1.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">=0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-buffer": { "version": "5.2.1", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", @@ -9527,41 +7657,6 @@ ], "license": "MIT" }, - "node_modules/safe-push-apply": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/safe-push-apply/-/safe-push-apply-1.0.0.tgz", - "integrity": "sha512-iKE9w/Z7xCzUMIZqdBsp6pEQvwuEebH4vdpjcDWnyzaI6yl6O9FHvVpmGelvEHNsoY6wGblkxR6Zty/h00WiSA==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "isarray": "^2.0.5" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/safe-regex-test": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.1.0.tgz", - "integrity": "sha512-x/+Cz4YrimQxQccJf5mKEbIa1NzeCRNI5Ecl/ekmlYaampdNLPalVyIcCZNNH3MvmqBugV5TMYZXv0ljslUlaw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "es-errors": "^1.3.0", - "is-regex": "^1.2.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/safe-stable-stringify": { "version": "2.5.0", "resolved": "https://registry.npmjs.org/safe-stable-stringify/-/safe-stable-stringify-2.5.0.tgz", @@ -10083,55 +8178,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/set-function-length": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", - "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "function-bind": "^1.1.2", - "get-intrinsic": "^1.2.4", - "gopd": "^1.0.1", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-function-name": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz", - "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-data-property": "^1.1.4", - "es-errors": "^1.3.0", - "functions-have-names": "^1.2.3", - "has-property-descriptors": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/set-proto": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/set-proto/-/set-proto-1.0.0.tgz", - "integrity": "sha512-RJRdvCo6IAnPdsvP/7m6bsQqNnn1FCBX5ZNtFL98MmFF/4xAIJTIg1YbHW5DC2W5SKZanrC6i4HsJqlajw/dZw==", - "dev": true, - "license": "MIT", - "dependencies": { - "dunder-proto": "^1.0.1", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/setprototypeof": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", @@ -10268,25 +8314,8 @@ "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", "license": "MIT", - "dependencies": { - "memory-pager": "^1.0.2" - } - }, - "node_modules/stable-hash": { - "version": "0.0.5", - "resolved": "https://registry.npmjs.org/stable-hash/-/stable-hash-0.0.5.tgz", - "integrity": "sha512-+L3ccpzibovGXFK+Ap/f8LOS0ahMrHTf3xu7mMLSpEGU0EO9ucaysSylKo9eRDFNhWve/y275iPmIZ4z39a9iA==", - "dev": true, - "license": "MIT" - }, - "node_modules/stable-hash-x": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/stable-hash-x/-/stable-hash-x-0.2.0.tgz", - "integrity": "sha512-o3yWv49B/o4QZk5ZcsALc6t0+eCelPc44zZsLtCQnZPDwFpDYSWcDnrv2TtMmMbQ7uKo3J0HTURCqckw23czNQ==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=12.0.0" + "dependencies": { + "memory-pager": "^1.0.2" } }, "node_modules/statuses": { @@ -10298,20 +8327,6 @@ "node": ">= 0.8" } }, - "node_modules/stop-iteration-iterator": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.1.0.tgz", - "integrity": "sha512-eLoXW/DHyl62zxY4SCaIgnRhuMr6ri4juEYARS8E6sCEqzKpOiE521Ucofdx+KnDZl5xmvGYaaKCk5FEOxJCoQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "es-errors": "^1.3.0", - "internal-slot": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - } - }, "node_modules/streamx": { "version": "2.28.1", "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.28.1.tgz", @@ -10340,105 +8355,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/string.prototype.matchall": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.1.0.tgz", - "integrity": "sha512-tHNHTxInrYLCga9O9YGxWA3G9/nnzQw8UGAyqGx3Ar1pSTTzIuM4woFSq4SowkXCjJIwq5sIiQvEfRI9tCH1qQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.2", - "es-errors": "^1.3.0", - "es-object-atoms": "^1.1.2", - "get-intrinsic": "^1.3.0", - "gopd": "^1.2.0", - "has-symbols": "^1.1.0", - "internal-slot": "^1.1.0", - "regexp.prototype.flags": "^1.5.4", - "set-function-name": "^2.0.2", - "side-channel": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.repeat": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/string.prototype.repeat/-/string.prototype.repeat-1.0.0.tgz", - "integrity": "sha512-0u/TldDbKD8bFCQ/4f5+mNRrXwZ8hg2w7ZR8wa16e8z9XpePWl3eGEcUD0OXpEH/VJH/2G3gjUtR3ZOiBe2S/w==", - "dev": true, - "license": "MIT", - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.5" - } - }, - "node_modules/string.prototype.trim": { - "version": "1.2.11", - "resolved": "https://registry.npmjs.org/string.prototype.trim/-/string.prototype.trim-1.2.11.tgz", - "integrity": "sha512-PwvK7BU+CMTJGYQCTZb5RWXIML92lftJLhQz1tBzgKiqGxJaMlBAa48POXaNAC2s4y8jr3EFqrkF9+44neS46w==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "define-data-property": "^1.1.4", - "define-properties": "^1.2.1", - "es-abstract": "^1.24.2", - "es-object-atoms": "^1.1.2", - "has-property-descriptors": "^1.0.2", - "safe-regex-test": "^1.1.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimend": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.10.tgz", - "integrity": "sha512-2+3aDAOmPTmuFwjDnmJG2ctEkQKVki7vOSqaxkv42Mowj1V6PnvuwFCRrR5lChUux1TBskPjfkeTOhqczDMxTw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.1.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/string.prototype.trimstart": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.8.tgz", - "integrity": "sha512-UXSH262CSZY1tfu3G3Secr6uGLCFVPMhIqHjlgCUtCCcgihYc/xKs9djMTMUOb2j1mVSeU8EU6NWc/iQKU6Gfg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.7", - "define-properties": "^1.2.1", - "es-object-atoms": "^1.0.0" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/strip-ansi": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", @@ -10455,18 +8371,6 @@ "url": "https://github.com/chalk/strip-ansi?sponsor=1" } }, - "node_modules/strip-json-comments": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", - "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", - "license": "MIT", - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "node_modules/strip-literal": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-literal/-/strip-literal-4.0.0.tgz", @@ -10485,31 +8389,6 @@ "integrity": "sha512-lM/UBzQmfJRo9ABXbPWemivdCW8V2G8FHaHdypQaIy523snUjog0W71ayWXTjiR+ixeMyVHN2XcpnTd/liPg/Q==", "license": "MIT" }, - "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==", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/supports-preserve-symlinks-flag": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", - "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/sync-child-process": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/sync-child-process/-/sync-child-process-1.0.2.tgz", @@ -10725,29 +8604,6 @@ "typescript": ">=4.8.4" } }, - "node_modules/ts-declaration-location": { - "version": "1.0.7", - "resolved": "https://registry.npmjs.org/ts-declaration-location/-/ts-declaration-location-1.0.7.tgz", - "integrity": "sha512-EDyGAwH1gO0Ausm9gV6T2nUvBgXT5kGoCMJPllOaooZ+4VvJiKBdZE7wK18N1deEowhcUptS+5GXZK8U/fvpwA==", - "dev": true, - "funding": [ - { - "type": "ko-fi", - "url": "https://ko-fi.com/rebeccastevens" - }, - { - "type": "tidelift", - "url": "https://tidelift.com/funding/github/npm/ts-declaration-location" - } - ], - "license": "BSD-3-Clause", - "dependencies": { - "picomatch": "^4.0.2" - }, - "peerDependencies": { - "typescript": ">=4.0.0" - } - }, "node_modules/tslib": { "version": "2.8.1", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", @@ -10837,83 +8693,6 @@ "url": "https://opencollective.com/express" } }, - "node_modules/typed-array-buffer": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-buffer/-/typed-array-buffer-1.0.3.tgz", - "integrity": "sha512-nAYYwfY3qnzX30IkA6AQZjVbtK6duGontcQm1WSG1MD94YLqK0515GNApXkoxKOWMusVssAHWLh9SeaoefYFGw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "es-errors": "^1.3.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - } - }, - "node_modules/typed-array-byte-length": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/typed-array-byte-length/-/typed-array-byte-length-1.0.3.tgz", - "integrity": "sha512-BaXgOuIxz8n8pIq3e7Atg/7s+DpiYrxn4vdot3w9KbnBhcRQq6o3xemQdIfynqSeXeDrF32x+WvfzmOjPiY9lg==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.8", - "for-each": "^0.3.3", - "gopd": "^1.2.0", - "has-proto": "^1.2.0", - "is-typed-array": "^1.1.14" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-byte-offset": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/typed-array-byte-offset/-/typed-array-byte-offset-1.0.5.tgz", - "integrity": "sha512-0FHJvLPqZ7KJzp17O13jfsAjsqazgrxBu2zEK95PmUz8lv2+GjRuxUInCr2Rk9Dms3ihN21zJ929ZO43yJ95QQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.9", - "for-each": "^0.3.5", - "gopd": "^1.2.0", - "is-typed-array": "^1.1.15", - "reflect.getprototypeof": "^1.0.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/typed-array-length": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/typed-array-length/-/typed-array-length-1.0.8.tgz", - "integrity": "sha512-phPGCwqr2+Qo0fwniCE8e4pKnGu/yFb5nD5Y8bf0EEeiI5GklnACYA9GFy/DrAeRrKHXvHn+1SUsOWgJp6RO+g==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bind": "^1.0.9", - "for-each": "^0.3.5", - "gopd": "^1.2.0", - "is-typed-array": "^1.1.15", - "possible-typed-array-names": "^1.1.0", - "reflect.getprototypeof": "^1.0.10" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/typescript": { "version": "6.0.3", "resolved": "https://registry.npmjs.org/typescript/-/typescript-6.0.3.tgz", @@ -10973,25 +8752,6 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "node_modules/unbox-primitive": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.1.0.tgz", - "integrity": "sha512-nWJ91DjeOkej/TA8pXQ3myruKpKEYgqvpw9lz4OPHj/NWFNluYrjbz9j01CJ8yKQd2g4jFoOkINCTW2I5LEEyw==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.3", - "has-bigints": "^1.0.2", - "has-symbols": "^1.1.0", - "which-boxed-primitive": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/undefsafe": { "version": "2.0.5", "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz", @@ -11005,6 +8765,19 @@ "integrity": "sha512-KTDyRTYX8sWmKXAikPHHSyc63CRPETMctyjKFupcC6OBLXT3xsN0e9aF7m+mIXutFWpUXuedtowG7iLOzp0kQg==", "license": "MIT" }, + "node_modules/unicorn-magic": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.3.0.tgz", + "integrity": "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/unimport": { "version": "6.5.0", "resolved": "https://registry.npmjs.org/unimport/-/unimport-6.5.0.tgz", @@ -11406,44 +9179,6 @@ } } }, - "node_modules/unrs-resolver": { - "version": "1.12.2", - "resolved": "https://registry.npmjs.org/unrs-resolver/-/unrs-resolver-1.12.2.tgz", - "integrity": "sha512-dmlRxBJJayXjqTwC+JtF1HhJmgf3ftQ3YejFcZrf4+KKtJv0qDsK1pjqaaVjG7wJ5NJ6UVP1OqRMQ71Z4C3rxQ==", - "dev": true, - "hasInstallScript": true, - "license": "MIT", - "dependencies": { - "napi-postinstall": "^0.3.4" - }, - "funding": { - "url": "https://opencollective.com/unrs-resolver" - }, - "optionalDependencies": { - "@unrs/resolver-binding-android-arm-eabi": "1.12.2", - "@unrs/resolver-binding-android-arm64": "1.12.2", - "@unrs/resolver-binding-darwin-arm64": "1.12.2", - "@unrs/resolver-binding-darwin-x64": "1.12.2", - "@unrs/resolver-binding-freebsd-x64": "1.12.2", - "@unrs/resolver-binding-linux-arm-gnueabihf": "1.12.2", - "@unrs/resolver-binding-linux-arm-musleabihf": "1.12.2", - "@unrs/resolver-binding-linux-arm64-gnu": "1.12.2", - "@unrs/resolver-binding-linux-arm64-musl": "1.12.2", - "@unrs/resolver-binding-linux-loong64-gnu": "1.12.2", - "@unrs/resolver-binding-linux-loong64-musl": "1.12.2", - "@unrs/resolver-binding-linux-ppc64-gnu": "1.12.2", - "@unrs/resolver-binding-linux-riscv64-gnu": "1.12.2", - "@unrs/resolver-binding-linux-riscv64-musl": "1.12.2", - "@unrs/resolver-binding-linux-s390x-gnu": "1.12.2", - "@unrs/resolver-binding-linux-x64-gnu": "1.12.2", - "@unrs/resolver-binding-linux-x64-musl": "1.12.2", - "@unrs/resolver-binding-openharmony-arm64": "1.12.2", - "@unrs/resolver-binding-wasm32-wasi": "1.12.2", - "@unrs/resolver-binding-win32-arm64-msvc": "1.12.2", - "@unrs/resolver-binding-win32-ia32-msvc": "1.12.2", - "@unrs/resolver-binding-win32-x64-msvc": "1.12.2" - } - }, "node_modules/upath": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/upath/-/upath-2.0.1.tgz", @@ -11905,95 +9640,6 @@ "node": ">= 8" } }, - "node_modules/which-boxed-primitive": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.1.1.tgz", - "integrity": "sha512-TbX3mj8n0odCBFVlY8AxkqcHASw3L60jIuF8jFP78az3C2YhmGvqbHBpAjTRH2/xqYunrJ9g1jSyjCjpoWzIAA==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-bigint": "^1.1.0", - "is-boolean-object": "^1.2.1", - "is-number-object": "^1.1.1", - "is-string": "^1.1.1", - "is-symbol": "^1.1.1" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-builtin-type": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/which-builtin-type/-/which-builtin-type-1.2.1.tgz", - "integrity": "sha512-6iBczoX+kDQ7a3+YJBnh3T+KZRxM/iYNPXicqk66/Qfm1b93iu+yOImkg0zHbj5LNOcNv1TEADiZ0xa34B4q6Q==", - "dev": true, - "license": "MIT", - "dependencies": { - "call-bound": "^1.0.2", - "function.prototype.name": "^1.1.6", - "has-tostringtag": "^1.0.2", - "is-async-function": "^2.0.0", - "is-date-object": "^1.1.0", - "is-finalizationregistry": "^1.1.0", - "is-generator-function": "^1.0.10", - "is-regex": "^1.2.1", - "is-weakref": "^1.0.2", - "isarray": "^2.0.5", - "which-boxed-primitive": "^1.1.0", - "which-collection": "^1.0.2", - "which-typed-array": "^1.1.16" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-collection": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/which-collection/-/which-collection-1.0.2.tgz", - "integrity": "sha512-K4jVyjnBdgvc86Y6BkaLZEN933SwYOuBFkdmBu9ZfkcAbdVbpITnDmjvZ/aQjRXQrv5EPkTnD1s39GiiqbngCw==", - "dev": true, - "license": "MIT", - "dependencies": { - "is-map": "^2.0.3", - "is-set": "^2.0.3", - "is-weakmap": "^2.0.2", - "is-weakset": "^2.0.3" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, - "node_modules/which-typed-array": { - "version": "1.1.24", - "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.24.tgz", - "integrity": "sha512-wk4Mf4pR5mRP7eYuuTBCIQ9d0ud2Fv2jRLQpfgnRjbOxAFHmjKFValgTpitVKzJJS8ajnYQV2Du1SZ8j6b/EUQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "available-typed-arrays": "^1.0.7", - "call-bind": "^1.0.9", - "call-bound": "^1.0.4", - "for-each": "^0.3.5", - "get-proto": "^1.0.1", - "gopd": "^1.2.0", - "has-tostringtag": "^1.0.2" - }, - "engines": { - "node": ">= 0.4" - }, - "funding": { - "url": "https://github.com/sponsors/ljharb" - } - }, "node_modules/word-wrap": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz", @@ -12025,19 +9671,6 @@ "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/wrap-ansi/node_modules/string-width": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz", @@ -12195,7 +9828,7 @@ "shared": { "name": "@data-fair/processings-shared", "dependencies": { - "@data-fair/lib-node": "~2.15.0", + "@data-fair/lib-node": "^2.16.1", "@data-fair/lib-utils": "^1.13.1", "croner": "^9.1.0", "dayjs": "^1.11.13", @@ -12248,16 +9881,16 @@ "vue": "^3.5.30", "vue-i18n": "^11.1.11", "vue-router": "^5.0.3", - "vue-tsc": "^3.0.1", + "vue-tsc": "^3.3.0", "vuetify": "^4.0.3" }, "devDependencies": { - "@data-fair/lib-express": "~1.28.1" + "@data-fair/lib-express": "^1.31.0" } }, "worker": { "dependencies": { - "@data-fair/lib-node": "~2.15.0", + "@data-fair/lib-node": "^2.16.1", "@data-fair/lib-node-registry": "0.7.2", "@data-fair/lib-validation": "^1.0.2", "@data-fair/processings-shared": "*", @@ -12275,7 +9908,7 @@ "tree-kill": "^1.2.2" }, "devDependencies": { - "@data-fair/lib-express": "~1.28.1", + "@data-fair/lib-express": "^1.31.0", "@types/nodemailer": "^8.0.1", "@types/resolve-path": "^1.4.3" } diff --git a/package.json b/package.json index 0be5a6dc..86d0ada0 100644 --- a/package.json +++ b/package.json @@ -5,22 +5,18 @@ "type": "module", "scripts": { "build-types": "df-build-types ./", - "check-types": "tsc", - "dev-api": "mkdir -p dev/logs && npm -w api run dev 2>&1 | tee dev/logs/dev-api.log", - "dev-deps": "mkdir -p dev/logs && docker compose --profile dev up -d --wait && docker compose --profile dev logs -f 2>&1 | tee dev/logs/docker-compose.log", - "dev-ui": "mkdir -p dev/logs && npm -w ui run dev 2>&1 | tee dev/logs/dev-ui.log", - "dev-worker": "mkdir -p dev/logs && npm -w worker run dev 2>&1 | tee dev/logs/dev-worker.log", - "dev-zellij": "export DEV_SHELL=$(basename \"$SHELL\") && dotenv -- zellij --layout .zellij.kdl", + "check-types": "tsc && npm -w ui run check-types", + "dev-zellij": "df-dev zellij", "lint": "eslint . && npm -w ui run lint", "lint-fix": "eslint --fix . && npm -w ui run lint-fix", "prepare": "husky || true", - "stop-dev-deps": "docker compose --profile dev stop", - "test": "playwright test --max-failures=1", - "test-unit": "playwright test --project unit --max-failures=1", - "test-api": "playwright test --project api --max-failures=1", - "test-e2e": "playwright test --project e2e --max-failures=1", - "test-images": "docker compose --profile dev --profile testImages up -d --build --wait", - "quality": "npm run lint && npm run build-types && npm run check-types && npm -w ui run build && npm test && npm audit --omit=dev --audit-level=critical" + "stop-dev-deps": "docker compose --profile '*' stop", + "test": "playwright test", + "test-unit": "playwright test --project=unit", + "test-api": "playwright test --project=api", + "test-api-fast": "playwright test --project=api --max-failures=1", + "test-e2e": "playwright test --project=e2e", + "quality": "npm run lint && npm run build-types && npm -w ui run build && npm run check-types && npm test && npm audit --omit=dev --audit-level=critical" }, "repository": { "type": "git", @@ -46,25 +42,26 @@ "node": "v24" }, "dependencies": { - "@data-fair/lib-types-builder": "^1.14.3" + "@data-fair/lib-types-builder": "^1.14.5" }, "devDependencies": { + "@commitlint/cli": "^21.2.3", "@commitlint/config-conventional": "^21.2.3", "@data-fair/lib-common-types": "^1.23.0", - "@data-fair/lib-node": "~2.15.0", - "@data-fair/lib-utils": "^1.13.1", + "@data-fair/lib-dev": "^0.1.0", + "@data-fair/lib-node": "^2.16.1", + "@data-fair/lib-utils": "^1.14.0", "@playwright/test": "^1.52.0", "@types/config": "^3.3.5", "@types/debug": "^4.1.12", - "commitlint": "^21.2.3", "dotenv": "^16.4.5", "dotenv-cli": "^7.4.4", - "eslint": "^9.35.0", - "eslint-plugin-vue": "^10.4.0", - "eslint-plugin-vuetify": "^2.7.2", + "eslint": "^10.12.0", + "eslint-plugin-vue": "^10.11.1", + "eslint-plugin-vuetify": "^2.7.3", "form-data": "^4.0.6", "husky": "^9.1.7", - "neostandard": "^0.12.2", + "neostandard": "^0.14.1", "nodemon": "^3.1.14", "tough-cookie": "^5.0.0", "typescript": "^6.0.3" diff --git a/playwright.config.ts b/playwright.config.ts index f1f09bb5..6bfe8a23 100644 --- a/playwright.config.ts +++ b/playwright.config.ts @@ -3,33 +3,36 @@ import 'dotenv/config' export default defineConfig({ testDir: './tests', + // the api and e2e tests share the state of one dev env workers: 1, fullyParallel: false, forbidOnly: !!process.env.CI, + // a flake must not cost a full re-run in CI retries: process.env.CI ? 1 : 0, - reporter: 'dot', - timeout: 60_000, + // the json report keeps the per-test durations of the last run, used to size the smoke set + reporter: [['dot'], ['json', { outputFile: 'dev/logs/test-timings.json' }]], + // per test, hooks included: specs that run plugins call test.slow() (x3) instead of raising this + timeout: 30_000, expect: { timeout: 5_000 }, use: { - baseURL: `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT1}/processings`, + baseURL: `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT}/processings`, actionTimeout: 5_000, - navigationTimeout: 5_000, + navigationTimeout: 10_000, + trace: 'retain-on-failure', + screenshot: 'only-on-failure', }, projects: [ { name: 'state-setup', testMatch: /state-setup\.ts/, - teardown: 'state-teardown' - }, - { - name: 'state-teardown', - testMatch: /state-teardown\.ts/, }, { name: 'unit', testMatch: /.*\.unit\.spec\.ts/, + // no server, no shared state + fullyParallel: true, }, { name: 'api', @@ -37,14 +40,13 @@ export default defineConfig({ dependencies: ['state-setup'], }, { - // Walks the heavy UI routes once so Vite finishes optimizing its lazy - // deps before the specs run — a mid-test re-optimization forces a full - // page reload and fails a random spec on a timeout. + // Walks the heavy UI routes once so a cold Vite transforms them before + // the specs run. name: 'e2e-warmup', testMatch: /e2e-warmup\.ts/, dependencies: ['state-setup'], timeout: 180_000, - use: { ...devices['Desktop Chrome'] }, + use: { ...devices['Desktop Chrome'], navigationTimeout: 60_000 }, }, { name: 'e2e', diff --git a/shared/package.json b/shared/package.json index fb944080..1ed1dc33 100644 --- a/shared/package.json +++ b/shared/package.json @@ -2,7 +2,7 @@ "name": "@data-fair/processings-shared", "type": "module", "dependencies": { - "@data-fair/lib-node": "~2.15.0", + "@data-fair/lib-node": "^2.16.1", "@data-fair/lib-utils": "^1.13.1", "croner": "^9.1.0", "dayjs": "^1.11.13", diff --git a/tests/e2e-warmup.ts b/tests/e2e-warmup.ts index 4f2ad495..298189de 100644 --- a/tests/e2e-warmup.ts +++ b/tests/e2e-warmup.ts @@ -3,18 +3,17 @@ import { axiosAuth, clean } from './support/axios.ts' import { publishFixturePlugin } from './support/registry.ts' /** - * Vite serves the UI in dev mode, and discovers dependencies lazily: the first - * page that mounts the vjsf form or opens an action menu pulls in Vuetify - * components that were not in the optimized bundle yet. Vite then re-optimizes - * and forces a full page reload — which wipes whatever assertion was running, - * and makes a random e2e spec fail on a timeout at every cold start. + * Vite serves the UI in dev mode and transforms each route's modules on its + * first visit, slower than the e2e timeouts on a cold start. Dependency + * discovery is off (`optimizeDeps.noDiscovery` in ui/vite.config.ts: no page + * reload), so this run also fails fast on a commonjs dependency missing from + * `optimizeDeps.include` (blank page, the module named in the console). * - * This project runs before the e2e ones and walks the heavy routes so all the - * lazy deps are optimized once, up front. + * This project runs before the e2e ones and walks the heavy routes once. */ -setup('Warmup heavy dev routes', async ({ page, goToWithAuth }) => { +setup('Warmup heavy dev routes', async ({ page, goToWithAuth }, testInfo) => { const start = Date.now() - const stamp = (label: string) => console.log(`[warmup] ${label}: ${((Date.now() - start) / 1000).toFixed(1)}s`) + const stamp = (label: string) => testInfo.annotations.push({ type: 'warmup', description: `${label}: ${((Date.now() - start) / 1000).toFixed(1)}s` }) await clean() const superadmin = await axiosAuth('test_superadmin@test.com') diff --git a/tests/features/processings/available-plugin.e2e.spec.ts b/tests/features/processings/available-plugin.e2e.spec.ts deleted file mode 100644 index 72523901..00000000 --- a/tests/features/processings/available-plugin.e2e.spec.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, expect } from '../../fixtures/login.ts' -import { axiosAuth, clean } from '../../support/axios.ts' -import { publishFixturePlugin } from '../../support/registry.ts' - -/** - * Happy-path counterpart to broken-plugin.e2e.spec.ts: a processing whose - * plugin IS available in the registry must render its config form on the edit - * page — and must NOT show the "plugin unavailable" banner. - * - * Regression guard: the edit page fetched the registry artefact through the - * API-scoped `$fetch` (baseURL `/processings/api/v1`), so `/registry/...` was - * rewritten to `/processings/api/v1/registry/...` → 404 → every processing - * looked broken. - */ -test.describe('processing with available plugin — UI', () => { - test.beforeEach(clean) - test.afterAll(clean) - - test('edit page renders the config form, no broken-plugin banner', async ({ page, goToWithAuth }) => { - const superadmin = await axiosAuth('test_superadmin@test.com') - const fixture = await publishFixturePlugin({ - name: '@data-fair/processing-hello-world', - version: '1.2.2' - }) - const processing = (await superadmin.post('/api/v1/processings', { - title: 'Healthy e2e processing', - plugin: fixture.pluginId, - owner: { type: 'user', id: 'test_superadmin', name: 'Test Super Admin' } - })).data - - await goToWithAuth(`/processings/processings/${processing._id}`, 'test_superadmin') - - await expect(page.getByText('Healthy e2e processing').first()).toBeVisible({ timeout: 10000 }) - // The broken-plugin banner must NOT appear for an available plugin. - await expect(page.getByText(/Plugin indisponible/)).toHaveCount(0) - // The vjsf config form is rendered (v-if="processingSchema && !pluginBroken"). - await expect(page.locator('.vjsf')).toBeVisible() - }) -}) diff --git a/tests/features/processings/branch-plugin.api.spec.ts b/tests/features/processings/branch-plugin.api.spec.ts index 05d6f732..813c37b9 100644 --- a/tests/features/processings/branch-plugin.api.spec.ts +++ b/tests/features/processings/branch-plugin.api.spec.ts @@ -15,21 +15,8 @@ test.describe('processing — branch ref artefact', () => { test.beforeEach(clean) test.afterAll(clean) - test('creates a processing pointed at a branch ref artefact', async () => { - const superadmin = await axiosAuth('test_superadmin@test.com') - const plugin = await installBranchPlugin() - expect(plugin.pluginId).toBe(BRANCH_PLUGIN_ID) - - const processing = (await superadmin.post('/api/v1/processings', { - title: 'Branch processing', - plugin: plugin.pluginId, - owner: { type: 'user', id: 'test_superadmin', name: 'Test Super Admin' } - })).data - expect(processing._id).toBeTruthy() - expect(processing.plugin).toBe(plugin.pluginId) - }) - test('runs a branch-backed processing end-to-end', async () => { + test.slow() // a real run through the worker const superadmin = await axiosAuth('test_superadmin@test.com') const plugin = await installBranchPlugin() @@ -45,35 +32,10 @@ test.describe('processing — branch ref artefact', () => { message: 'Branch hello' } })).data + expect(processing.plugin).toBe(BRANCH_PLUGIN_ID) const triggered = (await superadmin.post(`/api/v1/processings/${processing._id}/_trigger`)).data const finishedRun = await waitForRunStatus(triggered._id, 'finished', 30_000) expect(finishedRun.status).toBe('finished') }) - - test('re-uploading the same branch ref bumps dataUpdatedAt (cache invalidation signal)', async () => { - // The end-to-end "second run picks up the new tarball" path runs through - // data-fair (the plugin creates a dataset on first run, mode flips to - // update for subsequent runs). That introduces orthogonal flakiness that - // has nothing to do with branch-ref resolution. Instead we assert the - // contract lib-node-registry relies on: re-uploads bump `dataUpdatedAt`, - // which is the cache key. - await installBranchPlugin() - const { axiosRegistryInternal } = await import('../../support/registry.ts') - const before = (await axiosRegistryInternal.get( - '/api/v1/artefacts/' + encodeURIComponent(BRANCH_PLUGIN_ID) - )).data - expect(before.format).toBe('npm') - expect(before.dataUpdatedAt).toBeTruthy() - - // Wait long enough that the second timestamp can't tie with the first. - await new Promise(resolve => setTimeout(resolve, 10)) - - await publishFixtureBranchPlugin({ artefactId: BRANCH_PLUGIN_ID }) - const after = (await axiosRegistryInternal.get( - '/api/v1/artefacts/' + encodeURIComponent(BRANCH_PLUGIN_ID) - )).data - expect(after.dataUpdatedAt).not.toBe(before.dataUpdatedAt) - expect(new Date(after.dataUpdatedAt) > new Date(before.dataUpdatedAt)).toBe(true) - }) }) diff --git a/tests/features/processings/broken-plugin.api.spec.ts b/tests/features/processings/broken-plugin.api.spec.ts index b7957021..ff5c802f 100644 --- a/tests/features/processings/broken-plugin.api.spec.ts +++ b/tests/features/processings/broken-plugin.api.spec.ts @@ -50,7 +50,7 @@ test.describe('processing with unavailable plugin', () => { expect(res.data.title).toBe('New title') }) - test('PATCH /processings/:id with a config field surfaces a 404 with the plugin id', async () => { + test('PATCH /processings/:id with a config field surfaces a 404 with the plugin id', { tag: '@smoke' }, async () => { const superadmin = await axiosAuth('test_superadmin@test.com') const id = await createBrokenProcessing(superadmin) diff --git a/tests/features/processings/lifecycle.api.spec.ts b/tests/features/processings/lifecycle.api.spec.ts index 291615a1..81070e2f 100644 --- a/tests/features/processings/lifecycle.api.spec.ts +++ b/tests/features/processings/lifecycle.api.spec.ts @@ -13,10 +13,12 @@ const installTestPlugin = async () => publishFixturePlugin({ }) test.describe('processing', () => { + // every test here runs the plugin through the worker (up to ~60 s measured, two runs) + test.beforeEach(() => { test.slow() }) test.beforeEach(clean) test.afterAll(clean) - test('should create a new processing, activate it and run it', async () => { + test('should create a new processing, activate it and run it', { tag: '@smoke' }, async () => { const superadmin = await axiosAuth('test_superadmin@test.com') const plugin = await installTestPlugin() diff --git a/tests/features/processings/memory-oom.e2e.spec.ts b/tests/features/processings/memory-oom.api.spec.ts similarity index 98% rename from tests/features/processings/memory-oom.e2e.spec.ts rename to tests/features/processings/memory-oom.api.spec.ts index 3cd40805..33f4fec9 100644 --- a/tests/features/processings/memory-oom.e2e.spec.ts +++ b/tests/features/processings/memory-oom.api.spec.ts @@ -116,7 +116,6 @@ test.describe('memory pressure diagnostics', () => { }) test('CPU-saturated task still reports RSS via external sampler', async () => { - test.skip(process.platform !== 'linux', 'external sampler is Linux-only') test.setTimeout(120_000) const superadmin = await axiosAuth('test_superadmin@test.com') diff --git a/tests/features/processings/operations.unit.spec.ts b/tests/features/processings/operations.unit.spec.ts new file mode 100644 index 00000000..2a524776 --- /dev/null +++ b/tests/features/processings/operations.unit.spec.ts @@ -0,0 +1,30 @@ +import { test, expect } from '@playwright/test' +import { translateRegistryError } from '../../../api/src/processings/operations.ts' + +// the api specs plugin-access and plugin-info-transitivity check the real registry round trip; +// the message of each status lives here +const processing = { plugin: '@test-plugin-1', owner: { type: 'user', id: 'test_user1', name: 'Test User 1' } } as any + +test.describe('translateRegistryError', () => { + test('403 names the owner and the plugin', () => { + const err = translateRegistryError({ status: 403 }, processing) + expect(err.status).toBe(403) + expect(err.message).toBe("Le compte Test User 1 n'a pas accès au plugin @test-plugin-1.") + }) + + test('403 falls back to the owner id without a name', () => { + const err = translateRegistryError({ statusCode: 403 }, { ...processing, owner: { type: 'user', id: 'test_user1' } }) + expect(err.message).toContain('Le compte test_user1 ') + }) + + test('404 says the plugin is missing from the registry', () => { + const err = translateRegistryError({ status: 404 }, processing) + expect(err.status).toBe(404) + expect(err.message).toBe('Le plugin @test-plugin-1 est introuvable dans le registre.') + }) + + test('anything else is a registry outage (502)', () => { + expect(translateRegistryError({ status: 500 }, processing).status).toBe(502) + expect(translateRegistryError(new Error('ECONNREFUSED'), processing).status).toBe(502) + }) +}) diff --git a/tests/features/processings/permissions.api.spec.ts b/tests/features/processings/permissions.api.spec.ts index ab7814cd..58b33906 100644 --- a/tests/features/processings/permissions.api.spec.ts +++ b/tests/features/processings/permissions.api.spec.ts @@ -11,7 +11,7 @@ test.describe('processing permissions', () => { test.beforeEach(clean) test.afterAll(clean) - test('should create a processing and check permissions across roles', async () => { + test('should create a processing and check permissions across roles', { tag: '@smoke' }, async () => { const plugin = await installTestPlugin() const adminTestOrg1 = await axiosAuth({ email: 'test_admin1@test.com', org: 'test_org1' }) diff --git a/tests/features/processings/save-button.e2e.spec.ts b/tests/features/processings/save-button.e2e.spec.ts index c1b03c45..0f3febf8 100644 --- a/tests/features/processings/save-button.e2e.spec.ts +++ b/tests/features/processings/save-button.e2e.spec.ts @@ -25,10 +25,13 @@ test.describe('processing edit page — explicit save', () => { return { superadmin, id: processing._id as string } } - test('save button appears on edit, cancel restores, save persists', async ({ page, goToWithAuth }) => { + test('save button appears on edit, cancel restores, save persists', { tag: '@smoke' }, async ({ page, goToWithAuth }) => { const { superadmin, id } = await setup() await goToWithAuth(`/processings/processings/${id}`, 'test_superadmin') await expect(page.locator('.vjsf')).toBeVisible({ timeout: 20000 }) + // an available plugin: the form renders and no broken-plugin banner shows (regression: the + // registry artefact was fetched under the API base URL, 404, every processing looked broken) + await expect(page.getByText(/Plugin indisponible/)).toHaveCount(0) // first "Titre" field is the processing title, the plugin config has one too const titleField = page.getByLabel('Titre', { exact: true }).first() await expect(titleField).toHaveValue('Save e2e processing') @@ -67,7 +70,8 @@ test.describe('processing edit page — explicit save', () => { // router navigation (the breadcrumbs live in the parent frame). await goToWithAuth('/processings/processings', 'test_superadmin') await page.getByText('Save e2e processing').first().click() - await page.waitForURL(new RegExp(`/processings/processings/${id}$`)) + // an in-app navigation: web-first assertion on the URL, no wait for a load event + await expect(page).toHaveURL(new RegExp(`/processings/processings/${id}$`), { timeout: 20_000 }) await expect(page.locator('.vjsf')).toBeVisible({ timeout: 20000 }) // first "Titre" field is the processing title, the plugin config has one too const titleField = page.getByLabel('Titre', { exact: true }).first() diff --git a/tests/features/ui/layout.e2e.spec.ts b/tests/features/ui/layout.e2e.spec.ts index 79366473..a912a6fe 100644 --- a/tests/features/ui/layout.e2e.spec.ts +++ b/tests/features/ui/layout.e2e.spec.ts @@ -1,30 +1,12 @@ import { test, expect } from '../../fixtures/login.ts' -import { axiosAuth, clean } from '../../support/axios.ts' -import { publishFixturePlugin } from '../../support/registry.ts' +import { clean } from '../../support/axios.ts' test.describe('UI layout', () => { test.beforeEach(clean) test.afterAll(clean) - test('authenticated user sees the processings list with empty state', async ({ page, goToWithAuth }) => { + test('authenticated user sees the processings list with empty state', { tag: '@smoke' }, async ({ page, goToWithAuth }) => { await goToWithAuth('/processings/processings', 'test_user1') await expect(page.getByText(/n'avez pas encore créé de traitement/)).toBeVisible({ timeout: 10000 }) }) - - test('processings list renders a card for an existing processing', async ({ page, goToWithAuth }) => { - const superadmin = await axiosAuth('test_superadmin@test.com') - const fixture = await publishFixturePlugin({ - name: '@data-fair/processing-hello-world', - version: '1.2.2' - }) - - await superadmin.post('/api/v1/processings', { - title: 'My e2e processing', - plugin: fixture.pluginId, - owner: { type: 'user', id: 'test_superadmin', name: 'Test Super Admin' } - }) - - await goToWithAuth('/processings/processings', 'test_superadmin') - await expect(page.getByText('My e2e processing')).toBeVisible({ timeout: 10000 }) - }) }) diff --git a/tests/features/worker-utils/proc-stat.unit.spec.ts b/tests/features/worker-utils/proc-stat.unit.spec.ts index a1898541..900a7599 100644 --- a/tests/features/worker-utils/proc-stat.unit.spec.ts +++ b/tests/features/worker-utils/proc-stat.unit.spec.ts @@ -69,19 +69,12 @@ test.describe('parseStatFields', () => { test.describe('isSupported', () => { test('returns true on Linux', () => { - if (process.platform !== 'linux') test.skip() expect(isSupported()).toBe(true) }) - - test('returns false on non-Linux', () => { - if (process.platform === 'linux') test.skip() - expect(isSupported()).toBe(false) - }) }) test.describe('readProcStat', () => { test('returns plausible snapshot for the current process on Linux', () => { - if (process.platform !== 'linux') test.skip() const s = readProcStat(process.pid) expect(s).not.toBeNull() expect(s!.rssBytes).toBeGreaterThan(1024 * 1024) // at least 1 MB @@ -91,14 +84,8 @@ test.describe('readProcStat', () => { }) test('returns null for a non-existent pid', () => { - if (process.platform !== 'linux') test.skip() expect(readProcStat(999999999)).toBeNull() }) - - test('returns null on non-Linux (isSupported is false)', () => { - if (process.platform === 'linux') test.skip() - expect(readProcStat(process.pid)).toBeNull() - }) }) test.describe('computeCpuRatio', () => { diff --git a/tests/fixtures/login.ts b/tests/fixtures/login.ts index 09136bab..218d2ae5 100644 --- a/tests/fixtures/login.ts +++ b/tests/fixtures/login.ts @@ -1,61 +1,56 @@ -import { test as base, expect } from '@playwright/test' +import { test as base, expect, request, type BrowserContext } from '@playwright/test' -const cookieCache = new Map>>() +const baseUrl = `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT}` +const directoryUrl = `${baseUrl}/simple-directory` -async function performLogin (page: any, context: any, baseUrl: string, url: string, user: string) { - const fullUrl = `${baseUrl}${url}` - const password = user === 'test_superadmin' ? 'superpasswd' : 'passwd' - const loginUrl = `${baseUrl}/simple-directory/login?redirect=${encodeURIComponent(fullUrl)}` - await page.goto(loginUrl) - await page.getByLabel('Adresse mail').fill(`${user}@test.com`) - await page.getByLabel('Mot de passe', { exact: true }).fill(password) - await page.getByRole('button', { name: 'Se connecter' }).click() - // Superadmin logins hit a simple-directory "Mode administration" interstitial - // asking whether to enable admin mode for the session. e2e specs never request - // admin mode (goToWithAuth takes no adminMode flag), so choose a normal session - // to let the redirect to fullUrl proceed. - if (user === 'test_superadmin') { - await page.getByRole('button', { name: 'Session Normale' }).click() +type Cookies = Awaited> + +// One API login per user and worker process. id_token lives 15 min: log in again after 10. +const sessions = new Map() +const maxAge = 10 * 60 * 1000 + +const apiLogin = async (user: string): Promise => { + const cached = sessions.get(user) + if (cached && Date.now() - cached.at < maxAge) return cached.cookies + const ctx = await request.newContext() + try { + // no adminMode: e2e specs browse with a normal session, superadmin included + const res = await ctx.post(`${directoryUrl}/api/auth/password`, { + params: { redirect: directoryUrl }, + data: { email: `${user}@test.com`, password: user === 'test_superadmin' ? 'superpasswd' : 'passwd' } + }) + if (!res.ok()) throw new Error(`login of ${user} failed: ${res.status()} ${await res.text()}`) + // the callback sets the session cookies (id_token, id_token_sign, id_token_ex) and redirects + const callback = await ctx.get(await res.text(), { maxRedirects: 0 }) + if (callback.status() !== 302) throw new Error(`login callback of ${user} answered ${callback.status()}`) + const { cookies } = await ctx.storageState() + sessions.set(user, { cookies, at: Date.now() }) + return cookies + } finally { + await ctx.dispose() } - await page.waitForURL(fullUrl, { timeout: 10000 }) - const cookies = await context.cookies() - cookieCache.set(user, cookies) } export const test = base.extend<{ goToWithAuth: (url: string, user: string) => Promise }>({ - page: async ({ page }, use) => { - const baseUrl = `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT1}` - await page.context().addCookies([{ - name: 'i18n_lang', - value: 'fr', - url: baseUrl - }, { - name: 'cache_bypass', - value: '1', - url: baseUrl - }]) - await use(page) - }, + page: async ({ page }, use) => { + await page.context().addCookies([ + { name: 'i18n_lang', value: 'fr', url: baseUrl }, + { name: 'cache_bypass', value: '1', url: baseUrl } + ]) + // lib-vue skips its keepalive while this timestamp is recent: a future one turns it off, so the + // browser never rotates the single-use exchange token that every test of this worker shares + await page.addInitScript(() => window.localStorage.setItem('sd-keepalive', String(Date.now() + 365 * 86400e3))) + await use(page) + }, - goToWithAuth: async ({ page, context }, use) => { - const baseUrl = `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT1}` - const goToWithAuth = async (url: string, user: string) => { - const cached = cookieCache.get(user) - if (cached) { - await context.addCookies(cached) - await page.goto(url) - if (page.url().includes('/simple-directory/login')) { - cookieCache.delete(user) - await performLogin(page, context, baseUrl, url, user) - } - } else { - await performLogin(page, context, baseUrl, url, user) - } - } - await use(goToWithAuth) - } + goToWithAuth: async ({ page, context }, use) => { + await use(async (url: string, user: string) => { + await context.addCookies(await apiLogin(user)) + await page.goto(url) }) + } +}) export { expect } diff --git a/tests/state-setup.ts b/tests/state-setup.ts index 1f8d9d09..c97e0d4a 100644 --- a/tests/state-setup.ts +++ b/tests/state-setup.ts @@ -1,5 +1,4 @@ import assert from 'node:assert/strict' -import { spawn } from 'node:child_process' import { axiosBuilder } from '@data-fair/lib-node/axios.js' import { test as setup } from '@playwright/test' import { apiUrl } from './support/axios.ts' @@ -12,21 +11,10 @@ setup('Stateful tests setup', async () => { await assert.doesNotReject( ax.get(`${apiUrl}/api/v1/test-env/pending-tasks`), `Dev API server seems to be unavailable at ${apiUrl}. -If you are an agent do not try to start it. Instead check for a startup failure at the end of dev/logs/dev-api.log and report this problem to your user.` +If you are an agent, read its logs with "npx --no df-dev logs api" and report the problem to your user (or "npx --no df-dev restart api" if the pane exited).` ) // Seed an admin-mode API key in data-fair's mongo so the worker can talk // to data-fair on behalf of any test owner. Idempotent. await seedDataFairApiKey() - - // More visible dev server logs straight in the test output - try { - const { existsSync, mkdirSync } = await import('node:fs') - if (!existsSync('dev/logs')) mkdirSync('dev/logs', { recursive: true }) - const tailApi = spawn('tail', ['-n', '0', '-f', 'dev/logs/dev-api.log'], { stdio: 'inherit', detached: true }) - const tailWorker = spawn('tail', ['-n', '0', '-f', 'dev/logs/dev-worker.log'], { stdio: 'inherit', detached: true }) - process.env.TAIL_PIDS = [tailApi.pid, tailWorker.pid].filter(Boolean).join(',') - } catch { - // log tailing is optional - } }) diff --git a/tests/state-teardown.ts b/tests/state-teardown.ts deleted file mode 100644 index 663f2756..00000000 --- a/tests/state-teardown.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { test as teardown } from '@playwright/test' - -teardown('Stateful tests teardown', () => { - const pids = process.env.TAIL_PIDS - if (pids) { - for (const pid of pids.split(',')) { - try { - process.kill(parseInt(pid)) - } catch { - // process may have already exited - } - } - } -}) diff --git a/tests/support/axios.ts b/tests/support/axios.ts index 4c0e12e9..84e39bb5 100644 --- a/tests/support/axios.ts +++ b/tests/support/axios.ts @@ -12,9 +12,9 @@ import { axiosAuth as _axiosAuth } from '@data-fair/lib-node/axios-auth.js' * Loaded by simple-directory (STORAGE_TYPE=file in docker-compose.yml). */ -export const directoryUrl = `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT1}/simple-directory` +export const directoryUrl = `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT}/simple-directory` export const apiUrl = `http://localhost:${process.env.DEV_API_PORT}` -export const baseURL = `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT1}/processings` +export const baseURL = `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT}/processings` const axiosOpts = { baseURL } @@ -31,12 +31,16 @@ export const axiosAuth = (opts: string | Omit => { const start = Date.now() + let pending: any[] = [] while (Date.now() - start < timeoutMs) { const res = await anonymousAx.get(`${apiUrl}/api/v1/test-env/pending-tasks`) - if (res.data.triggered.length === 0 && res.data.running.length === 0) return + pending = [...res.data.triggered, ...res.data.running] + if (pending.length === 0) return await new Promise(resolve => setTimeout(resolve, 200)) } - throw new Error(`worker still has pending tasks after ${timeoutMs}ms`) + // a run left over by an earlier test: name it, the culprit is the test that started it + const list = pending.map(r => `${r.status} run ${r._id} of "${r.processing?.title}" (${r.processing?._id})`).join(', ') + throw new Error(`worker still busy after ${timeoutMs}ms: ${list}`) } export const clean = async () => { diff --git a/tests/support/registry.ts b/tests/support/registry.ts index 9b598eb4..014e9c87 100644 --- a/tests/support/registry.ts +++ b/tests/support/registry.ts @@ -15,7 +15,7 @@ import { axiosBuilder } from '@data-fair/lib-node/axios.js' */ // Through nginx for browser-visible reads (matches what the UI does in dev). -export const registryBaseUrl = `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT1}/registry` +export const registryBaseUrl = `http://${process.env.DEV_HOST}:${process.env.NGINX_PORT}/registry` // Direct to the registry container for internal-secret writes — the registry // only honours x-secret-key when reqIsInternal is true, which checks for the // absence of x-forwarded-host. nginx adds that header, so internal calls have diff --git a/tsconfig.json b/tsconfig.json index a9bf9a49..3619dc88 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,6 +9,8 @@ "allowJs": true, "checkJs": true, "skipLibCheck": true, + "erasableSyntaxOnly": true, + "types": ["node"], "paths": { "#api/types": ["./api/types/index.ts"], "#api/type/*": ["./api/types/*"] diff --git a/ui/eslint.config.mjs b/ui/eslint.config.mjs index 927525c6..5852f234 100644 --- a/ui/eslint.config.mjs +++ b/ui/eslint.config.mjs @@ -5,8 +5,8 @@ import dfLibRecommended from '@data-fair/lib-utils/eslint/recommended.js' export default [ ...dfLibRecommended, - ...pluginVue.configs['flat/base'], - ...pluginVuetify.configs['flat/base'], + ...pluginVue.configs['flat/recommended'], + ...pluginVuetify.configs['flat/recommended-v4'], { files: ['**/*.vue'], languageOptions: { @@ -23,5 +23,5 @@ export default [ 'no-undef': 'off' // typescript takes care of this with autoImport support } }, - { ignores: ['dist/*', 'dts/*'] }, + { ignores: ['dist/*', 'dts/*', 'src/components/vjsf/*'] }, ] diff --git a/ui/package.json b/ui/package.json index 35441ffd..783c6a3b 100644 --- a/ui/package.json +++ b/ui/package.json @@ -38,10 +38,10 @@ "vue": "^3.5.30", "vue-i18n": "^11.1.11", "vue-router": "^5.0.3", - "vue-tsc": "^3.0.1", + "vue-tsc": "^3.3.0", "vuetify": "^4.0.3" }, "devDependencies": { - "@data-fair/lib-express": "~1.28.1" + "@data-fair/lib-express": "^1.31.0" } } diff --git a/ui/src/components/run/run-logs-list.vue b/ui/src/components/run/run-logs-list.vue index 27d813d4..7203152a 100644 --- a/ui/src/components/run/run-logs-list.vue +++ b/ui/src/components/run/run-logs-list.vue @@ -60,14 +60,14 @@ class="overflow-auto" max-height="300" > - - {{ t('copy') }} - + + {{ t('copy') }} +