From 1f288598d19777d59171362d03e4e699a67a3773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Tue, 22 Sep 2026 08:31:40 +0200 Subject: [PATCH 1/4] Add Memory Match Rstest showcase example --- .github/workflows/memory-match.yml | 81 + README.md | 12 + examples.json | 23 + memory-match/.gitignore | 19 + memory-match/.meteor/.gitignore | 2 + memory-match/.meteor/packages | 11 + memory-match/.meteor/platforms | 2 + memory-match/.meteor/release | 1 + memory-match/.meteor/versions | 62 + memory-match/.meteorignore | 7 + memory-match/.npmrc | 1 + memory-match/README.md | 312 + memory-match/client/main.css | 278 + memory-match/client/main.html | 10 + memory-match/client/main.tsx | 12 + memory-match/docs/SHOWCASE.md | 78 + memory-match/docs/preview.png | Bin 0 -> 58956 bytes .../concurrency.server.meteor.rstest.test.ts | 55 + memory-match/imports/api/games.ts | 16 + .../methods-spy.server.meteor.rstest.test.ts | 31 + .../api/methods.server.meteor.rstest.test.ts | 57 + memory-match/imports/api/methods.ts | 124 + ...ngo-isolation.server.meteor.rstest.test.ts | 14 + ...ackage-engine.server.meteor.rstest.test.ts | 11 + .../publications.server.meteor.rstest.test.ts | 34 + memory-match/imports/api/publications.ts | 38 + .../imports/api/runtime-context.test.ts | 7 + .../api/startup.server.meteor.rstest.test.ts | 8 + .../subscription.client.meteor.rstest.test.ts | 74 + memory-match/imports/api/validation.ts | 29 + .../game/__snapshots__/completed-game.txt | 4 + .../game/__snapshots__/snapshots.test.ts.snap | 22 + memory-match/imports/game/concurrency.test.ts | 26 + .../imports/game/globals.rstest.test.ts | 7 + memory-match/imports/game/rng.ts | 19 + memory-match/imports/game/rstest-env.d.ts | 12 + memory-match/imports/game/rules.test.ts | 81 + memory-match/imports/game/rules.ts | 111 + .../imports/game/score-mocking.test.ts | 14 + memory-match/imports/game/score.test.ts | 40 + memory-match/imports/game/score.ts | 23 + memory-match/imports/game/shuffle.test.ts | 23 + memory-match/imports/game/shuffle.ts | 31 + memory-match/imports/game/snapshots.test.ts | 23 + memory-match/imports/game/types.ts | 32 + .../ui/App.client.meteor.rstest.test.tsx | 18 + memory-match/imports/ui/App.tsx | 88 + .../imports/ui/CardGrid.dom.rstest.test.tsx | 32 + memory-match/imports/ui/CardGrid.tsx | 27 + memory-match/imports/ui/GameStatus.tsx | 22 + memory-match/imports/ui/Leaderboard.tsx | 19 + memory-match/imports/ui/MemoryCard.tsx | 32 + .../imports/ui/MemoryGame.dom.rstest.test.tsx | 48 + .../ui/MemoryGame.interactions.test.tsx | 50 + memory-match/imports/ui/MemoryGame.tsx | 27 + .../imports/ui/NameForm.dom.rstest.test.tsx | 26 + memory-match/imports/ui/NameForm.tsx | 39 + memory-match/imports/ui/types.ts | 10 + memory-match/imports/ui/useMemoryGame.ts | 27 + memory-match/package-lock.json | 9178 +++++++++++++++++ memory-match/package.json | 67 + .../memory-match-engine/engine.tests.ts | 44 + .../packages/memory-match-engine/engine.ts | 11 + .../packages/memory-match-engine/meteor.d.ts | 10 + .../packages/memory-match-engine/package.js | 24 + memory-match/rspack.config.ts | 10 + memory-match/rstest.config.ts | 91 + memory-match/scripts/checkout.mjs | 163 + memory-match/scripts/setup.mjs | 35 + memory-match/server/health.ts | 22 + memory-match/server/main.ts | 5 + memory-match/tests/e2e/helpers.ts | 39 + memory-match/tests/e2e/memory-game.test.ts | 59 + .../rstest/pure/server/compatibility.test.ts | 10 + memory-match/tests/setup/common.ts | 7 + memory-match/tests/setup/dom.ts | 15 + memory-match/tests/tooling/checkout.test.mjs | 138 + .../tests/tooling/showcase-layout.test.mjs | 80 + memory-match/tsconfig.json | 26 + package.json | 3 + 80 files changed, 12379 insertions(+) create mode 100644 .github/workflows/memory-match.yml create mode 100644 memory-match/.gitignore create mode 100644 memory-match/.meteor/.gitignore create mode 100644 memory-match/.meteor/packages create mode 100644 memory-match/.meteor/platforms create mode 100644 memory-match/.meteor/release create mode 100644 memory-match/.meteor/versions create mode 100644 memory-match/.meteorignore create mode 100644 memory-match/.npmrc create mode 100644 memory-match/README.md create mode 100644 memory-match/client/main.css create mode 100644 memory-match/client/main.html create mode 100644 memory-match/client/main.tsx create mode 100644 memory-match/docs/SHOWCASE.md create mode 100644 memory-match/docs/preview.png create mode 100644 memory-match/imports/api/concurrency.server.meteor.rstest.test.ts create mode 100644 memory-match/imports/api/games.ts create mode 100644 memory-match/imports/api/methods-spy.server.meteor.rstest.test.ts create mode 100644 memory-match/imports/api/methods.server.meteor.rstest.test.ts create mode 100644 memory-match/imports/api/methods.ts create mode 100644 memory-match/imports/api/mongo-isolation.server.meteor.rstest.test.ts create mode 100644 memory-match/imports/api/package-engine.server.meteor.rstest.test.ts create mode 100644 memory-match/imports/api/publications.server.meteor.rstest.test.ts create mode 100644 memory-match/imports/api/publications.ts create mode 100644 memory-match/imports/api/runtime-context.test.ts create mode 100644 memory-match/imports/api/startup.server.meteor.rstest.test.ts create mode 100644 memory-match/imports/api/subscription.client.meteor.rstest.test.ts create mode 100644 memory-match/imports/api/validation.ts create mode 100644 memory-match/imports/game/__snapshots__/completed-game.txt create mode 100644 memory-match/imports/game/__snapshots__/snapshots.test.ts.snap create mode 100644 memory-match/imports/game/concurrency.test.ts create mode 100644 memory-match/imports/game/globals.rstest.test.ts create mode 100644 memory-match/imports/game/rng.ts create mode 100644 memory-match/imports/game/rstest-env.d.ts create mode 100644 memory-match/imports/game/rules.test.ts create mode 100644 memory-match/imports/game/rules.ts create mode 100644 memory-match/imports/game/score-mocking.test.ts create mode 100644 memory-match/imports/game/score.test.ts create mode 100644 memory-match/imports/game/score.ts create mode 100644 memory-match/imports/game/shuffle.test.ts create mode 100644 memory-match/imports/game/shuffle.ts create mode 100644 memory-match/imports/game/snapshots.test.ts create mode 100644 memory-match/imports/game/types.ts create mode 100644 memory-match/imports/ui/App.client.meteor.rstest.test.tsx create mode 100644 memory-match/imports/ui/App.tsx create mode 100644 memory-match/imports/ui/CardGrid.dom.rstest.test.tsx create mode 100644 memory-match/imports/ui/CardGrid.tsx create mode 100644 memory-match/imports/ui/GameStatus.tsx create mode 100644 memory-match/imports/ui/Leaderboard.tsx create mode 100644 memory-match/imports/ui/MemoryCard.tsx create mode 100644 memory-match/imports/ui/MemoryGame.dom.rstest.test.tsx create mode 100644 memory-match/imports/ui/MemoryGame.interactions.test.tsx create mode 100644 memory-match/imports/ui/MemoryGame.tsx create mode 100644 memory-match/imports/ui/NameForm.dom.rstest.test.tsx create mode 100644 memory-match/imports/ui/NameForm.tsx create mode 100644 memory-match/imports/ui/types.ts create mode 100644 memory-match/imports/ui/useMemoryGame.ts create mode 100644 memory-match/package-lock.json create mode 100644 memory-match/package.json create mode 100644 memory-match/packages/memory-match-engine/engine.tests.ts create mode 100644 memory-match/packages/memory-match-engine/engine.ts create mode 100644 memory-match/packages/memory-match-engine/meteor.d.ts create mode 100644 memory-match/packages/memory-match-engine/package.js create mode 100644 memory-match/rspack.config.ts create mode 100644 memory-match/rstest.config.ts create mode 100644 memory-match/scripts/checkout.mjs create mode 100644 memory-match/scripts/setup.mjs create mode 100644 memory-match/server/health.ts create mode 100644 memory-match/server/main.ts create mode 100644 memory-match/tests/e2e/helpers.ts create mode 100644 memory-match/tests/e2e/memory-game.test.ts create mode 100644 memory-match/tests/rstest/pure/server/compatibility.test.ts create mode 100644 memory-match/tests/setup/common.ts create mode 100644 memory-match/tests/setup/dom.ts create mode 100644 memory-match/tests/tooling/checkout.test.mjs create mode 100644 memory-match/tests/tooling/showcase-layout.test.mjs create mode 100644 memory-match/tsconfig.json diff --git a/.github/workflows/memory-match.yml b/.github/workflows/memory-match.yml new file mode 100644 index 00000000..bd77c323 --- /dev/null +++ b/.github/workflows/memory-match.yml @@ -0,0 +1,81 @@ +name: Memory Match (Rstest checkout) + +on: + workflow_dispatch: + pull_request: + paths: + - "memory-match/**" + - ".github/workflows/memory-match.yml" + push: + branches: [main] + paths: + - "memory-match/**" + - ".github/workflows/memory-match.yml" + +permissions: + contents: read + +jobs: + showcase: + runs-on: ubuntu-22.04 + timeout-minutes: 45 + env: + METEOR_CHECKOUT: ${{ github.workspace }}/meteor + DO_NOT_TRACK: "1" + defaults: + run: + working-directory: examples/memory-match + steps: + - uses: actions/checkout@v4 + with: + path: examples + - uses: actions/checkout@v4 + with: + repository: meteor/meteor + ref: rspack-rstest-integration + path: meteor + - uses: actions/setup-node@v4 + with: + node-version: "24" + - name: Prepare checkout packages and generated types + run: npm run setup + - name: Install Chromium and system dependencies + run: ./meteor-checkout npx playwright install --with-deps chromium + - run: npm run test:tooling + - run: npm run typecheck + - run: npm run test:unit + - run: npm run test:component + - run: npm run test:browser + - run: npm run test:integration + - run: npm run test:package + - run: npm run test:e2e + - run: npm run test:parallel:native + - run: npm run test:parallel:meteor + - run: npm run test:coverage + - name: Verify normal development startup + run: | + mkdir -p reports + ./meteor-checkout run --port 4100 > reports/development.log 2>&1 & + meteor_pid=$! + trap 'kill "$meteor_pid" 2>/dev/null || true' EXIT + for attempt in $(seq 1 120); do + if curl --fail --silent http://localhost:4100/health | grep -q '"mongo":"ready"'; then + exit 0 + fi + if ! kill -0 "$meteor_pid" 2>/dev/null; then + break + fi + sleep 1 + done + cat reports/development.log + exit 1 + - uses: actions/upload-artifact@v4 + if: always() + with: + name: memory-match-reports + path: | + examples/memory-match/coverage/ + examples/memory-match/reports/ + examples/memory-match/test-results/ + if-no-files-found: ignore + retention-days: 7 diff --git a/README.md b/README.md index 4086d5c7..df5e1edf 100644 --- a/README.md +++ b/README.md @@ -12,6 +12,7 @@ Each example doubles as a reference for [community packages](https://docs.meteor - [Notes Offline](#notes-offline) - [Simple Blog](#simple-blog) - [Tic-Tac-Toe](#tic-tac-toe) + - [Memory Match](#memory-match) - [Parties](#parties) - [Complex Todos (Svelte)](#complex-todos-svelte) - [Welcome Meteor Cordova](#welcome-meteor-cordova) @@ -67,6 +68,17 @@ Each example doubles as a reference for [community packages](https://docs.meteor - Last Updated At: Apr/21/2026 - Meteor Version: 3.5.2 +### Memory Match +- Repository: [meteor/examples/memory-match](./memory-match) +- Why: A cosmic card game with a live leaderboard showcasing Rstest unit, component, browser, Meteor runtime, local package, and end-to-end tests +- Stack: Meteor, Rspack, React, TypeScript, MongoDB, Rstest, Testing Library, Playwright +- Last Updated At: Sep/22/2026 +- Meteor Version: Checkout (`rspack-rstest-integration`, experimental) + +Run this example with the Meteor source checkout on `rspack-rstest-integration`. +Its [setup guide](./memory-match/README.md) and [showcase walkthrough](./memory-match/docs/SHOWCASE.md) +cover the local integration packages and demo commands. + ### Parties - Repository: [meteor/examples/parties](./parties) - Demo: https://parties.sandbox.galaxycloud.app/ diff --git a/examples.json b/examples.json index e7409e55..b5fafd55 100644 --- a/examples.json +++ b/examples.json @@ -119,6 +119,29 @@ "lastUpdatedAt": "Apr/21/2026", "meteorVersion": "3.5.2" }, + { + "title": "Memory Match", + "slug": "memory-match", + "demo": null, + "tutorial": null, + "repository": "meteor/examples", + "repositoryUrl": "https://github.com/meteor/examples/tree/main/memory-match", + "isInternal": true, + "internalPath": "memory-match", + "why": "A cosmic card game with a live leaderboard showcasing Rstest unit, component, browser, Meteor runtime, local package, and end-to-end tests", + "stack": [ + "Meteor", + "Rspack", + "React", + "TypeScript", + "MongoDB", + "Rstest", + "Testing Library", + "Playwright" + ], + "lastUpdatedAt": "Sep/22/2026", + "meteorVersion": "Checkout (`rspack-rstest-integration`, experimental)" + }, { "title": "Parties", "slug": "parties", diff --git a/memory-match/.gitignore b/memory-match/.gitignore new file mode 100644 index 00000000..3cb9203f --- /dev/null +++ b/memory-match/.gitignore @@ -0,0 +1,19 @@ +node_modules/ +meteor-checkout +meteor-checkout.tmp-* +coverage/ +reports/ +test-results/ +playwright-report/ +*.log +.DS_Store + +# Meteor and Rspack generated output +_build +*/build-assets +*/build-chunks +.rsdoctor +.swc/ +_build-*/ +**/build-assets-*/ +**/build-chunks-*/ diff --git a/memory-match/.meteor/.gitignore b/memory-match/.meteor/.gitignore new file mode 100644 index 00000000..81fd0156 --- /dev/null +++ b/memory-match/.meteor/.gitignore @@ -0,0 +1,2 @@ +local*/ +.id diff --git a/memory-match/.meteor/packages b/memory-match/.meteor/packages new file mode 100644 index 00000000..a6976859 --- /dev/null +++ b/memory-match/.meteor/packages @@ -0,0 +1,11 @@ +meteor-base +mongo +ecmascript +typescript +zodern:types +shell-server +static-html +react-meteor-data +rspack +rstest +memory-match-engine diff --git a/memory-match/.meteor/platforms b/memory-match/.meteor/platforms new file mode 100644 index 00000000..efeba1b5 --- /dev/null +++ b/memory-match/.meteor/platforms @@ -0,0 +1,2 @@ +server +browser diff --git a/memory-match/.meteor/release b/memory-match/.meteor/release new file mode 100644 index 00000000..621e94f0 --- /dev/null +++ b/memory-match/.meteor/release @@ -0,0 +1 @@ +none diff --git a/memory-match/.meteor/versions b/memory-match/.meteor/versions new file mode 100644 index 00000000..4676a655 --- /dev/null +++ b/memory-match/.meteor/versions @@ -0,0 +1,62 @@ +allow-deny@2.1.0 +autoupdate@2.0.1 +babel-compiler@7.14.1 +babel-runtime@1.5.2 +base64@1.0.14 +binary-heap@1.0.13 +boilerplate-generator@2.1.0 +caching-compiler@2.0.1 +callback-hook@1.8.0 +check@1.5.0 +core-runtime@1.0.0 +ddp@1.4.2 +ddp-client@3.3.0 +ddp-common@1.4.5 +ddp-server@3.3.0 +diff-sequence@1.1.3 +dynamic-import@0.7.4 +ecmascript@0.18.1 +ecmascript-runtime@0.8.3 +ecmascript-runtime-client@0.13.0 +ecmascript-runtime-server@0.11.1 +ejson@1.2.0 +es5-shim@4.8.1 +facts-base@1.0.2 +fetch@0.2.0 +geojson-utils@1.0.12 +hot-code-push@1.0.5 +id-map@1.2.0 +inter-process-messaging@0.1.2 +logging@1.3.6 +memory-match-engine@0.0.1 +meteor@2.3.1 +meteor-base@1.5.2 +minimongo@2.2.0 +modern-browsers@0.2.3 +modules@0.20.3 +modules-runtime@0.13.2 +mongo@2.4.0 +mongo-decimal@0.2.0 +mongo-dev-server@1.1.1 +mongo-id@1.0.9 +npm-mongo@6.16.1 +ordered-dict@1.2.0 +promise@1.0.0 +random@1.2.2 +react-fast-refresh@0.3.0 +react-meteor-data@4.0.1 +reload@1.3.2 +retry@1.1.1 +routepolicy@1.1.2 +rspack@1.1.0 +rstest@0.1.0-beta.0 +shell-server@0.7.0 +socket-stream-client@0.7.0 +static-html@1.5.0 +static-html-tools@1.0.0 +tools-core@1.1.0 +tracker@1.3.4 +typescript@5.10.1 +webapp@2.2.0 +webapp-hashing@1.1.2 +zodern:types@1.0.13 diff --git a/memory-match/.meteorignore b/memory-match/.meteorignore new file mode 100644 index 00000000..7a94a750 --- /dev/null +++ b/memory-match/.meteorignore @@ -0,0 +1,7 @@ +coverage/ +reports/ +test-results/ +playwright-report/ +docs/ +scripts/ +tests/tooling/ diff --git a/memory-match/.npmrc b/memory-match/.npmrc new file mode 100644 index 00000000..c7d35173 --- /dev/null +++ b/memory-match/.npmrc @@ -0,0 +1 @@ +install-links=true diff --git a/memory-match/README.md b/memory-match/README.md new file mode 100644 index 00000000..e7095c9e --- /dev/null +++ b/memory-match/README.md @@ -0,0 +1,312 @@ +# Memory Match + +Small React and TypeScript Meteor app demonstrating Meteor's Rspack/Rstest +integration through direct Meteor CLI commands. Same Memory Match code runs as +native unit tests, jsdom components, Rstest Browser Mode, real Meteor +server/client tests, Atmosphere package tests, and full-app Playwright E2E. + +**Experimental checkout example:** this app requires the Meteor source branch +[`rspack-rstest-integration`](https://github.com/meteor/meteor/tree/rspack-rstest-integration). +Setup loads the integration packages directly from that checkout. The examples +repository branch and the Meteor checkout branch are separate. + +Play sixteen cards, find eight cosmic pairs, and watch completed scores appear +in a second browser through Meteor's live publication. Start another round with +**New game**. For a presentation, follow the [showcase walkthrough](docs/SHOWCASE.md). + +![A completed Memory Match board with the live leaderboard](docs/preview.png) + +Meteor owns command parsing, Isobuild, Atmosphere compilation, MongoDB, DDP, +application/browser hosts, ports, shutdown, and result aggregation. Rstest owns +native collection plus embedded Meteor-runtime collection, Rspack test +compilation, assertions, fixtures, snapshots, and exit status. Native Rstest +also owns file workers, coverage, Browser Mode, Playwright fixtures, and +reporters. + +Unlike a driver package, Rstest participates before Meteor build/runtime +selection. Existing Mocha and Tinytest files stay compatible with their driver +flows. Showcase tests stay beside application features. One Rspack dependency +graph uses direct and transitive imports to select native Node, Browser Mode, +external E2E, or real Meteor hosts. Filename markers handle globals, jsdom, and +explicit server/client ownership. One compatibility-root test remains on +purpose. Meteor runtime tests use real collections, methods, publications, +Minimongo, Tracker, DDP, and MongoDB rather than mocks. Every lane imports its +test API from `@rstest/core`; runtime tests import Meteor modules separately. + +## Setup from a Meteor checkout + +This showcase declares optional capabilities it uses: jsdom, Browser Mode, +Istanbul coverage, Rstest Playwright, Testing Library, and Playwright. Meteor +integration installs only required Rstest core/Rspack adapter dependencies. + +Use Node.js 22.12 or newer and Git. A sibling Meteor checkout is detected by +default: + +```text +workspace/ +├── meteor/ # branch: rspack-rstest-integration +└── examples/ + └── memory-match/ +``` + +For a fresh checkout, run this from the directory containing `examples`: + +```bash +git clone --branch rspack-rstest-integration https://github.com/meteor/meteor.git meteor +cd examples/memory-match +npm run setup +./meteor-checkout npx playwright install chromium +npm start +``` + +If Meteor is already elsewhere, select it explicitly: + +```bash +cd /path/to/examples/memory-match +METEOR_CHECKOUT=/absolute/path/to/meteor npm run setup +./meteor-checkout npx playwright install chromium +``` + +From the examples repository root, `npm run setup:memory-match`, +`npm run start:memory-match`, and `npm run test:memory-match` run the same scripts. +On Linux, Playwright may also need system libraries: use +`./meteor-checkout npx playwright install --with-deps chromium`. + +Setup validates the branch and checkout packages, creates ignored local package +links, installs dependencies using Meteor's bundled Node/npm, generates +Atmosphere declarations through `zodern:types`, then writes ignored executable +`./meteor-checkout`. The launcher checks the branch on every invocation, +exports checkout-local package paths, and executes checkout Meteor directly. +It does not switch the checkout's branch. To use a compatible development branch, +set `METEOR_RSTEST_BRANCH=your-branch` when running setup. + +The two unpublished npm integrations use stable `file:.meteor/local/npm/...` +specs. Run setup before `npm install` or `npm ci` on a fresh clone so those links +exist. `install-links=true` installs package copies whose dependencies resolve +inside this app. Machine-specific paths stay in ignored files. + +The current checkout's development config expects React Refresh's older default +export. Setup applies a small compatibility fix to the installed +`@meteorjs/rspack` copy to accept the v2 `ReactRefreshRspackPlugin` export. +The Meteor source checkout is unchanged. This workaround is in +`scripts/checkout.mjs` and can be removed when the integration branch includes +the export fix. Rerun setup after reinstalling npm dependencies. + +After setup, `METEOR_CHECKOUT` no longer needs exporting for normal commands. +Checkout wrapper source edits are used directly through internal mirror paths. +Rerun setup after changing checkout location, package contents consumed through +normal app imports, or local package dependency metadata. + +The checkout's first run may download its development bundle and Atmosphere +dependencies. No global Meteor installation is needed. Generated builds, +Mongo data, reports, and coverage are ignored. The external recordings project +and local integration design notes are not needed to run this example. + +Equivalent direct use: + +```bash +./meteor-checkout test --once --server-only \ + --project meteor-pure-server \ + --project showcase-in-source +``` + +## Run application + +```bash +npm start +npm start -- --port 4100 +``` + +Open `http://localhost:3000` (or the selected port). Leave another browser window +on the starting screen to watch the leaderboard update after a completed game. + +## Test commands + +Every retained script shows complete Meteor command in `package.json`. + +| Command | Distinct execution model | +| --- | --- | +| `npm run test:unit` | Native Node unit tests, module mocks, snapshots, and `import.meta.rstest` | +| `npm run test:watch` | Same native projects in watch mode | +| `npm run test:component` | React components in jsdom | +| `npm run test:browser` | Rstest Browser Mode in Chromium | +| `npm run test:integration` | Combined real Meteor server/client runtime | +| `npm run test:package` | Local Atmosphere package harness | +| `npm run test:e2e` | Full Meteor app driven through Rstest Playwright | +| `npm run test:coverage` | One Istanbul report across native, real Meteor server/client, local package, and full-app E2E lanes | +| `npm run test:parallel:native` | Rstest file workers | +| `npm run test:parallel:meteor` | Isolated Meteor server-runtime workers | +| `npm run test:tooling` | Checkout setup and launcher checks without starting Meteor | +| `npm run typecheck` | TypeScript checks after setup generates Meteor declarations | + +`npm test` runs same direct command as `test:unit`. + +The [GitHub Actions workflow](../.github/workflows/memory-match.yml) checks out +the same Meteor integration branch, runs the test modes sequentially, and saves +coverage and failure artifacts. It also starts the normal development server +and checks its Mongo-backed health endpoint. It runs for changes to this example and can +also be started manually. The experimental Meteor branch can evolve; the npm +lockfile pins this app's external dependencies. + +Normal Meteor/Rstest arguments append without wrapper translation: + +```bash +npm run test:unit -- --test-name-pattern deck +npm run test:unit -- --test-file imports/game/score.test.ts +npm run test:package -- --server-only +npm run test:package -- --test-name-pattern "package export" +``` + +Watch mode is activated by omitting `--once`, not by passing unsupported +`--watch` to Rstest: + +```bash +npm run test:watch +``` + +Stop with Ctrl+C. + +## How execution is inferred + +Folders describe application domains, not runner lanes. Dependency analysis is +the default: Meteor asks Rspack for each test's direct and transitive imports, +then selects the required executor. + +| Test kind | Example | Dependency signal | Execution | Command | +| --- | --- | --- | --- | --- | +| Native Node | `imports/game/snapshots.test.ts` | `@rstest/core` | Upstream Rstest in Node | `npm run test:unit` | +| Browser Mode | `imports/ui/MemoryGame.interactions.test.tsx` | `@rstest/browser` | Upstream Rstest in Chromium | `npm run test:browser` | +| Meteor runtime | `imports/api/runtime-context.test.ts` | Direct or transitive `meteor/*` imports | Real Meteor server and browser hosts | `npm run test:integration` | +| External E2E | `tests/e2e/memory-game.test.ts` | `@rstest/playwright` | Playwright against Meteor-owned full app | `npm run test:e2e` | +| Atmosphere package | `packages/memory-match-engine` | `Package.onTest` strongly uses `rstest` | Real `local-test:*` package harness | `npm run test:package` | + +Snapshots, coverage, mocking, parameterization, and concurrency are Rstest +features inside these execution types. They do not create separate routing +lanes. For example, `imports/game/snapshots.test.ts` is inferred as native Node +because it imports `@rstest/core`; snapshot assertions then run within that +project. + +### Explicit fallbacks + +Filename markers stay available when dependency imports cannot express enough +information. They are fallback hints, not default organization: + +| Ambiguity | Example | Fallback signal | Result | +| --- | --- | --- | --- | +| Global Rstest APIs provide no import edge | `imports/game/globals.rstest.test.ts` | `.rstest.test` | Native Node ownership | +| `@rstest/core` alone cannot distinguish jsdom from Node | `imports/ui/MemoryGame.dom.rstest.test.tsx` | `.dom.rstest.test` | jsdom project | +| `meteor/*` can run on both architectures | `imports/api/methods.server.meteor.rstest.test.ts` | `.server.meteor.rstest.test` | Server-only Meteor host | +| `meteor/*` can run on both architectures | `imports/ui/App.client.meteor.rstest.test.tsx` | `.client.meteor.rstest.test` | Client-only Meteor host | +| Existing integration layout needs gradual migration | `tests/rstest/pure/server/compatibility.test.ts` | Compatibility root | Native Node project | + +In-source tests remain explicit Rstest configuration: `imports/game/shuffle.ts` +uses `import.meta.rstest` and belongs to the `showcase-in-source` project in +`rstest.config.ts`. + +Native game tests also cover deterministic shuffle, scoring, hooks, +parameterization, spies, snapshots, module mocking, and concurrency. React +tests cover jsdom and real-browser behavior. Meteor server/client tests cover +methods, publications, MongoDB, DDP, Minimongo, Tracker, package exports, and +isolated runtime workers. + +`imports/game/score-mocking.test.ts` uses upstream Rstest `rs.mock` and `rs.fn`; +mock hoisting happens during native Rspack compilation. +`imports/api/methods-spy.server.meteor.rstest.test.ts` uses upstream +`rs.spyOn` only to observe `Games.insertAsync` while real `Meteor.callAsync`, +method code, collection, and MongoDB keep running. Runtime `rs.mock` may replace +app/npm modules in the Rspack graph, but Meteor and Atmosphere modules cannot be +replaced. + +## Useful one-off options + +Keep flag variations visible instead of adding npm aliases: + +```bash +# Update selected snapshots +./meteor-checkout test --once --server-only \ + --project meteor-pure-server \ + --test-file imports/game/snapshots.test.ts \ + --update-snapshots + +# Visible Browser Mode or E2E +SHOWCASE_HEADED=1 npm run test:browser +SHOWCASE_HEADED=1 npm run test:e2e + +# Detailed test rows without generic Meteor --verbose diagnostics +npm run test:integration -- -- --reporters=verbose + +# Native reporter and CI shard +npm run test:unit -- --reporters=verbose +npm run test:unit -- --shard 1/2 + +# Native Rstest passthrough +npm run test:unit -- -- --retry 2 +npm run test:unit -- -- --trace +npm run test:unit -- -- --detectAsyncLeaks +``` + +`npm run test:coverage` is one `--once --coverage --full-app` selection. It +keeps the tests' ordinary `@rstest/core` and `@rstest/playwright` imports, while +collecting native tests, real Meteor server/client runtime tests, the loaded +local `memory-match-engine` package, and Rstest Playwright fixture pages into +one Istanbul report. The coverage include list deliberately contains the +package source root, so the report contains the physical +`packages/memory-match-engine/engine.ts` path as well as app sources. Meteor, +MongoDB, DDP, Atmosphere packages, and browser hosts remain real; no Meteor +mocks are introduced. + +Coverage writes `coverage/index.html` and +`coverage/coverage-summary.json`. Failure screenshots go under +`reports/failures`; E2E traces are retained on failure. Native-only selections +may use upstream Istanbul or V8 coverage, but any selection containing Meteor +uses Istanbul. Meteor watch generations are not aggregated; included sources +that no selected host loads do not get zero-hit entries; and custom-compiler +package sources are not covered. Standard local `ecmascript` and `typescript` +packages are supported. + +## Parallelism + +`test:parallel:native` forwards +`--pool.type threads --pool.maxWorkers 4` to native Rstest. One coordinator +runs test files across Node workers; no extra Meteor host starts. Inside each +file, `test.concurrent` and `describe.concurrent` use `maxConcurrency: 2` from +`rstest.config.ts`; explicit `.sequential` cases form ordering barriers. + +`test:parallel:meteor` passes `--runtime-workers 2` to Meteor. Meteor +partitions server runtime files across isolated hosts with separate local build +directories, ports, Mongo databases, and aggregated results. Within each host, +Meteor-runtime `.concurrent` cases use same bounded scheduler and share that +host's Meteor process and Mongo database. + +These are separate scheduling layers. CI sharding remains an ordinary +`--shard index/count` option rather than another project script. + +Run same-file concurrency examples directly: + +```bash +npm run test:unit -- \ + --test-file imports/game/concurrency.test.ts \ + -- --reporters=verbose + +./meteor-checkout test --once --server-only \ + --project meteor-runtime-server \ + --test-file imports/api/concurrency.server.meteor.rstest.test.ts \ + -- --reporters=verbose +``` + +## Configuration boundaries + +`rstest.config.ts` uses `defineConfig` from `@meteorjs/rstest`. Dynamic +Meteor context supplies roots, sides, lifecycle phase, and protected generated +projects with exact import-inferred file manifests. App config adds shared +setup, timeouts, Browser Mode, coverage, in-source project, and app-specific +Rspack adjustments. Shared setup stays environment-neutral because it loads in +native and Meteor-runtime lanes. + +`rspack.config.ts` uses `defineConfig` from `@meteorjs/rspack` and adds +only application behavior. Meteor aliases, externals, entries, lifecycle +plugins, and Atmosphere package handling stay integration-owned. + +Optional npm capabilities remain project-owned. E2E imports +`@rstest/playwright` directly while Meteor supplies managed application URL +and lifecycle. diff --git a/memory-match/client/main.css b/memory-match/client/main.css new file mode 100644 index 00000000..c8b12a34 --- /dev/null +++ b/memory-match/client/main.css @@ -0,0 +1,278 @@ +:root { + color-scheme: dark; + font-family: Inter, ui-rounded, "SF Pro Rounded", system-ui, sans-serif; + background: #050816; + color: #f5f7ff; + --accent: #7cf7d4; + --accent-strong: #24d6a5; + --panel: #080f24; + --panel-raised: #111b3d; + --text-muted: #aeb9db; +} + +* { + box-sizing: border-box; +} + +body { + min-width: 320px; + min-height: 100vh; + margin: 0; + background: + radial-gradient(circle at 12% 8%, #1a2d69 0, transparent 32rem), + radial-gradient(circle at 90% 20%, #173e4c 0, transparent 28rem), + #050816; +} + +button, +input { + font: inherit; +} + +button { + cursor: pointer; +} + +button:disabled { + cursor: default; +} + +button:focus-visible, +input:focus-visible { + outline: 3px solid var(--accent); + outline-offset: 3px; +} + +.app-shell { + width: min(70rem, calc(100% - 2rem)); + margin: 0 auto; + padding: 1.5rem 0 2rem; +} + +.app-header { + margin-bottom: 1.5rem; + text-align: center; +} + +.app-header h1 { + margin: 0; + font-size: clamp(2rem, 7vw, 3.5rem); + letter-spacing: -0.05em; +} + +.app-header p { + margin: 0.5rem 0 0; + color: var(--text-muted); +} + +.name-form, +.memory-game { + border: 1px solid #2b386b; + border-radius: 1.5rem; + background: color-mix(in srgb, var(--panel) 92%, transparent); + box-shadow: 0 1.5rem 4rem #0008; + padding: clamp(1rem, 4vw, 2rem); +} + +.memory-game { + display: grid; + grid-template-columns: minmax(0, 24rem) minmax(12rem, 1fr); + column-gap: 1.5rem; + max-width: 48rem; + margin: 0 auto; + padding: 1.25rem; +} + +.memory-game h2 { + margin: 0 0 0.25rem; +} + +.memory-game > :not(.leaderboard) { + grid-column: 1; +} + +.memory-game .leaderboard { + grid-column: 2; + grid-row: 1 / 4; + margin: 0; + border-top: 0; + border-left: 1px solid #2b386b; + padding: 0 0 0 1.5rem; +} + +.memory-game .leaderboard h2 { + margin-bottom: 1rem; +} + +.new-game { + display: block; + margin: 1rem auto 0; + min-height: 2.5rem; + padding: 0.5rem 1.5rem; + border: 1px solid var(--accent); + border-radius: 0.75rem; + background: var(--panel-raised); + color: var(--accent); + font-weight: 700; +} + +.name-form { + width: min(32rem, 100%); + margin: 0 auto; +} + +.name-form label { + display: block; + margin-bottom: 0.5rem; + font-weight: 700; +} + +.name-form__controls { + display: flex; + gap: 0.75rem; +} + +.name-form input, +.name-form button { + min-height: 3rem; + border-radius: 0.75rem; +} + +.name-form input { + min-width: 0; + flex: 1; + border: 1px solid #46558a; + background: #070d21; + color: inherit; + padding: 0 0.875rem; +} + +.name-form button { + border: 0; + background: var(--accent); + color: #03231b; + font-weight: 800; + padding: 0 1.25rem; +} + +.game-status { + margin: 0.5rem 0 0.75rem; + min-height: 1.5rem; + color: var(--accent); + font-weight: 700; +} + +.card-grid { + display: grid; + grid-template-columns: repeat(4, minmax(3.5rem, 1fr)); + gap: clamp(0.5rem, 2vw, 1rem); + border: 1px solid #26335f; + border-radius: 1.25rem; + background-color: rgb(8, 15, 36); + padding: clamp(0.75rem, 2.5vw, 1.5rem); + perspective: 80rem; +} + +.memory-card { + position: relative; + aspect-ratio: 1; + border: 1px solid #5265aa; + border-radius: 1rem; + background: var(--panel-raised); + color: #fff; + transform-style: preserve-3d; + transition: transform 180ms ease, border-color 180ms ease, background 180ms ease; +} + +.memory-card:not(:disabled):hover { + border-color: var(--accent); + transform: translateY(-2px); +} + +.memory-card[data-state="revealed"], +.memory-card[data-state="matched"] { + background: #173e4c; + border-color: var(--accent-strong); + transform: rotateY(180deg); +} + +.memory-card[data-state="matched"] { + box-shadow: inset 0 0 0 2px #7cf7d455; +} + +.memory-card__face { + position: absolute; + inset: 0; + display: grid; + place-items: center; + backface-visibility: hidden; + font-size: clamp(1.3rem, 5vw, 2.4rem); +} + +.memory-card__front { + transform: rotateY(180deg); +} + +.leaderboard { + margin-top: 2rem; + border-top: 1px solid #2b386b; + padding-top: 1rem; +} + +.leaderboard ol { + display: grid; + gap: 0.5rem; + margin: 0; + padding: 0; + list-style: none; +} + +.leaderboard li { + border-radius: 0.6rem; + background: #111b3d; + padding: 0.65rem 0.8rem; +} + +@media (max-width: 38rem) { + .app-shell { + width: min(100% - 1rem, 70rem); + padding-top: 1rem; + } + + .name-form__controls { + flex-direction: column; + } + + .card-grid { + gap: 0.45rem; + } + + .memory-game { + display: block; + max-width: 28rem; + } + + .memory-game .leaderboard { + margin-top: 1.5rem; + border-left: 0; + border-top: 1px solid #2b386b; + padding: 1rem 0 0; + } +} + +@media (prefers-reduced-motion: reduce) { + *, + *::before, + *::after { + scroll-behavior: auto !important; + transition-duration: 0.01ms !important; + } +} + +@media (forced-colors: active) { + .memory-card, + .name-form, + .memory-game { + border: 2px solid CanvasText; + } +} diff --git a/memory-match/client/main.html b/memory-match/client/main.html new file mode 100644 index 00000000..120e97b7 --- /dev/null +++ b/memory-match/client/main.html @@ -0,0 +1,10 @@ + + + + + Memory Match · Meteor Rstest Showcase + + + +
+ diff --git a/memory-match/client/main.tsx b/memory-match/client/main.tsx new file mode 100644 index 00000000..110b14e6 --- /dev/null +++ b/memory-match/client/main.tsx @@ -0,0 +1,12 @@ +import { Meteor } from 'meteor/meteor'; +import React from 'react'; +import { createRoot } from 'react-dom/client'; + +import { App } from '../imports/ui/App'; +import './main.css'; + +Meteor.startup(() => { + const container = document.getElementById('react-target'); + if (!container) throw new Error('Missing #react-target application mount'); + createRoot(container).render(); +}); diff --git a/memory-match/docs/SHOWCASE.md b/memory-match/docs/SHOWCASE.md new file mode 100644 index 00000000..882ebf93 --- /dev/null +++ b/memory-match/docs/SHOWCASE.md @@ -0,0 +1,78 @@ +# Memory Match showcase walkthrough + +Run setup from the [README](../README.md) before presenting. Keep the Meteor +checkout on `rspack-rstest-integration`; the launcher validates it every time. +Run commands from `memory-match`. The full-app tests start and stop their own +Meteor app and MongoDB, so the normal game does not need to be running. + +## Preflight + +```bash +npm run test:tooling +npm run typecheck +npm run test:unit +npm run test:component +npm run test:browser +npm run test:integration +npm run test:package +npm run test:e2e +``` + +Run these sequentially; some Meteor commands share default ports. Complete the +first build and browser installation before recording or presenting. + +## A five-minute demo + +1. **Play the app.** Run `npm start`, enter a player name, and flip a few cards. + Matching pairs stay face up; mismatches turn back after a short pause. Open + another browser window on the starting screen. Complete a game to show the + shared leaderboard updating without a refresh. Use **New game** to restart. + Stop the development server before running the test demo. +2. **Start with fast feedback.** Run `npm run test:unit`. Open + `imports/game/rules.test.ts` and `imports/game/shuffle.ts`: the same game + logic has table-driven tests, snapshots, mocks, and an in-source test. +3. **Show a real browser.** Run `SHOWCASE_HEADED=1 npm run test:browser`. + `imports/ui/MemoryGame.interactions.test.tsx` exercises cards and keyboard + focus in Chromium. Compare its `@rstest/browser` import with the + jsdom example in `imports/ui/MemoryGame.dom.rstest.test.tsx`. +4. **Test the real Meteor runtime.** Run `npm run test:integration`. Open + `imports/api/methods.server.meteor.rstest.test.ts` and + `imports/api/subscription.client.meteor.rstest.test.ts`: these use real + methods, MongoDB, DDP, Minimongo, and Tracker. +5. **Finish with the full application.** Run + `SHOWCASE_HEADED=1 npm run test:e2e`. It completes a deterministic game and + verifies the score arrives in a second browser context. The seed is accepted + only in Meteor test mode; normal play remains random. + +## Deeper examples + +| What to show | Command | Source to open | +| --- | --- | --- | +| Local Atmosphere package | `npm run test:package` | `packages/memory-match-engine/package.js` and `engine.tests.ts` | +| Watch feedback | `npm run test:watch` | `imports/game/score.test.ts` | +| Native file workers | `npm run test:parallel:native` | `imports/game/concurrency.test.ts` | +| Isolated Meteor processes | `npm run test:parallel:meteor` | `imports/api/mongo-isolation.server.meteor.rstest.test.ts` | +| Combined Istanbul report | `npm run test:coverage` | `coverage/index.html` after the run | + +In watch mode, change an assertion, show the failure, restore it, then stop with +Ctrl+C. Coverage includes the game, UI, and local package across selected native, +Meteor, and full-app E2E tests. Configuration is in `rstest.config.ts`. + +## Existing recording tools + +The separate `meteor-rstest-recordings` project can target this example without +copying recordings or adding recorder dependencies to the app. From that +project, set the example path for setup and recording: + +```bash +export SHOWCASE_DIR=/absolute/path/to/examples/memory-match +npm run setup +npm run record -- unit +npm run record -- integration +npm run record:all +``` + +Its README covers asciinema/agg installation and rendering. Casts and GIFs stay +in that project's `recordings/` and `gifs/` directories. Browser failure +screenshots from this example go in `reports/failures/`; E2E retains traces on +failure. Run `SHOWCASE_HEADED=1 npm run test:e2e` for a visible browser demo. diff --git a/memory-match/docs/preview.png b/memory-match/docs/preview.png new file mode 100644 index 0000000000000000000000000000000000000000..27b1f4a81fd2b99917a9549cd4b6e3d0f1c577ce GIT binary patch literal 58956 zcmb5V2UJtbw=fB_OK|qj>AOfLD3rQ#;z?CXNT0&72R4z3LNbd*%LI_Pt zXb}rY7Z3;?M0yiM0a29e|DgBxfA4#1y>G2=AT#^ynb|Y5XU;ye_n!GR_Ui+P!${9i z55&X-0xo7p!eC7mj`SQ{yo2 zrW3*EF#TTwK=tRKP>+kD09{Gw*O&UhvBftCtbYINFZec ze*7Q;$O5Df(motN@C*cR5(uQS3j!T^@?SW|3=pV390cN?_%EDj9tdIwpVDF%T~*?>Tt??51S+uwOW^uP4&0+7WI^vfIga|7K5xqvQ! z3_)HXCy)#P$%8I~D8<4=^T4O%Kbhs4%4NS~Ofc_q1I}T*qae$bP z9ARQUb`*S^<@ga6<|Clr+2EsRg^qDT zl(j9;j!u5bB8rxwqW*~~1%)+?+1i#Z9o+!Z#V{4UR)9Po(C(k`pT_@?KY9$vR00F< z#u1=1$B(drj{NQ)&^Gw29E%Ww^SW;WE98pB%}4oF1H$sJk2)sKZb3ypYyX-6odn7< zgO7kg*FfLETAJ%`iiC_G@XUHebW2Kt=~Vh@u9kSD1ehZUF)V@bB()qpy`A1FW# z0R8aKpdd`<;abFSZJ|UKjxM%vkOh<(24#ydKyl=OU@R~e6b#G`)?#DT&gbZ24}~&A zK|)$=`Ap^)!nMM+9%)Gcm_sy#NsA4H1<5e^aJ+hL{@2l?Cqf@xHfMjx%FO(jiOJ_O z3+pRp<_}CvS{&&T%zvfJ3$eVu>=OEy6hDBBJ{kS6?79{YBwRD*x|T$dkQRg)V8|l_ zi#&4+fC9i1fF0ToFG#Xceh;4Qa0Gdw9EHG$L1B_7qqH9$vf($Q4jCe${RGIo@H=0d ziCv2VJTpH5xX5+^beQpw`H%r&lE?of5aREWS{FdSd13)!<`LqcfXyko!0;usz(!#( z$RQgZL72lhC>#`4?I-!n`5Y7!3SbaOJ5M`|T{{oT9;TfK*M3r@Rrs4}C!YWldVvE9 z0vN>1`U(bm^;%1dIa&KL7s&V|7waqCSFZuCyn3B_6!hk=o+BWqN1-47Iv#omI-Yp+ zP>vOtmqTQz)L9;mlh=JfhupydYs3OVIpk0{z$YVsMMNf}hpfMsiny-`*9#}Cv6;*TVhei7`)bh}fi z%SF`K0n~L7Qlc_}){BM7zM{BJ2kl`BPKnnKPC?cMkgmja=UP1RICiPp3I#tu(mm@F zhnH1@-H%MDGiP8oQOOYFc^I|G8GL0ocTrdO`|z2SfRyT?)m~-Knt?r{1P{A9_aw?> z(}BGLeIF)cRqUAFv-P6-!zlXJq_fp2_-#*V(HhZHK`6MGeK{fF@+fRuaq{P}*lP|! zvJaH%W_F)D?6_XLK!gqRBswvjZqMuppcZ3@wswB+gk7BDayD`IDd}o^Rd0i;HY^*t z*oo;Vg~tXK99o2u4K5f}e;8@IE>`4Lk*UJJq&$lkqmW5D-sKI3ZSO2lXv6(yy33VsqYSMe zkuoo)ZM~CX8W0SNuKk)fOR{e%zQFRwmw%mD&n|^F5y=(0#-$gc2Vvr`qTs%4o|I6G z`^+g_Goq_ZPx{wV?C=`O-U$IL0;Zg+@+cIXMS3DtUxa&V9#$Hrv-%74LmsUVX|e9F8{ zD!x7>Sf;_+$!|_s_p__ddHuOeIEyt$dN`H zmq$oU_U$zyc%!$d`8zK=x!8Vzp79*`U&{?VA1)xd`iZSHfD(_3>){e?1|wWUY$u#u7F{`i2l)%~T3KJEnio-)-oCQ!sbK z@E2(J<<5YhazSB9d4^CyaV80E{86{<-V0|1g?#hn(Q%o&5s^)$?lnExE5(mK7Y|0V z0#fnJxMrlZWU<%%vl!T>C7+24D$%T75zdd-7|U46z>}!6V2T@dFf~=C9o~|)lA!J z*}`ns?>+LE&zH=kP-zcxS&H(#-u&7fNat{>E;amzx~U#{sSzDWB?x`!pSF*B`L?g{ z+mm0Q(Z@e^yl7K0rUXxhBHGJa?fQvA)b}U43+b&9C?(WT?~N<@)CdC??+WKw%SKHI z5(7;E#9bcq!{5RY3T1!9{*WUd1V0pxhXOFnoIM=)X275<653&)-?B09Iy+D%4+=7W zc;X?J#h44!!2DMO@D0d2+}D7PhdvZL%FbN%>a`x|O}e}oC`|q}^KYrnMqvlNDU{r? zwRlp*{19dFB+r})F3FDiH)aREm0CNOBzr`QuPyAathF>`H z)hyp(8!5P5^I+o|-~SMBEqfcd*coeL^>Hb;Lgy&jWw}H{K_kT>k+*HN1PyakaGvN`oL6i zp*~|g)Ap*ZXTSX0pR}y!$Ln6O>Rz+$axfFla_uO(H#J{uIagPWO(;d`^Iw|uzA`~wR_yv< zNtL-OKBefINyFhVDzeYyNpXoqv~1(ts!b1URQ$TPe>Oqpa-(tn=#Y8cdC2-YCMpJT z>rq?_p;Rm_=x3bn_cMYkq$bp)ibRQv$TaT=qwR)B<|6K+40d7q9i1Ds3P)U{7TgLJ z?zme$%_FKLmC{s|Jmxg6uP$oPlz^bpuTH%`^2R6p_0gvzL5ahG)JIRcPL5X?(8J53 zc^f=Z)B+MpX#F+G{Yuxa?DMWI7tO}CcZ%NQF;8lfLiogcpWV9|G~{0H5YBP%s0Hr# zweJk=q9=bGk$l2mH^E@IrD~P$*}@j-)1@~X zZ;-v(M#HCnJDnA-d1fQ%hiSi|4U0)b6|vSoOJhoQWu~tjz3eSt91ccq)ulEtY!ywY zvnC>0NLDPKHjbqhBm`DQ7SCQQXrcObai-1B=yb4{uXPh+Mv5cgwTSL#9VR)s2>GCm zikygVs>8lH-7)**ii*~Pk8d#BOZ-{!B8 zbMEI-J^a^3g+CfZmE~S^7{+@We=_L~ahx3uRkITbs>7X9<;-v?DUE{>UF-_U33iRP zL(evTq-6xUu}9^I=Nla$J!kd!uwMAV>Aw;sMfwS~?P_{-0r%>KUm*FX)H`N*#Kk;s zpT0K)8&euv%)6CgQQXfB?T~Thp!?^8h^JKZH%uOh*H4rHqpx_kI`^b(cZmLuy>+n6?CHb}$gQ!8ciTQ`%ghidf*r3QbXhOpZz3AUygSPs)qi$$XmIT($f(VQ zww)NbNkeWJL=Px5;7Pwg2_oMa-Xe3EgvnEt-zm>)uNC1{dH8al_rlSye=>%0$2=eO z!WZ)oB&c5%X22o&=BtX*6@S~V5GNmScir-;eL8L&U7Jn_C`eG-qRW^)I@AlbC39n7G$GPKB?Pw&id%m2D$G*B-vzNSUnLGT%Z1vP2aiMe1 zs53XtlClEeFIY>cw3h^G(VoyZX7wQe z><&tgJrLUTR8~9DcGABtvpZ-4P%mDX^rvgZ2Tm(~hJ0%~>@=YF8o=}|V9 zVxzePPI>4axf4rR<;vfxpyX_yCsbM4xhpbOrKGk2_CG;V7e+#)ZS z)2#g51@Q}J+Z&ZFROKYM4NQ}XMtPaUMAXJ!mWj4ZPlBx!SAjI10P`m;LcaAq{ILGz zUh9`O-Q^ek4!3i0`WpDM*7=E8t0LRfPiuI;g>M}!{L-Ua-e$h!i12z|qk4JW2*Xr` z=oKPyp+#2hCf8gs;_D{+9ZXhO99W`+dg+2`HBC)-8&)6}gRJHKY=4Tas@S=R{i(@UOB znRf<0w(pusb4ir+(c@|&)Q9zQKXjN+QF6bnIg#h)5@I6d`tfr7G4D!fPoMleVTMrD zK>1(3A?goq7IiMe7i2DA3lf63)V~-!PEvVrefKM|X8j)j$a?P;{zY6NRAOdBa^~Gq z<+W@2^4pT%PJh3h+Y?kt8xh85O3s*xsiwTe)6iG>;#UGv8#Fh_o?JZ0vzCZf^M$SE zsKx#MH&_k5v2PBHUdNl~@+-buDp3z$n4pVh%;Cb2$;>cTEjH&c?R*4a1CZBxWMF>y z1ZejO>?rmy9Z?t?iVX!aXFg2WC@5hlh+-k6%_?M`XKo$}0j!W0*e`?rYT#!6>#u@C zZU4xh=uoe}0AkY-X4M8%dIM*`E&=HIEZm2hJt;ZLA`}u1lQb}w5HgZ9upos(NXZW= zog76F4q#6UddQ*024}P20JM4Ya3Nsd3;M0TbNoS}K;T2{zwu!qU^fgpNLsP_$>{j` zaps3vd&jC5NX2we4f*%iN$))`LrjWASKAl&!c8k~Y!&gTVf#npp)P9RU2pjPLF87k zcjmDsRj0a^uNtM{9*H(+C|B8mY@YX)hx92Ax|H?O$k5!K&r^lbshv}@dV{K(N4{8* z#8Kn4kS212`$V6OUN_sUUp8{Sb>It(d_L-VpXuL>eZFtzweEZ_g9B8L)WqmPC332% zn4vn&B(1&yj#|QzKL%~q~b=xhPdu9jPHqQ#hFl^IQ@S{(R%&x>t zkq5V(=%xkz`}{P!G<}bt^@xJ<1;0ewr$(^|xfi-e2z%`46FT$k~CDA1!P(Bf^AQxqrMj!k37=H%pV<0zK9@E$=6|2ibKR5?msuw| zdEa=&X|k_ecM0`ADk|On@vV#^LhquY-7iphuv|#uFo8Z};TKdbUWHvkiR%<#0}V>P z6wA-zBZq1&qh~DvH9cZJU{qP^(h#gvQq1Y8@RfXQhDnOukH*jO5BGBf+4s*@KvJa< zo*w8c(azR6|MVnqty~SD?_6KKcTqH9b-8?VzL__H_BK3bWSQ!17Lz^CV~SsLOTOOK z^Pz6?ZuM4tNS(v3LQ@1;%JXWr$AImd4MTC?aCFNocm~EV2(MqNJF}atsT=wB4%@8S zq{na*X}4l?lSp0a9KPr$Z&#$#4@K5H`m~Y%K zY9LTa<2h6ym01NY_FW90oxR7cG1`b!EH=@^ zm|AY7XipvId5T$puP&SPyervveckF6`h2Kb_l3TWRFX_YW6X(+4`}0PxO&{Z=@+Dk)Hv}Dqm+}@GoqCyDFh7tD}uVvuY{J%meE{pmEPnNJT}U6 z5$~IV>z2sMmdcSzD2;zaUA}(`S^jcsGOujsQ-XJuWoLA1t9DyPzkMNU6S;`GChJqw zQtrmaOP;wpP!3IuaQ4@L$qdfBUlG}VPs!m+P!=~T6_?6}d12ePa8*5ahN8ZzlN0fld#Aq(RKFDZIe#s9 z>x6&lb05QEn8*A*apx0eX(3ro_^OJn#d4E_yHNl0H0blCSZcw! zo#5Uo$qAnko-e%#eYvEwH7h9)@n2>!xK$PTTgqzy8-Hf@zzr~%a_~lrjwp@6HCJgDJu0&m7d@$ z@8Xbqe5BYRc`Lo)lqkw5)f*=xAN7J?{Otp|`FjNkm9c$J6O?j-6+1CUqIe@#dgb8& zlovlKy}#Qf)AuO5;=I0kLiPOV78)@f-A(4ofSX@ERv?1jFmW49?w@+IxNDH(k=p)L zX@YtOQ_MIxIg=rv{0sE;!LIz%#|>Hx{Mv?l;EUec>}vn}o`LEjri-x-k0^}qX9lrH zed z*(#a?Yd0T~vi))?-eLQ^$be*-e@J5O#KNH53z&P3xKxFUn(?!FHy8Q*}LY|er><(D!mzuxxQb)%T2u)_jc_4YK6s6SLC(h)gyAemF>ITRB>gc zpE+hHvt@4u!(SJD8Fp>{lDVHgHbz=Vs&Ti_qkbZQIRPtm+~>7}6Q4X9cxnpJP+Mtj zRkgIZpaY}Gu3&D!{A*pEriV{PDWoA1iu%!>}?zdm%9~;Tk7IPo*?b2V?Or;GqJ$f4V=J z{mnXIGEIKi+(y|!CvF@`=%p4pO^5gO3|#)YT+Sb7_T*>jO4NsmUGLH1y%?8jYV|PT zfyC|P0X0(@c>AP77#2o{WlT}%jcHted+~}6@aArtp!qh{T&tUK5p^=(*&ElVJF*tM8+Dr{c`E9^p!jXa@g$o!QN}9bkW1fXwx7~{{)q~GP@JK z&0X=2OfoAYgTYRP35#jYdyrpT^@Orw_mnGI9(*3;hCB@_a)bIJD}Yz=&J; zxZJB9_r{WEEyfZh8bv=&yeY%~o=Vs!kPvuy|fZ@E7Q+ zT3VgkftVo4&*2m=^K?NOO0j+uM$HUmb8!=)*rnAe6(mXWl4cQin3&890T0u|3veA#VJNc% zh?H+0g@VB#LfTABfW1{)$Xpn}I6nkQnjbps01s6j;HM0Ic<5jPoN+#&zy8W20l$+z zm(2mMo3k;8(?e&ivg-yctQUY?BCwT&fSAevORE3`gfP-hHU|M_R>XC7z~lw!ZT*i=s$Hn)% zUL>N@VpUoBB+4|RO1=0#8}Wf^r=xrKi-gwV<7Z~MQ2L5j1W#p#R}kaG$^4C|iG*pR zk7Ao)IKSm9@xwCbnoJ;zd)zI z>bGFCWKe5ZK8ZQ!-6uMi-iE4*dI(4jpsPp~(4N?Dri6hlZxel+7S@UrN!yhlj8; zl+X%!o2#-w;FAI)s)c31T{++E2|3<1hPF<0?6?%406lurk+k^JsSYW~w6ni#Um}5X z9#B}nh#Jjo$69jRiVRqoeVkZ8VXwGJ4R3#1#HojyUw$(j$XlK zw=1gb=_P)olEgJJPvr$whMxWcNmXvFQd0VD*11!TU-7M_KJPPQpM{)J&{-Wd+A#DB z_7@}9x2GCNk({f0*!4RnstbHi)Vn~HWh5Ohv_^;BZ}gzg5j4Qbh_TI@59SP6AEw-Fq_Gxx1Zap=laFJ{3)e`PDV`Oc&^{ z2ClNZBzQPyrK+i%g=eCYPQ{t@gpIdzN+zStE7OjQjPXgSSkzZjQ`wEe=z59B*Kso9 zz9p&kL7VXD$0Zvw!(1_8n28t*i_ZZ;+=apCr`7bvE*gS`4W`3(J4?5UTVI@s%kC)` zh2XU&aAO{PqL)(oqM_h8RCg6VdnLGuno8ocEU2DZ6DuVWdqoD>HhPJ~V|5AyXd-Mw zb$oU8ee*Hvl);G-snU|O3MG-o=4#3sQ41c`4E>vdE~-NzbObQgB9`$p_)ye%Ut@FY96sBzBrRSKUUzfIuUO&I5F+%fBRBt zenHCSy$l5dVmUm3OV(>f<<Y8K53q|~2O3ay^y)ex8}_-j&+Bx}hX z^;AdGgff`xEW&Sv*SoVr%3}0HA>MS)j)FxkgHhz)-fovt6Z8AgF&ukn!;whTPbxVg9^oIv3gYr zFku&HXH%fi|s2Qz}bx_E<>u`W7^c&kb{nRxqi1Ii1n{DHiVX-`pqG zZd^)*jY*PI5}Po$s0a)(-H;b>d&vi@RR{eL2(2#GHt#o4*ejVW^>EMpo`)0m^?`{E ziUd|{HcyME&sK?=;24?buEP+>f;q>VWp-gb$XD5KGJTKQvj~zto(PV?j^8TViP|`w zJYaZY@Msw<+d^jIrNH*%e$x;_@rO0F_27CFc#pV|ZHjRm#)!|u<@VcoB`oc1Ujny`6sgs@iVgW>uc!3e>m|v?@UPqPL+@86Tj?0S8G3Q+TRZi0zpoZeo)RZwoEC z|43oZ$7Sx_@-X7{sk#WV+L&u*fp=^%4yJZ0?WR&npv<7Rv7lRhmw%+iY7ew7y86~y zCbyl`xtvnSN58wN`gFdW6#HC1)8_qJdVV3z-KHe7i$sk0vg8{J*Dt^}Oqgcp4Z3`W zzyz^%b{>l7a)$Qq^@OkZsIO2Ce(i|%)^TpQyTL6c}?nK!+_wll*#nYvNf&s}aM?DPTt z-kUMveu*o?bK9uvDW6DCa}*_}uKnf8#Osfq${sa$xGRhEb6tphp*kWWIGHx}xu8a_ zfThy3?A=|iiS8F?9mwL=IWCm?f{TwFy#t=dKh~$ts~b?FVsf3eSHtdKq6GJwp>%Ln z?kb+2rxr&QMyarWOEZ00li$>i`{$qb!{S!!Km`+^9$X|QhmO-o0y=Cn|M;0wI<`Xth?+@w=z?{onyA3X+m*~}znY<>n!DQvRlzLva)r4N_sS@S_yJ@jW41K8l z>M>gco{=VfqMQqfY>qy|(V1%G7awDlTp3r*U5|@QtLI@ip7^C!(jGGN8 z6NFJ+%DvUU>J@7r!{a3uQ>-e=i}l-%Y=X-@OMtwX$DFaI(nRF-*w z7SLrV7?&imEsn)@E*dKmp0Zb*hAw@&NSvgW-d3o_ECsh`@OI5Q8ZtLQtzgPcfY$yE zJblFAd(PUxMY5FBLQ3LAe-Ye7tQjVbkaS{p)AZR7^$JX4ZkDcmzwxR&Zq>gptyGa z*Ahv${Kjdo+M$cpMG`9`%@QjXcgGPTXzYlx#AA31jG9&Hf2L;CeiK#o(dtF(4f8#- zBba|wUGz$)dN=ep;T`g@Q(}T(omxg+^d;p9y7OSQjpS6URn_H~WcUxWybiyYHKy)s zSr93-^q_l=ZxFK16d}tK8yzUa=~fW%v1GZyqM#%Ti{qt~ECwr_ZBOhTfz@e{X?(TM zyHb|A#8gGv0X;`p(!A~D6XE12b0SI(25}D8fyiq;e)8wQkB%stPy$C0^OOIamITh{ zfV3Y1is#`;pChcVI9U!4ICcQg5q^%&N5GNB->T1(Kj7g3R?wgYWUqO z$+m;h-vhg|mfD!q)lSD*(nm$ob`pXRcl+Q&4ARviRfZa5gFKkAZ7xM{rHFf;WDZP%Vj%~)G=rcg5t zmlFb>ipE)~_KZ;J42JgUmf4^tY+l@n@a{S)_vj_(?ZyqQ^zU*S`iXzUh)BKgOrd|p|}BrZGXb&ea_p^u0pxH>te^y)PuU9jnPeeEB&KlDup zHDTrw)jhlG5>>fmZ*w*&;CHFQ*~}b-k5*8c!z~%C1Ai^;S9;03*9u*Eed`=x8@w{Xpma;gO5Gk za$cof*@-guV%7euYJ3HiAjtU_!O{(O$#b_1)n9Hb#+h+i2$CTX3;nur-C!TXm*cN^ zyCRND1N|7ijPjO;Wimm>CM)ajVNXX)`d1c& z_f1-_t_kv?$8`I^$Plpdw^QEFu`_tjwmsesEMKohO{0s+*woMEtU%S*Lh`D9%CI$d z8a2PHgj|AMvM#jLAoMpYXP5;xnjsKZ_t+c7C~i=NxQy;q8+s#tImpYThY`sFwhwKi zWVlpMOO{By{73JFI8u$~ij_Zhdqa-ru}eU3K#-Znlj{j%BMvgOTH}JU#!-~T6~4e=n{S*OtLb0+tj`n^0~+{^JxKBcQS^dhkAR`lB})%K5GY9EZ_JY+`Cp@tapFUo0< z&xPjQNvZ;zU?{j8yU5925;omz>Xpt=RFW!U)mF0sgq}rdqAzvq{f@C4-vAe1&Ep)Q z<4LCn*F&1@gbk#;ph<&OlZe-sHt&h7wZLXC$NbIaop#GhwgFD4aJe_+vU@6LRU`?2 z(=MCpW%8ayZH^PRT(?c|?DaBf7`gcR?pk7?Zz=u!OVy>R+a!i^CN$?(#VEUfPWN|9 zSY-WU{C4A*-TJIrRiZOtqrSALe6VTUx2(W#`tx5o0~#56PA$)Zd5CevWnLuw>(xb^R{^~|c=RTj^e*b20V7Bq&1iPe9qk)rWr+yR>%2%Qo zWK3k)9aHD=KDiI7nIZp7N>_hoQSeNxo;9t_E*g~micsgf^|&2sb^K+)F>Q+_#JJ9V zx{jxR6JL&>-)T6UeEXBZFjtNe;jxUB7}(D1avKC;HC!!`{%zjL6)(d33uMnQ-qiOi zHZyz$J8~MU%--of&Z6iKe${0W(B1{*9S2{I*Im+g3b@<5ccZs&qix^Ax2$~bz)d1! z@b>ak9=oXyEQ&{8p15cSKc%bSpQ5nEsCNv2OJ$DRh8wGL<|tQQ!(zv8=p;|Qs8~QIN%mZ-%K#ww#322yKxk-pr`nm_bn-QKmV?a<>z)uxY*^^xm^#A2xM?uOMyAMQBuD+PjH&*EUCw7Z=-6oD=gm{X9m7(NpxscXRr-s7|V| zi}40AAK~g~KuM&^Al=n`=tCOfJnYzlx-y0pb>$pyPjfqoOZlc#YSAXHUZMeoexITH z{mERfgN;U@bZ!O7sJAfi{CB8xx6_GQ`j>RG^f@7O=KwCg-oB-8Pw@>S=q8!3HE)+o zHBVM-IxAbQo#?%PI-+jFhZ5ea*O-^^95>yh`R!pPy^GO zr;4MMoT6#6dNjGm!fyDRXifBG(u-+|`(0`1U{h|EhX;`uSk<`P2lnwVx}GqOu-~jz zs84b3D&v?{DB{!1w5pm_&?ozv zn8dtpb&RLZ-J)<|GJQ%onmeI@$KoqV?n=ZgSB5^VjY*s($n3Bx%uD_bdz1`f?A`Px3i4&>-4tv!FYSf?$v!8C0pPvZoHDFPJ3d$uHN{0KOOoOkjhgvIzIgei_m%TiQc4!97*{;-h!O@yw66bFcdh`xXV zG39X-HxC~4VfreUvnq;8nNrU+(3m=j9Y7hJ4>-VQzrnB$s&big*iNp5)O??%* z7uzlPb76n#o&GmHCGXO9Op5p~(dZ(8xY6A=Lt)%6`*n07_SR=$_d)xk}BMe`JDpGH{)_R z-@i-hxyxa>A)wr47XE+X|13eE90eseFZp|+`QDlE_B&kGcJk?|2FUYDe_oN(YJbvG z@{Trt|L1`#{?B4>H6~}cMi}7cSO2W}yTJQ(_#W{(4@pyyW)kEBcVOwZEh_wZ4c(K6 zq&raxUoyQ%vJS$wBVj=P%P}*RCKrXCAm}M+DjD6u{q-BRzY+C5I(0)1v$RXY%SkG{ zg#q%Xi>*ggUWY|qyFfS}q-S6ulwc0{jSlZY$OG5sgdt1@C^n8B7T~rXaI(u0deS&5 z-#q*R*r4d}k`=2qJ%rsx;g#z!FG!ywYD7-)dM%VQH%{58_J0O1?pY9 z1^V*#?RJ_L2o4CW-vRL1fjE9cfc#>HJY)kM-hKT)gVyiI!+W#8Z({%{(;0w|6@+1M5;-4ai*?l|?Ck8&#Pwb|H)T3N(fA)^K<=fa`m4TX|FR45NQC>$oFRR{=L zX6_OLD1>Ms@y9s{T-^Zl#zQgPF3GeRaCi?yI|a}VAskFkE=c_59qA#^J7A2=uyl$A zlQD`c`b0Qf4k=H{z7b#jva|oX0*T}VtNvJZ5_8HEjA|sVC<+q)JuVthttS#E5mQ|pF8iT;+Ri=IUzYZw!_?V@$zqL-6P`IJ;m#m6a} zGG6E_^cG@BT;!vTBV>Pg#EcBJG#>SN0F7+Bl2Ij3TWJ{A+ml$tk%Z~0OB3y7tVVUFExrlUIK{Z_>9GK4G2IoHqjUXvzo&;dse5>3HQPy})1>^XE66i? zL>d&VSK(|BT}!_)5H_dtLc>Zjyl=sn8mp@YI`*Y&gBn&QVu6JAlbD!Mc9BNP#s6`L^ zGAmVd#WMbO0Yd&Ij5GZ7@!KQir;b*?tB>}wt$W_#BFWZcQ(@>;nKQl6Ly4a{3`cb@A~;py({B~8M=rOf;Of!S6$(4&#sm>I z<~z;^IpyYQgWyrbmPR2@aNb~(w}lykDqcC3tC}6>siE{H9#2)I5WmvOr)x9p!}>mX zkiT7er{)oM&qSaUiKe68bxstKC<$?fe2=L&xzhu>H-z0(X2MMthK~xS`JakdEtZkG zexH;|tm2KgE;9Kc^|lxj96#XjeeA)P%fCRInkqQ)%ZVWNhrmt>i2g?a3_E{9L9hs7 zu#rEiq^&vdCt87Tg}zN!y&A5-)c{h3oGx|=zEWzvJXjcOgBfmV%rGf5J1y_3pEopd z1ic2+v~qohg_S^|w(5?S?LTF>TzbL+c2F(OYipOdf^4TOgGxQ^GzP7zRaRZ2of7)+ zvy@mYfl59z@l)t}Sw(=lq8Uq?hn?aHM=L3C0@e7fa*V-nF9AV`qSJH#UYJ-$&dBWl z_&X-x*}!J?dv`BJh0#KZp$G-n`6huoYRbvO#kX!F*DE`nSUnRXv6yvIM{xZ9>RP;>uc2@%usj(R%+K* zEv%^Qf+=~Kp(#!I#!s&GX}m$c_yTU|T2j1NUQtTGEWy)+Y4~!Fr?pdFD<~`>-?5A= z$aie@-h(4o`EZfb(m~hIQ{v6$%5=iixG)^u0-IARm`rZB-srG-J<6;W@;%SB8E0G6 zGH!DNq2O;c?quM2+pKjvmAWlbzsxi9fj6&pd+eH)`#;BOBMO?QD*}42TV$RaXZNKM zzZO=e@X&-kRik1(knGg*)s{OdnZ=>OQuuf1{mQ?k7SZjQ?<@U{72V?&V<$rTtVe}O zFm?8b<^}fN zwcM$65{<6?Pxj4j>ZONn=C zoLIoZB=% zG`hu!Z?nuWvX!HFVt1Jp<9X*=l8p}`sH73I`o07SH45}JDa3u;JB6~OlBlZ6G(zs} zua>4KRh05-#t*F5B{ftU3ov7z+wDubd%}TI)gANf4HNhRLn`N)NBljC6?MCW&}kew zky__(*>Tc6O%(wRydPCOx~t5T0=WvCP-v@b{9^0n+mxR|P*lo~&6o#|O)U!xJK=>( zld|saYzVwg4IR2FHtGH`GnHy$=84WU;?3aRlq=;+Koa;Og;fQ@&{(mZnFK&+EPCvw z&KGauCo2^a5hHJ6ty;y^fLRM>kF*cT9J$YD*rH52d%!Y$x`>8A4t7~xk*kl?&60Kv zbn&5&;)P{37woC_$7=OTYwTuTrxun~G)*GFTMX(Yyv$Ew*>f{?)eU%;Mzdtx-)H*u z@8Sln)@gBd+nzKA3bXR{JNyP%$!Q#?I{uB9QapY~^8>-q{+ndpa8tytPhIJ^4n}8U z`I~XLO2fX-sfMZpHFSlyupe_?QD&jO-orANq{%81;HNK zn_)}e4HYlxe5PE}Lv2YG_@8^yFr}i(KnL>fL-10r331NxUb{Gw9CaAATl$vXxK}c` zV#-$g!;dAXBg|tMUN@;J$buT17(=(Br+ZS+Q!69INL!V$iWy_(g=a!uxXSam%5t1 z($I#|#ode_e@_8y7H&Z#aUB$QNTB524>Kmqk*(LZMKYtj3U4k+e|oebsFasCxNn7EpmE|>QXW}SnO}#HBIlPYc;A@Rjyw6%*3*K- z0{=hK-UF}Gaz=A3h%a}RKT8+ZpRM+Z93`Qeh( zal->n%8`ZJt zFVlxP!18-_``@>?MBW`kB)=S!rc}8HIHzjFXLd-Lo*ONmOW5zAd65_+yVERS5Q73B z)Q=R-V|vbnJJsoRtzQxsr9`9&2QdQ8migM9o>WH~p{mN2MlfAQjLA=6K?o@8<`>`2 zI8qO9XMpIBQ?r6V3JMv=Ky>j>e`tb&tQSE*SQ&sEe2#zewF;|B9`O`Joqg&EGsr## zXoczuN0$4=W5C;!i%KU!)K4`HKjd2F7|;lV5iToNTfc+YW#YxLnNv&Y>wrdx>`20R z(rwAm+IK;c4qI*E9+<%;K28;AxTD#BbM4*UT4!g3b5|f!iuHnb!@p#QFxHB;^?+4p?ei*6V(fCYUIk z!sw1eFD!#+$0*ob&xun5u5%Rv|q+*1~(k`hvcs(;afNk9uASFDpqM zUVIlO;;UKrYA;}bLkc~0YQf>8k-Nj-sD|QD&YdikOvlzT!c9cKd3>{ZPnCR#gvS0f ztZ=K$^1$w@`>JnvBB2v%4JM3PncBY-PF!?4{dvH7&GBJwk7+`eZ?KrYnN3@2PXPno zNVV5U);u0E7Ue`k%l)igAZF9lV1ACPxPVWVS}I8izR0Lv(AnH(9Z}DQBMky37L`ty zZU^rr#|HN40I@!%+&U>bGEACg9mJdFbD%$YnWku5jw~-yzuW{lDr0u#G+UJ{ohDv; zBd~y$<@g|lhIju^lB7LGSrQ*~V}dW)OlGHjtgv2GxF;Bz9;Lo}^{ZgCPs*SZ3`}HP zJDc6UB^Tx>PhJ~BvR5bHQ#U(coBAS46A3G~@uATZUm{c$hrWTXjM?N*Rjk>)<&=x8 zg=VD9n{HYUA9vj5Pi5gr3a_KE)uYi9T5_83hgheylmUrF9nef5ob%2YsRp{ulR|96 z;UR`ensq)>2;9J_r;p{d_>^*d5(l-wlF+&0F<$LQu0+EwH{t{?dA9>nmtJN09TaUC zu)r>VX1Ol>)Jo_OT#WaQpIzj-I~#q!PsleqO}6r`;Woj zNLZQ=GKM16U$NJ$ZJ5LFFSYK+%YTcG0>Rj+p1lAWf*(+LPa9w~9&NgyW3}OR z(j{^44Q~A@_&k|08$|NVCwv+Met9;EC**XcN9FV>{~W}@qoj zrCKGJcLzq2hH(SV63v>MmI^K1P`gABGk;BVGQhfY!vu3&53bFHKy(zZMi@fDca*+^ z@?PxOVl!S3t$hbsh3hG42<0TG=r!qw=DW>{EwQZ_vwI9&KG%`vcIOKngJxYulD#{V z>GSzhhYsgGh{jUGS_;u>gB%`WGb7^!n$Rllh(hJ1{qh2c>;>;-J(t6DXRXN&?%k^@ zwJMIPB+0R1SE8nJaQoJo3=RE0d~~gSl4%>vTwy*Nmqny#w=8312!CccG7NXcrcC)i z(!;MXw6(k|ThD^R_(at>x;1nt_&6^UO;gbiv#2_KjKM(O5fliyi`QwMZOw_bTkc?= z@eoWTK%4<40hE7b&HUH3fw$#JPU(c626M$1`T21-n%{r?$`ScK6gLJY(w>WNxji$~ zV1sA8o>3b+q-E6haV{Y#JzmgLbyk|vaN><-=1S*^^}3>~oGhMi#kTh$zHOSjzxKqj z?DkESS3{#>nTOi)yxZ017Tn+17wDju21-RLlMquzdqxmZNTEZvvFJirje$LMpcx|0 zFPr)fEc7!dDHX*sZHwlR>?s_u>~iRu;lMoxs{a8(jI zl+&Y9Q9h8Q`a=q14c+;8ZJ}ax4j%H^Cq+&amMQ5{f%IO5J|fAJY4FCW7He+5-y*?> zz;!oNYS@h&rSBO_OOB^iU%r*NJnom9TRM5ZlFKZm=$(d%im`Hu+M+c)m7xscEi{{H zmnFT;Y;)n1kl7o!xg+0a6knhE?q3*)h2(}BV^aRY@C1nqn71O_(jz{kvQIP%cEMkE zbinX>b!T*YZNBNZV3!9A6;BtHjDguPxrBGO7mU@Osnkj&@^+bK_2|i*>xEy>8}i_B z>?P*AizSwi+8e;QGcsb0Rg-r|<{3lymqf*o5a%?O2DGaNN2K-rm{o_%Hn}A55=P&h z;xuO7YogfuJk3HVVjG7Oy_vki)9oSm946%xeQXbpD9_>MhQSsxk}@DvY}VLJ6?q;& zP6K>7$YXA3%OVMpUd>PPstXRy=*nKrGDb?+tyH9H&o>IKY$aoYWdxjS`QW1=an zjZ$f1x4b;oQsx>3o6_^A!qm7P=+uLU-B?cSc?NwOXa*!4BJ@(hHHfj$RryHdd~c*u zyIBf&lZ)8W&!Xg9)_>PPkt-pim!}Cx({*^$QU-mgimU+)#!NOG5dyEntO?Qrf(qS!nehTpRl?LGUR*qRpA7W=8A$&) zi1nB*5Sai_k#K9?esb|xm?44&1aeVV@L}!;l$7jaN2&^%6MO?;a(V&~rya4?fldN$ z!24um)PnjknmBF*5>Q(r4Erp9YALX!yo0zyWv?5qg|_qKEua~*xdndF{!KSMDbu7d zMryr^)J{nKwN`8jJdugTDBuMAORU*cf4P@C^}}iAhYo8i52x)tNz9Jg!Lt*-U&D1Q z9MW~$7`5uL{i{ZrFAU_g`C2=p>iMZ-3^gKaxduLT2$$rYk&A72E4Uw>RX*4+bUjWR1vka;Mym~%`%)aARGYPMx7;jkT!h$Bvr4XtNhMHsJp+@3w8=~?*#zFcmW z(<{mHuzYY(NWfy@F$2uXV6-bCWh>%2<x#_d)WEd zC>mAA1Dz>07c*l}C(gv)qa!pVdJ0W>Za5i~q^og2nG6;HzM|qGJ{GRegbGQI@{(`W zAL(tKdgw@X*O6zeP3~27H=Qpl$L&2vyNX?J*Z#_ZsD3|SI8k?ObfM#%Pw%GKLRG5# zSDGR*ML6Ae&=RsWK1#Dp%<^09DSC^+h(O<2S;q^VQxH`=tfF^08&RyT!o%{clOgXJbcfpZQdPg6b|ogRF{tN(87IxQ zo>(AJ^r7J*<5*!)fgy-!uII?CvtIX2!Z^m-Ts> zGWcG4czBoZmaISast9}e+{v=Sfq~@N7V2t$1H8y%rlO)Dt7L}MV?~Ji4Cv7qQ)qpQ zp`De?Ll|nSWqgfQZW3 z)Fse!-m!9RZsDh*>TIU+L=zY9IJULAm)~Kk;IVOM(qFM&;GSf(Tmxs`=g;jFT6{Nb z_|a*z{OeHvNZwS2D_eP{x@Wnl(rg1#uzFElv2h7>znQS=aCZQn@(q>`)jOwlkcYkh&Z>4D@qT*}YG8rIb0G z*VAs)=ySWdPr)3@G#=yK7&cT9;m2jT=f7c~*@kdXs)u>e&C~O`b-|&7dnC5ZdwNpF zukHgs@h)W(Zz808&nlsfSh2B=*FNMqsJ5P$G*$1=@FmnHRDMx=5LUz+CTm;(QBoY< z@x<*TgtXimHA!}=7qTZMcoU);)ZnF)H=LI8a5l`++&u=7F>ToA1Y<@dt^DyVMuF-} z1EY?{^mD65i;;eKk%Zdkr_A4&MG$GcwrxB!owREj2PmnUO;Y?ZAD(VT%D#iIT=8*q z965MYs^$(gnf}t#O!LYx-dCJW8mW zVjp$j$OOC??zbz5uiI^vx&klzI6lxM(4^-_vwt|~L2H(t2;d4ZQvqJeD52h9v7_%) zrve?=2=!8o0R<-D#RXLTIRLs=6?gRnx&~fA*R12MlR(##z!m(%!BN-G{;`?DXrpvN zR;cIEdHN};?^KRRgt#Al|4)S)TC?oLql+u$QP;*D`G2>%awgMF;H^k&!mDGT6|iia zK#OJmeCGsaSZLpUuT@&`Zl8!~X$KjRx4VPlfo<@;m{>X_dBltNZ(EQ5h_M6FpSTo6 zPIl}GfDb(ZvFbi~b{s^_$`(vU2D*6a$1D|}4bp!Z50DVB0nn5_=mtPQYBiXQK7j7BbGsuyBCBgg+Jg!@hG&Lp&a_v~bAB z{c#y{k17w@*=NA>tid(B8!jQ6rS`Ct_8g~UXXX&!XM0994Feh(!x)#&7ACy5kT!|D z00Je7!?|~pBLb*nmaD>*Iy*h>3QtQy!FH}Md%pPYy&+$WfLLm;Kx^qI8!q&EqifME zHdD&QeZp9wLZ#l0W#w89dvfMM0eb>UOO%C3~Mwy`A~+TdK^ z74C)t{As=ch{>e9W%}B|sd^EHPO`FK8^7MCm8Ka~tTvjVnao`u8lPUa8AYa&r*`f;DH?X&+7*T3LJ_#!l-7Ptd}pUI zedpPXHb3ShtCSY4S}JBwV$~)@bR9Q}c`W$6RgX`U!hN8pCT!1zcSpJET?oLucX8I7 zA6daU<^8-eW22|1wFL*is2y=CGK{<#>J}TnhqmcNi&D`rs5Oq6AQWwJoj8l1K*O&iP517Uv5+)ti#F zzvzkK)vhbq@!TD{x2j~m5Z&e86Wn>B14cAdgg_K$H8(C+GGcmqG!aXj}Y;yTPOqxft(ikC5Ti13pS28_^`r5P*i>b<2MM5$9awanW;#i{h` ziQf3wYFYsQYFg9AwNJcCm>o8p>`srSY0Cx7r7!}O_gQ2;m*+JRLAi(nDR=jkwVl=0 zErB~2l4xDK*4L{ElYVc8CD^+u%Le39?J8?xm;93-@A@Fu1k_o`PNP%W`#hh8mo1{^ z+nI%T{TQFW;ZA(c6A!NoMaQc9i!N&}Wj0;yD;ny=Oqe3E*l8oP2j=M5;U@1aQ*?n* zb2Ge|B+=EnXEGpll%x^N zR>SaPwqbou*!ee}Z7&TbA+Ws3nF^?JPFn_#{UfKqvoRmt^uENP+l@1B;?lWyXM&U9 z{1uNSs-VV(%TX(F>3Lf=?su5$Iq&?HK;};4lwf5>j3Wydsg~~_$HALJuz>L+!MM<7F6fJ_k`JN8=m4noGy6R5(ur)F-m(0Q z+&rs39hXWmBgru<9%gFbZdSO0D?FBVbUttzg8`!k$2Fs5aqm^M@@IP->_hXR*W#`} zda!2*Dw2?iCuo`3Kq`pl%x>-?G=B9{5e^k)<{b%Tc}S(U&HWRKVBuF;`FF9$ge6Qd9R=W0|$IETysxJPX{yQ^0uVsx@2);sj+(L!)A|Eu4-d zEYQ#JnQp4AZ%mXztA12#en2M9%wd5I_uOsTth|VSTQqb4z>ByTW`;FWEy-Rla;fFz z%~W;^tM(hP-9`$PEujz{9l_YtMBGXzkd3%X(&@y*QzLUA_4kCT-z&M|*ueP9D5)^& zd&G*l-7FT|b>dWo?CztEy`E@-TE62pf_%Z&*{xkaJFK~gRdLvZXm=X}uVaj%5$^US znJh50%b%3eOCZPQ&Mk6cRX7|%q&R%aP4m{Iy}mI06jWqv!4-3JXe(QIbcp8a7gE(% z3W$dt`i<$0ONCkmCDu`XtuMOEWp^Di4K3y`pG|=~%^9pC1H0s2^@}9rIT%Ogq1bIb zmoOTMZ^Mw5$GHa``2hiFC)slAoR);!)EgaRL?((PzirvDJQ8O(`mmbI-hr7tsY4!} zbN`a0R{~_5BdSHJLVEwkN=bKlt6sLi7%MEV@wK;}xt5S#Rip~1MvghUj7ofEYw$*|pT3`$=tA3wHIGcm|( zM(Vm*4{qXsA=8n^!@w0xvXNRRbhu>>Y)@QT@_->cjfQTWcrX?$sNo9|HB}s*&7x2!h_G z%mEb)hy*#k$G^YQsdG*1PvO+c@iL(q?Xq|0Ggl*abc50WG8=8HpfP6+$KGu|m6K9s z0|qVwH}!kF6%Z4$>vcBJ?M!sL3BU!ZXUrXCBmLpCP(woyVX)Nj>$r`7MrJf3C#Nts z@QNc(`Q2frNKO1!JsUhV{ZyrYvfiSUlv$d7-w8`&i+vpXUy(QxQBO~gmTU|o*4@SX z((9%ltIyiY_Dl%iN?qD2e=|R?!UYtY63iHw`B4{hXD_Wa9P!-Ibl5Qh4`S=_N>kLlxy-q zk2jY(a5EnrzreCh93mDCVuC4Tb#mOtM|zalv$LNr`|^9rU->G!tYneG9wXcr)Xot0 z!RBY!5TKX;!*+%tCpSuIQ6zbxPK7AK1RKw#9Kj3=`?~LSW-sIXkm7*S+PKv80MJ!4 zlIUF%9@su7yZ`(spzAMye*8X=ZF2Iy!KG(E)KJim@F)-~+cO|Q>iCn3Hxv|3o&-EK zpN~^-RRPH(fPQ-8XD|>o;7$3__@}B$M*RdpkHR!H+cIBb4VyIIBkq|mJ==*`*KO5w zsCki2m3EtHVK~?2?HRErfC3&P%vLUPuvNc5Hhn@@?2F#F&jP4P=g(Q&jh4dIJx{Y4 zALkx?q5ZJ>#^qPlTR?3$^xp}e^&FGjJgq=PPg41Iehc|kb)NlSPgy(lH1|K8@{T8U*HQl+Od7IBS0nP*gVQUVX}iEx zBuOOr%nG0;9@Lixd0y)BZTi`2<3}s|e{1y?Fkv)gf7H70Zh!doBj5b$;&qn>rgo!8-n{R^``;=@@QR{i==nb$K^M{_V0} z{-0X?_4mbFT+3Uu3o|C_6r4W&#EwHJ(!ddinzabt)dZftNu|lu;no@MSAPmMZ*6FO z?dqR%X+mXjHRP(yPsbl1Mtp2bUK4RO1G_JW-paP~=Y1nVL?3XNzniz!V!-{)q$`b#p@Yi$+F8Rp}b%yWQ*= zFsN1SMfqT%hqig(bM4%z>M> zac8aA+DUOW^fBHb)D!fiD2owwckIV$IAh#T6t?O;&d$e1NlD&wz_Pp*d`rh%TIE?J6+5jepaAJ`$>avHk*9*4L(04-HlgIS24B2Ts=u-#)1u%44LQ&h-jroBnb>l;nAHO!0wcYu6?@T&q zLbz`MItOiK9iHW2B;ugwm1qO`xCoJ?1$S`gh$LXL`e;cO;6i*9o#}`@o2jX7jYSn~ zMhnAF^+qQod-pHlOj>~+F>R{l@*CXvi;K90Z{~bpjw|3K4x$s1zLFbE6*k8Hy2_;a zGUJ!J1~Z=0!Tj#8Jlg0wsaCW5xw#gC{i`VOE7UwYQcTZz(?gHSKP@`(DYYWKchu!F zYKA;>bEi$0O0Zhmpu!OR%R}qC0~YyNdM-V2?N5#%v7?a3f8Ch83ww5fc`j$7f8nPr z8^jD79LciWW!N8C_E5Lu{6)Y=+z$AN5rB{Q{*TD?;*MkF!Ajg=3ORzH`(($D*iZ5u@W~K&=sz8DU27%E6E>p^z5(=vC!jAwt{=6N1io;cj`p7qDO|0X(tviV zM_)+!OSJW8Pnc86S@}sHVw>niKOVwr)Xo!n(S7qgZJszlgaPpsyfKxm=Y80Fcb#kHrImD3zx52^{ zq#&)HZlm>Od@I#tc)$nzC~7r7u7rk-KBM4#cYE?LpuzS&FfRrxE8V%2q4$FI_><#* z9c4!z-Lfb8$4~vh8g2vSXCMWdrjuu|K!CB{Q3wS2DIk3kVDnL+`uzZ1Ja+rVG0?Rm zd_j$kI}pWGIfnFJ=6GTGRL1+Hsl z6%L#qaXjAgDalB&PIwIAv~@05cK*!P3onw3Xm7b)UaB5Dyt`>w=haX+oY zQdhH+!Ms$-JT-0GOXd>kH#^XmK9+UdU-vO;1rOaefjnjhm>9ynAxrzg_@^~)vGLxa z%SO4GOOHw$T0u_Pm{>dx{Ft$fH%hro25ekz%O=cg|0yBUwn>MPh-`me6lo0JCkqLn zMAWr)WM??YT6q+ju9fu?C6Sx}7Gfx&d2u7+z2o@>FgSbuQd(jA^vQq{U3&pWBE-~>8=iOVDI-cw^qrh%Vrn*PmdJV(kT4^7M z=0!yL#5lt6%9S#0OEq3T&jNTHpXb||F$`$W=G5{x9vv44m_5hX*BasYwXHN`le@$A z`S<%#rVP(U!u>srbF#m9lr(-A$ee+%%nL{z>nt(LsT|A54kDYU^+`lwdvm;TIPNf< z$8!W&Drvr#L4q?4GJD_ASfJapXfAvousWGk!@Ku#P3wfJt{0@?(^_=q{gT8=$ig^q zDELr;_t1hA2Fk-kFvZrY;LdB-`hF32ASo)Uw4@wN_5b;uU;ZA)zC_5kg#fy&U%N}d z_?h}*))x+b|F<6h8A+1;&;PC7uU**h$4|R^?`Z+VRKl1U;*2}EAY~R=Sv(3>vD6Ti z9`bgHG;DLv+}sa&t-jX?%>jtTc@ZA*#&;L3X2f3(>uGVV%u6N~zOAJSV-Ky-k;>$f zW2!^>zGbe>EvamWyOH5`t|q(47vv31Nj=%_ff{Qeqz-K3Czi0zlqN7yru&0cEoue*rko6>timix&Zt zN)tEFNu4^^W`z^EC-GRB+(^Twq|3bK%&Q>13|9!}}3kJEIZWZ)YZWJB_b!KzJn@uRVJY964w&E%$TTZ)tCtkjctYR|MH7g zF`eoiyy1Xkt~6;*$@wjKJ)RJXqU;|lSlzVC!h7G|H_0Liq$*`?oy3KX zYUzW~dQ2Ti!yW1chdG?%mJYfgQ1!YU-nx%GWQ^HBf9`9l?zZIkjpaGam1&3Ufqn-i z=hPx7+qjl~!Q`5B0qx5jDD9Rg?aCZJMa6h-2M8<#=bI!aI1C7m554bKXP zAHl6tMH1vt`^yJFg@ie`StmKMQWiDS1uPr+XbW*xJCar26}UyTLTe%TWW&>6Ujt+LrLyt1`5_iA2KULs|p z-H`R$)BqD;fgfw3@hW#{o)&*z0uwpPL)oIA9N&EoDL96 z5Gtd-iQS@)lgVu&=dxp5Uu%x1pEf=N_3+f`7`FtnjFB<}tD5`PE4w|*kA)*IIpo~- zeE*jga>v-~b2R*2x>v2o`Mv(wtuM9B{+5sJW7@U}?KKcrr;O~}!u;p42-*$<;a-Vp zE1NFY6~#NZ79@E0XYA9rp2?Xqr0Gs++FCKzaaDHhi@SaS%l|HTtx#{JVRNQ<3=Mi= z(jRUrxu7DVq=p#=MXv&&FqG}8*}!07=dyv{VXdXa)JXqV?=o3S_5Gwp`L*%(#@ycp z>_%=GzR2fwQrdoAKXUzm^s1m1w%{$%i_u@8Pl)p`sqiy3OOPm})#Gq%}ui>9va9&EcP#bx!&m*e~<<=JcOJ&07$_W_~0Ye{9Er><-=F+iq(J)8_GFQx)H)vCw&$F;vu-}; zQl+|e42awXqG?_|VS51>OCWB*L?Qz{`Qi5g65H@MuIXqL2ObAPe~%0+0Fwm$K_`De zlt9~yPn1sTgMm02Ra*!Gv2u81DzPQ}Z7TgybF==axy=jRAlB7Q+VXF94{FuZ0=Etp z4Zd{AzpAMil~!6e+@vjBHBFCV_w1}&Ce_QWPqCQS$f<+RF&h|11ga}@^?Itl)DB*Q zv#`l}g!LEo2;_J+xecn7By8kUTG*B3)%&ihuNgEA_c1msd!OkQSz}VheN8i&+w8HR z=Wy~E;fZq<6}PT;>idvZxvSnR=}aP;N4BNP-|EWk`C5e#)1dj9WR%IpF*4$#7hrwbvEQQZh*m0f?-WS*SzvU4c|S$jw}T&B1a>ky%V(`TOt^ zYD5tsKrOr`Z{x3n=*&V}REco;1k3#XcJEggcv8;^<&=_;HBBMdA)WIO?vej&vdw8lE~;P(Aw==zg&pp7!HgU`67y%>2dl9nRDGF zT)uj;b%x*5v^{HNVHkRlb|130f4!Fg8(;XQ;hS|x+VHK!f05xVG_H}?K18+1Xdevo zZ=ZEaq|XD>K-Q(D_byI7@eFOWVgcI;qyC7&-JVS|%AapX{KjP&RcF%jd*pu)Gq2OM=jgx`h3%fH2^ca;rwDuGy1`(YtgYC_WlV2j zy`Wd3HoDZRqvafh$BWstGD3{(rIM@s58nGus=ExV#VeX-!f^PQ6knUKvghiZtCjY@ zl+9N#Zlyny0jRxZw?#6PgYK*fIYMY-6F@C?aI(G|RIcR=$$f%99w82(5G$mo1KOFuD)#L(kp@9L5 zr45hEi@W<($z0b0yP0k#wELE zxwUTZsB`j?40Z?iE+m8`%Bq}7Pl*&hd>zt$2ja*t;y>qQacPb-Z^{5tPM69)?w(3j zpo!atInTSLTGE$5PGq>k%jSdS67x9AM|YI^MFkR+Q2cP7o`{LY5sP^m60?Lu(>Fs`)*!t4|RGSke)cAYuZWKD-u3>RHE&k61Wn?Uwx(?Q4Fw9Tz1sSG+HT1 z3v4mbDii095nHj&uGQY5Lh@&S&h&+S9DiNl5F>6wi}9wn#Kp#@S0*qJc-S7syl;h= zle10R7!;n35D+9Ttk4Me7Sr3ttTl!=HRB-;!ZpsRjGc-6eVPx@m&Of*^8||5dY3C5 z&#w;lZ7y!U+0EEYqn8cJkl*(J7Lat=ux?Urnw;c!D*c*hzdY0`b8K}BQ(C3tRIB#s zEXA5dr|*67TN5}RAWhr;cL8>lVE;cklz_?Qx4!->b@|0b-Jc3OPz5BQ0L~JipaAIa z423owN4^%9kAVIj@I!y^Z#q8$pba+99{^4k+hCiRn5XLP>>M|R6u31Nlofu(y8tuF zv*UsHPXW^zz{3mB`#u3;Id2`C1Co)ce>&=p5>HM7WL2Qw-Z~J-@Z`x;g8EqMz@L$v zIBtikJ&%X$7n?Nme0~%@EY&QZ979Gk3w> z=Z3ZmbXsH%gN}4|`LEbH0m})bJd^TjYQX4z)++x+P_Ga|rE$|&2hNnzHc+3|r|Fy+ zP*g+DF>k51r)#)vvcudN5_U#9A-9SSFEsD8?12%{X2ESLmlZGI)Fj!Y($HdT9a?PL zS~`P|Os{Q3E1sgJx$vseV9GA~fWiI1V;UxoG4-C2yQ5?*OJV3P5+_GLZH|@=4_1=) zyMuEw-eE;dvqL|^ONw8TWXj)w9ifQa;rXg&tx>p^PbE7c<15C0iTNwD;8^!JgE|k& zZx{-V(%#`XLG+MPUO`Xc&|bX z@?H`8^^D~T5V3}mcrC1S!HOmr&?a}i{Vq2Rd9PA=F z42xgYwh(Zr_igtZbd^(Sm=A&y(HO;XjmuuC*B3RH?9MG3obB{o$Fe`?)^ll=mxMlY z-NYq5;CH8nbmduPBPku?VA_j5apbi$6D}Mvy)~BX$WHSGoY&GGS0xV`oVVFWwUPc= z>^o>xeD00Tf~kZy<#OeXj-F@78SJE z+-Vu#$QoO-n|PEOBv&RQxFR94Dqagn+HEAjB&2~sc6d^yM+0z+2Z^`_kMTL(s;v^*i`OJL`;+eRVWTifOvP^RJW$;Xr5^t z5T^VWv8wL&WpO4A^x}tZ|6=@%H+HG7%|82gA=jIj4f;E+=O6NWen`+CPG&%O{vd$> zR^>be5JCJnJbDA9DmftVfK8gb&ZcWbdQoa4-FT_BO2yCC&K72M1moJ?{fXwqd>;1~Io%6CM< z^MeRb7jSDI0}cR706~pVQep!_TUL;UgNj zjrOKj1Wak{01n{P>~AGR`4D}|(MRh3P5sy2dCEy0HhwudNQeB>sfs7C#?gf63hsmzeu54UX*zV9&GPRUSvogp?rmdi+ z`|7TQic2=0w`>xN$Z=JwtgT;m1w6A zZTdDeSsVSD4yljvx4*PI-;P`WTvx@y?MZXC_%foPxb zm(Z@^fuQm~zw6I1(CT}nj~efEP4)k$S_&2WgR+2#LuR!U!CHGpCP#qE@R_2tY|V}2 z1DUQMMB-YMs5Y*2K*KIq;$C(qQ zl)4bx7Fylfvzc~&(hMT&Xo#fImr~0%$4Gi>o%Gr9F-Ov+ej9I&eN#N-kIqH9kmDP} zzu~->Z{1!nZBdX=}*V7dc%w{hC^C_dZ!PnJ&?f^2Fw9azg zzTMiwtx?B$ozc3roc(JRIhO-4s5KYh3F!xhO&)kKOwK<_Qf^^{02~HX6nnE7@mEYW zG?>Dr2RM;bUU6CT!q@?$WT>`d)R}$=Kd@xSRM=Ggs%4PN)FKR1fQ!wdp?AJ94u*dOOdR z?C~R@m=1;mn=a!{6g~>lC%K~tJR2wee>@wNQ9vH^^QKE+T;T`!p!tpdE(~nnAE5-S zz_jzgd2!2+<|Ji^_S;RQC!c0VvmE$Q+m7)pR}LaC4@uqWFDSU}vZI(ES(sh+b~!u8 z>3;o&thbzXGkrTdF{W3Q2p=QBk*+xONxySfs=#djL2kMyyg2qJ=;=@4)XI?zJK7X} zy#ElAfF{TtrW^R=_^*!uKMCL%Q3bsMoslaXj@$S2vjdSJ--P^oCQZP@NiQ>E>3~cl zo1~vvMu0>4ujfk23c%_TKomCX@rW14Tz@$@0Kyx9;0N$2zdCZmOdqFSSpxhZ`T&#A zac-ddAG+&LS|Pv*4I*P@1!e1IvjJf+F$fe=Nw{FOV`+N*;vl;1x72L-caMk~V`lJg& z7qtFh2`#ziw^mi<^MktRg9ev;zWlGXl)e8Eo-3~GF&AyNPk9TX01fM$EW0cQemu#G zhl)nP2*#fjrFZ@f7gCX0HLLix5c(xC6GrZTL;s$jS|lCLWQ8bM5^Z~R%hJxm*dklkCEug} z#yC+S7fg#*TT*1+%ZmRQv#Wm~P}>V;|5kf0qwF}B7sn9_81Zh=Lw08)1a(I4Kfre> z$Eyq=KSz)JgdYvFmfJi9)1@x(hLBiZ;+*uyO{GKStk@_Hr8z%CK1-B&tW9Ut;BqGq zj=kC9;nn0n_c;2`I0>Kk9*_2ynVP*dU-R#v(DcnewdNUHCrojr&Uh)@6lCwJTLq)L zO}SxIZ34^_zd6l-jbBun-#u-bd4MBPLoUmobpf4nr|9;?rFF=lleB&n63+fNJMeEy z5cq>BfIvVB!;5TS|7!zmL0~(k?PynWeVKVH<#MXYQtLMrzx#Rj6M(=oGTZ0Z05k9? z_RLU7@HP@4Av-B_M9gJyX@)KE=)V_uM9-yrq@w6wJTf{@>Rvq7eDaJZntAHx1mC?AID#KoC^M$D(5STUEKT1TIG*tsG{%XM{Vwau@NyVt>tSyq^hFftOE znd&^(mn8mJhTKuwLp*+Nv|69v?6O3o4mq6u<*KzTQqMI#y_rQ!T;HJ87(ydMF_NId zZkk3Tl7-JQv)xlfVhlpE~z^TsK&>icgRbbT*jC$VRclm@eJG$V&D3I~4nya52rWVwyfh`5DhnqKcA9?eBtG>?gmC^B(A%Up@E$lb zDeE$2-M<04m{hqC|3^2v`D2yZ-U)m7(nDEfgfCd0g$^h-nKe#T{$CL9GcP|)TxrLe z5=jW!_X7)tI{T@?e}1(&k@VTF6iA`%*?t&HG+{>?p$&KNhB~hre%?|H6NBB~H}hu{ z#5Agbp`C|aMHEL=Y)>RhCl9(f`g4%EmmFP1D5G@d{<%R?%yJ-4Cqkf|Qzji6kMn#mrLL`3ev?WeoYyI!= z^X1HwFKzSO2IvyiaJ(zUW8=rcwP(;{I*YKa9qm`!mCMy0sL}y>-_Wf{+IJCYWFKU! z`C9Q~T4pT*tiNroe=xc@|C`ZuB&2>@SwGCH<3}_o*HoVzRs7msfk5y)S(N;P)%;H> zBVD#Sfc3>`#!;4$^iR5j0rd^Qhn2;uV5qBbTA}gS3qg?XtrvhKd-3Gl3k4-W7y_D# z!pUP$s~61UhQG|MAKdHIN4_i&==>AVeb5P3Km`EOz+P~l1=C>-8{Z=wf9VeW=#ihg z!`U&sWM$m1pdt6`KZAx8okX6HNgteAt{ol`h{e3B3GnXUhj+~hIDYNy@kPp>TKqPM znGPM_DE#KN7G3>DMYn9D!I%efNws_}(u1h;RC{c&oq7QN{u_K$dJOMfj}5v05j!>J zC$HRNMQlayf962EZjMDup(U*#BQTo}h7*1LrVr2Ko<^a1^TtAnAL~U!t4D`YUFyyb zx_gW37#0(C7gI$_zbHnymMuZmB6pM)7Uh;PT&3Q(T+&P*XD3BnH_X=G;9(eO6L*EL z+?n#W>}8Ta=32>}C($zW(0zPU!vD0>A(qIp9rw91PN)AaG0b8nA?abhYXydBu0}mX z-6vHk-%%<{t5Qncv$sF%s%Saw-Wg%VKBx;o!^zW{*b4Fc! z|Ist{KL93W5In#`jNUY`(J8jsS=>tMsD8bNPpUF7w1*MsA3evHU+3+LlupF^d1s>c zH}^3%YVRD}ncTLOIe;Z|o^w>|m(eVQf11^K_NAK2fX}GtX}D0+B~j>M&Vo+*nRzX7 zi_wSe_HQzU$*b=SB?rvyGpoG&?2yK=)Tg+S_NdS{ZDIlznSQQr4caEbX=*~6eu--6 zp`qT5bmWb9r$pRuNWv^JL(aPj8pAmhS0LWLPCmw{_kNeV7j-z2qDVq)Uj%!>lHNjj zRSS|9q2SY^e4_6|W5Knwj}2TgqZ{c-6^(lpIk+iodY`3?TOR%1c5Rtal@mFC=jK64 zNXtL@tA3#fo9=R=K7G?Ho}GWA)N3t-PhHiM(x?4kYTi4O)^dW|&!3P_LetL@oI^iM zeJIm+t$Z^L=X8VBj5IO4pRLGoe$JQW+dts0_b^9RBrE0f>_h;*7FxT&I`4kfAQ}8i`-Unt6;JpZ?B&GA{qs{P&ksJ7XyJPUb3T@p8FS% zwVXU-_ph2Dpb;vaJi!)tEan#I{i`Q{2qnX1pJYWSWE+4HPQRpRFM8pp6g}fSos5-U ztPzO8Asuil)CrB~!5|L@MMa}~qG@--w`_;^0bz7uw zq^gGvrtHf31-y|uhlJpg99JIpuM=v^l1-FaET)Im>P3^vN9Ms|({a`x$1EVspFGuB z*a*h8#q)ZmsSP>ab!U6hf?5~i&GAVqEz2o2$S(#;!dFP1>G^#$r7vvi<^@G*^m=eO z%$OOcmSVBaDUE^UC=sK)zA6=)%j7lEB^y@}Nz)vD5|*!!#VsP*G5@c;}CQS#da$$8H? z_kGX3f80OrZ-0Eo+H38y_TFnfYpv(`KHrBFXd-`NB zc?J<-b_>_a2tTnfA`&{4KvdU3hj?X`lst0E1U33eha?^9dhI09BV|(@Pq2=K)!{7aB}OorB^$|rjA9t zc7^f`td0@+4*h8mg=;sn*GDBKLuwu&OCfPoYq2*vLm8TGd#;SlQp5zhsHPhl(TkzF zgVn;sA({S9i{vP?>oCP3ylit@G@JwH%yEk5BRV8;upYRMIBB?r^GN5%uX^TOXWL;W z!`_abeP-riD4O3!NyQhMJLrO;ae z><2Bopz1km14mGfErFz z%7pl!x*We|ey>p^wS(R$0Z_hKpd;Jd{c>BuE6>A5Nv%y4-llHwmLm&Q5_oc;8$!9Z z49hrAjOgo6jzL!M+tSE&6xl4%QhEyQvL*&gEn-xkd;@T%hViw1nEvR8g<^y#2S)g0 zJqr=(B$`xDT>RTN@!1jWqYf!!#^SG#aV2GbaT}56q_u|-I5u`%T2yc?>DwTMH-y5O7Jrj(@6>t%6-btKUm=^jep@?P{(cW zl0Ean>@J*6L~vW$u&<9MIkm-JI0;Qh=L0MAuzK@W={_YZTJpwkH_E^AQI_5+|7c-b z`3PHS9xr{@zz_iE__tJ>zV52wG?|~{XXazh$m48!5yEu$Ypb8(XWwRW_zZu;3lpj9 zsx)M2^crh<*Sjp_yEW_6S~}E2S0v~-xQZd4tDthw+38`UR?2L^=F^*L7n%e!PkwyG zy>e8x2@;O5Jh1taIAsVWb=z4kDuA9+6|(CKbN&gx2`16Vbw178YCUdcZgckeVS@c7 zp!Yi14%BPF{)gQ>CBVXP_Fx_j?DJWc?FslO(O~uI?p>MB+;tP+@d5sV^ng$TuDSta zpHrbgQ~{=4!^2Zh?GftS^ycCx;)uE@uu-z1A@lC};I^OGd>f6%Qsjc%vvCFNyykIA!jd_qy? zM0(9s9Fkit7<~bRr3HcNhp+a6j$z_83S+`{>v%^ThYn%A9hpOCm((PJ5qn@S`e3RJdP<$#XEDUtw zISb_&n;OdV9s?JK)F)CmdQqZ-8GOwvX0)(A;&o9#gfudej1|u3_?8<>R(;(Nr5~*{ z))z`i4WnC1pRU=IZ1ywDOruMTPtN{`2>=f>LMOD|Z7L8yv>HrUmebT1shR&nof(iE z5H=@G$DC$^V!tGKgkb@Lj?wSSQ-(`1{og^NS#-(}Cj%Ky`tH>wQveX-$UV@wR?~%b zCZcawwVX}Jeel)5gx#J<_6CCPp?l2vInii%1z;cWPzk{z?}TzQJ%&q;bd95XMkr!!_l#ao!-%qI9t-0oAQWjY02&b9Ksraqdny{ zW;1v$UWLLhT7lS>h}6Qj%hs?ReJjPVif%JIFf4T+o$Al~9)BX>Q~YsR%4;Z%hXO9HEb&xn2yHeUv2e z@Y!P*X3iggzg;c(zFrQ5+LZ%GLAOqW5_i2qhu@G*PVANf&Y-)!c9&~^@BhIMFm-c2 zaymXN_~CueD9>iXuGNs3{~&ezh0LEjrwoM;?a?E>_-#?uXSRuFy9{D5_P^P7zOp|z zB$|9AVj_9O0L4Y}feV5!ikZzHP(AL|{5~&JA=V&PF*K!Hw0}+Ew}C2Q+tZ7LU?H4B z)qkxN`?+92A;#G@$_~4{ zC4^JXiBI%s%<2iwX6MFT>Dz%e1NKF;K|x(z=t>?Z6ef+=vmFK0V$d(g^3c>?8u)=! z5KGP%{0s#CT%Xa70`{O}{$XL)RF{@tlHe)FKB=TJxgyVN>oMgC6xT)+LXFE6m*!;! zaq}UQ(Teqsf2_{?!|K!^Yf42FD*xT1I3+?NBF55&T*^HG%S`&qj}tGrHG<(l;B~tA z@)5CKuX$9=jT63S2fl-l;S2h={X!(ASfbW|_*Z;@4F*I$MIxG#C#M+~6+LYXJG=CW zZdgB4*H$=ap8C~AuMj-unvr*z^Itu~ukZa>(&h0!}h?ZREA!E`T88g4Di)y ziHkecdSEUO!33XW3#(GyKqLA`8+Hjn!$5O}RhPYz6t48)*YveNhO?HR_7 z1@4c%)qLdr`|B;&>^M*I^Yq-eJjqgMT-h*6mA1u05dI9SK(K28m#u2^oz1+lw3Hw|hG32u(U7H}6Qd--Q zqJ~`V$Yy0X)+J|A%WGrM52e7_mK~p@Z~3e}y&%UC9=pjdB=>6i&U%G=`8>>+2~u80)qrxPM5oZ$qGX!;u|njUGdgw#rW{b<>S`ArqQy zou#wT4YewT#AWi}i>kM-zR08FdLoh=OllY1QAU$Gk?6n3r%B&CZixYa3EKRxybAcR z1f9w9pAY<>Jv;D{?i@Q=42_YDI7<_R5y91qlrO;!A52QN`=jZsyEZ zLlYf>q97GxFnyolv}Q81^O!noUZ}J$-J9qospiyvy%e=fPDU45;~=G8lM71s!UN#+ zkWWLxeyWP(0sbKkO7uLWn^KCrm_DN+!rRb`j>e6OVu;v;mcM#aT^jh&*bBiMAoI>L5W;j(VaWkysah2 zD_SHhts*5EMmq-O=RY#cK6$%)K5_Cw5;`O`#9-(}5Wa<*t;f(_=+nW z(|}JorN3y()xf&fw?TpMax09|_HOqi%lc|Dvhcs~GXoPf0Lq#JHoC*aE-jt&PoW5; zXn)z;^DhGwRJ63UfZ-5ewX@Da2>=kPxBH1_X-|-Qil~o(4$4(rS6U1NtWmBqa~@h4 zPwb_x?|O;vBB_o8#G|0ykY*C?fJ50{6tms`fVS(`Gftl-fB3;ujO;U@iMmynK9@e7 zuz2AcvVK36mBo5;QvL@tRc>ESf+-S!$17>&;4y|9``|;;%b&)C5LO&I;xsUozuWZv zQPFQkQ3fxGYB6Bh;~hG$F&*_xh?2pVY}PY*0p`Icxo3wbX6* z;#O4e5PzV}@Uk0)!U;VSSkrPT=|nd`Nx}-b>$~Re_txj$IK4JGw~3Zp^FR(`Y+0Al zG%QWV{PokotA#m>_CK`R2P5|YAB`Un?~0wXBHDjqhwU2msBC#Ryg zC`3qLTw+aN(<8l*JchQ*$s%?-9$Fqly%ysK{to0XhOAe&hG#e8CfC6}*@oh9hSmG@ z*pI31Hlm#`pUn6wj6T~u-!M?M3HUsqYFH-65E$H~0na{AKfR}p0)#i1g-DD_MON1Y z*NFNHWAjrY_}xPuYUZ|Uu&cw73gSDLW_&Gc7{T0h(B z%G?y8>`PtEDi!_?Ix_K!0Xy5S_H95m9WF}RW?*enX;T(OW4HXkKxHad3D#N>WqI<3 zT+l#v6fkHi5Y4g~_b0piYJLX^l@ENH%BvK&O2!NnkCqc0At37U_W~?fB`uOsyR~!( z2gP9h;FSD<<=`sPb1kJ>crKc{=dA>T$>L7bOI}?^azUv>%>EB_Xu}*48w?Q)kA^d{ zH5sRtXd1A#vl^jLNiR6S&0XS%&@-hrzE}V3A4cubdv@w1Ms31)Vx%`UFKbjdz)^g~ z8lzs0_L~!yshGsPg5bgsarK3tz8z(3W{f3&>t*Kg^G%Uv zckPID6VXM&MQ3Gt%_O-O%o@LqNX8d1hu6PSly@e;&o_QUa!;f7YbcldpC;oX?(bKLg0!&KV`K3+cx{lXjQ=bYl=YHrZ}-fuc@wZ z%Qkh6X$*sgn|&QKM=+{U&ald`Rz;D~xAOgqx%@Y$_;id2L`#NIHnZ=g7{G*@a ztofFkxKgH9?Vv`cPfIx?5kgimqf=T53;q+68F0@8(uEzGQVib6I-}YH7Zcl1J71GD zV1aE)PjbT_Ndbj@s9An3J41$b04t*mZn>B?uUD+J;3G*Szca(-}c34!^w`HpWKn)W>-7}c4G z--_mQU!Y=MbFM$r5K?RwGpQf8+Cp2;2|r0+xtXKXbL&QaR%;!ZXNjzPq_Mam^OA*r z;!yvTCL%dA7Yk*+f19bMzND`{ewa#Cki1f%^GntZS4(AgpqNTXD53J~Ku%-h7aAQCqbLKTBv6DR&EE z3@0C6nN#FwGP!AG1E|4%N@__)`E!O_PVTm||KiA-<9Fc0%ttOg_8^$UO)dwM^>I(B%v|U$kR}W7vdivCEAxh-20V~PVwxv3uc>niJ zbo3e{<4_?gV?l6kHl#g^hRh>-EK{1=w!zjx{P=HBUOh<;^12w^Pc4>B?vdFkqXx_6 zB;3vV4vU-MmuqxpZhjeqeiHOl^fL=$?c-1lIvUWBRaY`AxU~)6hdXa|(?|m?CTp?6 z_R@jItxw0IKvYV~)VzvZTEOs`Cf@hm{JKJO3nFF((F@R(zyK=9l%8cx@B#;=ER0_u zfs1c;Y-3B;qQ@gA8T{&noBqC?+4uKDJ^mWA{lOq|sIedVX}8_;F1FX1BRZ8jn6u=c z?9_2#oB>{!V zkHHgER+;l^cM19|dhLAl%|8^(zfJ9bFLh%EBcHwYuw8kEZ3N%)ZUUkN;pu&!razn* zYLZeUX7n{CkD{2VWOIu#xhjqOvz+~CT9i0~i>!uG=V?I?>z9@j70Q*A^TlU-)4Ioo z6e;_Y`uw6Mz~}S)A@{XeF4Cs@sGn<9OC2$pebygVBNe~$G9@MX;RG`sa?~tuaSYu3 zx^{H-A{-z`l+S6DVd<~Yg<0P!4qdo*%U8-oPaoPaW6#Z}EfW`2GL?c1#hWdO;srVF zPCam1pW)pZ9;@;637MM<-cv^g53?6;QqRO z__1S}xoW8ZAY#6lWUe~wCYscV0JnoXK(NWz0Vh?D9`*jT>nVJoGyE~cTnG62k3cUt z1AGgBvEWD|$RH1xCO>e#wd;TU=pH90_Y8izk}}EndV!0jqEva<%v)(5iTl%Ewf-Rqx8Q5&=>}` zJicu}hkr0-zIW^))lMXCtyF+txJQ#k6??AJkeAUVt#INyGBX*{_~e(=Rh&qM9tTWLYi z`Pi#EK#+&&gGe^=4$Vt1izF#nCKIEx=1jWB&vn>5ADjS)TSc+jmtpnX%2U7k_lgy^ zS>rUjUIW}Joysk-`;*?O!aJ)qjEmV0ZvH~1Cz(A`N9vcb4`UU>yXL-a`)Co%9bi;~ zr98tCgdb>?Ra+W}`f?t*xYB*FW`};FJtR7Zlx`eu(vKb!TUXGx93pN}G`46&3@BoB zUh7n3*#_H`L569^dGO(lMOa&u&V`}c-3YPzpYQyvWyP< z4tl=PTG#WYyPW15_2C$1zVD|z{PJmPgs*I-5Vyw)Wkh0?EN0u1&_Gexx4QC5RJDJ? zRzle@(%yV6zph$f(BwPl_X(eN7~)HNc6(HeLgv;|u!#?sF!(hs}>HcwJUYe3p8WN5L zl*cGCe6fW-F?cGJuOS!)j*ZINW~@-udtMxlvLn25D(EQ17vp+60kRi`hM6r^De?h8 z$e8mjF9NK0mzgp&8(cR0+$j?aVM*sw+v4S=N4r(>i=(0-lLW@r6~~Q5^~EoXQ-z~yCgePk(X173>5)GuQial)N^=y~Tw~~{&h{>86ZoY#0PL$l3 zeCO&Jr-~2SWPd@dk=(sb!tJlg1H06tm|N0NH?T&dt#u9DhE|@tktW0kv8lyA z@nPu%7*4bO9VEX53!k+&4baTbsYM0zW4N+bt~4nCbP2j;NvR%FHUc}t(*uVmof=Kh z*y;2lFbRG_WfI_;XrCy~gaEGxH++u{cc7-E|?-C(J5q=*+gZ7x1bE7)dI`@ck=s4Vvc=k+Wu$Y2csR+l?F$|XAnq9l{ zkUSeJWWIi51wFrhx#FG8t4J`MLzAMWgQ}LVv7KO&Qk+rHai4A}k<|!0-mTxRd#FB_ zL5|>{rm`FS^H$V{EZ#ARMimMScmLM&c+U9=maOMXlL0fRVGtM7g#E3)QjSfC%i6*ElZ(2SYmA>l9%u zN#RqWLJh%+T%j^nMi{7^nY$m~^FNtZ5$Q+f_E_<)LfbNz1%A7!%exwsLnoAJ%CnTh zKO=-PoH;)-r(>83k2!OhLdcG#bvea(t_R6oQdgiTs!iIttfQmhu{cvOdGW4&SNv!u z7OFo?<93|N?a+Sk^Z51zkDSCW?Krz_0$D5&i=)`RHW@zlNPQ{mpVZvrB2DUmbJ1sE16;Ehx9Qw4xp7RWh&%G>LaDW6YeWuEvm#_L%;m z9gN}N4qPKspT7QTWZO5MNF+c3w>`F!KfEnG*;q0Lwf@BPn~wx?O}}14?Y}hJa%6U7 zRUV7`z11A1y;I`p`5oj>YR+DPdR6z#KAT@kW4yFsPe_wCbvH#!p;^!z7kfW0Ut_>i zWiR898W4G$r}$(G=ayUSaXU73ub?K0Hv#>MQ=j>8E4jx<6rXl}PgSOJwZ-8~aNCQD} z`H=xbvZ{L^EXhM7N3+ue=kE+hPfdPu);HyWE@5ONfMBBc>7<7=jcMlM9fj0m+ z$q4{M{Q+dWYg^hQ=-l`5_;F9**IC1b7Ig3Q@#A!EJZWWI*#O$(4FXj>EWot&j#s{| zG54>fABbWC$;^VHI6=uCp^xD32tLDg@oI>(Ey4JRg+C@H{!REm+6`a8J(vKlTaGOM zX#|ih*}>@d6J)B6b??Xns!fCL9h>s=jz5#nRvLsH1J_@Du+#ommH8&b@k-rPi0wAx z{KCCuxEz($2M?^7VtYm3tb;)Q@6m?1%B-PJ*~3FUV}G@=6#Z6dsb@cdkfnt+YOtMFqJW$i{ou%W9llf!Fs`-cJ+7&r}07 zMnAL7iG+;A=+OSb@iP_Jd3%MRF!b&94E$~VvcepT+ILWdX(hi=bx4s~ylRR|HY7#x zOR+I>emSMyof9VrL#14VFRWQSK3eQd*`S*bfDb=Ef|MEX;V2s0r(k1Z^QqDRX%$%h zdgZAsx3^P)UExNoUy745?Rt@md7iOSIg8fXoARAYP3zAZT6W*dP2lEEKi~B)wiiy@ z(U@|nEx|`ZnTIyLig_C?kL^(-?IpQ&9Y(b3)N*WP)v=Ni1EVC=&4^d(H~A4w=kmK_ zNu=#l-6Y_KY!GuUu@TV8k5)WhV26H5&NtC*^bQD|V!CO?Xs=tm-`gIq2v5T13nK#B z0)<@Scoc4y>5*q*ffMY%L*02;S)HG$+ka85n!^fKD`@0&;zis%Pvu&l3O#O!(lGYb zO0+26dDZN?l!8{aknDhbBiFc*g`uw6fP~whbGd5h%YZ{9Gmnq1S<)UY{uBK6KeGlO zc8V5}eDTM)ns1v>VKmM9ezzc(9k2KEnnE)Z0WmKNB#2Xej$bYj|D&8U^>-38m= ztrpbE!m8p15m>%0;LztPu}|s;m7ZBKD=mo2mA8q7&W9&vjb1I9_1VG3|jlBO=$GB7luX0l2-aiP>}(zsU1@DQOtYs+lF5G4!obh#f^{Cj!&P3Zt^aiZ-=~nuvTDsm&no z)1-`18-YT5Q%g@i$H+P5YZ}I*c;A62p2_vr=o^(l6{X$B)8C`VIeONp9-o16K%Z(j zAoN^)pPP^oNwmToy&wphHjhEPAaYsekGlVjE_d5k{A14}^ow4Osxu`O_R=Q4=DLBF zNO@b~K%E`Wa+97lBvIl8<7z;>DWa&ea)ny|tx69=BFx6IEXWiX+vg!$#s98(f z5WWVti~O_r=!DtM8-D)vc`J7`kB#Vlo47%|p|L;;^)FuJO3q+6xO zG!IOh?80N`Q(wL@A59-Mj@B48UqOxV!J1)OmKyKdC8(L1Jn1ih&VB)bJX0~^Q0*hV zYNjL}z2bU|N&Y+=>cX4uypA%@A!-ZJSOJbK-12A_2em`S}|Yy*>oML!7578*(= zv2qpLM;Yb_69s;{;+FFcZB#%g@YT9sM7#n4=$Wum2Z=|^GXI&WbWd;`{?Hz#Kvy-K zN|=k`4u((F{nlLI!00ZE%dV6rt2+AxnkvRj4n$Wx`erw3)h|nwJyQZOQty&)@7fc< z&c~$pfMI*C)qtz#>67AzcK}pE_W;N05ATlszArBLmkv_A5^ceUu#v;nOs@%G|NSdf z&$%9loLudj3ioYyR*>u8cV(@G_%)F(^(#4EXPa^t-mUd#d!qnp*h)`Q=&3AxgX|{Jq*aY$UDS`9jmubDa=us zv2sCVw7>rdM7ULHmyM3fc-C6Pr{=2@c-E`Uz9DpM#sQ7JQq!Sza zrr3(LiW(C2s>J&4-2$=BwCysB!&f(T==?NLe zOLo6bA@Y9G-ba0`LA)nb3{)n@d?KH>>m$5%;X-yz>UrcXd^MZC3K^0l649LV+*WJt zZEz^Z%OL+mU&B1Rbo8A_ADo4PI+zM^EAg2^y)c}wn9T}K!4%ngCz|mK`{iyKF%Bu! zT<_p5b*rm+rI5r$c+vCJ71r!N(qQAfrNp+j%#3c?WFEZ5h~hXbQanc1D&j17~q&+ufer7 zal@4(#;?xVPxna4fi*>GlROq1S1MIL*P~*S;=ZU6&sKM|DbdFT78zn2i_hB1fRn3I z=%Lx_A5sD-fJnwWmH^G=WaLHJiDXNQ7=2M*98wbrI+=5G<$-fW9o<#GCAW-O!!ruF0|2exQJ znjKDbXM6BG39oIzH4l$3l+c(Gkp0xnmp!I2u$(z?Xm_MqQqjbkoLKLI65XguGzCF@ zh2~Z#FB_+1TDc5H--W*!r75R=<9QclW(`l<_{qYt6m)n%OHgnLzS(P$2H=~X37=u{ zDH8TxxRmMWsc$VytXaWx!`GhKi@L4gR-+lo7xm2CWM+Hypyw!qLwWQEo=o0P#@c=h zB!?`|2NqJZ^#kk0{>XNy$L}^M&Zua$dSeG|_O&$UJ=3_oRUge{ssG^%bUGCmvRWUm zLsQLcIi38{?Auhb7kQ_K9vy>bp{-tVE>`xN-V?%Xjdif`ym^v%=o6kYN>hPTnvuTa zG<@?Ja+%2VY5UtiP>u;#@Ys4o>q?A{{L2JEOB3U+NDiUCMt?`Q*N`OPz>Q9lPXx6U zk76aC72VK&%X4EphNup2Oq->9SwV$a+~wg7|k3me0fe%^(T-YCS4v1}A+5ATn0yku zWUZx~)KK)260AjjE$hlG>(_2E7?jXVRCJZjf-fMcKHa>rOYvfcW5-MsVis(^4U^#T zh#uAV@=Oi)>0M9w*5#AJ2ZOp^SAr^KUtjnDa18B5zyc!7080F0 zzr6z_^?QyZsu%V&TJMh0?UKs_rU1am`FGm|@gw&xfTSKxGnd*s1UZVzmmH>ojBmI9 zd7+%RJKud<_NB!LY@F4sK_|6(Ya-KFxzCWRZ93++5WxSvN>IkFdc@qG$$>M^yZn)) zRY7tahU2zDbEm}zU!{#L+2_UN&DbjzAZ8#QxS}E??tZdHk8$^qkz-#`etdYJAk?#W zi^(d`NK=a2h+>Xhodsj1;iDbR8}o|NXlS}O4Q3(MQhmKGG7ozt8R@>DFWA;XS10Hf zAU=-hMWroUGbJ(kgqSu z;C~cApcE%H$3d%?NFd6d-AF~7Re;HuYV?~&o*C!3$xcUvMfa>V%4s}(0&s^K1l*yx zK%k7*0RA*G2*e}B9RSYopByU)C+i^A%pVZ4pLup$GiuI?_c|S2*k^Ls0JNYFclFbX zs3t~RfMaOZFFK|{TO&^5lYW9ZKfi7xTD+cxP$pU(?&e4w?#Y0hiz?MWX(}_C{%hR{C;nW^tYW{5*Vy%}!Z!K2m`3asB&*jr@Qq_=^7HqR z-XBKc%xS?exGl;VRCmKxA}gV<3N@-8U0;60{TRp!ZYlB7;Zdgvyt(m}U4r-@9_Mps zCzImusuR7wzTpTKe{;{B%=b;2SE`GHTB#5t3n>MIt#w&8dUh%IdKtA=1n>75uw<*w zU2LIa{YunT^{gh7OwKfVbQ=Lk3KsP}1I4eRV&s4tv<5p#UG zdvcDvVu(tJF21de*UKm{yrHf9$e64st^&f{Gd>W$^cQfr{!_0zMiII@{rV2d zkOe?X{b0?sojfirVAL5r7HH@~cNC!QII)Xy`>=oJ5g@+LuJU=WAOGoUzh)dc@(@OQ z0VGabk=9uQI6H7pH6Nt#5^YU#42Q_xWye~Hoop6I3+Sf2e=#fQ=#iFO%`{_jO3U;0 zRhrF)$!g1!P|f<6AZeuMu$*F;UDyha8yV^1do^*&*ZAE=R403z?qmmchvGXZTz`oA z0x1bEQWYC&X1iR*lG|tZJU?-9pw5QG^V;P`R>@6No8Aws2#02Tt>QUl)&{>v3%khUC+N41f#kkcdnHn_k9 z$e1#pV_?ObCl%x83`ZtWd|M1U(`$|gHMp>1WbhqC^c~cgGw*l$B;~d=5OX26p^xzM z8AN|pT#)vP(9Z*w4I0^(Zg0_}i>A~j3#k;u$)FdQpS(&>!|~@A35$u=zjj3qPJbS! zMsTeKYfc5zp0E|o%Nj_V&Sq|V=tWv;&&hzLTC`wyxsw7t25yxzOHOSR!h);Ld*rD; z_LaIEt;!D;*3}8cv!|&mtefuW#=d)XPgZazNk4I;Wps91t=p;638=vJUq8rs#=rU= z2UV>&^0qyFIhJp$6xONM3Hvx{%M}0NHRN2Ct`-uP*SbhYt!j;iIt%pViKkXwbOymC zZJxBRo#T211dYZA1A!SlGdAvE6#V74i~4&<8VNR;fl2C*+7*()gqG81++xZu;SeaD z*a|)27VDq2A~|dt^UhEFlycha#~1(h6Oine8)alX5BHN#(EO671fcVGBo*v%xV5{= zG2FfZ!Pd85j*{1HHfv7Jn~}-Vv>z{Cxw&lQz92_3kYxB2OOw zZH%&C`_kX1&mVMJP7aLIE1Xp(p}olta3ysnmP@^NA@u_QQ*!?Mv;U^VIg$DO=?_e2 zsa)Whet-$dpflPlnNG$yv= zO(I1N->}WQks9|)i6WdVL#tAvfJlv2`=u1zJ5%gl3U`4Rj5GVCJOYYZf5;H5=heKtd)v6f@7wu>As=oj?0!N|iAxWHXyzTy&A=%$?b zA@Stjw5y-l)uY?Pu%om$jnAsEg_qxooLOqCM36rQQ;(+xVs(@x903+mqW z75--%F!U%LAtQeX8h=n?d5zAx)|S6JZI#Ut@kal6rYqFm$c+&@$jarxz}ZhUW5jHS zGH$_pz-{fRoK%x)GhmW*@hK0YRqp+>oBordiRy?O6j#nwNp>Jh9gpLWVl&BnQ?0oj z3o2&)%18Kz9bl4_8Ahaf47MHHX+zwUQ)z;6sm`>gb(5Gcr0!0h_uQ8M$sIvQ?|D8- zyx>CT47w=#zPsBskJKAZhoEnz@{1aNP0Eq|q;3?uBKqy>8fj?D7R`m0!r{OZop8v7 zk;M%{+`{=ykB0Fb5_kPxGuM+vML-P1{iDnQ(&4wjS(GnGk7;VkiU#i=#%KQ>^a(i4 zm+j=<@hty(yvBJVOG^%7ID726@b%c2qe}pF$7inDyMzWzUlxxpU{y@sFSGksdn%`e(b;`JR>cjpE;=Dc)Gb$yYa=D7$>as0yW< z89eEg?HL9&WPn}fGl2*JVd;JGsOenNwFuPL$4*riK8D-+I#%d_Q43T?WSIheB6LDF zlhcw8LHCL{KNTm~%O=~1cVow%<2Nx0%w@J<8Bd38nDH}y5#q>odN`op?KDy&SYRKJ5>{(8(k;E?COIpZRs#(1BEEk?ZsT*^0mM2!hUI`(ruHnG+)ktNz4aV`5^wV})>T(Q zHnT8x$>m6NcZ(X^Mf<0DiZJp!NQ|O9fwzb^ZvoR}2O~!t4k<#Ch)QU)d~lYWS*iUn zA|aiK_6qvs*8#<6=1UcXy6IwG_F=-(uSyx$0j+Qsp8i2;RG(qNCAVjItC@HO?TFsXME84tkT!&lO< z(TSSd0vq{0YLWM=kl>7>809)iN%1GHh9Oun50>ZxI(oIRl?In_`L|SJd!T!Ie(+HvVDV zm?|CJd`ZIj zRHx`XvgsqA)93+v|a^kQfRtIUS9V|Z4(^!g=aP)3BMBp=l~Nq{L{ zAh>(O&uD|cb%oq|@|;8e%*~1x*$oDr?$1X39?iI}F>zUD#GLG{B^KijOI+@n0jez` z4wr#+kgq7EH!nBP$k@IiH{~0nGsi0=r(2-DLSCUZ!?uz3ypKZDI9OW|##}(uW3v5j zps5cr3cI5=mik##Lk^ybmE#hywj3?4dES41I&@R+Xp!;#2IfK4OBq3tWbccw0+Bk+ zchd7-7LJSh=?wzVZ!TFiw3_dbxvOFE+nLFFO&7yb>Qx5LzPesrxYI}d7ekKMl)J`K zu}C4yqUc+ZEJm>u8#e+*L08>M-!KP+TTVIU0g=K^H@KQl&Y0s6e zzNv+%OkNHSHE~K9goDq$MFj|3nUacmsh>ipDPFQoYZctBKrBVMzmiLcaeZy7X2Rmr<_UxdL0YPJQFObfdak$L znRSZ2`?0E8&zBS6=jy}S+hcT>(p+xjlCN-Ep7sC>0@&-=bR1MWiRh%|Z|O^QEdHr@ zN;K5)$we3fbDnrE?P|@Pk(Vwrp6n~e<=;V)XKMH;uiHKK`eag&vK7U6uIIi&uHTs* z>K7oJ{(skF?|=Ydaqr&I!P72#efz_|>EVB0O#9dcbWh_vASjN!b_RuAVLJNw@rN_7 z-#9azJo}&T^0c z0Yd&ozaA?>pha9a?SqZJ5i5;3LoZ9w$02c zo363a3=wzpUo)}r6ImWU7WgxlL^;&aJ-u#TH5GUitJW`AM4}DQ=sD{QMvE;iTP#^) zq9MVsVFV=hNqPFpglSi>;7%Nd_1l`N)c;WGW igWLc2_s#3SETR1`OaG^Z`?L`M)64wtoiFme>;D03#-c6& literal 0 HcmV?d00001 diff --git a/memory-match/imports/api/concurrency.server.meteor.rstest.test.ts b/memory-match/imports/api/concurrency.server.meteor.rstest.test.ts new file mode 100644 index 00000000..3cabab04 --- /dev/null +++ b/memory-match/imports/api/concurrency.server.meteor.rstest.test.ts @@ -0,0 +1,55 @@ +import { Mongo } from 'meteor/mongo'; +import { + afterAll, + beforeAll, + describe, + expect, + test, +} from '@rstest/core'; + +interface Probe { + _id: string; + lane: string; +} + +const ConcurrentProbes = new Mongo.Collection('showcase_concurrent_probes'); +let active = 0; +let started = 0; +let inserted = 0; +let release: () => void; +const firstPairStarted = new Promise((resolve) => { + release = resolve; +}); + +describe.concurrent('Meteor runtime concurrency', () => { + beforeAll(async () => { + await ConcurrentProbes.removeAsync({}); + }); + + afterAll(async () => { + await ConcurrentProbes.removeAsync({}); + }); + + for (const lane of ['methods', 'publications', 'collections']) { + test(lane, async () => { + active += 1; + started += 1; + try { + expect(active <= 2).toBe(true); + await ConcurrentProbes.insertAsync({ _id: lane, lane }); + inserted += 1; + if (inserted === 2) release(); + await firstPairStarted; + expect((await ConcurrentProbes.find().countAsync()) >= 2).toBe(true); + } finally { + active -= 1; + } + }); + } + + test.sequential('observes completed cases in same Meteor host', async () => { + expect(active).toBe(0); + expect(started).toBe(3); + expect(await ConcurrentProbes.find().countAsync()).toBe(3); + }); +}); diff --git a/memory-match/imports/api/games.ts b/memory-match/imports/api/games.ts new file mode 100644 index 00000000..03a6b80e --- /dev/null +++ b/memory-match/imports/api/games.ts @@ -0,0 +1,16 @@ +import { Mongo } from 'meteor/mongo'; + +import type { GameState } from '../game/types'; + +export interface GameDocument { + _id?: string; + playerName: string; + seed: string; + state: GameState; + score?: number; + createdAt: number; + updatedAt: number; + revision?: number; +} + +export const Games = new Mongo.Collection('memory_games'); diff --git a/memory-match/imports/api/methods-spy.server.meteor.rstest.test.ts b/memory-match/imports/api/methods-spy.server.meteor.rstest.test.ts new file mode 100644 index 00000000..bb4ed277 --- /dev/null +++ b/memory-match/imports/api/methods-spy.server.meteor.rstest.test.ts @@ -0,0 +1,31 @@ +import { Meteor } from 'meteor/meteor'; +import { afterEach, describe, expect, rs, test } from '@rstest/core'; + +import { Games } from './games'; +import './methods'; + +const playerName = `spy-${process.env.METEOR_TEST_WORKER_ID ?? 'single'}-Ada`; + +describe.sequential('Rstest spies inside real Meteor runtime', () => { + afterEach(async () => { + await Games.removeAsync({ playerName }); + }); + + test('spies without replacing Meteor or Mongo', async () => { + const insert = rs.spyOn(Games, 'insertAsync'); + + const gameId = await Meteor.callAsync('memory.start', { + playerName, + seed: 'rstest-runtime', + }) as string; + const persisted = await Games.findOneAsync(gameId); + + expect(insert).toHaveBeenCalledTimes(1); + expect(insert).toHaveBeenCalledWith(expect.objectContaining({ + playerName, + seed: 'rstest-runtime', + })); + expect(persisted?.playerName).toBe(playerName); + expect(persisted?.seed).toBe('rstest-runtime'); + }); +}); diff --git a/memory-match/imports/api/methods.server.meteor.rstest.test.ts b/memory-match/imports/api/methods.server.meteor.rstest.test.ts new file mode 100644 index 00000000..871530ec --- /dev/null +++ b/memory-match/imports/api/methods.server.meteor.rstest.test.ts @@ -0,0 +1,57 @@ +import { Meteor } from 'meteor/meteor'; +import { afterEach, beforeEach, describe, expect, test } from '@rstest/core'; + +import { Games } from './games'; +import { flipGameCard, startGame } from './methods'; + +const prefix = `methods-${process.env.METEOR_TEST_WORKER_ID ?? 'single'}-`; + +describe('memory methods in real Meteor runtime', () => { + beforeEach(async () => { + await Games.removeAsync({ playerName: { $regex: `^${prefix}` } }); + }); + + afterEach(async () => { + await Games.removeAsync({ playerName: { $regex: `^${prefix}` } }); + }); + + test('rejects invalid player names with Meteor error code', async () => { + let error: Meteor.Error | undefined; + try { + await startGame({ playerName: ' ' }); + } catch (caught) { + error = caught as Meteor.Error; + } + expect(error?.error).toBe('invalid-player-name'); + }); + + test('registered method inserts deterministic test game', async () => { + const gameId = await Meteor.callAsync('memory.start', { + playerName: `${prefix}Ada`, + seed: 'server-runtime', + }) as string; + const game = await Games.findOneAsync(gameId); + expect(game?.seed).toBe('server-runtime'); + expect(game?.state.cards.length).toBe(16); + expect(game?.state.cards.every((card) => !card.isMatched)).toBe(true); + }); + + test('server-authoritative flips persist a matching pair', async () => { + const gameId = await startGame({ + playerName: `${prefix}Grace`, + seed: 'matching-pair', + }); + const game = await Games.findOneAsync(gameId); + const first = game!.state.cards.findIndex((card, index, cards) => + cards.findIndex((candidate) => candidate.symbol === card.symbol) !== index); + const second = game!.state.cards.findIndex((card, index) => + index !== first && card.symbol === game!.state.cards[first].symbol); + + await flipGameCard({ gameId, cardIndex: first, now: 100 }); + await flipGameCard({ gameId, cardIndex: second, now: 200 }); + const matched = await Games.findOneAsync(gameId); + expect(matched?.state.cards[first].isMatched).toBe(true); + expect(matched?.state.cards[second].isMatched).toBe(true); + expect(matched?.state.moves).toBe(1); + }); +}); diff --git a/memory-match/imports/api/methods.ts b/memory-match/imports/api/methods.ts new file mode 100644 index 00000000..1204b9f9 --- /dev/null +++ b/memory-match/imports/api/methods.ts @@ -0,0 +1,124 @@ +import { Meteor } from 'meteor/meteor'; +import { Random } from 'meteor/random'; + +import { calculateScore } from '../game/score'; +import { createDeck } from '../game/shuffle'; +import { + createInitialState, + flipCard, + GameRuleError, + hideUnmatched, +} from '../game/rules'; +import { Games } from './games'; +import { validateCardIndex, validateGameId, validatePlayerName } from './validation'; + +function testClock(value: unknown): number { + if (value === undefined) return Date.now(); + if (!(Meteor.isTest || Meteor.isAppTest)) { + throw new Meteor.Error('test-option-forbidden', 'Explicit clock is test-only'); + } + if (typeof value !== 'number' || !Number.isFinite(value)) { + throw new Meteor.Error('invalid-clock', 'Clock must be a finite number'); + } + return value; +} + +function selectedSeed(value: unknown): string { + if (value !== undefined && typeof value !== 'string') { + throw new Meteor.Error('invalid-seed', 'Seed must be text'); + } + if (value !== undefined && !(Meteor.isTest || Meteor.isAppTest)) { + throw new Meteor.Error('test-option-forbidden', 'Explicit seed is test-only'); + } + return value as string | undefined || Random.id(); +} + +export async function startGame({ + playerName: rawPlayerName, + seed: rawSeed, +}: { + playerName: unknown; + seed?: unknown; +}): Promise { + const playerName = validatePlayerName(rawPlayerName); + const seed = selectedSeed(rawSeed); + const now = Date.now(); + return Games.insertAsync({ + playerName, + seed, + state: createInitialState(createDeck(seed), now), + createdAt: now, + updatedAt: now, + revision: 0, + }); +} + +async function resolveMismatch(gameId: string, revision: number): Promise { + const game = await Games.findOneAsync({ _id: gameId, revision }); + if (!game || game.state.status !== 'resolving') return; + await Games.updateAsync( + { _id: gameId, revision }, + { + $set: { state: hideUnmatched(game.state), updatedAt: Date.now() }, + $inc: { revision: 1 }, + }, + ); +} + +export async function flipGameCard({ + gameId: rawGameId, + cardIndex: rawCardIndex, + now: rawNow, +}: { + gameId: unknown; + cardIndex: unknown; + now?: unknown; +}): Promise { + const gameId = validateGameId(rawGameId); + const cardIndex = validateCardIndex(rawCardIndex); + const now = testClock(rawNow); + const game = await Games.findOneAsync(gameId); + if (!game) throw new Meteor.Error('game-not-found', 'Game does not exist'); + + let state; + try { + state = flipCard(game.state, cardIndex, now); + } catch (error) { + if (error instanceof GameRuleError) { + throw new Meteor.Error(`game-${error.code}`, error.message); + } + throw error; + } + + const revision = game.revision ?? 0; + const set: Record = { state, updatedAt: now }; + if (state.status === 'completed') { + set.score = calculateScore({ + moves: state.moves, + durationMs: now - state.startedAt, + }); + } + const updated = await Games.updateAsync( + { _id: gameId, revision }, + { $set: set, $inc: { revision: 1 } }, + ); + if (updated !== 1) { + throw new Meteor.Error('game-conflict', 'Game changed while card was being flipped'); + } + if (state.status === 'resolving') { + Meteor.setTimeout(() => { + resolveMismatch(gameId, revision + 1).catch((error) => { + console.error('[memory] mismatch resolution failed', error); + }); + }, 650); + } +} + +Meteor.methods({ + 'memory.start'(args) { + return startGame(args); + }, + 'memory.flip'(args) { + return flipGameCard(args); + }, +}); diff --git a/memory-match/imports/api/mongo-isolation.server.meteor.rstest.test.ts b/memory-match/imports/api/mongo-isolation.server.meteor.rstest.test.ts new file mode 100644 index 00000000..7f20f6a9 --- /dev/null +++ b/memory-match/imports/api/mongo-isolation.server.meteor.rstest.test.ts @@ -0,0 +1,14 @@ +import { Mongo } from 'meteor/mongo'; +import { expect, test } from '@rstest/core'; + +test('runtime worker owns isolated real Mongo database', async () => { + const workerId = process.env.METEOR_TEST_WORKER_ID ?? 'single'; + const collection = new Mongo.Collection<{ _id: string; workerId: string }>( + 'memory_showcase_worker_isolation', + ); + const id = 'same-id-in-every-worker'; + await collection.removeAsync(id); + await collection.insertAsync({ _id: id, workerId }); + expect((await collection.findOneAsync(id))?.workerId).toBe(workerId); + await collection.removeAsync(id); +}); diff --git a/memory-match/imports/api/package-engine.server.meteor.rstest.test.ts b/memory-match/imports/api/package-engine.server.meteor.rstest.test.ts new file mode 100644 index 00000000..f12f17fd --- /dev/null +++ b/memory-match/imports/api/package-engine.server.meteor.rstest.test.ts @@ -0,0 +1,11 @@ +import { expect, test } from '@rstest/core'; +import { createPairDeck } from 'meteor/memory-match-engine'; + +test('app runtime executes source from a local Meteor package', () => { + expect(createPairDeck(['moon', 'star'])).toEqual([ + { id: 'moon-1', symbol: 'moon' }, + { id: 'moon-2', symbol: 'moon' }, + { id: 'star-1', symbol: 'star' }, + { id: 'star-2', symbol: 'star' }, + ]); +}); diff --git a/memory-match/imports/api/publications.server.meteor.rstest.test.ts b/memory-match/imports/api/publications.server.meteor.rstest.test.ts new file mode 100644 index 00000000..e81ddb10 --- /dev/null +++ b/memory-match/imports/api/publications.server.meteor.rstest.test.ts @@ -0,0 +1,34 @@ +import { afterEach, expect, test } from '@rstest/core'; + +import { Games } from './games'; +import { leaderboardDocuments } from './publications'; + +const prefix = `leaderboard-${process.env.METEOR_TEST_WORKER_ID ?? 'single'}-`; + +afterEach(async () => { + await Games.removeAsync({ playerName: { $regex: `^${prefix}` } }); +}); + +test('leaderboard uses score, moves, and completion ordering with limit ten', async () => { + await Promise.all(Array.from({ length: 12 }, (_, index) => Games.insertAsync({ + playerName: `${prefix}${String(index).padStart(2, '0')}`, + seed: `seed-${index}`, + state: { + cards: [], + firstSelection: null, + secondSelection: null, + moves: index + 8, + status: 'completed', + startedAt: 1, + completedAt: 100 + index, + }, + score: 1_000 - index, + createdAt: 1, + updatedAt: 100 + index, + }))); + + const rows = await leaderboardDocuments({ playerPrefix: prefix }); + expect(rows.length).toBe(10); + expect(rows[0].score).toBe(1_000); + expect(rows[9].score).toBe(991); +}); diff --git a/memory-match/imports/api/publications.ts b/memory-match/imports/api/publications.ts new file mode 100644 index 00000000..cc92151e --- /dev/null +++ b/memory-match/imports/api/publications.ts @@ -0,0 +1,38 @@ +import { Meteor } from 'meteor/meteor'; + +import { Games, type GameDocument } from './games'; +import { validateGameId } from './validation'; + +export async function leaderboardDocuments({ + playerPrefix, +}: { + playerPrefix?: string; +} = {}): Promise { + return Games.find( + { + 'state.status': 'completed', + score: { $exists: true }, + ...(playerPrefix ? { playerName: { $regex: `^${playerPrefix}` } } : {}), + }, + { + sort: { score: -1, 'state.moves': 1, 'state.completedAt': 1, playerName: 1 }, + limit: 10, + fields: { seed: 0 }, + }, + ).fetchAsync(); +} + +Meteor.publish('memory.game', function publishGame(gameId: unknown) { + return Games.find({ _id: validateGameId(gameId) }, { fields: { seed: 0 } }); +}); + +Meteor.publish('memory.leaderboard', function publishLeaderboard() { + return Games.find( + { 'state.status': 'completed', score: { $exists: true } }, + { + sort: { score: -1, 'state.moves': 1, 'state.completedAt': 1, playerName: 1 }, + limit: 10, + fields: { seed: 0 }, + }, + ); +}); diff --git a/memory-match/imports/api/runtime-context.test.ts b/memory-match/imports/api/runtime-context.test.ts new file mode 100644 index 00000000..2b771300 --- /dev/null +++ b/memory-match/imports/api/runtime-context.test.ts @@ -0,0 +1,7 @@ +import { Meteor } from 'meteor/meteor'; +import { expect, test } from '@rstest/core'; + +test('imports infer a real Meteor runtime on each selected architecture', () => { + expect(Meteor.isTest).toBe(true); + expect(Meteor.isServer || Meteor.isClient).toBe(true); +}); diff --git a/memory-match/imports/api/startup.server.meteor.rstest.test.ts b/memory-match/imports/api/startup.server.meteor.rstest.test.ts new file mode 100644 index 00000000..07014a1c --- /dev/null +++ b/memory-match/imports/api/startup.server.meteor.rstest.test.ts @@ -0,0 +1,8 @@ +import { Meteor } from 'meteor/meteor'; +import { expect, test } from '@rstest/core'; + +import '../../server/main'; + +test('client runtime support host loads real application server modules', () => { + expect(Meteor.isServer).toBe(true); +}); diff --git a/memory-match/imports/api/subscription.client.meteor.rstest.test.ts b/memory-match/imports/api/subscription.client.meteor.rstest.test.ts new file mode 100644 index 00000000..79e0d154 --- /dev/null +++ b/memory-match/imports/api/subscription.client.meteor.rstest.test.ts @@ -0,0 +1,74 @@ +import { Meteor } from 'meteor/meteor'; +import { Tracker } from 'meteor/tracker'; +import { expect, test } from '@rstest/core'; + +import { Games } from './games'; +import { createDeck } from '../game/shuffle'; + +function subscribe(name: string, ...args: unknown[]): Promise { + return new Promise((resolve, reject) => { + const handle = Meteor.subscribe(name, ...args, { + onReady: () => resolve(handle), + onStop: (error?: Error) => error && reject(error), + }); + }); +} + +function waitFor(read: () => T | undefined): Promise { + return new Promise((resolve) => { + Tracker.autorun((computation) => { + const value = read(); + if (value !== undefined) { + computation.stop(); + resolve(value); + } + }); + }); +} + +test('real DDP subscription fills Minimongo and reacts to method update', async () => { + expect(Meteor.isClient).toBe(true); + const gameId = await Meteor.callAsync('memory.start', { + playerName: 'Client Ada', + seed: 'client-ddp', + }) as string; + const subscription = await subscribe('memory.game', gameId); + const inserted = await waitFor(() => Games.findOne(gameId)); + expect(inserted.seed).toBeUndefined(); + expect(inserted.state.cards.length).toBe(16); + + await Meteor.callAsync('memory.flip', { gameId, cardIndex: 0, now: Date.now() }); + const revealed = await waitFor(() => { + const game = Games.findOne(gameId); + return game?.state.cards[0].isRevealed ? game : undefined; + }); + expect(revealed.state.cards[0].isRevealed).toBe(true); + subscription.stop(); +}); + +test('completed score arrives through reactive leaderboard publication', async () => { + const seed = 'client-leaderboard'; + const gameId = await Meteor.callAsync('memory.start', { + playerName: 'Client Grace', + seed, + }) as string; + const deck = createDeck(seed); + const grouped = new Map(); + deck.forEach((card, index) => grouped.set(card.symbol, [ + ...(grouped.get(card.symbol) ?? []), + index, + ])); + let now = Date.now(); + for (const [first, second] of grouped.values()) { + await Meteor.callAsync('memory.flip', { gameId, cardIndex: first, now: ++now }); + await Meteor.callAsync('memory.flip', { gameId, cardIndex: second, now: ++now }); + } + + const subscription = await subscribe('memory.leaderboard'); + const completed = await waitFor(() => Games.findOne({ + _id: gameId, + 'state.status': 'completed', + })); + expect(completed.score).toBeDefined(); + subscription.stop(); +}); diff --git a/memory-match/imports/api/validation.ts b/memory-match/imports/api/validation.ts new file mode 100644 index 00000000..4dd35966 --- /dev/null +++ b/memory-match/imports/api/validation.ts @@ -0,0 +1,29 @@ +import { Meteor } from 'meteor/meteor'; + +export function validatePlayerName(value: unknown): string { + if (typeof value !== 'string') { + throw new Meteor.Error('invalid-player-name', 'Player name must be text'); + } + const playerName = value.trim().replace(/\s+/g, ' '); + if (playerName.length < 2 || playerName.length > 24) { + throw new Meteor.Error( + 'invalid-player-name', + 'Player name must contain between 2 and 24 characters', + ); + } + return playerName; +} + +export function validateGameId(value: unknown): string { + if (typeof value !== 'string' || !value.trim()) { + throw new Meteor.Error('invalid-game-id', 'Game id is required'); + } + return value; +} + +export function validateCardIndex(value: unknown): number { + if (!Number.isSafeInteger(value) || (value as number) < 0 || (value as number) >= 16) { + throw new Meteor.Error('invalid-card-index', 'Card index must be between 0 and 15'); + } + return value as number; +} diff --git a/memory-match/imports/game/__snapshots__/completed-game.txt b/memory-match/imports/game/__snapshots__/completed-game.txt new file mode 100644 index 00000000..010f40f9 --- /dev/null +++ b/memory-match/imports/game/__snapshots__/completed-game.txt @@ -0,0 +1,4 @@ +Player: Ada +Moves: 8 +Score: 7800 +Status: completed diff --git a/memory-match/imports/game/__snapshots__/snapshots.test.ts.snap b/memory-match/imports/game/__snapshots__/snapshots.test.ts.snap new file mode 100644 index 00000000..05074aa8 --- /dev/null +++ b/memory-match/imports/game/__snapshots__/snapshots.test.ts.snap @@ -0,0 +1,22 @@ +// Rstest Snapshot v1 + +exports[`captures deterministic board order externally 1`] = ` +[ + "☄️", + "🌌", + "👾", + "🪐", + "⭐", + "🛰️", + "🛰️", + "🌙", + "☄️", + "🌌", + "🚀", + "🪐", + "🚀", + "🌙", + "👾", + "⭐", +] +`; diff --git a/memory-match/imports/game/concurrency.test.ts b/memory-match/imports/game/concurrency.test.ts new file mode 100644 index 00000000..495b14eb --- /dev/null +++ b/memory-match/imports/game/concurrency.test.ts @@ -0,0 +1,26 @@ +import { describe, expect, test } from '@rstest/core'; + +let active = 0; +let started = 0; +let release: () => void; +const firstPairStarted = new Promise((resolve) => { + release = resolve; +}); + +describe.concurrent('native Rstest concurrency', () => { + for (const name of ['shuffle', 'rules', 'score']) { + test(name, async () => { + active += 1; + started += 1; + expect(active <= 2).toBe(true); + if (started === 2) release(); + await firstPairStarted; + active -= 1; + }); + } + + test.sequential('waits before checking shared state', () => { + expect(active).toBe(0); + expect(started).toBe(3); + }); +}); diff --git a/memory-match/imports/game/globals.rstest.test.ts b/memory-match/imports/game/globals.rstest.test.ts new file mode 100644 index 00000000..30c4ed53 --- /dev/null +++ b/memory-match/imports/game/globals.rstest.test.ts @@ -0,0 +1,7 @@ +/// + +import { createDeck } from './shuffle'; + +test('filename marker owns a test using global Rstest APIs', () => { + expect(createDeck('global-api')).toHaveLength(16); +}); diff --git a/memory-match/imports/game/rng.ts b/memory-match/imports/game/rng.ts new file mode 100644 index 00000000..fe162086 --- /dev/null +++ b/memory-match/imports/game/rng.ts @@ -0,0 +1,19 @@ +export function hashSeed(seed: string): number { + let hash = 2_166_136_261; + for (const character of seed) { + hash ^= character.codePointAt(0) ?? 0; + hash = Math.imul(hash, 16_777_619); + } + return hash >>> 0; +} + +export function createSeededRandom(seed: string): () => number { + let state = hashSeed(seed) || 0x9e3779b9; + return () => { + state += 0x6d2b79f5; + let value = state; + value = Math.imul(value ^ (value >>> 15), value | 1); + value ^= value + Math.imul(value ^ (value >>> 7), value | 61); + return ((value ^ (value >>> 14)) >>> 0) / 4_294_967_296; + }; +} diff --git a/memory-match/imports/game/rstest-env.d.ts b/memory-match/imports/game/rstest-env.d.ts new file mode 100644 index 00000000..b0d491c5 --- /dev/null +++ b/memory-match/imports/game/rstest-env.d.ts @@ -0,0 +1,12 @@ +import type { expect, test } from '@rstest/core'; + +declare global { + interface ImportMeta { + readonly rstest?: { + readonly expect: typeof expect; + readonly test: typeof test; + }; + } +} + +export {}; diff --git a/memory-match/imports/game/rules.test.ts b/memory-match/imports/game/rules.test.ts new file mode 100644 index 00000000..6278f965 --- /dev/null +++ b/memory-match/imports/game/rules.test.ts @@ -0,0 +1,81 @@ +import { beforeEach, describe, expect, rs, test } from '@rstest/core'; + +import { + createInitialState, + hideUnmatched, + flipCard, +} from './rules'; +import type { CardDefinition } from './types'; + +const deck: CardDefinition[] = [ + { id: 'moon-a', symbol: '🌙' }, + { id: 'star-a', symbol: '⭐' }, + { id: 'moon-b', symbol: '🌙' }, + { id: 'star-b', symbol: '⭐' }, +]; + +describe('Memory Match rules', () => { + beforeEach(() => { + rs.useFakeTimers(); + rs.setSystemTime(new Date('2026-08-08T10:00:00.000Z')); + }); + + test('starts with every card hidden', () => { + const state = createInitialState(deck); + expect(state.cards.every((card) => !card.isRevealed && !card.isMatched)).toBe(true); + expect(state.startedAt).toBe(Date.now()); + expect(state.moves).toBe(0); + }); + + test('resolves a matching pair immutably', () => { + const initial = createInitialState(deck); + const first = flipCard(initial, 0, Date.now()); + const matched = flipCard(first, 2, Date.now() + 100); + + expect(initial.cards[0].isRevealed).toBe(false); + expect(matched.cards[0].isMatched).toBe(true); + expect(matched.cards[2].isMatched).toBe(true); + expect(matched.moves).toBe(1); + expect(matched.firstSelection).toBeNull(); + }); + + test('holds a mismatch until hideUnmatched runs', () => { + const first = flipCard(createInitialState(deck), 0, 1_000); + const mismatch = flipCard(first, 1, 1_100); + expect(mismatch.status).toBe('resolving'); + expect(mismatch.cards[0].isRevealed).toBe(true); + expect(mismatch.cards[1].isRevealed).toBe(true); + + const hidden = hideUnmatched(mismatch); + expect(hidden.status).toBe('playing'); + expect(hidden.cards[0].isRevealed).toBe(false); + expect(hidden.cards[1].isRevealed).toBe(false); + }); + + test.each([ + ['negative index', -1, 'invalid-index'], + ['past-end index', 4, 'invalid-index'], + ] as const)('rejects %s', (_label, index, code) => { + expect(() => flipCard(createInitialState(deck), index, 0)).toThrowError( + expect.objectContaining({ code }), + ); + }); + + test('rejects same-card double flip and flips while resolving', () => { + const first = flipCard(createInitialState(deck), 0, 0); + expect(() => flipCard(first, 0, 1)).toThrowError(/already revealed/); + const mismatch = flipCard(first, 1, 2); + expect(() => flipCard(mismatch, 2, 3)).toThrowError(/resolve mismatch/); + }); + + test('marks game complete after final pair', () => { + let state = createInitialState(deck); + state = flipCard(state, 0, 100); + state = flipCard(state, 2, 200); + state = flipCard(state, 1, 300); + state = flipCard(state, 3, 400); + expect(state.status).toBe('completed'); + expect(state.completedAt).toBe(400); + expect(state.cards.every((card) => card.isMatched)).toBe(true); + }); +}); diff --git a/memory-match/imports/game/rules.ts b/memory-match/imports/game/rules.ts new file mode 100644 index 00000000..961578f1 --- /dev/null +++ b/memory-match/imports/game/rules.ts @@ -0,0 +1,111 @@ +import type { CardDefinition, CardState, GameState } from './types'; + +export type GameRuleErrorCode = + | 'already-completed' + | 'already-matched' + | 'already-revealed' + | 'invalid-index' + | 'mismatch-pending' + | 'no-mismatch'; + +export class GameRuleError extends Error { + constructor( + readonly code: GameRuleErrorCode, + message: string, + ) { + super(message); + this.name = 'GameRuleError'; + } +} + +export function createInitialState( + deck: readonly CardDefinition[], + startedAt = Date.now(), +): GameState { + return { + cards: deck.map((card): CardState => ({ + ...card, + isRevealed: false, + isMatched: false, + })), + firstSelection: null, + secondSelection: null, + moves: 0, + status: 'playing', + startedAt, + completedAt: null, + }; +} + +function reveal(cards: readonly CardState[], index: number): readonly CardState[] { + return cards.map((card, cardIndex) => cardIndex === index + ? { ...card, isRevealed: true } + : card); +} + +export function flipCard(state: GameState, index: number, now = Date.now()): GameState { + if (!Number.isSafeInteger(index) || index < 0 || index >= state.cards.length) { + throw new GameRuleError('invalid-index', `Card index ${index} is outside this board`); + } + if (state.status === 'completed') { + throw new GameRuleError('already-completed', 'Game is already complete'); + } + if (state.status === 'resolving') { + throw new GameRuleError('mismatch-pending', 'Must resolve mismatch before another flip'); + } + const selected = state.cards[index]; + if (selected.isMatched) { + throw new GameRuleError('already-matched', 'Card is already matched'); + } + if (selected.isRevealed) { + throw new GameRuleError('already-revealed', 'Card is already revealed'); + } + + const revealed = reveal(state.cards, index); + if (state.firstSelection === null) { + return { ...state, cards: revealed, firstSelection: index }; + } + + const firstIndex = state.firstSelection; + const matched = state.cards[firstIndex].symbol === selected.symbol; + if (!matched) { + return { + ...state, + cards: revealed, + secondSelection: index, + moves: state.moves + 1, + status: 'resolving', + }; + } + + const cards = revealed.map((card, cardIndex) => + cardIndex === firstIndex || cardIndex === index + ? { ...card, isMatched: true, isRevealed: true } + : card); + const completed = cards.every((card) => card.isMatched); + return { + ...state, + cards, + firstSelection: null, + secondSelection: null, + moves: state.moves + 1, + status: completed ? 'completed' : 'playing', + completedAt: completed ? now : null, + }; +} + +export function hideUnmatched(state: GameState): GameState { + if (state.status !== 'resolving' || state.firstSelection === null || state.secondSelection === null) { + throw new GameRuleError('no-mismatch', 'No mismatch is waiting to be hidden'); + } + const selections = new Set([state.firstSelection, state.secondSelection]); + return { + ...state, + cards: state.cards.map((card, index) => selections.has(index) + ? { ...card, isRevealed: false } + : card), + firstSelection: null, + secondSelection: null, + status: 'playing', + }; +} diff --git a/memory-match/imports/game/score-mocking.test.ts b/memory-match/imports/game/score-mocking.test.ts new file mode 100644 index 00000000..2cd960f8 --- /dev/null +++ b/memory-match/imports/game/score-mocking.test.ts @@ -0,0 +1,14 @@ +import { expect, rs, test } from '@rstest/core'; + +import { calculateScore } from './score'; + +rs.mock('./score', () => ({ + calculateScore: rs.fn(() => 1_337), +})); + +test('hoists an app-module mock before its static import', () => { + const input = { moves: 8, durationMs: 9_000 }; + + expect(calculateScore(input)).toBe(1_337); + expect(calculateScore).toHaveBeenCalledWith(input); +}); diff --git a/memory-match/imports/game/score.test.ts b/memory-match/imports/game/score.test.ts new file mode 100644 index 00000000..fcab4601 --- /dev/null +++ b/memory-match/imports/game/score.test.ts @@ -0,0 +1,40 @@ +import { describe, expect, rs, test } from '@rstest/core'; + +import { calculateScore, compareLeaderboard } from './score'; + +describe('scoring', () => { + test.each([ + [{ moves: 8, durationMs: 20_000 }, 7_800], + [{ moves: 20, durationMs: 300_000 }, 2_000], + [{ moves: 100, durationMs: 9_000_000 }, 100], + ])('calculates score for %o', (input, expected) => { + expect(calculateScore(input)).toBe(expected); + }); + + test('sorts by score, moves, completion time, then player', () => { + const rows = [ + { playerName: 'Zoe', score: 500, moves: 9, completedAt: 30 }, + { playerName: 'Ada', score: 700, moves: 10, completedAt: 20 }, + { playerName: 'Bea', score: 700, moves: 9, completedAt: 30 }, + { playerName: 'Cal', score: 700, moves: 9, completedAt: 10 }, + ]; + const spy = rs.spyOn(String.prototype, 'localeCompare'); + expect(rows.toSorted(compareLeaderboard).map(({ playerName }) => playerName)).toEqual([ + 'Cal', + 'Bea', + 'Ada', + 'Zoe', + ]); + expect(spy).not.toHaveBeenCalled(); + }); + + test('uses player name as final stable tie-breaker', () => { + const compare = rs.fn(compareLeaderboard); + const tied = [ + { playerName: 'Zoe', score: 700, moves: 9, completedAt: 10 }, + { playerName: 'Ada', score: 700, moves: 9, completedAt: 10 }, + ]; + expect(tied.toSorted(compare).map(({ playerName }) => playerName)).toEqual(['Ada', 'Zoe']); + expect(compare).toHaveBeenCalled(); + }); +}); diff --git a/memory-match/imports/game/score.ts b/memory-match/imports/game/score.ts new file mode 100644 index 00000000..8ccb521d --- /dev/null +++ b/memory-match/imports/game/score.ts @@ -0,0 +1,23 @@ +import type { LeaderboardEntry } from './types'; + +export function calculateScore({ + moves, + durationMs, +}: { + moves: number; + durationMs: number; +}): number { + const movePenalty = Math.max(0, moves) * 250; + const durationPenalty = Math.floor(Math.max(0, durationMs) / 1_000) * 10; + return Math.max(100, 10_000 - movePenalty - durationPenalty); +} + +export function compareLeaderboard( + left: LeaderboardEntry, + right: LeaderboardEntry, +): number { + return right.score - left.score + || left.moves - right.moves + || left.completedAt - right.completedAt + || left.playerName.localeCompare(right.playerName); +} diff --git a/memory-match/imports/game/shuffle.test.ts b/memory-match/imports/game/shuffle.test.ts new file mode 100644 index 00000000..85ca5894 --- /dev/null +++ b/memory-match/imports/game/shuffle.test.ts @@ -0,0 +1,23 @@ +import { describe, expect, test } from '@rstest/core'; + +import { createDeck } from './shuffle'; + +describe('createDeck', () => { + test('creates eight exact pairs deterministically', () => { + const first = createDeck('apollo'); + const second = createDeck('apollo'); + const counts = new Map(); + for (const card of first) counts.set(card.symbol, (counts.get(card.symbol) ?? 0) + 1); + + expect(first).toEqual(second); + expect(first).toHaveLength(16); + expect([...counts.values()].sort()).toEqual(Array(8).fill(2)); + expect(new Set(first.map((card) => card.id)).size).toBe(16); + }); + + test('different seeds produce different order', () => { + expect(createDeck('apollo').map(({ symbol }) => symbol)).not.toEqual( + createDeck('gemini').map(({ symbol }) => symbol), + ); + }); +}); diff --git a/memory-match/imports/game/shuffle.ts b/memory-match/imports/game/shuffle.ts new file mode 100644 index 00000000..2c278cb4 --- /dev/null +++ b/memory-match/imports/game/shuffle.ts @@ -0,0 +1,31 @@ +import { createSeededRandom } from './rng'; +import { CARD_SYMBOLS, type CardDefinition } from './types'; + +if (import.meta.rstest) { + const { expect, test } = import.meta.rstest; + test('normalizes human-entered seeds before shuffling', () => { + expect(normalizeSeed(' Memory LAB ')).toBe('memory lab'); + }); +} + +export function normalizeSeed(seed: string): string { + return seed + .normalize('NFKC') + .trim() + .toLocaleLowerCase('en-US') + .replace(/\s+/g, ' ') || 'memory-match'; +} + +export function createDeck(seed: string): readonly CardDefinition[] { + const random = createSeededRandom(normalizeSeed(seed)); + const cards = CARD_SYMBOLS.flatMap((symbol, symbolIndex) => [ + { id: `${symbolIndex}-a`, symbol }, + { id: `${symbolIndex}-b`, symbol }, + ]); + + for (let index = cards.length - 1; index > 0; index -= 1) { + const target = Math.floor(random() * (index + 1)); + [cards[index], cards[target]] = [cards[target], cards[index]]; + } + return cards; +} diff --git a/memory-match/imports/game/snapshots.test.ts b/memory-match/imports/game/snapshots.test.ts new file mode 100644 index 00000000..df8b721f --- /dev/null +++ b/memory-match/imports/game/snapshots.test.ts @@ -0,0 +1,23 @@ +import { expect, test } from '@rstest/core'; + +import { createDeck } from './shuffle'; + +test('captures stable deck metadata inline', () => { + const deck = createDeck('snapshot'); + expect({ cards: deck.length, pairs: new Set(deck.map(({ symbol }) => symbol)).size }) + .toMatchInlineSnapshot(` + { + "cards": 16, + "pairs": 8, + } + `); +}); + +test('captures deterministic board order externally', () => { + expect(createDeck('snapshot').map(({ symbol }) => symbol)).toMatchSnapshot(); +}); + +test('captures completed game summary as standalone file', async () => { + await expect('Player: Ada\nMoves: 8\nScore: 7800\nStatus: completed\n') + .toMatchFileSnapshot('./__snapshots__/completed-game.txt'); +}); diff --git a/memory-match/imports/game/types.ts b/memory-match/imports/game/types.ts new file mode 100644 index 00000000..7d68c5dc --- /dev/null +++ b/memory-match/imports/game/types.ts @@ -0,0 +1,32 @@ +export const CARD_SYMBOLS = ['☄️', '🪐', '🚀', '🌙', '⭐', '🛰️', '👾', '🌌'] as const; + +export type CardSymbol = (typeof CARD_SYMBOLS)[number]; + +export interface CardDefinition { + readonly id: string; + readonly symbol: CardSymbol; +} + +export interface CardState extends CardDefinition { + readonly isRevealed: boolean; + readonly isMatched: boolean; +} + +export type GameStatus = 'playing' | 'resolving' | 'completed'; + +export interface GameState { + readonly cards: readonly CardState[]; + readonly firstSelection: number | null; + readonly secondSelection: number | null; + readonly moves: number; + readonly status: GameStatus; + readonly startedAt: number; + readonly completedAt: number | null; +} + +export interface LeaderboardEntry { + readonly playerName: string; + readonly score: number; + readonly moves: number; + readonly completedAt: number; +} diff --git a/memory-match/imports/ui/App.client.meteor.rstest.test.tsx b/memory-match/imports/ui/App.client.meteor.rstest.test.tsx new file mode 100644 index 00000000..854c1aa4 --- /dev/null +++ b/memory-match/imports/ui/App.client.meteor.rstest.test.tsx @@ -0,0 +1,18 @@ +import { expect, test } from '@rstest/core'; +import React from 'react'; +import { flushSync } from 'react-dom'; +import { createRoot } from 'react-dom/client'; + +import { App } from './App'; + +test('App mounts inside real Meteor browser runtime', async () => { + expect(typeof window.localStorage).toBe('object'); + const container = document.createElement('div'); + document.body.append(container); + const root = createRoot(container); + flushSync(() => root.render()); + expect(container.textContent).toContain('Memory Match'); + expect(container.querySelector('input')?.getAttribute('aria-label')).toBeNull(); + root.unmount(); + container.remove(); +}); diff --git a/memory-match/imports/ui/App.tsx b/memory-match/imports/ui/App.tsx new file mode 100644 index 00000000..10db7acc --- /dev/null +++ b/memory-match/imports/ui/App.tsx @@ -0,0 +1,88 @@ +import { Meteor } from 'meteor/meteor'; +import { useSubscribe, useTracker } from 'meteor/react-meteor-data'; +import React, { useState } from 'react'; + +import { Games } from '../api/games'; +import type { LeaderboardEntry } from '../game/types'; +import { Leaderboard } from './Leaderboard'; +import { MemoryGame } from './MemoryGame'; +import { NameForm } from './NameForm'; +import { useMemoryGame } from './useMemoryGame'; + +function ActiveGame({ + gameId, + leaderboard, + onNewGame, +}: { + gameId: string; + leaderboard: readonly LeaderboardEntry[]; + onNewGame(): void; +}) { + const { error, flip, game, isFlipping, isLoading } = useMemoryGame(gameId); + if (isLoading) return

Loading game…

; + if (!game) return

Game could not be loaded.

; + return ( + <> + {error &&

{error}

} + + + + ); +} + +export function App() { + const [gameId, setGameId] = useState(null); + const [startError, setStartError] = useState(''); + const leaderboardLoading = useSubscribe('memory.leaderboard')(); + const leaderboard = useTracker(() => Games.find( + { 'state.status': 'completed', score: { $exists: true } }, + { sort: { score: -1, 'state.moves': 1, 'state.completedAt': 1 }, limit: 10 }, + ).fetch().map((game) => ({ + playerName: game.playerName, + score: game.score ?? 0, + moves: game.state.moves, + completedAt: game.state.completedAt ?? 0, + })), []); + + async function start(playerName: string) { + setStartError(''); + try { + const querySeed = new URLSearchParams(window.location.search).get('seed'); + const seed = querySeed && (Meteor.isTest || Meteor.isAppTest) ? querySeed : undefined; + const id = await Meteor.callAsync('memory.start', { + playerName, + ...(seed ? { seed } : {}), + }) as string; + setGameId(id); + } catch (caught) { + setStartError(caught instanceof Error ? caught.message : String(caught)); + } + } + + return ( +
+
+

Memory Match

+

Find eight cosmic pairs. Every completed game joins the shared leaderboard.

+
+ {startError &&

{startError}

} + {gameId + ? setGameId(null)} /> + : ( + <> + + {leaderboardLoading + ?

Loading leaderboard…

+ : } + + )} +
+ ); +} diff --git a/memory-match/imports/ui/CardGrid.dom.rstest.test.tsx b/memory-match/imports/ui/CardGrid.dom.rstest.test.tsx new file mode 100644 index 00000000..98d9c428 --- /dev/null +++ b/memory-match/imports/ui/CardGrid.dom.rstest.test.tsx @@ -0,0 +1,32 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { expect, rs, test } from '@rstest/core'; +import React from 'react'; + +import { createInitialState } from '../game/rules'; +import { createDeck } from '../game/shuffle'; +import { CardGrid } from './CardGrid'; + +test('renders sixteen accessible cards and reports clicked index', async () => { + const state = createInitialState(createDeck('component')); + const onFlip = rs.fn(); + const user = userEvent.setup(); + render(); + + const cards = screen.getAllByRole('button', { name: /Hidden card/ }); + expect(cards).toHaveLength(16); + await user.click(cards[3]); + expect(onFlip).toHaveBeenCalledWith(3); +}); + +test('matched cards expose symbol and remain disabled', () => { + const state = createInitialState(createDeck('matched')); + const matched = state.cards.map((card, index) => index === 0 + ? { ...card, isMatched: true, isRevealed: true } + : card); + render( undefined} disabled={false} />); + const card = screen.getByRole('button', { + name: `Matched ${matched[0].symbol}`, + }) as HTMLButtonElement; + expect(card.disabled).toBe(true); +}); diff --git a/memory-match/imports/ui/CardGrid.tsx b/memory-match/imports/ui/CardGrid.tsx new file mode 100644 index 00000000..39b06dbe --- /dev/null +++ b/memory-match/imports/ui/CardGrid.tsx @@ -0,0 +1,27 @@ +import type { CardState } from '../game/types'; +import React from 'react'; +import { MemoryCard } from './MemoryCard'; + +export function CardGrid({ + cards, + disabled, + onFlip, +}: { + cards: readonly CardState[]; + disabled: boolean; + onFlip(index: number): void | Promise; +}) { + return ( +
+ {cards.map((card, index) => ( + + ))} +
+ ); +} diff --git a/memory-match/imports/ui/GameStatus.tsx b/memory-match/imports/ui/GameStatus.tsx new file mode 100644 index 00000000..8d7877e6 --- /dev/null +++ b/memory-match/imports/ui/GameStatus.tsx @@ -0,0 +1,22 @@ +import type { GameStatus as Status } from '../game/types'; +import React from 'react'; + +export function GameStatus({ + moves, + score, + status, +}: { + moves: number; + score?: number; + status: Status; +}) { + return ( +

+ {status === 'completed' + ? `Game completed in ${moves} moves — score ${score ?? 0}` + : status === 'resolving' + ? `Moves: ${moves} — checking pair…` + : `Moves: ${moves}`} +

+ ); +} diff --git a/memory-match/imports/ui/Leaderboard.tsx b/memory-match/imports/ui/Leaderboard.tsx new file mode 100644 index 00000000..6b556c10 --- /dev/null +++ b/memory-match/imports/ui/Leaderboard.tsx @@ -0,0 +1,19 @@ +import type { LeaderboardEntry } from '../game/types'; +import React from 'react'; + +export function Leaderboard({ entries }: { entries: readonly LeaderboardEntry[] }) { + return ( +
+

Shared leaderboard

+ {entries.length ? ( +
    + {entries.map((entry, index) => ( +
  1. + {index + 1}. {entry.playerName} — {entry.score} +
  2. + ))} +
+ ) :

No completed games yet.

} +
+ ); +} diff --git a/memory-match/imports/ui/MemoryCard.tsx b/memory-match/imports/ui/MemoryCard.tsx new file mode 100644 index 00000000..cb80ca67 --- /dev/null +++ b/memory-match/imports/ui/MemoryCard.tsx @@ -0,0 +1,32 @@ +import type { CardState } from '../game/types'; +import React from 'react'; + +export function MemoryCard({ + card, + index, + disabled, + onFlip, +}: { + card: CardState; + index: number; + disabled: boolean; + onFlip(index: number): void | Promise; +}) { + const state = card.isMatched ? 'Matched' : card.isRevealed ? 'Revealed' : 'Hidden card'; + const label = card.isMatched || card.isRevealed ? `${state} ${card.symbol}` : `${state} ${index + 1}`; + return ( + + ); +} diff --git a/memory-match/imports/ui/MemoryGame.dom.rstest.test.tsx b/memory-match/imports/ui/MemoryGame.dom.rstest.test.tsx new file mode 100644 index 00000000..6c0b1407 --- /dev/null +++ b/memory-match/imports/ui/MemoryGame.dom.rstest.test.tsx @@ -0,0 +1,48 @@ +import { render, screen } from '@testing-library/react'; +import { expect, test } from '@rstest/core'; +import React from 'react'; + +import { createInitialState } from '../game/rules'; +import { createDeck } from '../game/shuffle'; +import { MemoryGame } from './MemoryGame'; + +test('shows move status and ordered leaderboard', () => { + const state = { ...createInitialState(createDeck('screen')), moves: 3 }; + render( + undefined} + />, + ); + expect(screen.getByText('Moves: 3')).toBeDefined(); + expect(screen.getAllByRole('listitem').map((row) => row.textContent)).toEqual([ + '1. Ada — 8000', + '2. Grace — 7500', + ]); +}); + +test('announces completed result', () => { + const initial = createInitialState(createDeck('complete')); + const state = { + ...initial, + cards: initial.cards.map((card) => ({ ...card, isMatched: true, isRevealed: true })), + moves: 8, + status: 'completed' as const, + completedAt: initial.startedAt + 20_000, + }; + render( + undefined} + />, + ); + expect(screen.getByRole('status').textContent).toMatch(/completed.*7800/i); +}); diff --git a/memory-match/imports/ui/MemoryGame.interactions.test.tsx b/memory-match/imports/ui/MemoryGame.interactions.test.tsx new file mode 100644 index 00000000..a37750ae --- /dev/null +++ b/memory-match/imports/ui/MemoryGame.interactions.test.tsx @@ -0,0 +1,50 @@ +import { page } from '@rstest/browser'; +import { render } from '@rstest/browser-react'; +import userEvent from '@testing-library/user-event'; +import { expect, test } from '@rstest/core'; +import React, { useState } from 'react'; + +import '../../client/main.css'; +import { createInitialState, flipCard } from '../game/rules'; +import { createDeck } from '../game/shuffle'; +import type { GameState } from '../game/types'; +import { MemoryGame } from './MemoryGame'; + +function BrowserHarness() { + const [state, setState] = useState(() => + createInitialState(createDeck('browser-mode'))); + return ( + setState((current) => flipCard(current, index))} + playerName="Browser" + state={state} + /> + ); +} + +test('runs memory-game behavior, focus, and CSS in real Chromium', async () => { + const { container } = await render(); + const user = userEvent.setup(); + expect(navigator.userAgent).toMatch(/Chrome|Chromium/); + + await expect.element(page.getByRole('heading', { name: "Browser's board" })).toBeVisible(); + await expect.element(page.getByRole('button', { name: /Hidden card/ })).toHaveCount(16); + + const deck = createDeck('browser-mode'); + const first = 0; + const second = deck.findIndex((card, index) => + index !== first && card.symbol === deck[first].symbol); + const firstCard = page.locator('.memory-card').nth(first); + const cardElements = container.querySelectorAll('.memory-card'); + cardElements[first].focus(); + await expect.element(firstCard).toBeFocused(); + await user.click(cardElements[first]); + await user.click(cardElements[second]); + + await expect.element(page.getByRole('button', { name: `Matched ${deck[first].symbol}` })) + .toHaveCount(2); + await expect.element(firstCard).toBeDisabled(); + await expect.element(page.getByRole('grid', { name: 'Memory cards' })) + .toHaveCSS('background-color', 'rgb(8, 15, 36)'); +}); diff --git a/memory-match/imports/ui/MemoryGame.tsx b/memory-match/imports/ui/MemoryGame.tsx new file mode 100644 index 00000000..eabde2f9 --- /dev/null +++ b/memory-match/imports/ui/MemoryGame.tsx @@ -0,0 +1,27 @@ +import { CardGrid } from './CardGrid'; +import React from 'react'; +import { GameStatus } from './GameStatus'; +import { Leaderboard } from './Leaderboard'; +import type { MemoryGameProps } from './types'; + +export function MemoryGame({ + playerName, + state, + score, + leaderboard, + onFlip, + disabled = false, +}: MemoryGameProps) { + return ( +
+

{playerName}'s board

+ + + +
+ ); +} diff --git a/memory-match/imports/ui/NameForm.dom.rstest.test.tsx b/memory-match/imports/ui/NameForm.dom.rstest.test.tsx new file mode 100644 index 00000000..0cae6cfd --- /dev/null +++ b/memory-match/imports/ui/NameForm.dom.rstest.test.tsx @@ -0,0 +1,26 @@ +import { render, screen } from '@testing-library/react'; +import userEvent from '@testing-library/user-event'; +import { expect, rs, test } from '@rstest/core'; +import React from 'react'; + +import { NameForm } from './NameForm'; + +test('submits trimmed accessible player name', async () => { + const onStart = rs.fn(); + const user = userEvent.setup(); + render(); + + await user.type(screen.getByLabelText('Player name'), ' Ada '); + await user.click(screen.getByRole('button', { name: 'Start game' })); + + expect(onStart).toHaveBeenCalledWith('Ada'); +}); + +test('shows useful validation instead of submitting empty name', async () => { + const onStart = rs.fn(); + const user = userEvent.setup(); + render(); + await user.click(screen.getByRole('button', { name: 'Start game' })); + expect(screen.getByRole('alert').textContent).toMatch(/at least 2/); + expect(onStart).not.toHaveBeenCalled(); +}); diff --git a/memory-match/imports/ui/NameForm.tsx b/memory-match/imports/ui/NameForm.tsx new file mode 100644 index 00000000..caab0c23 --- /dev/null +++ b/memory-match/imports/ui/NameForm.tsx @@ -0,0 +1,39 @@ +import React, { useId, useState, type FormEvent } from 'react'; + +export function NameForm({ + onStart, +}: { + onStart(playerName: string): void | Promise; +}) { + const inputId = useId(); + const [name, setName] = useState(''); + const [error, setError] = useState(''); + + function submit(event: FormEvent) { + event.preventDefault(); + const playerName = name.trim().replace(/\s+/g, ' '); + if (playerName.length < 2) { + setError('Player name needs at least 2 characters.'); + return; + } + setError(''); + void onStart(playerName); + } + + return ( +
+ +
+ setName(event.currentTarget.value)} + placeholder="Ada" + value={name} + /> + +
+ {error &&

{error}

} +
+ ); +} diff --git a/memory-match/imports/ui/types.ts b/memory-match/imports/ui/types.ts new file mode 100644 index 00000000..8c8c153d --- /dev/null +++ b/memory-match/imports/ui/types.ts @@ -0,0 +1,10 @@ +import type { GameState, LeaderboardEntry } from '../game/types'; + +export interface MemoryGameProps { + playerName: string; + state: GameState; + score?: number; + leaderboard: readonly LeaderboardEntry[]; + onFlip(index: number): void | Promise; + disabled?: boolean; +} diff --git a/memory-match/imports/ui/useMemoryGame.ts b/memory-match/imports/ui/useMemoryGame.ts new file mode 100644 index 00000000..8a770e44 --- /dev/null +++ b/memory-match/imports/ui/useMemoryGame.ts @@ -0,0 +1,27 @@ +import { Meteor } from 'meteor/meteor'; +import { useSubscribe, useTracker } from 'meteor/react-meteor-data'; +import { useCallback, useState } from 'react'; + +import { Games } from '../api/games'; + +export function useMemoryGame(gameId: string) { + const isLoading = useSubscribe('memory.game', gameId)(); + const game = useTracker(() => Games.findOne(gameId), [gameId]); + const [isFlipping, setIsFlipping] = useState(false); + const [error, setError] = useState(''); + + const flip = useCallback(async (cardIndex: number) => { + if (isFlipping) return; + setIsFlipping(true); + setError(''); + try { + await Meteor.callAsync('memory.flip', { gameId, cardIndex }); + } catch (caught) { + setError(caught instanceof Error ? caught.message : String(caught)); + } finally { + setIsFlipping(false); + } + }, [gameId, isFlipping]); + + return { error, flip, game, isFlipping, isLoading }; +} diff --git a/memory-match/package-lock.json b/memory-match/package-lock.json new file mode 100644 index 00000000..b03e5d0b --- /dev/null +++ b/memory-match/package-lock.json @@ -0,0 +1,9178 @@ +{ + "name": "memory-match", + "version": "0.0.0", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "name": "memory-match", + "version": "0.0.0", + "dependencies": { + "@babel/runtime": "^7.28.4", + "@swc/helpers": "^0.5.17", + "meteor-node-stubs": "^1.2.18", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@meteorjs/rspack": "file:.meteor/local/npm/meteor-rspack", + "@meteorjs/rstest": "file:.meteor/local/npm/meteor-rstest", + "@rsdoctor/rspack-plugin": "^1.5.9", + "@rspack/cli": "2.1.8", + "@rspack/core": "2.1.8", + "@rspack/dev-server": "^2.1.0", + "@rspack/plugin-react-refresh": "^2.0.0", + "@rstest/adapter-rspack": "0.11.6", + "@rstest/browser": "0.11.6", + "@rstest/browser-react": "0.11.6", + "@rstest/core": "0.11.6", + "@rstest/coverage-istanbul": "0.11.6", + "@rstest/playwright": "0.11.6", + "@swc/core": "^1.15.32", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.0", + "@testing-library/user-event": "^14.6.1", + "@types/meteor": "^2.9.8", + "@types/node": "^24.0.0", + "@types/react": "^19.2.0", + "@types/react-dom": "^19.2.0", + "jsdom": "29.1.1", + "playwright": "1.59.0", + "react-refresh": "^0.17.0", + "typescript": "^5.9.0" + }, + "engines": { + "node": ">=22.12.0" + } + }, + "node_modules/@asamuzakjp/css-color": { + "version": "5.1.11", + "resolved": "https://registry.npmjs.org/@asamuzakjp/css-color/-/css-color-5.1.11.tgz", + "integrity": "sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@csstools/css-calc": "^3.2.0", + "@csstools/css-color-parser": "^4.1.0", + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/dom-selector": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/dom-selector/-/dom-selector-7.1.1.tgz", + "integrity": "sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/generational-cache": "^1.0.1", + "@asamuzakjp/nwsapi": "^2.3.9", + "bidi-js": "^1.0.3", + "css-tree": "^3.2.1", + "is-potential-custom-element-name": "^1.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/generational-cache": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@asamuzakjp/generational-cache/-/generational-cache-1.0.1.tgz", + "integrity": "sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/@asamuzakjp/nwsapi": { + "version": "2.3.9", + "resolved": "https://registry.npmjs.org/@asamuzakjp/nwsapi/-/nwsapi-2.3.9.tgz", + "integrity": "sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/@aws-sdk/core": { + "version": "3.978.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.978.0.tgz", + "integrity": "sha512-2yX9LUmxPklVjSGTb8dfnWRJSiFQ3TeH2nn7G1mdKHTfnabzF0+gfrS8rYfLWmZrQ8A3mEcxMJjRc51dL5KWaA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.974.5", + "@aws-sdk/xml-builder": "^3.972.40", + "@aws/lambda-invoke-store": "^0.3.0", + "@smithy/core": "^3.33.3", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.17.2", + "bowser": "^2.11.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-cognito-identity": { + "version": "3.972.70", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-cognito-identity/-/credential-provider-cognito-identity-3.972.70.tgz", + "integrity": "sha512-KlU89w6Hmb4oZB5zFz/MNIhPOBQGVE7KrDr3BTPCwC4W+q566YH8tGNsAML781LKATtqmNCGFry8XvsJ2XPusg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/nested-clients": "^3.997.45", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.972.71", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.972.71.tgz", + "integrity": "sha512-JN+JHruYZw3GUZB8YGAlDk4wTDPOEAEEdEzj5nS0xodWR4smzHsN7PnK2j6IeOsDIj2aqua5DSbhXl9Gtf90FQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.978.0", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.972.73", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.972.73.tgz", + "integrity": "sha512-uyYYnJOnlis8uQzaYGPd7N1JoioCoNpXgnkXYixsWJXHXgXyYi8WXJSDfofxJeWfQIGWLe2Nwyq60Uc7MZdVOg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.978.0", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/fetch-http-handler": "^5.7.2", + "@smithy/node-http-handler": "^4.11.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.973.16", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.973.16.tgz", + "integrity": "sha512-i++ly+0Uxa+u3ebSSyr0S/3CFhFJDxCXT3+Zj+mW2bXenEx5bKGCdTIKFu39SgXBNhWDjex/8cXUx9MUTMCrTw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.978.0", + "@aws-sdk/credential-provider-env": "^3.972.71", + "@aws-sdk/credential-provider-http": "^3.972.73", + "@aws-sdk/credential-provider-login": "^3.972.78", + "@aws-sdk/credential-provider-process": "^3.972.71", + "@aws-sdk/credential-provider-sso": "^3.973.15", + "@aws-sdk/credential-provider-web-identity": "^3.972.77", + "@aws-sdk/nested-clients": "^3.997.45", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-login": { + "version": "3.972.78", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-login/-/credential-provider-login-3.972.78.tgz", + "integrity": "sha512-eUtswnXu0+Ii9ieRK+0L7aPFV3Z/dnW2VntJzjBP9xs8s+8p5nBNuymIXtXwZ+5r5+XJP3e32nMkuZ/r0HozEA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.978.0", + "@aws-sdk/nested-clients": "^3.997.45", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.972.83", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.972.83.tgz", + "integrity": "sha512-jdso7ejzfRnatxMUZK4S/U6KbaDPCvfIV4XL+IQAPFDBt5rj5Fq595euqlK8Le4lNCMFR9oUpt+1l0aMgaayOQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/credential-provider-env": "^3.972.71", + "@aws-sdk/credential-provider-http": "^3.972.73", + "@aws-sdk/credential-provider-ini": "^3.973.16", + "@aws-sdk/credential-provider-process": "^3.972.71", + "@aws-sdk/credential-provider-sso": "^3.973.15", + "@aws-sdk/credential-provider-web-identity": "^3.972.77", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.972.71", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.972.71.tgz", + "integrity": "sha512-lYmXJa4gvq4xN1lrT5NiP5vIYYKcGWAdj8y+8o6dlcateB5eF3Dn8DtmjjHKfMBrTPAMr2pebIiX/UOj8c1/UA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.978.0", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.973.15", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.973.15.tgz", + "integrity": "sha512-6Jhcf4v0pSFdjk1EW2kvzuEBKD+UZ2uNcHUIglKKLndD20YhvkL2kdmDOV5/j4mYuWWwe/a1FQ1aomU86/Cg5Q==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.978.0", + "@aws-sdk/nested-clients": "^3.997.45", + "@aws-sdk/token-providers": "3.1129.0", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.972.77", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.972.77.tgz", + "integrity": "sha512-uylIQSUWpfLuH2LovxEEfwzJGM/SabLOfLMg6YXu/E8jJEKUdpdILCVCQCdFvHyu/7dLJOHPMfrSwduxO56NkQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.978.0", + "@aws-sdk/nested-clients": "^3.997.45", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/credential-providers": { + "version": "3.1137.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-providers/-/credential-providers-3.1137.0.tgz", + "integrity": "sha512-4y1Y+51HKtSs5Lo7r2yztCnphxdkL2wcw5NAo9EkH3LwVLREuniymS0F4sFE1s8dS+nEsustJ59CGT0Ghp7H3A==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.978.0", + "@aws-sdk/credential-provider-cognito-identity": "^3.972.70", + "@aws-sdk/credential-provider-env": "^3.972.71", + "@aws-sdk/credential-provider-http": "^3.972.73", + "@aws-sdk/credential-provider-ini": "^3.973.16", + "@aws-sdk/credential-provider-login": "^3.972.78", + "@aws-sdk/credential-provider-node": "^3.972.83", + "@aws-sdk/credential-provider-process": "^3.972.71", + "@aws-sdk/credential-provider-sso": "^3.973.15", + "@aws-sdk/credential-provider-web-identity": "^3.972.77", + "@aws-sdk/nested-clients": "^3.997.45", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/credential-provider-imds": "^4.4.16", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/nested-clients": { + "version": "3.997.45", + "resolved": "https://registry.npmjs.org/@aws-sdk/nested-clients/-/nested-clients-3.997.45.tgz", + "integrity": "sha512-mooq9Q+jLa18VoM7HouczmslZU60iiB0aKc/Ztnq/luIL1ud0z4DnYprLR/ZO1gp331S9tJctM1HZr7u6YKBXQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.978.0", + "@aws-sdk/signature-v4-multi-region": "^3.996.46", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/fetch-http-handler": "^5.7.2", + "@smithy/node-http-handler": "^4.11.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/signature-v4-multi-region": { + "version": "3.996.46", + "resolved": "https://registry.npmjs.org/@aws-sdk/signature-v4-multi-region/-/signature-v4-multi-region-3.996.46.tgz", + "integrity": "sha512-L+2xZTye/2T96f3lwCws0Zw6GG2JHZW9e8FpVgGBeeExSKyeoZ6CWRpBml/7DNiK/O26jrgPM9F+Ay8VkgzUWQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/types": "^3.974.5", + "@smithy/signature-v4": "^5.6.12", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/token-providers": { + "version": "3.1129.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.1129.0.tgz", + "integrity": "sha512-Sbl3rpzQdsG4ZK2zh0JWUYyZPKKorJlVOddA2T0DVbKJFrsW8J6wgnslxxUH04+WaBMr4A1HzJZvZX0xUvkniA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@aws-sdk/core": "^3.978.0", + "@aws-sdk/nested-clients": "^3.997.45", + "@aws-sdk/types": "^3.974.5", + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/types": { + "version": "3.974.5", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.974.5.tgz", + "integrity": "sha512-LkwLL2BLbC6wNNm4JaH9mbEqBMdOZCct6VAYqhdN4U1xrWM+fUJQEfbHwQgDypapOWTRtlk25akb5afM0P8CIQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws-sdk/xml-builder": { + "version": "3.972.40", + "resolved": "https://registry.npmjs.org/@aws-sdk/xml-builder/-/xml-builder-3.972.40.tgz", + "integrity": "sha512-wlFmCIGUlwF4zx/kncw+bmxTQh1HeSJq4mYV/V5cZUSJadDP3kXvGW8Rn21cimj/7y9ju+47oYWXi97vF7czaA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=20.0.0" + } + }, + "node_modules/@aws/lambda-invoke-store": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@aws/lambda-invoke-store/-/lambda-invoke-store-0.3.0.tgz", + "integrity": "sha512-sl4Bm6yiMNYrZKkqqDFWN0UfnWhlS8ivKxrYl+6t0gCLrqr8y3B2IqZZbFRkfaVVp7C/baApyh71P+LeE1A2sQ==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.26.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.26.2.tgz", + "integrity": "sha512-RJlIHRueQgwWitWgF8OdFYGZX328Ax5BCemNGlqHfplnRT9ESi8JkFlvaVYbS+UubVY6dpv87Fs2u5M29iNFVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.25.9", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.29.7.tgz", + "integrity": "sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.29.7.tgz", + "integrity": "sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.7", + "@babel/helper-compilation-targets": "^7.29.7", + "@babel/helper-module-transforms": "^7.29.7", + "@babel/helpers": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/template": "^7.29.7", + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7", + "@jridgewell/remapping": "^2.3.5", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.29.8.tgz", + "integrity": "sha512-gZbepsdh3WDtgZKWL+vTPh71LSBrm/Y4/QDZBVCcYfmeTEEuoOYwlSy+G1StfJg+/Zy550u/3TATbm7qDbbMtg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/parser": "^7.29.8", + "@babel/types": "^7.29.8", + "@jridgewell/gen-mapping": "^0.3.12", + "@jridgewell/trace-mapping": "^0.3.28", + "jsesc": "^3.0.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz", + "integrity": "sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/compat-data": "^7.29.7", + "@babel/helper-validator-option": "^7.29.7", + "browserslist": "^4.24.0", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-globals": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-globals/-/helper-globals-7.29.7.tgz", + "integrity": "sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz", + "integrity": "sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/traverse": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz", + "integrity": "sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-module-imports": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7", + "@babel/traverse": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz", + "integrity": "sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz", + "integrity": "sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz", + "integrity": "sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz", + "integrity": "sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.29.7.tgz", + "integrity": "sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.29.9", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.29.9.tgz", + "integrity": "sha512-CjXrNHTnvqBVqHgdBysY3vk2T8tpJHb5/RMeHJBTyVa9xgugCB0CJTx/3oO8RV2QRQP391RWpB7D6hLjm8V9uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/types": "^7.29.8" + }, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.29.7.tgz", + "integrity": "sha512-Nq8OhGWiZIZGV6hLHoyAKLLcJihP/xFeBMGJoUrxTX2psI8dCifzLhZISFb+VWS3wFMRDmCGw5R+dOySCqPLhw==", + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.29.7.tgz", + "integrity": "sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/parser": "^7.29.7", + "@babel/types": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.29.8.tgz", + "integrity": "sha512-I5z7H3bf/41ktsNVLtpN0wAa336HkqIHQ5BuPLEhTkt1jVSyZpeNKIzTgEWmlxjdg81R0IgUCcaE+Ok3NvrfZg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.29.7", + "@babel/generator": "^7.29.8", + "@babel/helper-globals": "^7.29.7", + "@babel/parser": "^7.29.8", + "@babel/template": "^7.29.7", + "@babel/types": "^7.29.8", + "debug": "^4.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/code-frame": { + "version": "7.29.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.29.7.tgz", + "integrity": "sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-validator-identifier": "^7.29.7", + "js-tokens": "^4.0.0", + "picocolors": "^1.1.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.29.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.29.8.tgz", + "integrity": "sha512-Vj1jF3cPfxg7OAfoI7QnVKLoILlm2JF9pnVHrX8qx7AHMiYWT+NDAA7jChlNgRS4WTLc/fD1lXLmPixluj+3Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.29.7", + "@babel/helper-validator-identifier": "^7.29.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bramus/specificity": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/@bramus/specificity/-/specificity-2.4.2.tgz", + "integrity": "sha512-ctxtJ/eA+t+6q2++vj5j7FYX3nRu311q1wfYH3xjlLOsczhlhxAg2FWNUXhpGvAw3BWo1xBcvOV6/YLc2r5FJw==", + "dev": true, + "license": "MIT", + "dependencies": { + "css-tree": "^3.0.0" + }, + "bin": { + "specificity": "bin/cli.js" + } + }, + "node_modules/@csstools/color-helpers": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/@csstools/color-helpers/-/color-helpers-6.1.1.tgz", + "integrity": "sha512-gLNsunvwf3mCi5u5o46/Z/JcJMnhbHSaZ69rkgPzNM3J4s8hWwpPUQB6/tt0EDFyCiWzxANlx+2LJwpYj4zS1w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@csstools/css-calc": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/@csstools/css-calc/-/css-calc-3.4.0.tgz", + "integrity": "sha512-XQKj5B7QiZcHiegCOCAzcAOJdhGgWOHbbu62h5e5mkHnn8lWcfiJhllkqWmxu5zWR9jucPHuo1iTB56P033hcg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-color-parser": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/@csstools/css-color-parser/-/css-color-parser-4.2.3.tgz", + "integrity": "sha512-y4LpL+lmpuyKDiEFq2PnZUVFdAjsoB/qQJod79yLNokXyW7jewi+/WJ69EfItj8A2unWtxXnGjw6LYXgXu5ZjA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "dependencies": { + "@csstools/color-helpers": "^6.1.1", + "@csstools/css-calc": "^3.4.0" + }, + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-parser-algorithms": "^4.0.0", + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-parser-algorithms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@csstools/css-parser-algorithms/-/css-parser-algorithms-4.0.0.tgz", + "integrity": "sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + }, + "peerDependencies": { + "@csstools/css-tokenizer": "^4.0.0" + } + }, + "node_modules/@csstools/css-syntax-patches-for-csstree": { + "version": "1.1.14", + "resolved": "https://registry.npmjs.org/@csstools/css-syntax-patches-for-csstree/-/css-syntax-patches-for-csstree-1.1.14.tgz", + "integrity": "sha512-HpbVXyrofRXpHpgkNIjU/3EWR4WJvOkO3emNK/L6X/mTJU7bGUI3AkkpoTNXznQLp0KRjLHELTGeKI5dIkI9JQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT-0", + "peerDependencies": { + "css-tree": "^3.2.1" + }, + "peerDependenciesMeta": { + "css-tree": { + "optional": true + } + } + }, + "node_modules/@csstools/css-tokenizer": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@csstools/css-tokenizer/-/css-tokenizer-4.0.1.tgz", + "integrity": "sha512-bPlN9S9O1A0euCpEWE4qnvB5YDuyYVsUTrxSgmAM1Is0j4tICHoVyOVAXfWMP/kS9ZrjvyIXWV2PmomiAXXqOw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/csstools" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/csstools" + } + ], + "license": "MIT", + "engines": { + "node": ">=20.19.0" + } + }, + "node_modules/@emnapi/core": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.11.3.tgz", + "integrity": "sha512-zLpS5asjEb7lq8jYLq37N6XKaE41DIexlY1rF/z4/tIl3wo13Sqm28fRyfIsKZD+NZ8mM5RoKkpW/rBcuoSZSg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.3", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.11.3", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.11.3.tgz", + "integrity": "sha512-Xz4Tpyki7XyrpbUK1jR1AhdAdaXyhhY4lZ3neLodmhpuWfy2PAQN5B46sAiU4liOXGLkHypn/qU+jvfWSCYYLA==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/wasi-threads": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.3.tgz", + "integrity": "sha512-ELEBe8PsLvvJ6QMr0zLt8ffvOHW/dc1m3CEzNMg7aJUv3bMaoDtw2TXyDAwkYBuroxxuHEwhRTLJSe5sya547g==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, + "node_modules/@exodus/bytes": { + "version": "1.15.2", + "resolved": "https://registry.npmjs.org/@exodus/bytes/-/bytes-1.15.2.tgz", + "integrity": "sha512-ctkytT+9TXtv6uiVj6Y7IjKh1+PdBGAD34xd0PpQ/qF+R7O/hoEQbZmN89OaCEaZn5I1A9+ZoPxD03unuFhyhQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + }, + "peerDependencies": { + "@noble/hashes": "^1.8.0 || ^2.0.0" + }, + "peerDependenciesMeta": { + "@noble/hashes": { + "optional": true + } + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.6.tgz", + "integrity": "sha512-+Sg6GCR/wy1oSmQDFq4LQDAhm3ETKnorxN+y5nbLULOR3P0c14f2Wurzj3/xqPXtasLFfHd5iRFQ7AJt4KH2cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.13", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz", + "integrity": "sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.5.0", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/remapping": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/remapping/-/remapping-2.3.5.tgz", + "integrity": "sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.11.tgz", + "integrity": "sha512-ZMp1V8ZFcPG5dIWnQLr3NSI1MiCU7UETdS/A0G8V/XWHvJv3ZsFqutJn1Y5RPmAPX6F3BiE397OqveU/9NCuIA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.6.0.tgz", + "integrity": "sha512-T7jf+5zgsZHwNJ4lvQ7/aezbyk0nNX+zJVWpmHA7VYsEx7a7qr5Rg5IbtJFqkgze5Y2sruq1RUY8Q837Od7iFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.31", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz", + "integrity": "sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@meteorjs/rspack": { + "version": "3.0.0-beta.0", + "resolved": "file:.meteor/local/npm/meteor-rspack", + "dev": true, + "license": "ISC", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "ignore-loader": "^0.1.2", + "node-polyfill-webpack-plugin": "^4.1.0", + "rspack-merge": "^1.0.1" + }, + "peerDependencies": { + "@rspack/cli": ">=2.1.8", + "@rspack/core": ">=2.1.8", + "@rspack/dev-server": ">=2.1.0", + "@swc/core": ">=1.3.0" + } + }, + "node_modules/@meteorjs/rstest": { + "version": "0.1.0-beta.0", + "resolved": "file:.meteor/local/npm/meteor-rstest", + "dev": true, + "license": "MIT", + "dependencies": { + "@rstest/adapter-rspack": "0.11.6", + "@rstest/core": "0.11.6", + "@rstest/coverage-istanbul": "0.11.6", + "babel-plugin-istanbul": "7.0.1", + "picomatch": "4.0.5" + }, + "bin": { + "meteor-rstest": "bin/meteor-rstest.js" + }, + "peerDependencies": { + "@meteorjs/rspack": ">=3.0.0-beta.0", + "@rspack/cli": "2.1.8", + "@rspack/core": "2.1.8" + } + }, + "node_modules/@mongodb-js/saslprep": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.5.4.tgz", + "integrity": "sha512-05UC0jQsjKAOuXQ0H9Ud9vUTJpZIg+n/FinpR30tI5I8pY2inTfPOZ5OF/cg3Ce/N9MoD1xhRCeOsJtuTbFYlw==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "sparse-bitfield": "^3.0.3" + } + }, + "node_modules/@napi-rs/wasm-runtime": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.6.tgz", + "integrity": "sha512-ZLv/JdUfkvOy9eCnnBaGfiO+XimbjebAeO+MRQqD/B+FR1tnRN0tpKSJHRbE8sFfS6aqsXZ67TQjfwfsxULVbg==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@tybys/wasm-util": "^0.10.3" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Brooooooklyn" + }, + "peerDependencies": { + "@emnapi/core": "^1.7.1", + "@emnapi/runtime": "^1.7.1" + } + }, + "node_modules/@polka/url": { + "version": "1.0.0-next.29", + "resolved": "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.29.tgz", + "integrity": "sha512-wwQAWhWSuHaag8c4q/KN/vCoeOJYshAIvMQwD4GpSb3OiZklFfvAgmj0VCBBImRpuF/aFgIRzllXlVX93Jevww==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rsbuild/core": { + "version": "2.1.13", + "resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-2.1.13.tgz", + "integrity": "sha512-Z+6MzmjOio4+bFZQ24k+7ge/oNCOdXIunAssrswTNE8AIf6mcyXpJZevRXRiOEMZasRPA8VNyh+9JngQLg729Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rspack/core": "~2.1.10", + "@swc/helpers": "^0.5.23" + }, + "bin": { + "rsbuild": "bin/rsbuild.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "core-js": ">= 3.0.0" + }, + "peerDependenciesMeta": { + "core-js": { + "optional": true + } + } + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-2.1.10.tgz", + "integrity": "sha512-vnu/UP5HnrND15lO9+VeG6eUrbTyycHNQNQ3XEiRiFojuoiGZkIZC3Hbzr8qQH44C6vScPODEPvvIVvLcO2LpQ==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@rspack/binding-darwin-arm64": "2.1.10", + "@rspack/binding-darwin-x64": "2.1.10", + "@rspack/binding-linux-arm64-gnu": "2.1.10", + "@rspack/binding-linux-arm64-musl": "2.1.10", + "@rspack/binding-linux-ppc64-gnu": "2.1.10", + "@rspack/binding-linux-riscv64-gnu": "2.1.10", + "@rspack/binding-linux-riscv64-musl": "2.1.10", + "@rspack/binding-linux-s390x-gnu": "2.1.10", + "@rspack/binding-linux-x64-gnu": "2.1.10", + "@rspack/binding-linux-x64-musl": "2.1.10", + "@rspack/binding-wasm32-wasi": "2.1.10", + "@rspack/binding-win32-arm64-msvc": "2.1.10", + "@rspack/binding-win32-ia32-msvc": "2.1.10", + "@rspack/binding-win32-x64-msvc": "2.1.10" + } + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-darwin-arm64": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-2.1.10.tgz", + "integrity": "sha512-DZlcTpbIb2mjeS1aSG4k01UH33Zj7T+k8ZylPK6HmsKs4JvK4wgpWFC78WVv3p/Aj3MZS6DwtDLwpZ2Ihj/fpg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-darwin-x64": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-2.1.10.tgz", + "integrity": "sha512-my/0h2LwxCRT6cg3oDDC2e0ZOxQLVajAdIcv0fqnQk5JRNvVuL89PuTutitnSqie1A0/JSL8OQz5XHwmoS3kow==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-linux-arm64-gnu": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-2.1.10.tgz", + "integrity": "sha512-laevn9g+E5PAUEGqiKe6Ju5KApsuQYp+bPI17XS3Lkl8eqL5pS/BmHYU7QMlst4GzV8+wlruVTMh//+st6Vqzg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-linux-arm64-musl": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-2.1.10.tgz", + "integrity": "sha512-V71+Qz5G72+ROZXrJn5zxOszdG1AEbO8pcC/itXXtf4yRR6a3bVHKNKGhipBNxb8eI6cnD/01FH1h3ZG655jLw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-linux-riscv64-gnu": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-2.1.10.tgz", + "integrity": "sha512-GMGTJpy9/ecE+5F5IfxZH4bXv0Wx/b2TiehTlCbTksbL+pKpLHYy0rwGdjWDKbmBkhxMMqPiC7PDnn9LbdnnLA==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-linux-riscv64-musl": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-2.1.10.tgz", + "integrity": "sha512-rkurnAWc04vIbzG1QCrPBWSJadZvaOt1mazFH3EdiJO8VUiu0I1T9zdiwuDOPrd50lOKIZlcTXbd5aaAkWEnvQ==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-linux-x64-gnu": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-2.1.10.tgz", + "integrity": "sha512-Fat09V6jUuyo9qG7Wyj9cQ31VDfLmokXyBtGqKxY5OvSWHereB7QUub5btbPXHwbp6Iq4aAQyUbbLTzvR1YaBw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-linux-x64-musl": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-2.1.10.tgz", + "integrity": "sha512-lhHOnIJ4ClpIlA1f1L8aoxEZivYLjnjq5A6jKKz7BKsm+cHK8kqqEm6lO5KqA5xQT0Lonq1o28bmKHEj6JHInw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-wasm32-wasi": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-2.1.10.tgz", + "integrity": "sha512-KY5YbWbuvYcoaLXnV+vzZOvGRCeb6jt4EpVpKdph1h1IJjwX/ju15EQ+GOe3iecZEdf0OttQcNVcwBkLkFT9ag==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.3", + "@emnapi/runtime": "1.11.3", + "@napi-rs/wasm-runtime": "1.1.6" + } + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-win32-arm64-msvc": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.1.10.tgz", + "integrity": "sha512-z4GWzMLofaDGpAt9Z+MlN88LlUBDm+zM6R2GdOOPM6/4g/h3/+47OP7casmSL3AwTGYBEJqogwt08sRSosB6Cg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-win32-ia32-msvc": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-2.1.10.tgz", + "integrity": "sha512-7qcWdsZ+GuGtzKjqgy7wTN7Dso/ezIY8yhx1r2yIbcczdmXj4FhaEampMDp/25HwtKwIGBBoh6HHSt3JWxpTUg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/binding-win32-x64-msvc": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-2.1.10.tgz", + "integrity": "sha512-pgp23pLrzfhGnKycxzr7ifP17lAbWZEfnx1bX8gXtYrnpJ66DRNyTKSzxB6sa/HBWjS1L8PX5TjMZ44WfPydqQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rsbuild/core/node_modules/@rspack/core": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-2.1.10.tgz", + "integrity": "sha512-YSS2/Xxz8uiG/KXDkqOoA3dTetNo/vysk7bAexQOrU8iuq7JuzDTTAwLKvWZnwmvME8M8m5wcM4YvfIwYmidHA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rspack/binding": "2.1.10" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@module-federation/runtime-tools": "^0.24.1 || ^2.0.0", + "@swc/helpers": "^0.5.23" + }, + "peerDependenciesMeta": { + "@module-federation/runtime-tools": { + "optional": true + }, + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@rsbuild/plugin-check-syntax": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/@rsbuild/plugin-check-syntax/-/plugin-check-syntax-1.6.1.tgz", + "integrity": "sha512-26xtEYN0QjZYoyt0lWnvIztBWjEZJvcfw7MN4f5B4SpNggmnF7F7aNPrgkY3EccXVFx1VGQBhnCkBV//OoS07Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.15.0", + "browserslist-to-es-version": "^1.2.0", + "htmlparser2": "10.0.0", + "picocolors": "^1.1.1", + "source-map": "^0.7.6" + }, + "peerDependencies": { + "@rsbuild/core": "^1.0.0 || ^2.0.0-0" + }, + "peerDependenciesMeta": { + "@rsbuild/core": { + "optional": true + } + } + }, + "node_modules/@rsdoctor/client": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/client/-/client-1.6.4.tgz", + "integrity": "sha512-11GvDTusVzlqlyTVoeI0kw1n5TH9MTrzOJxL5L/Qgyzmf5SSl+iw3NrEPRqyi2pgzQsOumad6FSq2n0LdBKzrg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@rsdoctor/core": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/core/-/core-1.6.4.tgz", + "integrity": "sha512-Z504K+VjKpbqYnRG6ORr0BNidObjTZSb6Z6nXpZDkBSIdmA4fZcKz8U0iRLsZuy8kq7PN+Xm7ym0fTTGh8xeVQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsbuild/plugin-check-syntax": "^1.6.1", + "@rsdoctor/graph": "1.6.4", + "@rsdoctor/sdk": "1.6.4", + "@rsdoctor/types": "1.6.4", + "@rsdoctor/utils": "1.6.4", + "@rspack/resolver": "^0.2.8", + "browserslist-load-config": "^1.0.2", + "es-toolkit": "^1.49.0", + "filesize": "^11.0.17", + "fs-extra": "^11.1.1", + "semver": "^7.8.5", + "source-map": "^0.7.6" + } + }, + "node_modules/@rsdoctor/graph": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/graph/-/graph-1.6.4.tgz", + "integrity": "sha512-UnCRJ9uhH0+z5OX8UfLdVnDnxr21PuMa6wMt9+cD0NsJZTdd+6gts4RcEp3BFbzs0g/BQoNCciQzRBULZr+OUA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsdoctor/types": "1.6.4", + "@rsdoctor/utils": "1.6.4", + "es-toolkit": "^1.49.0", + "path-browserify": "1.0.1", + "source-map": "^0.7.6" + } + }, + "node_modules/@rsdoctor/rspack-plugin": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/rspack-plugin/-/rspack-plugin-1.6.4.tgz", + "integrity": "sha512-hHCRsHV0Qy0zPuDpNQq72dgnhevGxUFcPAL/JJPDzH3idI+IxMb08vCohWJWYvQVliNTACiS9kCMKUGZjIAzCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsdoctor/core": "1.6.4", + "@rsdoctor/graph": "1.6.4", + "@rsdoctor/sdk": "1.6.4", + "@rsdoctor/types": "1.6.4", + "@rsdoctor/utils": "1.6.4" + }, + "peerDependencies": { + "@rspack/core": "*" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + } + } + }, + "node_modules/@rsdoctor/sdk": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/sdk/-/sdk-1.6.4.tgz", + "integrity": "sha512-oLCUCqVlzbcVIoPoDLycqAqgUYxWcCZEK21cGu4ZDVVo+H8pmA2iEvi7T9KnE0sgkNm5U2bt6SkyNx/Tt1eTkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsdoctor/client": "1.6.4", + "@rsdoctor/graph": "1.6.4", + "@rsdoctor/types": "1.6.4", + "@rsdoctor/utils": "1.6.4", + "launch-editor": "^2.13.2", + "safer-buffer": "2.1.2", + "socket.io": "4.8.1", + "tapable": "2.3.3" + } + }, + "node_modules/@rsdoctor/types": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/types/-/types-1.6.4.tgz", + "integrity": "sha512-+nE5MoP7smDrJt5LkeoY6cj8P/ZJBF7lNvvJ658+sV8cde6agu2bEreSUjR5zcAldUs1j4oSgLY5x6TukeseEQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "3.4.38", + "@types/estree": "1.0.5", + "@types/tapable": "2.3.0", + "source-map": "^0.7.6" + }, + "peerDependencies": { + "@rspack/core": "*", + "webpack": "5.x" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/@rsdoctor/utils": { + "version": "1.6.4", + "resolved": "https://registry.npmjs.org/@rsdoctor/utils/-/utils-1.6.4.tgz", + "integrity": "sha512-7oliDqtaLVtmVFkfSN3AKWoMQb8kuZA9AURCgb26cUW7+ZD3qgADg9uyD+WevpA6IOeF6gqo3hezTZKlwFR2Sg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "7.26.2", + "@rsdoctor/types": "1.6.4", + "@types/estree": "1.0.5", + "acorn": "^8.10.0", + "acorn-import-attributes": "^1.9.5", + "acorn-walk": "8.3.5", + "deep-eql": "4.1.4", + "envinfo": "7.21.0", + "fs-extra": "^11.1.1", + "get-port": "5.1.1", + "json-stream-stringify": "3.0.1", + "lines-and-columns": "2.0.4", + "picocolors": "^1.1.1", + "rslog": "^2.1.2", + "strip-ansi": "^7.2.0" + } + }, + "node_modules/@rspack/binding": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-2.1.8.tgz", + "integrity": "sha512-tmAyHzDbPiy8V7HvQqtuPsbs6dPgwV0YjzW5XrPRV9gzf+Hdm7pvsZJKE1QKO9WV5RuvGYav98xIX6O+abZxzQ==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@rspack/binding-darwin-arm64": "2.1.8", + "@rspack/binding-darwin-x64": "2.1.8", + "@rspack/binding-linux-arm64-gnu": "2.1.8", + "@rspack/binding-linux-arm64-musl": "2.1.8", + "@rspack/binding-linux-riscv64-gnu": "2.1.8", + "@rspack/binding-linux-riscv64-musl": "2.1.8", + "@rspack/binding-linux-x64-gnu": "2.1.8", + "@rspack/binding-linux-x64-musl": "2.1.8", + "@rspack/binding-wasm32-wasi": "2.1.8", + "@rspack/binding-win32-arm64-msvc": "2.1.8", + "@rspack/binding-win32-ia32-msvc": "2.1.8", + "@rspack/binding-win32-x64-msvc": "2.1.8" + } + }, + "node_modules/@rspack/binding-darwin-arm64": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-2.1.8.tgz", + "integrity": "sha512-kia+eWtyWPvR4ntg1bWYoVU8nLPbUg2fG3zgBEocsTcsh5ZENSiEPxEKymDgMyIMONUqj611E0775cdUBoNmqw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/binding-darwin-x64": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-2.1.8.tgz", + "integrity": "sha512-08pBkFhlD3Y3Qzh94w/Fc3skaIE3e96kl2P14m8+tnYTcglpOfpA2OwS3iHt9fOqy0HjoAVe6/MW3cBgs5iabA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/binding-linux-arm64-gnu": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-2.1.8.tgz", + "integrity": "sha512-KLniMc9GzhKpVqhPzaJo3KJwzdAllXVVqZIk/uL1QipXOxs57fgM4u7IexKPFVla0o/u1PQG/Ah2YLDmda24Ow==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-arm64-musl": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-2.1.8.tgz", + "integrity": "sha512-yUKAxHNGnICtw5RnxFWu4dHtsz/tdt7rbeFcsINNVre9HcrRxf5XP+FbOGL/SMxd9oM9XCo10paU2WckTKwbEA==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-ppc64-gnu": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-2.1.10.tgz", + "integrity": "sha512-U7HlNzHcDtZ+LYOtOJmtx67kHEybZzUUAaP7aEXjGYO5WTCgh/176sW2UYP0rmZLrgUNFUuzn+B98RLaClNaVg==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-riscv64-gnu": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-gnu/-/binding-linux-riscv64-gnu-2.1.8.tgz", + "integrity": "sha512-gg4S1jaitwYPHR9HZ3zNGH1EK2GXINm66p4kEpOP1gbc+akyOouVF/dMcu9NGPlRg58FbEhVRZYKu7Z/zcpKHg==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-riscv64-musl": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-riscv64-musl/-/binding-linux-riscv64-musl-2.1.8.tgz", + "integrity": "sha512-b/aU5j1h368SLNyz5u+flqpZVhzSZ1UIslaj9sZJuAvqkGWv3xsjc/28/PTo/RYXCxd0FNVAxTxWHKvRiAAS8w==", + "cpu": [ + "riscv64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-s390x-gnu": { + "version": "2.1.10", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-2.1.10.tgz", + "integrity": "sha512-X+DyxkriZEAF/wihI7ERDv+CAS0mbMv36aEuQ+vXzTlvS6cSmpou/r29AHbvIF3NlG1UeAbDVlOs9QrMBZjpUQ==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-x64-gnu": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-2.1.8.tgz", + "integrity": "sha512-EyegohSx0BJRqieCg9f/caCqFARRWkqI5hwJt6k530MoOTLeq8I3vsbeg24/2MktwIC1dmJi8bl0+WhPKQs4eQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-linux-x64-musl": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-2.1.8.tgz", + "integrity": "sha512-I6E+goN+UQ297q4r1qdbiAyNCI3t0+a5Y0xDIAPOZfRDRxDTnH/LF8/y65gjsJoKRKyn7zxRC0T/NURTkRNQ9A==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/binding-wasm32-wasi": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-2.1.8.tgz", + "integrity": "sha512-om7GAKWAU3lcSvbCon2m7mzw8v9OTrO2LW2MZ1lGe/uVJJmwGGkl9HVoXFyWFLrN6YVFyx8iP+AkN4owDWB9Cw==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@emnapi/core": "1.11.3", + "@emnapi/runtime": "1.11.3", + "@napi-rs/wasm-runtime": "1.1.6" + } + }, + "node_modules/@rspack/binding-win32-arm64-msvc": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-2.1.8.tgz", + "integrity": "sha512-WDnsP/SUb9zbxyGX9XjPw5AXrX86u5oidn0MDdfJduOOqdCSpHwmRjlQ8NUJhbBq9WqVJMFlcab7NwZVWX/yyg==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding-win32-ia32-msvc": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-2.1.8.tgz", + "integrity": "sha512-QiMQMPNDiY3dhhaIdaFPzcPDC06cEYkNY89ea+EmDvNVgZq6V+2mFS/WnzZVMeEbGAYJCjsv/ABhhLT1hlYMvg==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/binding-win32-x64-msvc": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-2.1.8.tgz", + "integrity": "sha512-b7sA5eB64vo2mbsuc//MOYzVLeCKHPn0dfP/GmNEoHdWbhRgZ/orZLWurYMQj04ELTLW6YCJEy59g5KRzNYHfw==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/cli": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/cli/-/cli-2.1.8.tgz", + "integrity": "sha512-ewcLmPtmjudUVsPsz7LtuJFJObyFf6ShIC4aAvXra1RAnmzsEigSW+xCNSjXP6gXBZVr2Hsg3vWJJlacdDFacg==", + "dev": true, + "license": "MIT", + "bin": { + "rspack": "bin/rspack.js" + }, + "peerDependencies": { + "@rspack/core": "^2.0.0-0", + "@rspack/dev-server": "^2.0.0-0" + }, + "peerDependenciesMeta": { + "@rspack/dev-server": { + "optional": true + } + } + }, + "node_modules/@rspack/core": { + "version": "2.1.8", + "resolved": "https://registry.npmjs.org/@rspack/core/-/core-2.1.8.tgz", + "integrity": "sha512-na1kyA6Mj8/LWw9O3A8NsrG9rNKN3Iq2WiXrEuIwsU5r/Nl/evm3hO7bWKHxgsRyydI6W7okwx3MXgf8rzel6g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rspack/binding": "2.1.8" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@module-federation/runtime-tools": "^0.24.1 || ^2.0.0", + "@swc/helpers": "^0.5.23" + }, + "peerDependenciesMeta": { + "@module-federation/runtime-tools": { + "optional": true + }, + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@rspack/dev-middleware": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@rspack/dev-middleware/-/dev-middleware-2.0.4.tgz", + "integrity": "sha512-VCdT8hv9YvMPiBohhukD/OkGB+2GJ7mPRbeuDJ/jIT6hv5gvmJCnydMetJVARh6vXoBtfSHEd2gX78Dqaxh1NQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rspack/core": "^2.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + } + } + }, + "node_modules/@rspack/dev-server": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@rspack/dev-server/-/dev-server-2.2.1.tgz", + "integrity": "sha512-Il8HbYGK3rH5rM0XmUOsOGZVw69BKRpBZ61P28Fy8ry35CtfniDBWtbo/rvJtIT/sK0qwijmNrhF498ltsV+uA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rspack/dev-middleware": "^2.0.3" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rspack/core": "^2.0.0", + "selfsigned": "^5.0.0" + }, + "peerDependenciesMeta": { + "selfsigned": { + "optional": true + } + } + }, + "node_modules/@rspack/plugin-react-refresh": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@rspack/plugin-react-refresh/-/plugin-react-refresh-2.0.2.tgz", + "integrity": "sha512-dGNZiCxQxgAUI9sah7gd8u+O7OJZRCmqtEJNDOd8xW5RqcieC86F7p5qcShyw6onH5pKf57evpr2VjGbaFGkZg==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@rspack/core": "^2.0.0", + "react-refresh": ">=0.10.0 <1.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + } + } + }, + "node_modules/@rspack/resolver": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver/-/resolver-0.2.8.tgz", + "integrity": "sha512-FBWqdHhzS8mcf/WN4Ktzr7EaeaN+hsxbN98EweegX3924beZuY6H70CSFWCv1fIHAieCUv/9XCjKggHvhCsLwA==", + "dev": true, + "license": "MIT", + "optionalDependencies": { + "@rspack/resolver-binding-darwin-arm64": "0.2.8", + "@rspack/resolver-binding-darwin-x64": "0.2.8", + "@rspack/resolver-binding-linux-arm64-gnu": "0.2.8", + "@rspack/resolver-binding-linux-arm64-musl": "0.2.8", + "@rspack/resolver-binding-linux-x64-gnu": "0.2.8", + "@rspack/resolver-binding-linux-x64-musl": "0.2.8", + "@rspack/resolver-binding-wasm32-wasi": "0.2.8", + "@rspack/resolver-binding-win32-arm64-msvc": "0.2.8", + "@rspack/resolver-binding-win32-ia32-msvc": "0.2.8", + "@rspack/resolver-binding-win32-x64-msvc": "0.2.8" + } + }, + "node_modules/@rspack/resolver-binding-darwin-arm64": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver-binding-darwin-arm64/-/resolver-binding-darwin-arm64-0.2.8.tgz", + "integrity": "sha512-nTnK17kmxXEvR+WpOIZPSIzUFYeWCHoffgU9tvOLOwuTBH41kWnSQXXWu+AiMVwvJ6wdRO6Vo30hPhlXEG7Pyw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/resolver-binding-darwin-x64": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver-binding-darwin-x64/-/resolver-binding-darwin-x64-0.2.8.tgz", + "integrity": "sha512-Aqr4TK2rA6XVYUOmM5YCtYyCMZhOIR53P4cOGgGARg99A7OuMBMzUL4r1n0M0Fx35v6/sSx1OBe+odHmPxksEg==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rspack/resolver-binding-linux-arm64-gnu": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver-binding-linux-arm64-gnu/-/resolver-binding-linux-arm64-gnu-0.2.8.tgz", + "integrity": "sha512-wGvkxm2G4mNTztslaOzLzx5JuySQSy5DcOWEZxHcjJJzp5L3ODbYLK18HtUc6cvmaVOmjaGrrYPrqJJ0hHTVFg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/resolver-binding-linux-arm64-musl": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver-binding-linux-arm64-musl/-/resolver-binding-linux-arm64-musl-0.2.8.tgz", + "integrity": "sha512-EqRJ9zLQsLAvyDKJKVZ45BSqRIMS12f5HtJdy3KkAHU14ZmsGv8e5IKkwUZN5CNBRad8xVlOMMx3dOfF4whJzg==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/resolver-binding-linux-x64-gnu": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver-binding-linux-x64-gnu/-/resolver-binding-linux-x64-gnu-0.2.8.tgz", + "integrity": "sha512-eXbeotNCTntL4/+mxJRVCxK63YeWzTfp0F3POeHJFSs6Nt0f2J/mZNFlasJmd6xm7zvE80h/HWOwbwjRBLcElA==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/resolver-binding-linux-x64-musl": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver-binding-linux-x64-musl/-/resolver-binding-linux-x64-musl-0.2.8.tgz", + "integrity": "sha512-KWFHlOWGkT+eMngoUgPGXrDi+rU04VCh9jyk0U6Ot2RTWvhGxwKykjmLS+CWZI/EBrzr9A6g2U3jzKTMNz9oCw==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "MIT", + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rspack/resolver-binding-wasm32-wasi": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver-binding-wasm32-wasi/-/resolver-binding-wasm32-wasi-0.2.8.tgz", + "integrity": "sha512-I6GIhgICFViE88jejIV74oiiWHnpLpQ5ogaZM1ozM9KDnfqcHoX0IVEyrIh5KqA8iLDyhuoFSW+Hf0qN7VTBBQ==", + "cpu": [ + "wasm32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "@napi-rs/wasm-runtime": "^1.1.1" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/@rspack/resolver-binding-win32-arm64-msvc": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver-binding-win32-arm64-msvc/-/resolver-binding-win32-arm64-msvc-0.2.8.tgz", + "integrity": "sha512-ZXCt3qUfDAEbtc2sHpvxM7lNFZM+DxfblgXUIl3Jy6BuEZbHe1i6z+t9c34ayHoGTVbVSNCtaYuG/MaWdSnPHw==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/resolver-binding-win32-ia32-msvc": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver-binding-win32-ia32-msvc/-/resolver-binding-win32-ia32-msvc-0.2.8.tgz", + "integrity": "sha512-2LRymjDK8MpUERD8CL0PPae5y2crU5TAg4T4EzpeL5jLARVq6izsEruiWzB6Y+D15vUYlvmgs2370GXVSB861w==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rspack/resolver-binding-win32-x64-msvc": { + "version": "0.2.8", + "resolved": "https://registry.npmjs.org/@rspack/resolver-binding-win32-x64-msvc/-/resolver-binding-win32-x64-msvc-0.2.8.tgz", + "integrity": "sha512-hzRpfbtvv4M4EVrKKIAaHDs5wT8lVcbSUjtwPs5u4IeLEix45nQPQ6ZQjmE4lIH0GP/3L3XQhZroYmTcH/xdsQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "MIT", + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rstest/adapter-rspack": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@rstest/adapter-rspack/-/adapter-rspack-0.11.6.tgz", + "integrity": "sha512-vXmlLqz66OZ3mqI0I0rwMShrRUY4t3CXApn25n5IY3Tfco/Hit+2tCYmZD2Eut1AS1f4762Wtjgov5PkBM55YQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@rspack/cli": "^2.0.0", + "@rspack/core": "^2.0.0", + "@rstest/core": "^0.11.0" + } + }, + "node_modules/@rstest/browser": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@rstest/browser/-/browser-0.11.6.tgz", + "integrity": "sha512-X9C2M0pU35w6pYjDz1TnbJ2zzpAqOw+wKKqwzvJ56gefW6e7QwLlmIgkpJbX4KmN1rjYw2nOll7mQiIG61Xh9Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/trace-mapping": "0.3.31", + "convert-source-map": "^2.0.0", + "open-editor": "^6.0.0", + "pathe": "^2.0.3", + "sirv": "^3.0.2", + "ws": "^8.21.1" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rstest/core": "0.11.6", + "playwright": "^1.49.1" + }, + "peerDependenciesMeta": { + "playwright": { + "optional": true + } + } + }, + "node_modules/@rstest/browser-react": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@rstest/browser-react/-/browser-react-0.11.6.tgz", + "integrity": "sha512-mMiw1KSPFp6LbNB6dS7OJfKkVDJiiKsechKEr7JNRWVptUOIoFMW8dJyZ2ufUUHyNJ5XHVn7ikB3oFH2AUv7Ug==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rstest/core": "^0.11.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + } + }, + "node_modules/@rstest/core": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@rstest/core/-/core-0.11.6.tgz", + "integrity": "sha512-P3wgYGDF3JmhapwN3p4DnbNV9N6+E+dlbp0coT1lAuXN5Po6bHeP/rduGLsTUIX85qWxmJD7ekF7nlOKm9RoOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@rsbuild/core": "~2.1.9", + "@types/chai": "^5.2.3" + }, + "bin": { + "rstest": "bin/rstest.js" + }, + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "happy-dom": "^20.8.3", + "jsdom": ">=15.0.0" + }, + "peerDependenciesMeta": { + "happy-dom": { + "optional": true + }, + "jsdom": { + "optional": true + } + } + }, + "node_modules/@rstest/coverage-istanbul": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@rstest/coverage-istanbul/-/coverage-istanbul-0.11.6.tgz", + "integrity": "sha512-FvJf9EKLp7jxidaxHSY6HiPlDtQLHAATtG3HdxE3Je3aazp10Je4bjh9vmRDqOquaRIhMZgpLanENS6vA8P+HQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "istanbul-lib-coverage": "^3.2.2", + "istanbul-lib-report": "^3.0.1", + "istanbul-lib-source-maps": "^5.0.6", + "istanbul-reports": "^3.2.0", + "swc-plugin-coverage-instrument": "0.0.32" + }, + "peerDependencies": { + "@rstest/core": "^0.11.0" + } + }, + "node_modules/@rstest/playwright": { + "version": "0.11.6", + "resolved": "https://registry.npmjs.org/@rstest/playwright/-/playwright-0.11.6.tgz", + "integrity": "sha512-wsux9yY62UEyGfP4j0GZ1kv61LJ5lSZEvVmn6uNDXL+sQYKib0UM8ZWtZVPwFGIlpQcWST2RslmVW9A0QerItQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + }, + "peerDependencies": { + "@rstest/core": "^0.11.6", + "playwright": "^1.49.1" + } + }, + "node_modules/@sec-ant/readable-stream": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz", + "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@sindresorhus/merge-streams": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz", + "integrity": "sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@smithy/core": { + "version": "3.34.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-3.34.1.tgz", + "integrity": "sha512-dLcOUxz8YCv1RZUMKq6GbyUf95pLbrqh34bPvpCZ1+CByFF31BEAFewZjsGCnVsZTKdThNENfGyAgk2TJqVwSw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/types": "^4.18.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/credential-provider-imds": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-4.5.2.tgz", + "integrity": "sha512-A9uSdn72ozbRUSit0eib0TW7nXuNPlaeM0zcGkJ+nE6tFcSDbnmtwoxbTCFBukVQcszDAyvsd7+rTduPTXpygg==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/core": "^3.33.2", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/fetch-http-handler": { + "version": "5.8.0", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-5.8.0.tgz", + "integrity": "sha512-ycSJu3tFAQ4v04CBB0agqFMVsSQ1iG3yw+SpgxRqKfaURpQD4CZ8Wn0zPMmSnOuTpTh65Vz+EA0rMrw089wvkA==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.18.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/node-http-handler": { + "version": "4.12.1", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-4.12.1.tgz", + "integrity": "sha512-ThMkboGeONWXAelq9FvGsuJC4rOi+qyC4/zhUF58xYpxUg5sQKx2VXZYJmtNjr4dSuBJ1HeJXETQILCz3wOHvw==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.18.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-5.7.3.tgz", + "integrity": "sha512-7ImGm+FkHRLcBaRttIAMZ6bzJZWb2cJGoYjq46F2UjycujWzrL9GEN9h4w7eQyXJYnltrUhxbbieBAIRrdqpow==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "@smithy/core": "^3.33.3", + "@smithy/types": "^4.17.2", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@smithy/types": { + "version": "4.18.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-4.18.0.tgz", + "integrity": "sha512-CgB6HHWer/vrKps24ulRIbpcpb7K4xAU7SkZ7YHzBPlwHsvsrCJFEXK421s+cJzX+ZrqtA/TuU5w1HzI7k9N8A==", + "dev": true, + "license": "Apache-2.0", + "optional": true, + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=18.0.0" + } + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", + "integrity": "sha512-9BCxFwvbGg/RsZK9tjXd8s4UcwR0MWeFQ1XEKIQVVvAGJyINdrqKMcTRyLoK8Rse1GjzLV9cwjWV1olXRWEXVA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@swc/core": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.16.2.tgz", + "integrity": "sha512-95I4kiSMeveI/Mhi+tE4fiWcWLUMfzfKrk0jtr8LRMqHgOgq+xHS+zExkDqoO4b5OeeuXHMWVdD5MeP3X6sULw==", + "dev": true, + "hasInstallScript": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3", + "@swc/types": "^0.1.28" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/swc" + }, + "optionalDependencies": { + "@swc/core-darwin-arm64": "1.16.2", + "@swc/core-darwin-x64": "1.16.2", + "@swc/core-linux-arm-gnueabihf": "1.16.2", + "@swc/core-linux-arm64-gnu": "1.16.2", + "@swc/core-linux-arm64-musl": "1.16.2", + "@swc/core-linux-ppc64-gnu": "1.16.2", + "@swc/core-linux-s390x-gnu": "1.16.2", + "@swc/core-linux-x64-gnu": "1.16.2", + "@swc/core-linux-x64-musl": "1.16.2", + "@swc/core-win32-arm64-msvc": "1.16.2", + "@swc/core-win32-ia32-msvc": "1.16.2", + "@swc/core-win32-x64-msvc": "1.16.2" + }, + "peerDependencies": { + "@swc/helpers": ">=0.5.17" + }, + "peerDependenciesMeta": { + "@swc/helpers": { + "optional": true + } + } + }, + "node_modules/@swc/core-darwin-arm64": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-arm64/-/core-darwin-arm64-1.16.2.tgz", + "integrity": "sha512-i/j0HNbnn79qnTVPicvay92Nark8fW8NQqn1e2mGERjUXNpBV0+SwQxlRpk2zBhn6laJ8PDI6Kn1nHZhnz3LCA==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-darwin-x64": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-darwin-x64/-/core-darwin-x64-1.16.2.tgz", + "integrity": "sha512-HrwqHyEyHVXO3qTk8EkNK7/b6sOZSEoNh+pot6RdE5x0LbNqfo8LtJUvi3UTXr+5ja/o5HbJdW80eCXo+NjbiA==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm-gnueabihf": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm-gnueabihf/-/core-linux-arm-gnueabihf-1.16.2.tgz", + "integrity": "sha512-MdXi83Z/gGp1LIrg+h7HKxiul/z/Bty/ZJSvYAFqDl9zteC1XLSAZdScquKtXPp50rdyXqritTDCqQBhwVfZKA==", + "cpu": [ + "arm" + ], + "dev": true, + "license": "Apache-2.0", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-gnu": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-gnu/-/core-linux-arm64-gnu-1.16.2.tgz", + "integrity": "sha512-/jcTmK6Ktz3owM3YtiKvjofV6p3VpHnYzTIrOGwDIOsDigRAAVuZ8east33wYO/7UTdKYFlyHNnJNT0WJqOA3Q==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-arm64-musl": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-arm64-musl/-/core-linux-arm64-musl-1.16.2.tgz", + "integrity": "sha512-4gFarKaFnlJTSlJYKmMhV4u+3YE4uYfiydpBoYjmgQhCf9lAieOq+WilZaK9vVSHeqLuQpTEiGULZqAdsRX5Dw==", + "cpu": [ + "arm64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-ppc64-gnu": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-ppc64-gnu/-/core-linux-ppc64-gnu-1.16.2.tgz", + "integrity": "sha512-syqSLGd6KlZ1PciNzs6bIUlhOuFztZufebOHaERjc4N4SqNZxyqYd4I+jj/EfOYnpe0kNjccn9HJLN1p5dz3+w==", + "cpu": [ + "ppc64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-s390x-gnu": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-s390x-gnu/-/core-linux-s390x-gnu-1.16.2.tgz", + "integrity": "sha512-ZBBLK+ewGyXLzWeMS7wbKtWBdnif6etn7xvPY/iOfbdsjX/+bgkp1pQt2lWF2wlu2hXYZuhJ/tHZE/QR8/apzg==", + "cpu": [ + "s390x" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-gnu": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-gnu/-/core-linux-x64-gnu-1.16.2.tgz", + "integrity": "sha512-LyHJgxCA4Tje0ysBMbEb0tt/ie8kgUKoFE3JAKFhpevmTmhYEoC0H9s47WuDsqiFckF1ITUguZIXJG6K5e0dvg==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "glibc" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-linux-x64-musl": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-linux-x64-musl/-/core-linux-x64-musl-1.16.2.tgz", + "integrity": "sha512-PghXJlVM1cgtLfNUR1vxFo1z+PDRAe8cWAJlZZ7spmeiN7BospGXg/MHUg7oNSgwSX7Zo//YKv9P5yD9apsFJQ==", + "cpu": [ + "x64" + ], + "dev": true, + "libc": [ + "musl" + ], + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-arm64-msvc": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-arm64-msvc/-/core-win32-arm64-msvc-1.16.2.tgz", + "integrity": "sha512-StTOSefYBxemvNYYUI3UmO1a8y+hSPjjfHogC2TEHL+Z1PlEBim/XtLas5rS04jAzT9RrNmbtX911SZ42H9jSQ==", + "cpu": [ + "arm64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-ia32-msvc": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-ia32-msvc/-/core-win32-ia32-msvc-1.16.2.tgz", + "integrity": "sha512-fycER209DYIzsibpTMC+chND05OfOjgztWL9U8OE6/uUlsOUZH3eh98isBLEnOymYUhlJLEt5++W1+KL/FOh5Q==", + "cpu": [ + "ia32" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/core-win32-x64-msvc": { + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/@swc/core-win32-x64-msvc/-/core-win32-x64-msvc-1.16.2.tgz", + "integrity": "sha512-cSd1z6ivSrJPVr+moVwOHWjeKy6TpO4/Shwcv5KCrKYXCccxwh4pRy1C3fDioNx2PF1jPZWHKZjtXt+Be9VbaQ==", + "cpu": [ + "x64" + ], + "dev": true, + "license": "Apache-2.0 AND MIT", + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=10" + } + }, + "node_modules/@swc/counter": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz", + "integrity": "sha512-e2BR4lsJkkRlKZ/qCHPw9ZaSxc0MVUd7gtbtaB7aMvHeJVYe8sOB8DBZkP2DtISHGSku9sCK6T6cnY0CtXrOCQ==", + "dev": true, + "license": "Apache-2.0" + }, + "node_modules/@swc/helpers": { + "version": "0.5.23", + "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.23.tgz", + "integrity": "sha512-5lSsMOTXURePglDfvuAQUqkGek9Hg2kksOYay2m0+XR++b2NWYL/4sWyuvVBIs8oKnJaxkdi9whaL/sqN13afw==", + "license": "Apache-2.0", + "dependencies": { + "tslib": "^2.8.0" + } + }, + "node_modules/@swc/types": { + "version": "0.1.28", + "resolved": "https://registry.npmjs.org/@swc/types/-/types-0.1.28.tgz", + "integrity": "sha512-V6Mnml8v09QALx6K0elJ7o9K/MkVDtW3t6L+7Ou/JcWtb3xwId2AH4FeOceySd2JaO87IMw4+6vSZxLm34LPbw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@swc/counter": "^0.1.3" + } + }, + "node_modules/@testing-library/dom": { + "version": "10.4.2", + "resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.2.tgz", + "integrity": "sha512-yzr2S9HyAIdhz2/6qHgbs665Q7PKVcDF05vsOlHPxG1mo36gKVesdYVeDLnXgfjJ03CrKRk08knc6+E/9m8v2Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.10.4", + "@babel/runtime": "^7.12.5", + "@types/aria-query": "^5.0.1", + "aria-query": "5.3.0", + "dom-accessibility-api": "^0.5.9", + "lz-string": "^1.5.0", + "picocolors": "1.1.1", + "pretty-format": "^27.0.2" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/@testing-library/react": { + "version": "16.3.3", + "resolved": "https://registry.npmjs.org/@testing-library/react/-/react-16.3.3.tgz", + "integrity": "sha512-Uo193NgQbPMz6lrrhtRQQFcMC6Re/ELLFbbuVL30WDlZxlpZf9/lMHTAVxPRLw1q1iu9OJmR1c2BLiENRstdBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/runtime": "^7.12.5" + }, + "engines": { + "node": ">=18" + }, + "peerDependencies": { + "@testing-library/dom": "^10.0.0", + "@types/react": "^18.0.0 || ^19.0.0", + "@types/react-dom": "^18.0.0 || ^19.0.0", + "react": "^18.0.0 || ^19.0.0", + "react-dom": "^18.0.0 || ^19.0.0" + }, + "peerDependenciesMeta": { + "@types/react": { + "optional": true + }, + "@types/react-dom": { + "optional": true + } + } + }, + "node_modules/@testing-library/user-event": { + "version": "14.6.7", + "resolved": "https://registry.npmjs.org/@testing-library/user-event/-/user-event-14.6.7.tgz", + "integrity": "sha512-MPCpX8bxe8zS+JmmTwLp8jd0dy1rAm60Te/SL8JrQM3qvQJcBOs1d7IefJMyZzqM3EWBrDn/LWDt1BCGu4ASfg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12", + "npm": ">=6" + }, + "peerDependencies": { + "@testing-library/dom": ">=7.21.4" + } + }, + "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" + } + }, + "node_modules/@types/aria-query": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@types/aria-query/-/aria-query-5.0.4.tgz", + "integrity": "sha512-rfT93uj5s0PRL7EzccGMs3brplhcrghnDoV26NqKhCAS1hVo+WdNsPvE/yb6ilfr5hi2MEk6d5EWJTKdxg8jVw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/chai": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/@types/chai/-/chai-5.2.3.tgz", + "integrity": "sha512-Mw558oeA9fFbv65/y4mHtXDs9bPnFMZAL/jxdPFUpOHHIXX91mcgEHbS5Lahr+pwZFR8A7GQleRWeI6cGFC2UA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/deep-eql": "*", + "assertion-error": "^2.0.1" + } + }, + "node_modules/@types/connect": { + "version": "3.4.38", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", + "integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cors": { + "version": "2.8.19", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.19.tgz", + "integrity": "sha512-mFNylyeyqN93lfe/9CSxOGREz8cpzAhH+E93xJ4xWQf62V8sQ/24reV2nyzUWM6H6Xji+GGHpkbLe7pVoUEskg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/deep-eql": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/@types/deep-eql/-/deep-eql-4.0.2.tgz", + "integrity": "sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/jquery": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/@types/jquery/-/jquery-4.0.1.tgz", + "integrity": "sha512-9a59A/tycXgYuPABcp6/3spSShn0NT2UOM4EfHvMumjYi4lJWTsK5SZWjhx3yRm9IHGCeWXdV2YfNsrWrft/CA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@types/meteor": { + "version": "2.9.11", + "resolved": "https://registry.npmjs.org/@types/meteor/-/meteor-2.9.11.tgz", + "integrity": "sha512-GeqwF7eLnauPVVtLrANRIJegFpnATEujF9uE6ElW1DCMaZWzaXzPAPPKln5b01xC2QUHLGOWgpkPUS5fHtM1HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/connect": "*", + "@types/jquery": "*", + "@types/node": "*", + "@types/nodemailer": "*", + "@types/react": "*", + "@types/underscore": "*", + "mongodb": "^4.3.1" + } + }, + "node_modules/@types/node": { + "version": "24.13.6", + "resolved": "https://registry.npmjs.org/@types/node/-/node-24.13.6.tgz", + "integrity": "sha512-SGrw/h3KPFshy3OE6ZL53LMBG5vGQQ8/gIpiqz/kRZhPJ7HgwCEs8LBuNtWLa8dvGZVpSF7+Bf+c11HUrCb/yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "undici-types": "~7.18.0" + } + }, + "node_modules/@types/nodemailer": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@types/nodemailer/-/nodemailer-8.0.2.tgz", + "integrity": "sha512-c7M5ox8p0nEOfbJ2E9Qcmt8/QCu/VzsiAhzBiZbvky2PhKZDHpKB3sQHBM5MEZNkCfBOaS6S9//AGPRTNB7IaA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/react": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.3.0.tgz", + "integrity": "sha512-N0rFCuH9YoxG9/m61l9MfpJKfmLOVU0em7ipIz6TRgSSkvReLB9vL85GB+yr8Bs5leqpvg96JSwF4ZS1s4viQg==", + "dev": true, + "license": "MIT", + "dependencies": { + "csstype": "^3.2.2" + } + }, + "node_modules/@types/react-dom": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-ZI7bU42mZXXKHn/qNLEw2IrbiINU7X5+vfgdixBHkCNpYWXjKgfQ/P+uyGb5CjOLB9UcnTeg3rylQtV2hym44Q==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "@types/react": "^19.3.0" + } + }, + "node_modules/@types/tapable": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@types/tapable/-/tapable-2.3.0.tgz", + "integrity": "sha512-oMnbAXeVo+KUnje3hzdORXUbfnzTfqD0H92mLl19NE5hFqH9Q4ktq+xehNSxcNeeLm1COopYwa0zeP6Iz+oIXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "tapable": "^2.3.0" + } + }, + "node_modules/@types/underscore": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/@types/underscore/-/underscore-1.13.0.tgz", + "integrity": "sha512-L6LBgy1f0EFQZ+7uSA57+n2g/s4Qs5r06Vwrwn0/nuK1de+adz00NWaztRQ30aEqw5qOaWbPI8u2cGQ52lj6VA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/webidl-conversions": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@types/webidl-conversions/-/webidl-conversions-7.0.3.tgz", + "integrity": "sha512-CiJJvcRtIgzadHCYXw7dqEnMNRjhGZlYK05Mj9OyktqV8uVT8fD2BFOB7S1uwBE3Kj2Z+4UyPmFw/Ixgw/LAlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/@types/whatwg-url": { + "version": "8.2.2", + "resolved": "https://registry.npmjs.org/@types/whatwg-url/-/whatwg-url-8.2.2.tgz", + "integrity": "sha512-FtQu10RWgn3D9U4aazdwIE2yzphmTJREDqNdODHrbrZmmMqI0vMheC/6NE/J1Yveaj8H+ela+YwWTjq5PGmuhA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*", + "@types/webidl-conversions": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.18.1", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz", + "integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.14.1.tgz", + "integrity": "sha512-nuBEDgQfm1ccRp/8bCQrx1frohyufl4JlbMMZ4P1wpeOfDhF6FQkxZJ1b/e+PLwr6X1Nhw6OLme5usuBWYBvuQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/helper-numbers": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.13.2.tgz", + "integrity": "sha512-6oXyTOzbKxGH4steLbLNOu71Oj+C8Lg34n6CqRvqfS2O71BxY6ByfMDRhBytzknj9yGUPVJ1qIKhRlAwO1AovA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.13.2.tgz", + "integrity": "sha512-U56GMYxy4ZQCbDZd6JuvvNV/WFildOjsaWD3Tzzvmw/mas3cXzRJPMjP83JqEsgSbyrmaGjBfDtV7KDXV9UzFQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.14.1.tgz", + "integrity": "sha512-jyH7wtcHiKssDtFPRB+iQdxlDf96m0E39yb0k5uJVhFGleZFoNw1c4aeIcVUPPbXUVJ94wwnMOAqUHyzoEPVMA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.13.2.tgz", + "integrity": "sha512-FE8aCmS5Q6eQYcV3gI35O4J789wlQA+7JrqTTpJqn5emA4U2hvwJmvFRC0HODS+3Ye6WioDklgd6scJ3+PLnEA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.13.2", + "@webassemblyjs/helper-api-error": "1.13.2", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.13.2.tgz", + "integrity": "sha512-3QbLKy93F0EAIXLh0ogEVR6rOubA9AoZ+WRYhNbFyuB70j3dRdwH9g+qXhLAO0kiYGlg3TxDV+I4rQTr/YNXkA==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.14.1.tgz", + "integrity": "sha512-ds5mXEqTJ6oxRoqjhWDU83OgzAYjwsCV8Lo/N+oRsNDmx/ZDpqalmrtgOMkHwxsG0iI//3BwWAErYRHtgn0dZw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/wasm-gen": "1.14.1" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.13.2.tgz", + "integrity": "sha512-4LtOzh58S/5lX4ITKxnAK2USuNEvpdVV9AlgGQb8rJDHaLeHciwG4zlGr0j/SNWlr7x3vO1lDEsuePvtcDNCkw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.13.2.tgz", + "integrity": "sha512-Lde1oNoIdzVzdkNEAWZ1dZ5orIbff80YPdHx20mrHwHrVNNTjNr8E3xz9BdpcGqRQbAEa+fkrCb+fRFTl/6sQw==", + "dev": true, + "license": "Apache-2.0", + "peer": true, + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.13.2.tgz", + "integrity": "sha512-3NQWGjKTASY1xV5m7Hr0iPeXD9+RDobLll3T9d2AO+g3my8xy5peVyjSag4I50mR1bBSN/Ct12lo+R9tJk0NZQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.14.1.tgz", + "integrity": "sha512-RNJUIQH/J8iA/1NzlE4N7KtyZNHi3w7at7hDjvRNm5rcUXa00z1vRz3glZoULfJ5mpvYhLybmVcwcjGrC1pRrQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/helper-wasm-section": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-opt": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1", + "@webassemblyjs/wast-printer": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.14.1.tgz", + "integrity": "sha512-AmomSIjP8ZbfGQhumkNvgC33AY7qtMCXnN6bL2u2Js4gVCg8fp735aEiMSBbDR7UQIj90n4wKAFUSEd0QN2Ukg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.14.1.tgz", + "integrity": "sha512-PTcKLUNvBqnY2U6E5bdOQcSM+oVP/PmrDY9NzowJjislEjwP/C4an2303MCVS2Mg9d3AJpIGdUFIQQWbPds0Sw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-buffer": "1.14.1", + "@webassemblyjs/wasm-gen": "1.14.1", + "@webassemblyjs/wasm-parser": "1.14.1" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.14.1.tgz", + "integrity": "sha512-JLBl+KZ0R5qB7mCnud/yyX08jWFw5MsoalJ1pQ4EdFlgj9VdXKGuENGsiCIjegI1W7p91rUlcB/LB5yRJKNTcQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@webassemblyjs/helper-api-error": "1.13.2", + "@webassemblyjs/helper-wasm-bytecode": "1.13.2", + "@webassemblyjs/ieee754": "1.13.2", + "@webassemblyjs/leb128": "1.13.2", + "@webassemblyjs/utf8": "1.13.2" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.14.1.tgz", + "integrity": "sha512-kPSSXE6De1XOR820C90RIo2ogvZG+c3KiHzqUoO/F34Y2shGzesfqv7o57xrxovZJH/MetF5UjroJ/R/3isoiw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@webassemblyjs/ast": "1.14.1", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true, + "license": "Apache-2.0", + "peer": true + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.18.0.tgz", + "integrity": "sha512-lGq+9yr1/GuAWaVYIHRjvvySG5/4VfKIvC8EWxStPdcDh/Ka7FG3twP6v4d5BkravUilhIAsG4Qj83t02LWUPQ==", + "dev": true, + "license": "MIT", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-import-attributes": { + "version": "1.9.5", + "resolved": "https://registry.npmjs.org/acorn-import-attributes/-/acorn-import-attributes-1.9.5.tgz", + "integrity": "sha512-n02Vykv5uA3eHGM/Z2dQrcD56kL8TyDb2p1+0P83PClMnC/nc+anbQRhIOWnSq4Ke/KvDPrY3C9hDtC/A3eHnQ==", + "dev": true, + "license": "MIT", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/acorn-walk": { + "version": "8.3.5", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.5.tgz", + "integrity": "sha512-HEHNfbars9v4pgpW6SO1KSPkfoS0xVOM/9UzkJltjlsHZmJasxg8aXkuZa7SMf8vKGIBhpUsPluQSqhJFCqebw==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ajv": { + "version": "8.20.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.20.0.tgz", + "integrity": "sha512-Thbli+OlOj+iMPYFBVBfJ3OmCAnaSyNn4M1vz9T6Gka5Jt9ba/HIR56joy65tY6kx/FCF5VXNB819Y7/GUrBGA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3", + "fast-uri": "^3.0.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-3.0.1.tgz", + "integrity": "sha512-8iUql50EUR+uUcdRQ3HDqa6EVyo3docL8g5WJ3FNcWmu62IbkGUue/pEyLBW8VGKKucTPgqeks4fIU1DA4yowQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/aria-query": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz", + "integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "dequal": "^2.0.3" + } + }, + "node_modules/asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", + "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/assert": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz", + "integrity": "sha512-eLHpSK/Y4nhMJ07gDaAzoX/XAKS8PSaojml3M0DM4JpV1LAi5JOJ/p6H/XWrl8L+DzVEvVCW1z3vWAaB9oTsQw==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "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/babel-plugin-istanbul": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-7.0.1.tgz", + "integrity": "sha512-D8Z6Qm8jCvVXtIRkBnqNHX0zJ37rQcFJ9u8WOS6tkYOsRdHBzypCstaxWiu5ZIlqQtviRYbgnRLSoCEvjqcqbA==", + "dev": true, + "license": "BSD-3-Clause", + "workspaces": [ + "test/babel-8" + ], + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-instrument": "^6.0.2", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true, + "license": "MIT" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/baseline-browser-mapping": { + "version": "2.11.25", + "resolved": "https://registry.npmjs.org/baseline-browser-mapping/-/baseline-browser-mapping-2.11.25.tgz", + "integrity": "sha512-gMmEShwwq7FJqMwvfRwvCl00v4kN+KOfJqXn+f4nrufak5gNHJOksd/60Dvjuz7sI8Y5WiSFBa8FEYr+zoyqCw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "baseline-browser-mapping": "dist/cli.cjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/bidi-js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.1.0.tgz", + "integrity": "sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==", + "dev": true, + "license": "MIT", + "dependencies": { + "require-from-string": "^2.0.2" + } + }, + "node_modules/bn.js": { + "version": "5.2.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.5.tgz", + "integrity": "sha512-Vq886eXykuP5E6HcKSSStP3bJgrE6In5WKxVUvJ8XGpWWYs2xZHWqUwzCtGgEtBcxyd57KBFDPFoUfNzdaHCNg==", + "dev": true, + "license": "MIT" + }, + "node_modules/bowser": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.14.1.tgz", + "integrity": "sha512-tzPjzCxygAKWFOJP011oxFHs57HzIhOEracIgAePE4pqB3LikALKnSzUyU4MGs9/iCEUuHlAJTjTc5M+u7YEGg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "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==", + "dev": true, + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==", + "dev": true, + "license": "MIT" + }, + "node_modules/browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "resolve": "^1.17.0" + } + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz", + "integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.6", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.6.tgz", + "integrity": "sha512-sd+Q65fjlWCYWtZKXiKfrUc8d+4jtp/8f0W2NkwzLtoW4bI6UDnWusLWIurHnmurW0XShIRxpwiOX4EoPtXUAg==", + "dev": true, + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.3", + "browserify-rsa": "^4.1.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.6.1", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.9", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/browserify-sign/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-sign/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserslist": { + "version": "4.29.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.29.0.tgz", + "integrity": "sha512-3GSvyjvDI4Dur1Meg2BekJquu5uF+9R9a1+5M1Mde192eZoXbeXjzgOsgqPS2V8D5wrrip0gR5Hf/GhWQ9ZzaA==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "baseline-browser-mapping": "^2.11.23", + "caniuse-lite": "^1.0.30001810", + "electron-to-chromium": "^1.5.427", + "node-releases": "^2.0.55", + "update-browserslist-db": "^1.3.3" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/browserslist-load-config": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/browserslist-load-config/-/browserslist-load-config-1.0.3.tgz", + "integrity": "sha512-boNaPS4KlW6AITZQ60G+1oDJLuxauljDd7QNQFOYpRtldzcTDknMZ8awbwI0BT/8h1/Y/CG4k/tDOLip9lAGcg==", + "dev": true, + "license": "MIT" + }, + "node_modules/browserslist-to-es-version": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/browserslist-to-es-version/-/browserslist-to-es-version-1.4.2.tgz", + "integrity": "sha512-3NV13pCv0wmPxxZZcekHAG6vt8rQ94w2c4/UBe3ZU3NDUm5TP+QFK3rjS6XeKWSHWpnPYNfQzlhnljka0BrEOA==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserslist": "^4.28.2" + }, + "bin": { + "browserslist-to-es-version": "dist/cli.js" + } + }, + "node_modules/bson": { + "version": "4.7.2", + "resolved": "https://registry.npmjs.org/bson/-/bson-4.7.2.tgz", + "integrity": "sha512-Ry9wCtIZ5kGqkJoi6aD8KjxFZEx78guTQDnpXWiNthsxzrxAK/i8E6pCHAIZTbaEFWcOCvbecMukfK7XUvyLpQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "buffer": "^5.6.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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", + "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/call-bound": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/call-bound/-/call-bound-1.0.4.tgz", + "integrity": "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001810", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz", + "integrity": "sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "CC-BY-4.0" + }, + "node_modules/chrome-trace-event": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.4.tgz", + "integrity": "sha512-rNjApaLzuwaOTjCiT8lSDdGN1APCiqkChLMJxJPWLunPAt5fy8xgU9/jNOchV84wfIxrA0lRQB7oCT8jrn/wrQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=6.0" + } + }, + "node_modules/cipher-base": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.7.tgz", + "integrity": "sha512-Mz9QMT5fJe7bKI7MH31UilT5cEK5EHHRCccw/YRFsRY47AuNgaV6HY3rscp0/I4Q+tTW/5zoqpSeRRI54TkDWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true, + "license": "MIT" + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/cookie": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/core-util-is": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz", + "integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cors": { + "version": "2.8.6", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.6.tgz", + "integrity": "sha512-tJtZBBHA6vjIAaF6EnIaq6laBBP9aq/Y3ouVJjEfoHbRBcHBAHYcMh/w8LDrk2PvIMMq8gmopa5D4V8RmbrxGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/express" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", + "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/cross-spawn": { + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.1", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz", + "integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "browserify-cipher": "^1.0.1", + "browserify-sign": "^4.2.3", + "create-ecdh": "^4.0.4", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/css-tree": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-3.2.1.tgz", + "integrity": "sha512-X7sjQzceUhu1u7Y/ylrRZFU2FS6LRiFVp6rKLPg23y3x3c3DOKAwuXGDp+PAGjh6CSnCjYeAul8pcT8bAl+lSA==", + "dev": true, + "license": "MIT", + "dependencies": { + "mdn-data": "2.27.1", + "source-map-js": "^1.2.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, + "node_modules/csstype": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz", + "integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/data-urls": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-7.0.0.tgz", + "integrity": "sha512-23XHcCF+coGYevirZceTVD7NdJOqVn+49IHyxgszm+JIiHLoB2TkmPtsYkNWT1pvRSGkc35L6NHs0yHkN2SumA==", + "dev": true, + "license": "MIT", + "dependencies": { + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decimal.js": { + "version": "10.6.0", + "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.6.0.tgz", + "integrity": "sha512-YpgQiITW3JXGntzdUmyUR1V812Hn8T1YVXhCu+wO3OpS4eU9l4YdD3qjyiKdV6mvV29zapkMeD390UVEf2lkUg==", + "dev": true, + "license": "MIT" + }, + "node_modules/deep-eql": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.4.tgz", + "integrity": "sha512-SUwdGfqdKOwxCPeVYjwSyRpJ7Z+fhpwIAtmCUdZIWZ/YP5R9WAsyuSgpLVDi9bjWoN2LXHNss/dk3urXtdQxGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/default-browser": { + "version": "5.5.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.5.1.tgz", + "integrity": "sha512-m1pAzaJgZ/gssEqlOhJkPJp8Xly7QyW6xcrkUa2KKcDeDSEMP7X8xipU3snUcfisTQx0w1AGae+9UtJSfVnXGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.1.tgz", + "integrity": "sha512-x1VCxdX4t+8wVfd1so/9w+vQ4vx7lKd2Qp5tDRutErwmR85OgmfX7RlLRMWafRMY7hbEiXIbudNrjOAPa/hL8Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/dequal": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", + "integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/des.js": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz", + "integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", + "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-accessibility-api": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/dom-accessibility-api/-/dom-accessibility-api-0.5.16.tgz", + "integrity": "sha512-X7BJ2yElsnOJ30pZF4uIIDfBEVgF4XEBxL9Bxhy6dnrm5hkzqmsWHGTiHqRiITNhMyFLyAiWndIJP7Z1NTteDg==", + "dev": true, + "license": "MIT" + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/dom-serializer/node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/domain-browser": { + "version": "4.22.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-4.22.0.tgz", + "integrity": "sha512-IGBwjF7tNk3cwypFNH/7bfzBcgSCbaMOD3GsaY1AU/JRrnHnYgEM0+9kQt52iZxjNsjBtJYtao146V+f8jFZNw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "BSD-2-Clause" + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domutils": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.2.2.tgz", + "integrity": "sha512-6kZKyUajlDuqlHKVX1w7gyslj9MPIXzIFiz/rGu35uC1wMi+kMhQwGhl4lt9unC9Vb9INnY9Z3/ZA3+FhASLaw==", + "dev": true, + "license": "BSD-2-Clause", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/dunder-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", + "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/electron-to-chromium": { + "version": "1.5.434", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.434.tgz", + "integrity": "sha512-7EeFW9OLf1NN9NKQP9xdOE/XKqjxv7JDPP6AEAkHli11+Fae1OaLoNuAf13hQv1PPNtuES0pLQSPk2+fS3s8ww==", + "dev": true, + "license": "ISC" + }, + "node_modules/elliptic": { + "version": "6.6.1", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz", + "integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", + "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/engine.io": { + "version": "6.6.10", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.10.tgz", + "integrity": "sha512-9/lX2bdlizlCXMHRMOIm03VBQHQYC7VvydcxtTAUJRxNW1QzM/2PMFSmr6h/lCiMHcyCP6abK+t9Q+j4vekk8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "@types/ws": "^8.5.12", + "accepts": "~1.3.4", + "cookie": "~0.7.2", + "cors": "~2.8.5", + "debug": "~4.4.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.21.0" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/engine.io-parser": { + "version": "5.2.3", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.3.tgz", + "integrity": "sha512-HqD3yTBfnBxIrbnM1DoD6Pcq8NECnh8d4As1Qgh0z5Gg3jRRIqijury0CL3ghu/edArpUYiYqQiDUQBIs4np3Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/enhanced-resolve": { + "version": "5.25.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.25.1.tgz", + "integrity": "sha512-nGXts5znJzmWPu+mIE9izCOzdg63oJca2mDzGWWTth7sr4aCToKcoyFVBQwN75Ij5Pf6p510EwkTqViTRzDV+w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.3.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/entities": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/entities/-/entities-6.0.1.tgz", + "integrity": "sha512-aN97NXWF6AWBTahfVOIrB/NShkzi5H7F9r1s9mD3cDj4Ko5f2qhhVoYMibXF7GlLveb/D2ioWay8lxI97Ven3g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-editor": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/env-editor/-/env-editor-1.3.0.tgz", + "integrity": "sha512-EqiD/j01PooUbeWk+etUo2TWoocjoxMfGNYpS9e47glIJ5r8WepycIki+LCbonFbPdwlqY5ETeSTAJVMih4z4w==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/envinfo": { + "version": "7.21.0", + "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.21.0.tgz", + "integrity": "sha512-Lw7I8Zp5YKHFCXL7+Dz95g4CcbMEpgvqZNNq3AmlT5XAV6CgAAk6gyAMqn2zjw08K9BHfcNuKrMiCPLByGafow==", + "dev": true, + "license": "MIT", + "bin": { + "envinfo": "dist/cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/es-define-property": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", + "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-2.3.2.tgz", + "integrity": "sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/es-object-atoms": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.2.tgz", + "integrity": "sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-toolkit": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/es-toolkit/-/es-toolkit-1.52.0.tgz", + "integrity": "sha512-XTNEJQh1tY1ZJVcf6ayP/2n4ZPyaHlW2FWs7xvw5ddPuhUVjLD3olQVQS7kf58JbAB48iL0uL/jerTrjtV3lDA==", + "dev": true, + "license": "MIT", + "workspaces": [ + "docs", + "benchmarks", + "tests/types", + "tests/browser-compat" + ] + }, + "node_modules/escalade": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "license": "BSD-2-Clause", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/execa": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-9.6.1.tgz", + "integrity": "sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sindresorhus/merge-streams": "^4.0.0", + "cross-spawn": "^7.0.6", + "figures": "^6.1.0", + "get-stream": "^9.0.0", + "human-signals": "^8.0.1", + "is-plain-obj": "^4.1.0", + "is-stream": "^4.0.1", + "npm-run-path": "^6.0.0", + "pretty-ms": "^9.2.0", + "signal-exit": "^4.1.0", + "strip-final-newline": "^4.0.0", + "yoctocolors": "^2.1.1" + }, + "engines": { + "node": "^18.19.0 || >=20.5.0" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/fast-uri": { + "version": "3.1.8", + "resolved": "https://registry.npmjs.org/fast-uri/-/fast-uri-3.1.8.tgz", + "integrity": "sha512-GZMtZUTNRpOVIECoXwLNZS5xUGE+mVNbTB8h/7Rwh2TFWcBQiPzTgyZi05BF9UMZKkLJv8XBRJTlU7zg8+ZfMg==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fastify" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fastify" + } + ], + "license": "BSD-3-Clause", + "peer": true + }, + "node_modules/figures": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-6.1.0.tgz", + "integrity": "sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-unicode-supported": "^2.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/filesize": { + "version": "11.0.24", + "resolved": "https://registry.npmjs.org/filesize/-/filesize-11.0.24.tgz", + "integrity": "sha512-R+YVXTiRPxjX02Ul2Ta2cCas43gjdwKaxTIxl9/7bkaAy97U4BXb31N/xXk7Kp9pIkg3o/RScNypKr6RlcZMyA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 10.8.0" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "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/fs-extra": { + "version": "11.4.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.4.0.tgz", + "integrity": "sha512-EQsFzMUJkCKGr1ePqlYADkIUmHW1s3ZXr5Yqy6wbGrfUCphpl2maM/kyOIRA2HpP3AaFQTZXD4ldjek+nccddA==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true, + "license": "ISC" + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "license": "MIT", + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "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/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-intrinsic": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", + "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-port": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/get-port/-/get-port-5.1.1.tgz", + "integrity": "sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/get-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", + "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/get-stream": { + "version": "9.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz", + "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@sec-ant/readable-stream": "^0.4.1", + "is-stream": "^4.0.1" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "deprecated": "Old versions of glob are not supported, and contain widely publicized security vulnerabilities, which have been fixed in the current version. Please update. Support for old versions may be purchased (at exorbitant rates) by contacting i@izs.me", + "dev": true, + "license": "ISC", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/gopd": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", + "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=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-symbols": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", + "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", + "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz", + "integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.4.tgz", + "integrity": "sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A==", + "dev": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/html-encoding-sniffer": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-6.0.0.tgz", + "integrity": "sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.6.0" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true, + "license": "MIT" + }, + "node_modules/htmlparser2": { + "version": "10.0.0", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-10.0.0.tgz", + "integrity": "sha512-TwAZM+zE5Tq3lrEHvOlvwgj1XLWQCtaaibSN11Q+gGBAS7Y1uZSWwXXRe4iF6OXnaq1riyQAPFOBtYc77Mxq0g==", + "dev": true, + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "license": "MIT", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.2.1", + "entities": "^6.0.0" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==", + "dev": true, + "license": "MIT" + }, + "node_modules/human-signals": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-8.0.1.tgz", + "integrity": "sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18.18.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/ignore-loader": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ignore-loader/-/ignore-loader-0.1.2.tgz", + "integrity": "sha512-yOJQEKrNwoYqrWLS4DcnzM7SEQhRKis5mB+LdKKh4cPmGYlLPR0ozRzHV5jmEk2IxptqJNQA5Cc0gw8Fj12bXA==", + "dev": true + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "deprecated": "This module is not supported, and leaks memory. Do not use it. Check out lru-cache if you want a good and tested way to coalesce async requests by a key value, which is much more comprehensive and powerful.", + "dev": true, + "license": "ISC", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ip-address": { + "version": "10.7.2", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-10.7.2.tgz", + "integrity": "sha512-7H/2gFSIitxc0hG3nOI1glS8QLo/EHBFFLk8vEUjXY/xu0AdL8jZ9U1IzO2PUm0d2D/ofQcAifb0g6OBkt8U7w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 12" + } + }, + "node_modules/is-arguments": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.2.0.tgz", + "integrity": "sha512-7bVbi0huj/wrIAOzb8U1aszg9kdi3KN/CyU19CTI7tAoZYEZoL9yCDXpbXN+uPsuWnP02cyug1gleqq+TU+YCA==", + "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-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-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "dev": true, + "license": "MIT", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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-in-ssh": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-in-ssh/-/is-in-ssh-1.0.0.tgz", + "integrity": "sha512-jYa6Q9rH90kR1vKB6NM7qqd1mge3Fx4Dhw5TVlK1MUBqhEOuCagrEHMevNuCcbECmXZ0ThXkRm+Ymr51HwEPAw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-nan": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/is-nan/-/is-nan-1.3.2.tgz", + "integrity": "sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "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-potential-custom-element-name": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz", + "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ==", + "dev": true, + "license": "MIT" + }, + "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-stream": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz", + "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-unicode-supported": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz", + "integrity": "sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-wsl": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.1.tgz", + "integrity": "sha512-e6rvdUCiQCAuumZslxRJWR/Doq4VpPR82kqclvcS0efgt430SlGIk05vdCN58+VrzgtIcfNODjozVielycD4Sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==", + "dev": true, + "license": "MIT" + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true, + "license": "ISC" + }, + "node_modules/isomorphic-timers-promises": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/isomorphic-timers-promises/-/isomorphic-timers-promises-1.0.1.tgz", + "integrity": "sha512-u4sej9B1LPSxTGKB/HiuzvEQnXH0ECYkSVQU39koSwmFAxhlEAFl9RdTvLv4TOTQUgBS5O3O5fwUxk6byBZ+IQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", + "integrity": "sha512-O8dpsF+r0WV/8MNRKfnmrtCWhuKjxrq2w+jpzBL5UZKTi2LeVWnWOmWRxFlesJONmc+wLAGvKQZEOanko0LFTg==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-6.0.3.tgz", + "integrity": "sha512-Vtgk7L/R2JHyyGW07spoFlB8/lpjiOLTjMdms6AFMraYt3BaJauod/NGrfnVG/y4Ix1JEuMRPDPEj2ua+zz1/Q==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@babel/core": "^7.23.9", + "@babel/parser": "^7.23.9", + "@istanbuljs/schema": "^0.1.3", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.1.tgz", + "integrity": "sha512-GCfE1mtsHGOELCU8e/Z7YWzpmybrx/+dSTfLrvY8qRmaY6zXTKWn6WQIjaAFw069icm6GVMNkgu0NzI4iPZUNw==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^4.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-5.0.6.tgz", + "integrity": "sha512-yg2d+Em4KizZC5niWhQaIomgf5WlL4vOOjZ5xGCmF8SnPE/mDWWXgvRExdcpCgh9lLRRa1/fSYp2ymmbJ1pI+A==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.23", + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.2.0.tgz", + "integrity": "sha512-HGYWWS/ehqTV3xN10i23tkPkpH46MLCIMFNCaaKNavAXTF1RkqxawEPtnjnGZ6XKSInBKkiOA5BKS+aZiY3AvA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/js-yaml": { + "version": "3.15.2", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.15.2.tgz", + "integrity": "sha512-6EuL879VkRA+1Cz578mKMiKvjPNEuk6+r1JaFzoSWejZmtf7xWbIyw1e3KkxlkzTIt9Taw6JBhEppG7utc1P+w==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsdom": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-29.1.1.tgz", + "integrity": "sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "@asamuzakjp/css-color": "^5.1.11", + "@asamuzakjp/dom-selector": "^7.1.1", + "@bramus/specificity": "^2.4.2", + "@csstools/css-syntax-patches-for-csstree": "^1.1.3", + "@exodus/bytes": "^1.15.0", + "css-tree": "^3.2.1", + "data-urls": "^7.0.0", + "decimal.js": "^10.6.0", + "html-encoding-sniffer": "^6.0.0", + "is-potential-custom-element-name": "^1.0.1", + "lru-cache": "^11.3.5", + "parse5": "^8.0.1", + "saxes": "^6.0.0", + "symbol-tree": "^3.2.4", + "tough-cookie": "^6.0.1", + "undici": "^7.25.0", + "w3c-xmlserializer": "^5.0.0", + "webidl-conversions": "^8.0.1", + "whatwg-mimetype": "^5.0.0", + "whatwg-url": "^16.0.1", + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": "^20.19.0 || ^22.13.0 || >=24.0.0" + }, + "peerDependencies": { + "canvas": "^3.0.0" + }, + "peerDependenciesMeta": { + "canvas": { + "optional": true + } + } + }, + "node_modules/jsdom/node_modules/lru-cache": { + "version": "11.5.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.5.3.tgz", + "integrity": "sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==", + "dev": true, + "license": "BlueOak-1.0.0", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/jsesc": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-3.1.0.tgz", + "integrity": "sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA==", + "dev": true, + "license": "MIT", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/json-stream-stringify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-stream-stringify/-/json-stream-stringify-3.0.1.tgz", + "integrity": "sha512-vuxs3G1ocFDiAQ/SX0okcZbtqXwgj1g71qE9+vrjJ2EkjKQlEFDAcUNRxRU8O+GekV4v5cM2qXP0Wyt/EMDBiQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "license": "MIT", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonfile": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.2.1.tgz", + "integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/launch-editor": { + "version": "2.14.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.14.1.tgz", + "integrity": "sha512-QWBrQsMpH7gPr965dsKD/3cKWiNoTjpATQf++Xq63N6sKRGMwlVXz41O1IZTMfZQgBctD/K5Zt06+/I6pP6+HA==", + "dev": true, + "license": "MIT", + "dependencies": { + "picocolors": "^1.1.1", + "shell-quote": "^1.8.4" + } + }, + "node_modules/line-column-path": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/line-column-path/-/line-column-path-4.0.0.tgz", + "integrity": "sha512-Zvpvd56i9FRV5kaJFiiY1t+FNMEH+dGEaLyQprqKlGHBAxJXmdSk+8tVsh6b9YlxbfyyuLrhJCkzwB+AmOBZ0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "unicorn-magic": "^0.4.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lines-and-columns": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-2.0.4.tgz", + "integrity": "sha512-wM1+Z03eypVAVUCE7QdSqpVIvelbOakn1M0bPDoA4SGWPx3sNDVUiMo3L6To6WWGClB7VyXnhQ4Sn7gxiJbE6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "license": "ISC", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/lz-string": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/lz-string/-/lz-string-1.5.0.tgz", + "integrity": "sha512-h5bgJWpxJNswbU7qCrV0tIKQCaS3blPDrqKWx+QxzuzL1zGUzij9XCWLrSLsJPu5t+eWA/ycetzYAO5IOMcWAQ==", + "dev": true, + "license": "MIT", + "bin": { + "lz-string": "bin/bin.js" + } + }, + "node_modules/make-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-4.0.0.tgz", + "integrity": "sha512-hXdUTZYIVOt1Ex//jAQi+wTZZpUpwBj/0QsOzqegb3rGMMeJiSEu5xLHnYfBrRV4RH2+OCSOO95Is/7x1WJ4bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^7.5.3" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/math-intrinsics": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", + "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/mdn-data": { + "version": "2.27.1", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.27.1.tgz", + "integrity": "sha512-9Yubnt3e8A0OKwxYSXyhLymGW4sCufcLG6VdiDdUGVkPhpqLxlvP5vl1983gQjJl3tqbrM731mjaZaP68AgosQ==", + "dev": true, + "license": "CC0-1.0" + }, + "node_modules/memory-pager": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/memory-pager/-/memory-pager-1.5.0.tgz", + "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", + "dev": true, + "license": "MIT", + "optional": true + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/meteor-node-stubs": { + "version": "1.2.30", + "resolved": "https://registry.npmjs.org/meteor-node-stubs/-/meteor-node-stubs-1.2.30.tgz", + "integrity": "sha512-wxEuRYL1pi+9gIK7uXrW706M4fOp624j/DsJyEeWJwGpv8Mp+0zWRoIhke48vrx0cgSDrQHEFW3BbAYzFdtwYw==", + "bundleDependencies": [ + "@meteorjs/crypto-browserify", + "assert", + "browserify-zlib", + "buffer", + "console-browserify", + "constants-browserify", + "domain-browser", + "events", + "https-browserify", + "os-browserify", + "path-browserify", + "process", + "punycode", + "querystring-es3", + "readable-stream", + "stream-browserify", + "stream-http", + "string_decoder", + "timers-browserify", + "tty-browserify", + "url", + "util", + "vm-browserify" + ], + "license": "MIT", + "dependencies": { + "@meteorjs/crypto-browserify": "^3.12.1", + "assert": "^2.1.0", + "browserify-zlib": "^0.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.2.0", + "constants-browserify": "^1.0.0", + "domain-browser": "^4.23.0", + "events": "^3.3.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "process": "^0.11.10", + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.2", + "sha.js": "^2.4.12", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.3.0", + "timers-browserify": "^2.0.12", + "tty-browserify": "0.0.1", + "url": "^0.11.4", + "util": "^0.12.5", + "vm-browserify": "^1.1.2" + } + }, + "node_modules/meteor-node-stubs/node_modules/@meteorjs/browserify-sign": { + "version": "4.2.6", + "inBundle": true, + "license": "ISC", + "dependencies": { + "bn.js": "^5.2.1", + "brorand": "^1.1.0", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "hash-base": "~3.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1", + "parse-asn1": "^5.1.7", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/meteor-node-stubs/node_modules/@meteorjs/browserify-sign/node_modules/isarray": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/@meteorjs/browserify-sign/node_modules/readable-stream": { + "version": "2.3.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/meteor-node-stubs/node_modules/@meteorjs/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/@meteorjs/browserify-sign/node_modules/string_decoder": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/@meteorjs/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/@meteorjs/create-ecdh": { + "version": "4.0.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/meteor-node-stubs/node_modules/@meteorjs/create-ecdh/node_modules/bn.js": { + "version": "4.12.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/@meteorjs/crypto-browserify": { + "version": "3.12.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "@meteorjs/browserify-sign": "^4.2.3", + "@meteorjs/create-ecdh": "^4.0.4", + "browserify-cipher": "^1.0.1", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "diffie-hellman": "^5.0.3", + "hash-base": "~3.0.4", + "inherits": "^2.0.4", + "pbkdf2": "^3.1.2", + "public-encrypt": "^4.0.3", + "randombytes": "^2.1.0", + "randomfill": "^1.0.4" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/asn1.js": { + "version": "4.10.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/assert": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.2", + "is-nan": "^1.3.2", + "object-is": "^1.1.5", + "object.assign": "^4.1.4", + "util": "^0.12.5" + } + }, + "node_modules/meteor-node-stubs/node_modules/available-typed-arrays": { + "version": "1.0.7", + "inBundle": true, + "license": "MIT", + "dependencies": { + "possible-typed-array-names": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/base64-js": { + "version": "1.5.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/bn.js": { + "version": "5.2.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/brorand": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/browserify-aes": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/meteor-node-stubs/node_modules/browserify-cipher": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/browserify-des": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/meteor-node-stubs/node_modules/browserify-rsa": { + "version": "4.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bn.js": "^5.2.1", + "randombytes": "^2.1.0", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/meteor-node-stubs/node_modules/browserify-zlib": { + "version": "0.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/meteor-node-stubs/node_modules/buffer": { + "version": "5.7.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/meteor-node-stubs/node_modules/buffer-xor": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/builtin-status-codes": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/call-bind": { + "version": "1.0.8", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.0", + "es-define-property": "^1.0.0", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/call-bind-apply-helpers": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/call-bound": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "get-intrinsic": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/cipher-base": { + "version": "1.0.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/meteor-node-stubs/node_modules/console-browserify": { + "version": "1.2.0", + "inBundle": true + }, + "node_modules/meteor-node-stubs/node_modules/constants-browserify": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/core-util-is": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/create-hash": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/create-hmac": { + "version": "1.1.7", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/meteor-node-stubs/node_modules/define-data-property": { + "version": "1.1.4", + "inBundle": 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/meteor-node-stubs/node_modules/define-properties": { + "version": "1.2.1", + "inBundle": 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/meteor-node-stubs/node_modules/des.js": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/diffie-hellman": { + "version": "5.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/domain-browser": { + "version": "4.23.0", + "inBundle": true, + "license": "Artistic-2.0", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://bevry.me/fund" + } + }, + "node_modules/meteor-node-stubs/node_modules/dunder-proto": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.1", + "es-errors": "^1.3.0", + "gopd": "^1.2.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/es-define-property": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/es-errors": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/es-object-atoms": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/events": { + "version": "3.3.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/meteor-node-stubs/node_modules/evp_bytestokey": { + "version": "1.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/meteor-node-stubs/node_modules/for-each": { + "version": "0.3.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "is-callable": "^1.2.7" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/function-bind": { + "version": "1.1.2", + "inBundle": true, + "license": "MIT", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/get-intrinsic": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind-apply-helpers": "^1.0.2", + "es-define-property": "^1.0.1", + "es-errors": "^1.3.0", + "es-object-atoms": "^1.1.1", + "function-bind": "^1.1.2", + "get-proto": "^1.0.1", + "gopd": "^1.2.0", + "has-symbols": "^1.1.0", + "hasown": "^2.0.2", + "math-intrinsics": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/get-proto": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "dunder-proto": "^1.0.1", + "es-object-atoms": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/gopd": { + "version": "1.2.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/has-property-descriptors": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/has-symbols": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/has-tostringtag": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "has-symbols": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/hash-base": { + "version": "3.0.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/meteor-node-stubs/node_modules/hash.js": { + "version": "1.1.7", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/meteor-node-stubs/node_modules/hasown": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/hmac-drbg": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/meteor-node-stubs/node_modules/https-browserify": { + "version": "1.0.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/ieee754": { + "version": "1.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "BSD-3-Clause" + }, + "node_modules/meteor-node-stubs/node_modules/inherits": { + "version": "2.0.4", + "inBundle": true, + "license": "ISC" + }, + "node_modules/meteor-node-stubs/node_modules/is-arguments": { + "version": "1.2.0", + "inBundle": 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/meteor-node-stubs/node_modules/is-callable": { + "version": "1.2.7", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/is-generator-function": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.3", + "get-proto": "^1.0.0", + "has-tostringtag": "^1.0.2", + "safe-regex-test": "^1.1.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/is-nan": { + "version": "1.3.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/is-regex": { + "version": "1.2.1", + "inBundle": 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/meteor-node-stubs/node_modules/is-typed-array": { + "version": "1.1.15", + "inBundle": true, + "license": "MIT", + "dependencies": { + "which-typed-array": "^1.1.16" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/isarray": { + "version": "2.0.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/math-intrinsics": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/md5.js": { + "version": "1.3.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/meteor-node-stubs/node_modules/miller-rabin": { + "version": "4.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/meteor-node-stubs/node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/minimalistic-assert": { + "version": "1.0.1", + "inBundle": true, + "license": "ISC" + }, + "node_modules/meteor-node-stubs/node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/object-inspect": { + "version": "1.13.4", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/object-is": { + "version": "1.1.6", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/object-keys": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/object.assign": { + "version": "4.1.7", + "inBundle": 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/meteor-node-stubs/node_modules/os-browserify": { + "version": "0.3.0", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/pako": { + "version": "1.0.11", + "inBundle": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/meteor-node-stubs/node_modules/parse-asn1": { + "version": "5.1.7", + "inBundle": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "hash-base": "~3.0", + "pbkdf2": "^3.1.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/meteor-node-stubs/node_modules/path-browserify": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/pbkdf2": { + "version": "3.1.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "create-hash": "~1.1.3", + "create-hmac": "^1.1.7", + "ripemd160": "=2.0.1", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.11", + "to-buffer": "^1.2.0" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/meteor-node-stubs/node_modules/pbkdf2/node_modules/create-hash": { + "version": "1.1.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "sha.js": "^2.4.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/pbkdf2/node_modules/hash-base": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.1" + } + }, + "node_modules/meteor-node-stubs/node_modules/pbkdf2/node_modules/ripemd160": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "hash-base": "^2.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/meteor-node-stubs/node_modules/possible-typed-array-names": { + "version": "1.1.0", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/process": { + "version": "0.11.10", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/process-nextick-args": { + "version": "2.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/public-encrypt": { + "version": "4.0.3", + "inBundle": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/meteor-node-stubs/node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.3", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/punycode": { + "version": "1.4.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/qs": { + "version": "6.16.0", + "inBundle": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/querystring-es3": { + "version": "0.2.1", + "inBundle": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/meteor-node-stubs/node_modules/randombytes": { + "version": "2.1.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/randomfill": { + "version": "1.0.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/readable-stream": { + "version": "3.6.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/meteor-node-stubs/node_modules/ripemd160": { + "version": "2.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/meteor-node-stubs/node_modules/safe-buffer": { + "version": "5.2.1", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/safe-regex-test": { + "version": "1.1.0", + "inBundle": 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/meteor-node-stubs/node_modules/set-function-length": { + "version": "1.2.2", + "inBundle": 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/meteor-node-stubs/node_modules/setimmediate": { + "version": "1.0.5", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/sha.js": { + "version": "2.4.12", + "inBundle": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/side-channel": { + "version": "1.1.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/side-channel-list": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/side-channel-map": { + "version": "1.0.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/side-channel-weakmap": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/meteor-node-stubs/node_modules/stream-browserify": { + "version": "3.0.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/stream-http": { + "version": "3.2.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/meteor-node-stubs/node_modules/string_decoder": { + "version": "1.3.0", + "inBundle": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/timers-browserify": { + "version": "2.0.12", + "inBundle": true, + "license": "MIT", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/meteor-node-stubs/node_modules/to-buffer": { + "version": "1.2.1", + "inBundle": true, + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/tty-browserify": { + "version": "0.0.1", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/typed-array-buffer": { + "version": "1.0.3", + "inBundle": 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/meteor-node-stubs/node_modules/url": { + "version": "0.11.4", + "inBundle": true, + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/meteor-node-stubs/node_modules/util": { + "version": "0.12.5", + "inBundle": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/meteor-node-stubs/node_modules/util-deprecate": { + "version": "1.0.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/vm-browserify": { + "version": "1.1.2", + "inBundle": true, + "license": "MIT" + }, + "node_modules/meteor-node-stubs/node_modules/which-typed-array": { + "version": "1.1.19", + "inBundle": true, + "license": "MIT", + "dependencies": { + "available-typed-arrays": "^1.0.7", + "call-bind": "^1.0.8", + "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/meteor-node-stubs/node_modules/xtend": { + "version": "4.0.2", + "inBundle": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", + "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dev": true, + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true, + "license": "ISC" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==", + "dev": true, + "license": "MIT" + }, + "node_modules/minimatch": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.5.tgz", + "integrity": "sha512-VgjWUsnnT6n+NUk6eZq77zeFdpW2LWDzP6zFGrCbHXiYNul5Dzqk2HHQ5uFH2DNW5Xbp8+jVzaeNt94ssEEl4w==", + "dev": true, + "license": "ISC", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimizer-webpack-plugin": { + "version": "5.11.0", + "resolved": "https://registry.npmjs.org/minimizer-webpack-plugin/-/minimizer-webpack-plugin-5.11.0.tgz", + "integrity": "sha512-2JVy2DY+iBtfRyrQB5cRM7lfurnJIi6jFTgLip/7FxDu0WxswrIRzr4fBySQ0X7HqM7BcwE28zm+HfQ5V6y4Cg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.31", + "jest-worker": "^27.4.5", + "schema-utils": "^4.3.3", + "terser": "^5.51.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@minify-html/node": { + "optional": true + }, + "@napi-rs/image": { + "optional": true + }, + "@swc/core": { + "optional": true + }, + "@swc/css": { + "optional": true + }, + "@swc/html": { + "optional": true + }, + "clean-css": { + "optional": true + }, + "cssnano": { + "optional": true + }, + "csso": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "html-minifier-terser": { + "optional": true + }, + "imagemin": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "postcss": { + "optional": true + }, + "sharp": { + "optional": true + }, + "svgo": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/mongodb": { + "version": "4.17.2", + "resolved": "https://registry.npmjs.org/mongodb/-/mongodb-4.17.2.tgz", + "integrity": "sha512-mLV7SEiov2LHleRJPMPrK2PMyhXFZt2UQLC4VD4pnth3jMjYKHhtqfwwkkvS/NXuo/Fp3vbhaNcXrIDaLRb9Tg==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "bson": "^4.7.2", + "mongodb-connection-string-url": "^2.6.0", + "socks": "^2.7.1" + }, + "engines": { + "node": ">=12.9.0" + }, + "optionalDependencies": { + "@aws-sdk/credential-providers": "^3.186.0", + "@mongodb-js/saslprep": "^1.1.0" + } + }, + "node_modules/mongodb-connection-string-url": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/mongodb-connection-string-url/-/mongodb-connection-string-url-2.6.0.tgz", + "integrity": "sha512-WvTZlI9ab0QYtTYnuMLgobULWhokRjtC7db9LtcVfJ+Hsnyr5eo6ZtNAt3Ly24XZScGMelOcGtm7lSn0332tPQ==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "@types/whatwg-url": "^8.2.1", + "whatwg-url": "^11.0.0" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/tr46": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-3.0.0.tgz", + "integrity": "sha512-l7FvfAHlcmulp8kr+flpQZmVwtu7nfRV7NZujtN0OqES8EL4O4e0qqzL0DC5gAvx/ZC/9lk6rhcUwYvkBnBnYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/webidl-conversions": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", + "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + } + }, + "node_modules/mongodb-connection-string-url/node_modules/whatwg-url": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-11.0.0.tgz", + "integrity": "sha512-RKT8HExMpoYx4igMiVMY83lN6UeITKJlBQ+vR/8ZJ8OCdSiN3RwCq+9gH0+Xzj0+5IrM6i4j/6LuvzbZIQgEcQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tr46": "^3.0.0", + "webidl-conversions": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/mrmime": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.1.tgz", + "integrity": "sha512-Y3wQdFg2Va6etvQ5I82yUhGdsKrcYox6p7FfL1LbK2J4V01F9TGlepTIhnK24t7koZibmg82KGglhA1XK5IsLQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-polyfill-webpack-plugin": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/node-polyfill-webpack-plugin/-/node-polyfill-webpack-plugin-4.1.0.tgz", + "integrity": "sha512-b4ei444EKkOagG/yFqojrD3QTYM5IOU1f8tn9o6uwrG4qL+brI7oVhjPVd0ZL2xy+Z6CP5bu9w8XTvlWgiXHcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "node-stdlib-browser": "^1.3.0", + "type-fest": "^4.27.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "webpack": ">=5" + } + }, + "node_modules/node-releases": { + "version": "2.0.56", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.56.tgz", + "integrity": "sha512-x0InOIyzgdk+eyaWaRJFH5snEtiImgBgblZ2CyPrLmqqcuMQkEvcDPHbzqbD8eDsSeJbVOjn+crzyzHaM4D+/A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/node-stdlib-browser": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-stdlib-browser/-/node-stdlib-browser-1.3.1.tgz", + "integrity": "sha512-X75ZN8DCLftGM5iKwoYLA3rjnrAEs97MkzvSd4q2746Tgpg8b8XWiBGiBG4ZpgcAqBgtgPHTiAc8ZMCvZuikDw==", + "dev": true, + "license": "MIT", + "dependencies": { + "assert": "^2.0.0", + "browser-resolve": "^2.0.0", + "browserify-zlib": "^0.2.0", + "buffer": "^5.7.1", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "create-require": "^1.1.1", + "crypto-browserify": "^3.12.1", + "domain-browser": "4.22.0", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "isomorphic-timers-promises": "^1.0.1", + "os-browserify": "^0.3.0", + "path-browserify": "^1.0.1", + "pkg-dir": "^5.0.0", + "process": "^0.11.10", + "punycode": "^1.4.1", + "querystring-es3": "^0.2.1", + "readable-stream": "^3.6.0", + "stream-browserify": "^3.0.0", + "stream-http": "^3.2.0", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.1", + "url": "^0.11.4", + "util": "^0.12.4", + "vm-browserify": "^1.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/npm-run-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-6.0.0.tgz", + "integrity": "sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-key": "^4.0.0", + "unicorn-magic": "^0.3.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/node_modules/path-key": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-4.0.0.tgz", + "integrity": "sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/npm-run-path/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/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", + "integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "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/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "license": "ISC", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/open": { + "version": "11.0.4", + "resolved": "https://registry.npmjs.org/open/-/open-11.0.4.tgz", + "integrity": "sha512-++Zlftm0kVLPmzC06t6epuWmcRMDbI4z5P3NNX979WA/k23+NtSOynEGzsVfZwguKw2mi5umVgnBlJQMwRz4Pg==", + "dev": true, + "license": "MIT", + "dependencies": { + "default-browser": "^5.5.1", + "define-lazy-prop": "^3.0.0", + "is-in-ssh": "^1.0.0", + "is-inside-container": "^1.0.0", + "powershell-utils": "^0.2.1", + "wsl-utils": "^1.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open-editor": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/open-editor/-/open-editor-6.0.0.tgz", + "integrity": "sha512-LGd2Xn6NvFlbx/lg/HK69w6Dbg+21MzJzcPDPQRgDRqc+qiR+2/SN99rzZSo7Qa1ck1hcGYig0CAo53cmXCE0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "env-editor": "^1.3.0", + "execa": "^9.6.0", + "line-column-path": "^4.0.0", + "open": "^11.0.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==", + "dev": true, + "license": "MIT" + }, + "node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==", + "dev": true, + "license": "(MIT AND Zlib)" + }, + "node_modules/parse-asn1": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.9.tgz", + "integrity": "sha512-fIYNuZ/HastSb80baGOuPRo1O9cf4baWw5WsAp7dBuUzeTD/BoaG8sVTdlPFksBE2lF21dN+A1AnrpIjSWqHHg==", + "dev": true, + "license": "ISC", + "dependencies": { + "asn1.js": "^4.10.1", + "browserify-aes": "^1.2.0", + "evp_bytestokey": "^1.0.3", + "pbkdf2": "^3.1.5", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse-ms": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/parse-ms/-/parse-ms-4.0.0.tgz", + "integrity": "sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse5": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-8.0.1.tgz", + "integrity": "sha512-z1e/HMG90obSGeidlli3hj7cbocou0/wa5HacvI3ASx34PecNjNQeaHNo5WIZpWofN9kgkqV1q5YvXe3F0FoPw==", + "dev": true, + "license": "MIT", + "dependencies": { + "entities": "^8.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5/node_modules/entities": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-8.1.0.tgz", + "integrity": "sha512-kxL7msIffSuh9aaFAMD7rxAIuTRMAHMeBtgHW2yUdWw732ZNh4MehkF2gdjvtdmikkaIP9bFDDJOPlsvm7avrA==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20.19.0" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==", + "dev": true, + "license": "MIT" + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "license": "MIT", + "engines": { + "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/pathe": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/pathe/-/pathe-2.0.3.tgz", + "integrity": "sha512-WUjGcAqP1gQacoQe+OBJsFA7Ld4DyXuUIjZ5cc75cLHvJ7dtNsTugphxIADwspS+AraAUePCKrSVtPLFj/F88w==", + "dev": true, + "license": "MIT" + }, + "node_modules/pbkdf2": { + "version": "3.1.6", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.6.tgz", + "integrity": "sha512-BT6eelPB1EyGHo8pC0o9Bl6k6SYVhKO1jEbd3lcTrtr7XHdjP8BW1YpfCV3G9Kwkxgattk+S5q2/RvuttCsS1g==", + "dev": true, + "license": "MIT", + "dependencies": { + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "ripemd160": "^2.0.3", + "safe-buffer": "^5.2.1", + "sha.js": "^2.4.12", + "to-buffer": "^1.2.2" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/picocolors": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==", + "dev": true, + "license": "ISC" + }, + "node_modules/picomatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.5.tgz", + "integrity": "sha512-RvwwcruNjI1ncT5xRakeyS9Lf8lcItv34KD+aif+VH9kduAyfYBipGh12274xtenIPZ119/R9BdTBa8gAwSh0A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-5.0.0.tgz", + "integrity": "sha512-NPE8TDbzl/3YQYY7CSS228s3g2ollTFnc+Qi3tqmqJp9Vg2ovUpixcJEo2HJScN2Ez+kEaal6y70c0ehqJBJeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^5.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/playwright": { + "version": "1.59.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.59.0.tgz", + "integrity": "sha512-wihGScriusvATUxmhfENxg0tj1vHEFeIwxlnPFKQTOQVd7aG08mUfvvniRP/PtQOC+2Bs52kBOC/Up1jTXeIbw==", + "dev": true, + "license": "Apache-2.0", + "dependencies": { + "playwright-core": "1.59.0" + }, + "bin": { + "playwright": "cli.js" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "fsevents": "2.3.2" + } + }, + "node_modules/playwright-core": { + "version": "1.59.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.59.0.tgz", + "integrity": "sha512-PW/X/IoZ6BMUUy8rpwHEZ8Kc0IiLIkgKYGNFaMs5KmQhcfLILNx9yCQD0rnWeWfz1PNeqcFP1BsihQhDOBCwZw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "playwright-core": "cli.js" + }, + "engines": { + "node": ">=18" + } + }, + "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/powershell-utils": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.2.1.tgz", + "integrity": "sha512-C+y9x90UElAddDZmV4qOx9W53B61PO7cIqWz2dQsWlwswuq4mr8NEwytdGKboYbQlGZ3awrkTeNvcZiZNHnQ8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-format": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz", + "integrity": "sha512-Qb1gy5OrP5+zDf2Bvnzdl3jsTf1qXVMazbvCoKhtKqVs4/YK4ozX4gKQJJVyNe+cajNPn0KoC0MC3FUmaHWEmQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1", + "ansi-styles": "^5.0.0", + "react-is": "^17.0.1" + }, + "engines": { + "node": "^10.13.0 || ^12.13.0 || ^14.15.0 || >=15.0.0" + } + }, + "node_modules/pretty-ms": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/pretty-ms/-/pretty-ms-9.3.1.tgz", + "integrity": "sha512-HzMy3Geq23nVALD/M2LliU+F+M+gVNsvkQWWqeBZ8HDiCgzo6YPJ/Omrmtq24EFrIsk0a3EkQGEd7bDOo+IhGA==", + "dev": true, + "license": "MIT", + "dependencies": { + "parse-ms": "^4.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==", + "dev": true, + "license": "MIT" + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "license": "MIT", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.5", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.5.tgz", + "integrity": "sha512-3aRg6/JxfffFD+OlOjOFR3Vo79l39ooBTFucxx+MT3dhCtzn3EmiUPQo+6/OZuI2jbXi3YKgmiTFBgChQMwIRQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/qs": { + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.16.0.tgz", + "integrity": "sha512-h6fhOIaRrID2CbEY2fqs+7t+UXZo+MLAnU5gRIq85uFtdiUPCdsApMlHhXogKVM4HM2DVbIjGNTTYH2OcmP1vA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "es-define-property": "^1.0.1", + "side-channel": "^1.1.1" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==", + "dev": true, + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "license": "MIT", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/react": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react/-/react-19.3.0.tgz", + "integrity": "sha512-E8LUcbtBWt20bbl2YoHfx4ZDBdxVTfOKtCZn9cDSJ4l6/nuoApcpIBcj47t2wZoVX8g2ZHuMHbiShgCR1T5Sog==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/react-dom": { + "version": "19.3.0", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.3.0.tgz", + "integrity": "sha512-JDk8dgif51OjFoDE70+OT9ICyYr+69HlmihNwp1+Nsfbna3t5sIiCa9ZJktDmQ4/1b/rn26hIAR2uYXDMr5r0Q==", + "license": "MIT", + "dependencies": { + "scheduler": "^0.28.0" + }, + "peerDependencies": { + "react": "^19.3.0" + } + }, + "node_modules/react-is": { + "version": "17.0.2", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-17.0.2.tgz", + "integrity": "sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==", + "dev": true, + "license": "MIT" + }, + "node_modules/react-refresh": { + "version": "0.17.0", + "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.17.0.tgz", + "integrity": "sha512-z6F7K9bV85EfseRCp2bzrpyQ0Gkw1uLoCel9XBVWPg/TjRj94SkJzUTGfOa4bs7iJvBWtQG0Wq7wnI0syw3EBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.12", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.12.tgz", + "integrity": "sha512-TyeJ1zif53BPfHootBGwPRYT1RUt6oGWsaQr8UyZW/eAm9bKoijtvruSDEmZHm92CwS9nj7/fWttqPCgzep8CA==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "is-core-module": "^2.16.1", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/ripemd160": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.3.tgz", + "integrity": "sha512-5Di9UC0+8h1L6ZD2d7awM7E/T4uA1fJRlx6zk/NvdCCVEoAnFqvHmCuNeIKoCeIixBX/q8uM+6ycDvF8woqosA==", + "dev": true, + "license": "MIT", + "dependencies": { + "hash-base": "^3.1.2", + "inherits": "^2.0.4" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/hash-base": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.2.tgz", + "integrity": "sha512-Bb33KbowVTIj5s7Ked1OsqHUeCpz//tPwR+E2zJgJKo9Z5XolZ9b6bdUgjmYlwnWhoOQKoTd1TYToZGn5mAYOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^2.3.8", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ripemd160/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/ripemd160/node_modules/readable-stream": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz", + "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==", + "dev": true, + "license": "MIT", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/ripemd160/node_modules/readable-stream/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/ripemd160/node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/ripemd160/node_modules/string_decoder/node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true, + "license": "MIT" + }, + "node_modules/rslog": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/rslog/-/rslog-2.3.0.tgz", + "integrity": "sha512-g2wW/ermwzGTLlzGdJBDRc4YKz2/yPBjf57w9g5CvhtpZ91Xq95OaWku0oNHYi+XsuV6v8QrCo2oJJR/pCUR8g==", + "dev": true, + "license": "MIT", + "engines": { + "node": "^20.19.0 || >=22.12.0" + } + }, + "node_modules/rspack-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/rspack-merge/-/rspack-merge-1.0.1.tgz", + "integrity": "sha512-W/mzCdxfV+EXOdpfwcLWc2TZ9EYa2LYumAMgpTn27bSEOO0BQz/SA8qfnJRCMkJyNST2URxmwqBmQbh5tLFwsg==", + "dev": true + }, + "node_modules/run-applescript": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.1.0.tgz", + "integrity": "sha512-DPe5pVFaAsinSaV6QjQ6gdiedWDcRCbUuiQfQa2wmWV7+xC9bGulGI8+TdRmoFkAPaBXk8CrAbnlY2ISniJ47Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, + "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/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "license": "MIT" + }, + "node_modules/saxes": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz", + "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==", + "dev": true, + "license": "ISC", + "dependencies": { + "xmlchars": "^2.2.0" + }, + "engines": { + "node": ">=v12.22.7" + } + }, + "node_modules/scheduler": { + "version": "0.28.0", + "resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.28.0.tgz", + "integrity": "sha512-juorfCmIkIw8tT+p5BXSm6PJjQF/ycEYmKyzURCIt/RaZIhL+PulbQ9Yu2z1HdOJDdqDTlxA1+xKBmHXJsczAw==", + "license": "MIT" + }, + "node_modules/schema-utils": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.5.0.tgz", + "integrity": "sha512-zJlMCZ0cAR5p/Y4oVpRoqioDMJcGxaXRrQ/4rP4WyR84vc5z/DolXdbvXeDpTwbtocDFr2rhPqHPErDCUtz2kA==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/json-schema": "^7.0.15", + "ajv": "^8.20.0", + "ajv-formats": "^3.0.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/semver": { + "version": "7.8.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.8.5.tgz", + "integrity": "sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "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/setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha512-MATJdZp8sLqDl/68LfQmbP8zKPLQNV6BIZoIgrscFDQ+RsvK/BxeDQOgyxKKoh0y/8h3BqVFnCqQ/gd+reiIXA==", + "dev": true, + "license": "MIT" + }, + "node_modules/sha.js": { + "version": "2.4.12", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.12.tgz", + "integrity": "sha512-8LzC5+bvI45BjpfXU8V5fdU2mfeKiQe1D1gIMn7XUlF3OTUrpdJpPPH4EMAnF0DsHHdSZqCdSss5qCmJKuiO3w==", + "dev": true, + "license": "(MIT AND BSD-3-Clause)", + "dependencies": { + "inherits": "^2.0.4", + "safe-buffer": "^5.2.1", + "to-buffer": "^1.2.0" + }, + "bin": { + "sha.js": "bin.js" + }, + "engines": { + "node": ">= 0.10" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "license": "MIT", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.10.0.tgz", + "integrity": "sha512-w1aiOKwKuRgtwAReIIj89puqg+I7GvX4IbLrvmhXbzQsj1+Zwi4VO3+fa6ZF91TWSjIxoEkKnMeHcLEODK5ZXA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.1.tgz", + "integrity": "sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4", + "side-channel-list": "^1.0.1", + "side-channel-map": "^1.0.1", + "side-channel-weakmap": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-list": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.1.tgz", + "integrity": "sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w==", + "dev": true, + "license": "MIT", + "dependencies": { + "es-errors": "^1.3.0", + "object-inspect": "^1.13.4" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz", + "integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel-weakmap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz", + "integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==", + "dev": true, + "license": "MIT", + "dependencies": { + "call-bound": "^1.0.2", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.5", + "object-inspect": "^1.13.3", + "side-channel-map": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "dev": true, + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/sirv": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/sirv/-/sirv-3.0.2.tgz", + "integrity": "sha512-2wcC/oGxHis/BoHkkPwldgiPSYcpZK3JU28WoMVv55yHJgcZ8rlXvuG9iZggz+sU1d4bRgIGASwyWqjxu3FM0g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@polka/url": "^1.0.0-next.24", + "mrmime": "^2.0.0", + "totalist": "^3.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.6.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.2.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.8", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.8.tgz", + "integrity": "sha512-6Oy52pbg+kvdCVvjcN+FnY7BvxZ7cIHNScbvztT/It5d0vbwoJoVZmF2gjJmnV0/4WlXRfG15zc45ySk9Ah8bw==", + "dev": true, + "license": "MIT", + "dependencies": { + "debug": "~4.4.1", + "ws": "~8.21.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.7", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.7.tgz", + "integrity": "sha512-IH/iSeO9T6gz1KkFleGDWkG9N3dl4jXVYUtMhIqH10Md0ttMer8nUNWiP1DKuNrybD2xBrixLJdCC9J6ECoYkg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.4.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io/node_modules/debug": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.7.tgz", + "integrity": "sha512-Er2nc/H7RrMXZBFCEim6TCmMk02Z8vLC2Rbi1KEBggpo0fS6l0S1nnapwmIi3yW/+GOJap1Krg4w0Hg80oCqgQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/socks": { + "version": "2.8.10", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.10.tgz", + "integrity": "sha512-e0VyvkVTwVYViNovRkZ9aodhxVlyoMn7eJhVUPxZ+eK9P/7CBkxvvsBOHqFPEH416726W8tLXXXjKwqgTErrCQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ip-address": "^10.1.1", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/source-map": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.6.tgz", + "integrity": "sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">= 12" + } + }, + "node_modules/source-map-js": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", + "integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "license": "BSD-3-Clause", + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sparse-bitfield": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", + "integrity": "sha512-kvzhi7vqKTfkh0PZU+2D2PIllw2ymqJKujUcyPMd9Y75Nv4nPbGJZXNhxsgdQab2BmlDct1YnfQCguEvHr7VsQ==", + "dev": true, + "license": "MIT", + "optional": true, + "dependencies": { + "memory-pager": "^1.0.2" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true, + "license": "BSD-3-Clause" + }, + "node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/stream-http": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.2.0.tgz", + "integrity": "sha512-Oq1bLqisTyK3TSCXpPbT4sdeYNdmyZJv1LxpEm2vu1ZhK89kSE5YXwZc3cWk0MagGaKriBh9mCFbVGtO+vY29A==", + "dev": true, + "license": "MIT", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/string_decoder": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", + "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", + "dev": true, + "license": "MIT", + "dependencies": { + "safe-buffer": "~5.2.0" + } + }, + "node_modules/strip-ansi": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz", + "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.2.2" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/strip-ansi/node_modules/ansi-regex": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz", + "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/strip-final-newline": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-4.0.0.tgz", + "integrity": "sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "license": "MIT", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/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/swc-plugin-coverage-instrument": { + "version": "0.0.32", + "resolved": "https://registry.npmjs.org/swc-plugin-coverage-instrument/-/swc-plugin-coverage-instrument-0.0.32.tgz", + "integrity": "sha512-KsO1xNQdcVb331Rm98Op6uYf36/CYdF1kILQxOddmtCNlRLISpCUqHcnogu+QgELZvG48oie+w0fzS8uktjcEA==", + "dev": true, + "license": "MIT" + }, + "node_modules/symbol-tree": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz", + "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==", + "dev": true, + "license": "MIT" + }, + "node_modules/tapable": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.3.3.tgz", + "integrity": "sha512-uxc/zpqFg6x7C8vOE7lh6Lbda8eEL9zmVm/PLeTPBRhh1xCgdWaQ+J1CUieGpIfm2HdtsUpRv+HshiasBMcc6A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser": { + "version": "5.51.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.51.2.tgz", + "integrity": "sha512-bWnjSNscmuI+GJze6ZupnHP8G/cTcsJF+bXCeQknk2SHQsgbNJnLrqiH9jZ2W4STPVXH2mDKKRX3iwPhc9Cn/Q==", + "dev": true, + "license": "BSD-2-Clause", + "peer": true, + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.15.0", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "license": "ISC", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/timers-browserify": { + "version": "2.0.12", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz", + "integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "setimmediate": "^1.0.4" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/tldts": { + "version": "7.4.14", + "resolved": "https://registry.npmjs.org/tldts/-/tldts-7.4.14.tgz", + "integrity": "sha512-EahQoi+Q5oqmG3yxRHx+bwn36OaLbtw6jnTFcGjc8fcmktzTgk45xRnzAx8Ch87PFEiqRhoc3FWBmY+LBrvEGQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "tldts-core": "^7.4.14" + }, + "bin": { + "tldts": "bin/cli.js" + } + }, + "node_modules/tldts-core": { + "version": "7.4.14", + "resolved": "https://registry.npmjs.org/tldts-core/-/tldts-core-7.4.14.tgz", + "integrity": "sha512-KYkjfJHnIC5t+Gy7hPrMHgJmWc/N9FfmS+fggRPSlpFckidpB9HD6OzPsSTkfDH+MpZgcu2tJPGgLfHl979N1Q==", + "dev": true, + "license": "MIT" + }, + "node_modules/to-buffer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/to-buffer/-/to-buffer-1.2.2.tgz", + "integrity": "sha512-db0E3UJjcFhpDhAF4tLo03oli3pwl3dbnzXOUIlRKrp+ldk/VUxzpWYZENsw2SZiuBjHAk7DfB0VU7NKdpb6sw==", + "dev": true, + "license": "MIT", + "dependencies": { + "isarray": "^2.0.5", + "safe-buffer": "^5.2.1", + "typed-array-buffer": "^1.0.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/totalist": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/totalist/-/totalist-3.0.1.tgz", + "integrity": "sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-6.0.2.tgz", + "integrity": "sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==", + "dev": true, + "license": "BSD-3-Clause", + "dependencies": { + "tldts": "^7.0.5" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/tr46": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-6.0.0.tgz", + "integrity": "sha512-bLVMLPtstlZ4iMQHpFHTR7GAGj2jxi8Dg0s2h2MafAE4uSWF98FC/3MomU51iQAMf8/qDUbKWf5GxuvvVcXEhw==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^2.3.1" + }, + "engines": { + "node": ">=20" + } + }, + "node_modules/tr46/node_modules/punycode": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", + "integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/tslib": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", + "integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==", + "license": "0BSD" + }, + "node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==", + "dev": true, + "license": "MIT" + }, + "node_modules/type-detect": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.1.0.tgz", + "integrity": "sha512-Acylog8/luQ8L7il+geoSxhEkazvkslg7PSNKOX59mbB9cOveP5aq9h74Y7YU8yDpJwetzQQrfIwtf4Wp4LKcw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "4.41.0", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-4.41.0.tgz", + "integrity": "sha512-TeTSQ6H5YHvpqVwBRcnLDCBnDOHWYu7IvGbHT6N8AOymcr9PJGjc1GTtiWZTYg0NCgYwvnYWEkVChQAr9bjfwA==", + "dev": true, + "license": "(MIT OR CC0-1.0)", + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "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/typescript": { + "version": "5.9.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.3.tgz", + "integrity": "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/undici": { + "version": "7.29.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-7.29.1.tgz", + "integrity": "sha512-RYONW2MeafgYlkVOKYKkA/Ag7BmXqgIWCa8t1m0JcxrQg9pI9lEqRhAOruOBCbAohOa/gkCF+iPi9hrgvTzu6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20.18.1" + } + }, + "node_modules/undici-types": { + "version": "7.18.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", + "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "dev": true, + "license": "MIT" + }, + "node_modules/unicorn-magic": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/unicorn-magic/-/unicorn-magic-0.4.0.tgz", + "integrity": "sha512-wH590V9VNgYH9g3lH9wWjTrUoKsjLF6sGLjhR4sH1LWpLmCOH0Zf7PukhDA8BiS7KHe4oPNkcTHqYkj7SOGUOw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.3.3.tgz", + "integrity": "sha512-pJ2sYawQS0R/WI928Gj5GlPhTGzbMelq0+4INtSYNDV9ErKJcX6xjGWkoG/VnB3dpUm00zALaqkrUD77pO5TDQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "license": "MIT", + "dependencies": { + "escalade": "^3.2.0", + "picocolors": "^1.1.1" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/url": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz", + "integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "punycode": "^1.4.1", + "qs": "^6.12.3" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/util": { + "version": "0.12.5", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.5.tgz", + "integrity": "sha512-kZf/K6hEIrWHI6XqOFUiiMa+79wE/D8Q+NCNAWclkyg3b4d2k7s0QGepNjiABc+aR3N1PAyHL7p6UcLY6LmrnA==", + "dev": true, + "license": "MIT", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", + "dev": true, + "license": "MIT" + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/w3c-xmlserializer": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz", + "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==", + "dev": true, + "license": "MIT", + "dependencies": { + "xml-name-validator": "^5.0.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/watchpack": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.5.2.tgz", + "integrity": "sha512-6i/00NBjP4yGPs+caKSyRfpTF/8Torsu0MOW3mMzIbhgISFder8i7xbqgHlLMwJrdiN8ndBV3UA1/AfzPSr+jg==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webidl-conversions": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-8.0.1.tgz", + "integrity": "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ==", + "dev": true, + "license": "BSD-2-Clause", + "engines": { + "node": ">=20" + } + }, + "node_modules/webpack": { + "version": "5.111.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.111.1.tgz", + "integrity": "sha512-cNypaz0RP+S4cvQVi1M/3bRUkvNP0xZpL0TjFx+c6jg64VbxD+2weWDgY9UnjRI6dhZgtaj8DU76GGFcJ79xPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "dependencies": { + "@types/estree": "^1.0.8", + "@types/json-schema": "^7.0.15", + "@webassemblyjs/ast": "^1.14.1", + "@webassemblyjs/wasm-edit": "^1.14.1", + "@webassemblyjs/wasm-parser": "^1.14.1", + "browserslist": "^4.28.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.25.0", + "es-module-lexer": "^2.1.0", + "events": "^3.2.0", + "graceful-fs": "^4.2.11", + "mime-db": "^1.54.0", + "minimizer-webpack-plugin": "^5.7.0", + "schema-utils": "^4.5.0", + "tapable": "^2.3.0", + "watchpack": "^2.5.2", + "webpack-sources": "^3.5.1" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-sources": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.5.1.tgz", + "integrity": "sha512-jyuiGJdtvY434z5bUZrjz67v76/ePNvFZTp9Mdz29IlH4+GPsgyGjiv0fKI+M7BdkU6ADjulUcKAd3tUK3WlEw==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack/node_modules/@types/estree": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.9.tgz", + "integrity": "sha512-GhdPgy1el4/ImP05X05Uw4cw2/M93BCUmnEvWZNStlCzEKME4Fkk+YpoA5OiHNQmoS7Cafb8Xa3Pya8m1Qrzeg==", + "dev": true, + "license": "MIT", + "peer": true + }, + "node_modules/webpack/node_modules/mime-db": { + "version": "1.54.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.54.0.tgz", + "integrity": "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ==", + "dev": true, + "license": "MIT", + "peer": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/whatwg-mimetype": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-5.0.0.tgz", + "integrity": "sha512-sXcNcHOC51uPGF0P/D4NVtrkjSU2fNsm9iog4ZvZJsL3rjoDAzXZhkm2MWt1y+PUdggKAYVoMAIYcs78wJ51Cw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + } + }, + "node_modules/whatwg-url": { + "version": "16.0.1", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-16.0.1.tgz", + "integrity": "sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==", + "dev": true, + "license": "MIT", + "dependencies": { + "@exodus/bytes": "^1.11.0", + "tr46": "^6.0.0", + "webidl-conversions": "^8.0.1" + }, + "engines": { + "node": "^20.19.0 || ^22.12.0 || >=24.0.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "license": "ISC", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "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/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true, + "license": "ISC" + }, + "node_modules/ws": { + "version": "8.21.3", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz", + "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/wsl-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/wsl-utils/-/wsl-utils-1.0.0.tgz", + "integrity": "sha512-Hl0ZOAs672vg+06kfujwRhoS6/jehvULrlFkuF2dRu6pHgA8U06h3xqNIqNNU1LTXPcedxByAR4GS6pwQK0mgA==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-wsl": "^3.1.0", + "powershell-utils": "^0.1.0" + }, + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wsl-utils/node_modules/powershell-utils": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/powershell-utils/-/powershell-utils-0.1.0.tgz", + "integrity": "sha512-dM0jVuXJPsDN6DvRpea484tCUaMiXWjuCn++HGTqUWzGDjv5tZkEZldAJ/UMlqRYGFrD/etByo4/xOuC/snX2A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/xml-name-validator": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz", + "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==", + "dev": true, + "license": "Apache-2.0", + "engines": { + "node": ">=18" + } + }, + "node_modules/xmlchars": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz", + "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw==", + "dev": true, + "license": "MIT" + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true, + "license": "ISC" + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/yoctocolors": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/yoctocolors/-/yoctocolors-2.2.0.tgz", + "integrity": "sha512-xYqdZFUK/VYazNl/oCDYN+3WloWQwMfZxBoiNt6qNyk+xfOdi598muWE42rNZFp1kNOiqW936q5RhUdnpqElSg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + } + } +} diff --git a/memory-match/package.json b/memory-match/package.json new file mode 100644 index 00000000..22649abd --- /dev/null +++ b/memory-match/package.json @@ -0,0 +1,67 @@ +{ + "name": "memory-match", + "version": "0.0.0", + "private": true, + "description": "A Meteor Memory Match game showcasing Rstest from unit tests to live DDP and browser E2E", + "engines": { + "node": ">=22.12.0" + }, + "scripts": { + "setup": "node scripts/setup.mjs", + "typecheck": "tsc --noEmit", + "test:tooling": "node --test tests/tooling/*.test.mjs", + "start": "./meteor-checkout run", + "test": "./meteor-checkout test --once --server-only --project meteor-pure-server --project showcase-in-source", + "test:unit": "./meteor-checkout test --once --server-only --project meteor-pure-server --project showcase-in-source", + "test:watch": "./meteor-checkout test --server-only --project meteor-pure-server --project showcase-in-source", + "test:component": "./meteor-checkout test --once --client-only --project meteor-pure-client", + "test:browser": "./meteor-checkout test --once --client-only --browser chromium --project meteor-browser", + "test:integration": "./meteor-checkout test --once --browser chromium --project meteor-runtime-server --project meteor-runtime-client", + "test:package": "./meteor-checkout test-packages --once memory-match-engine", + "test:e2e": "./meteor-checkout test --once --full-app --browser chromium --project meteor-e2e", + "test:coverage": "./meteor-checkout test --once --coverage --full-app --runtime-workers 1", + "test:parallel:native": "./meteor-checkout test --once --server-only --project meteor-pure-server -- --pool.type threads --pool.maxWorkers 4", + "test:parallel:meteor": "./meteor-checkout test --once --server-only --runtime-workers 2 --project meteor-runtime-server" + }, + "dependencies": { + "@babel/runtime": "^7.28.4", + "@swc/helpers": "^0.5.17", + "meteor-node-stubs": "^1.2.18", + "react": "^19.2.0", + "react-dom": "^19.2.0" + }, + "devDependencies": { + "@meteorjs/rspack": "file:.meteor/local/npm/meteor-rspack", + "@meteorjs/rstest": "file:.meteor/local/npm/meteor-rstest", + "@rsdoctor/rspack-plugin": "^1.5.9", + "@rspack/cli": "2.1.8", + "@rspack/core": "2.1.8", + "@rspack/dev-server": "^2.1.0", + "@rspack/plugin-react-refresh": "^2.0.0", + "@rstest/adapter-rspack": "0.11.6", + "@rstest/browser": "0.11.6", + "@rstest/browser-react": "0.11.6", + "@rstest/core": "0.11.6", + "@rstest/coverage-istanbul": "0.11.6", + "@rstest/playwright": "0.11.6", + "@swc/core": "^1.15.32", + "@testing-library/dom": "^10.4.1", + "@testing-library/react": "^16.3.0", + "@testing-library/user-event": "^14.6.1", + "@types/meteor": "^2.9.8", + "@types/node": "^24.0.0", + "@types/react": "^19.2.0", + "@types/react-dom": "^19.2.0", + "jsdom": "29.1.1", + "playwright": "1.59.0", + "react-refresh": "^0.17.0", + "typescript": "^5.9.0" + }, + "meteor": { + "mainModule": { + "client": "client/main.tsx", + "server": "server/main.ts" + }, + "modern": true + } +} diff --git a/memory-match/packages/memory-match-engine/engine.tests.ts b/memory-match/packages/memory-match-engine/engine.tests.ts new file mode 100644 index 00000000..54ca5c37 --- /dev/null +++ b/memory-match/packages/memory-match-engine/engine.tests.ts @@ -0,0 +1,44 @@ +import { Meteor } from 'meteor/meteor'; +import { Mongo } from 'meteor/mongo'; +import { afterEach, expect, test } from '@rstest/core'; +import { createPairDeck } from 'meteor/memory-match-engine'; + +const PackageTestDocuments = Meteor.isServer + ? new Mongo.Collection<{ source: string }>('memory_match_engine_package_tests') + : null; + +test('local package export creates deterministic card pairs', () => { + expect(createPairDeck(['moon', 'sun'])).toEqual([ + { id: 'moon-1', symbol: 'moon' }, + { id: 'moon-2', symbol: 'moon' }, + { id: 'sun-1', symbol: 'sun' }, + { id: 'sun-2', symbol: 'sun' }, + ]); +}); + +if (Meteor.isServer && PackageTestDocuments) { + afterEach(async () => { + await PackageTestDocuments.removeAsync({}); + }); + + test('Package.onTest server owns real Meteor and Mongo context', async () => { + expect(Meteor.isServer).toBe(true); + const id = await PackageTestDocuments.insertAsync({ + source: 'memory-match-engine-package-test', + }); + expect(await PackageTestDocuments.findOneAsync(id)).toEqual({ + _id: id, + source: 'memory-match-engine-package-test', + }); + }); +} + +if (Meteor.isClient) { + test('Package.onTest client runs package export in Meteor browser', () => { + expect(Meteor.isClient).toBe(true); + expect(createPairDeck(['star'])).toEqual([ + { id: 'star-1', symbol: 'star' }, + { id: 'star-2', symbol: 'star' }, + ]); + }); +} diff --git a/memory-match/packages/memory-match-engine/engine.ts b/memory-match/packages/memory-match-engine/engine.ts new file mode 100644 index 00000000..c245906d --- /dev/null +++ b/memory-match/packages/memory-match-engine/engine.ts @@ -0,0 +1,11 @@ +export interface PairCard { + id: string; + symbol: string; +} + +export function createPairDeck(symbols: readonly string[]): PairCard[] { + return symbols.flatMap((symbol) => [ + { id: `${symbol}-1`, symbol }, + { id: `${symbol}-2`, symbol }, + ]); +} diff --git a/memory-match/packages/memory-match-engine/meteor.d.ts b/memory-match/packages/memory-match-engine/meteor.d.ts new file mode 100644 index 00000000..049ee47f --- /dev/null +++ b/memory-match/packages/memory-match-engine/meteor.d.ts @@ -0,0 +1,10 @@ +declare module 'meteor/memory-match-engine' { + export interface PairCard { + id: string; + symbol: string; + } + + export function createPairDeck( + symbols: readonly string[], + ): PairCard[]; +} diff --git a/memory-match/packages/memory-match-engine/package.js b/memory-match/packages/memory-match-engine/package.js new file mode 100644 index 00000000..cd393848 --- /dev/null +++ b/memory-match/packages/memory-match-engine/package.js @@ -0,0 +1,24 @@ +Package.describe({ + name: 'memory-match-engine', + version: '0.0.1', + summary: 'Local package example for Meteor Rstest package tests', +}); + +Package.onUse((api) => { + api.versionsFrom('3.4'); + api.use(['ecmascript', 'typescript']); + api.mainModule('engine.ts'); + api.addAssets('meteor.d.ts', 'server'); +}); + +Package.onTest((api) => { + api.versionsFrom('3.4'); + api.use([ + 'ecmascript', + 'typescript', + 'mongo', + 'rstest', + 'memory-match-engine', + ]); + api.mainModule('engine.tests.ts'); +}); diff --git a/memory-match/rspack.config.ts b/memory-match/rspack.config.ts new file mode 100644 index 00000000..f9885a7f --- /dev/null +++ b/memory-match/rspack.config.ts @@ -0,0 +1,10 @@ +import { defineConfig } from '@meteorjs/rspack'; +import { DefinePlugin } from '@rspack/core'; + +export default defineConfig(() => ({ + plugins: [ + new DefinePlugin({ + 'import.meta.rstest': 'false', + }), + ], +})); diff --git a/memory-match/rstest.config.ts b/memory-match/rstest.config.ts new file mode 100644 index 00000000..53cf607a --- /dev/null +++ b/memory-match/rstest.config.ts @@ -0,0 +1,91 @@ +import path from 'node:path'; +import { defineConfig } from '@meteorjs/rstest'; +import { defineInlineProject } from '@rstest/core'; + +export default defineConfig((context) => { + return { + globals: true, + clearMocks: true, + restoreMocks: true, + unstubEnvs: true, + unstubGlobals: true, + testTimeout: context.fullApp ? 45_000 : 10_000, + hookTimeout: 15_000, + maxConcurrency: 2, + setupFiles: [ + path.join(context.appRoot, 'tests/setup/common.ts'), + path.join(context.appRoot, 'tests/setup/dom.ts'), + ], + env: { + NODE_ENV: 'development', + SHOWCASE_CONFIG_PHASE: context.phase, + SHOWCASE_CONFIG_APP_ROOT: context.appRoot, + }, + browser: { + provider: 'playwright', + browser: 'chromium', + headless: process.env.SHOWCASE_HEADED !== '1', + viewport: { width: 1280, height: 800 }, + }, + coverage: { + provider: 'istanbul', + allowExternal: true, + include: [ + path.join(context.appRoot, 'imports/game/**/*.{ts,tsx}'), + path.join(context.appRoot, 'imports/ui/**/*.{ts,tsx}'), + path.join(context.appRoot, 'packages/memory-match-engine/**/*.{ts,tsx}'), + ], + exclude: [ + path.join(context.appRoot, 'imports/game/rstest-env.d.ts'), + '**/*.d.ts', + '**/*.{test,spec}.{ts,tsx}', + '**/__snapshots__/**', + ], + reportsDirectory: path.join(context.appRoot, 'coverage'), + reporters: ['text', 'html', 'json-summary'], + }, + performance: { buildCache: true }, + tools: { + rspack(config) { + const rules = config.module?.rules ?? []; + if (config.module) { + config.module.rules = rules.filter((rule) => !( + typeof rule === 'object' + && rule + && 'type' in rule + && rule.type === 'css/auto' + )); + } + for (const rule of rules) { + if ( + typeof rule === 'object' + && rule + && 'loader' in rule + && rule.loader === 'builtin:swc-loader' + ) { + const options = rule.options as { + jsc?: { + transform?: { + react?: { refresh?: boolean; runtime?: 'automatic' | 'classic' }; + }; + }; + } | undefined; + if (options?.jsc?.transform?.react) { + options.jsc.transform.react.refresh = false; + options.jsc.transform.react.runtime = 'automatic'; + } + } + } + return config; + }, + }, + projects: context.phase === 'native' + ? [defineInlineProject({ + name: 'showcase-in-source', + root: path.join(context.appRoot, 'imports/game'), + includeSource: ['shuffle.ts'], + testEnvironment: 'node', + })] + : [], + }; +}); diff --git a/memory-match/scripts/checkout.mjs b/memory-match/scripts/checkout.mjs new file mode 100644 index 00000000..7fe5ce8b --- /dev/null +++ b/memory-match/scripts/checkout.mjs @@ -0,0 +1,163 @@ +import { spawnSync } from 'node:child_process'; +import { + existsSync, + lstatSync, + mkdirSync, + readFileSync, + realpathSync, + renameSync, + rmSync, + symlinkSync, + unlinkSync, + writeFileSync, +} from 'node:fs'; +import path from 'node:path'; +import { fileURLToPath } from 'node:url'; + +export const appRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..'); +export const expectedBranch = 'rspack-rstest-integration'; + +const requiredPaths = [ + 'meteor', + 'packages/rspack/package.js', + 'packages/rstest/package.js', + 'npm-packages/meteor-rspack/package.json', + 'npm-packages/meteor-rstest/package.json', +]; + +export function resolveCheckout(env = process.env) { + const configuredRoot = env.METEOR_CHECKOUT || path.resolve(appRoot, '../../meteor'); + if (!path.isAbsolute(configuredRoot)) { + throw new Error(`METEOR_CHECKOUT must be absolute: ${configuredRoot}`); + } + const root = existsSync(configuredRoot) ? realpathSync(configuredRoot) : configuredRoot; + const missing = requiredPaths.filter((relative) => !existsSync(path.join(root, relative))); + if (missing.length) { + throw new Error( + `Meteor checkout is incomplete at ${root}. Missing:\n${missing.join('\n')}\n` + + `Set METEOR_CHECKOUT to a checkout of ${expectedBranch}.`, + ); + } + const branch = env.METEOR_RSTEST_BRANCH || expectedBranch; + const result = spawnSync('git', ['-C', root, 'branch', '--show-current'], { + encoding: 'utf8', + }); + if (result.error || result.status !== 0) { + throw new Error(`Unable to inspect Meteor checkout branch: ${result.error?.message || result.stderr}`); + } + const currentBranch = result.stdout.trim(); + if (currentBranch !== branch) { + throw new Error( + `Meteor checkout branch is ${currentBranch || '(detached HEAD)'}; expected ${branch}. ` + + 'Use a checkout on the required branch, or set METEOR_RSTEST_BRANCH for a compatible development branch.', + ); + } + return Object.freeze({ + root, + branch, + meteorBinary: path.join(root, 'meteor'), + packagesDir: path.join(root, 'packages'), + rspackNpmPackage: path.join(root, 'npm-packages/meteor-rspack'), + rstestNpmPackage: path.join(root, 'npm-packages/meteor-rstest'), + }); +} + +export function withCheckoutEnvironment(checkout, env = process.env) { + return { + ...env, + METEOR_CHECKOUT: checkout.root, + METEOR_PACKAGE_DIRS: [checkout.packagesDir, env.METEOR_PACKAGE_DIRS].filter(Boolean).join(path.delimiter), + METEOR_RSPACK_NPM_SPEC: checkout.rspackNpmPackage, + METEOR_RSTEST_NPM_SPEC: checkout.rstestNpmPackage, + DO_NOT_TRACK: env.DO_NOT_TRACK || '1', + }; +} + +// Stable app-relative specs keep machine paths out of package.json and its lockfile. +// npm's install-links option copies these packages into the app so their imports +// resolve against the app's dependency tree instead of the Meteor repository. +export function prepareLocalPackages(checkout, root = appRoot) { + const directory = path.join(root, '.meteor/local/npm'); + mkdirSync(directory, { recursive: true }); + for (const [name, source] of [ + ['meteor-rspack', checkout.rspackNpmPackage], + ['meteor-rstest', checkout.rstestNpmPackage], + ]) { + const target = path.join(directory, name); + const existing = lstatSync(target, { throwIfNoEntry: false }); + if (existing && !existing.isSymbolicLink()) { + throw new Error(`Expected a generated package symlink at ${target}`); + } + if (existing) unlinkSync(target); + symlinkSync(source, target, 'dir'); + // Refresh same-version checkout packages when setup is run again. + rmSync(path.join(root, 'node_modules/@meteorjs', name.slice('meteor-'.length)), { + recursive: true, + force: true, + }); + } +} + +export function createSetupPlan({ checkout, appRoot: root }) { + return [ + { + command: checkout.meteorBinary, + args: ['npm', 'install', '--include=dev', '--install-links=true', '--no-audit', '--no-fund'], + cwd: root, + }, + { command: checkout.meteorBinary, args: ['lint'], cwd: root }, + ]; +} + +// The experimental checkout still requires the pre-v2 default export here. +// Patch only the app's installed copy; the source checkout remains untouched. +// Remove this once rspack-rstest-integration accepts the v2 named export. +export function patchInstalledReactRefresh(root = appRoot) { + const configPath = path.join(root, 'node_modules/@meteorjs/rspack/rspack.config.js'); + const source = readFileSync(configPath, 'utf8'); + const original = '? safeRequire("@rspack/plugin-react-refresh")'; + if (!source.includes(original)) return false; + const replacement = `? (() => { + const refresh = safeRequire("@rspack/plugin-react-refresh"); + return refresh?.ReactRefreshRspackPlugin ?? refresh?.default ?? refresh; + })()`; + writeFileSync(configPath, source.replace(original, replacement)); + return true; +} + +function shellQuote(value) { + return `'${String(value).replaceAll("'", "'\"'\"'")}'`; +} + +export function renderCheckoutLauncher(checkout) { + return [ + '#!/bin/sh', + 'set -eu', + `checkout=${shellQuote(checkout.root)}`, + `expected=${shellQuote(checkout.branch)}`, + 'current=$(git -C "$checkout" branch --show-current)', + 'if [ "$current" != "$expected" ]; then', + ' printf "Meteor checkout branch is %s; expected %s. Rerun npm run setup with a compatible checkout.\\n" "${current:-detached HEAD}" "$expected" >&2', + ' exit 2', + 'fi', + 'export METEOR_CHECKOUT="$checkout"', + 'export METEOR_PACKAGE_DIRS="$checkout/packages${METEOR_PACKAGE_DIRS:+:$METEOR_PACKAGE_DIRS}"', + 'export METEOR_RSPACK_NPM_SPEC="$checkout/npm-packages/meteor-rspack"', + 'export METEOR_RSTEST_NPM_SPEC="$checkout/npm-packages/meteor-rstest"', + 'export DO_NOT_TRACK="${DO_NOT_TRACK:-1}"', + 'exec "$checkout/meteor" "$@"', + '', + ].join('\n'); +} + +export function writeCheckoutLauncher({ checkout, appRoot: root }) { + const launcherPath = path.join(root, 'meteor-checkout'); + const temporaryPath = `${launcherPath}.tmp-${process.pid}`; + try { + writeFileSync(temporaryPath, renderCheckoutLauncher(checkout), { mode: 0o755 }); + renameSync(temporaryPath, launcherPath); + } finally { + rmSync(temporaryPath, { force: true }); + } + return launcherPath; +} diff --git a/memory-match/scripts/setup.mjs b/memory-match/scripts/setup.mjs new file mode 100644 index 00000000..d4c96fc4 --- /dev/null +++ b/memory-match/scripts/setup.mjs @@ -0,0 +1,35 @@ +#!/usr/bin/env node +import { spawnSync } from 'node:child_process'; +import { + appRoot, + createSetupPlan, + patchInstalledReactRefresh, + prepareLocalPackages, + resolveCheckout, + withCheckoutEnvironment, + writeCheckoutLauncher, +} from './checkout.mjs'; + +try { + const checkout = resolveCheckout(); + console.log(`Meteor checkout: ${checkout.root} (${checkout.branch})`); + prepareLocalPackages(checkout); + for (const step of createSetupPlan({ checkout, appRoot })) { + console.log(`\n$ meteor ${step.args.join(' ')}`); + const result = spawnSync(step.command, step.args, { + cwd: step.cwd, + env: withCheckoutEnvironment(checkout), + stdio: 'inherit', + }); + if (result.error) throw result.error; + if (result.status !== 0) process.exit(result.status ?? 1); + } + if (patchInstalledReactRefresh()) { + console.log('Applied React Refresh v2 compatibility to the installed Rspack package.'); + } + writeCheckoutLauncher({ checkout, appRoot }); + console.log('\nReady. Run npm start, or npm run test:unit.'); +} catch (error) { + console.error(error.message); + process.exitCode = 1; +} diff --git a/memory-match/server/health.ts b/memory-match/server/health.ts new file mode 100644 index 00000000..b175e0d1 --- /dev/null +++ b/memory-match/server/health.ts @@ -0,0 +1,22 @@ +import type { IncomingMessage, ServerResponse } from 'node:http'; +import { WebApp } from 'meteor/webapp'; + +import { Games } from '../imports/api/games'; + +WebApp.connectHandlers.use('/health', async ( + _request: IncomingMessage, + response: ServerResponse, +) => { + try { + await Games.rawCollection().estimatedDocumentCount({ maxTimeMS: 1_000 }); + response.writeHead(200, { 'content-type': 'application/json; charset=utf-8' }); + response.end(JSON.stringify({ ok: true, mongo: 'ready' })); + } catch (error) { + response.writeHead(503, { 'content-type': 'application/json; charset=utf-8' }); + response.end(JSON.stringify({ + ok: false, + mongo: 'unavailable', + error: error instanceof Error ? error.message : String(error), + })); + } +}); diff --git a/memory-match/server/main.ts b/memory-match/server/main.ts new file mode 100644 index 00000000..22e893ba --- /dev/null +++ b/memory-match/server/main.ts @@ -0,0 +1,5 @@ +import '../imports/api/methods'; +import '../imports/api/publications'; +import './health'; + +console.log('[memory] server ready'); diff --git a/memory-match/tests/e2e/helpers.ts b/memory-match/tests/e2e/helpers.ts new file mode 100644 index 00000000..26091f8c --- /dev/null +++ b/memory-match/tests/e2e/helpers.ts @@ -0,0 +1,39 @@ +import { mkdirSync } from 'node:fs'; +import path from 'node:path'; +import { expect } from '@rstest/playwright'; +import type { Page } from 'playwright'; + +import { createDeck } from '../../imports/game/shuffle'; + +export const baseUrl = process.env.METEOR_RSTEST_BASE_URL; + +export function requireBaseUrl(): string { + if (!baseUrl) throw new Error('METEOR_RSTEST_BASE_URL was not provided'); + return baseUrl; +} + +export function failureScreenshotPath(taskId: string): string { + const safeId = taskId.replace(/[^a-z0-9._-]+/gi, '-'); + const destination = path.resolve('reports/failures', `${safeId}.png`); + mkdirSync(path.dirname(destination), { recursive: true }); + return destination; +} + +export async function completeGame(page: Page, seed: string): Promise { + const cards = page.getByRole('grid', { name: 'Memory cards' }).getByRole('button'); + const groups = new Map(); + createDeck(seed).forEach((card, index) => groups.set(card.symbol, [ + ...(groups.get(card.symbol) ?? []), + index, + ])); + + let pairNumber = 0; + for (const [first, second] of groups.values()) { + await cards.nth(first).click(); + await expect(cards.nth(first)).toHaveAttribute('data-state', 'revealed'); + await cards.nth(second).click(); + pairNumber += 1; + await expect(page.locator('.memory-card[data-state="matched"]')) + .toHaveCount(pairNumber * 2); + } +} diff --git a/memory-match/tests/e2e/memory-game.test.ts b/memory-match/tests/e2e/memory-game.test.ts new file mode 100644 index 00000000..8827a465 --- /dev/null +++ b/memory-match/tests/e2e/memory-game.test.ts @@ -0,0 +1,59 @@ +import { expect, test, type PlaywrightOptions } from '@rstest/playwright'; + +import { completeGame, failureScreenshotPath, requireBaseUrl } from './helpers'; + +const headed = process.env.SHOWCASE_HEADED === '1'; +const e2e = test.extend({ + playwright: { + launchOptions: { headless: !headed, slowMo: headed ? 100 : 0 }, + trace: 'retain-on-failure', + } satisfies PlaywrightOptions, +}); + +e2e('completed game appears reactively in second browser context', async ({ + browser, + onTestFailed, + page, + request, +}) => { + onTestFailed(async ({ task }) => { + await page.screenshot({ fullPage: true, path: failureScreenshotPath(task.id) }); + }); + + const seed = 'e2e-showcase'; + const url = requireBaseUrl(); + const health = await request.get(new URL('/health', url).toString()); + expect(health.status()).toBe(200); + expect(await health.json()).toEqual({ ok: true, mongo: 'ready' }); + + const observerContext = await browser.newContext(); + const observer = await observerContext.newPage(); + try { + await observer.goto(url); + await expect(observer.getByText('No completed games yet.')) + .toBeVisible({ timeout: 15_000 }); + + await page.goto(`${url}?seed=${seed}`); + await expect(page).toHaveTitle(/Memory Match.*Meteor Rstest Showcase/i); + await expect(page.getByRole('heading', { name: 'Memory Match' })).toBeVisible(); + await expect(page.getByLabel('Player name')).toBeVisible(); + await page.getByLabel('Player name').fill('E2E Ada'); + await page.getByRole('button', { name: 'Start game' }).click(); + await expect(page.getByRole('grid', { name: 'Memory cards' })).toBeVisible(); + + await completeGame(page, seed); + await expect(page.getByRole('status')).toContainText('Game completed'); + await expect(page.getByRole('status')).toContainText('8 moves'); + await expect(observer.getByRole('listitem').filter({ hasText: 'E2E Ada' })) + .toBeVisible({ timeout: 10_000 }); + + await page.getByRole('button', { name: 'New game' }).click(); + await page.getByLabel('Player name').fill('E2E Grace'); + await page.getByRole('button', { name: 'Start game' }).click(); + await expect(page.getByRole('heading', { name: "E2E Grace's board" })).toBeVisible(); + await expect(page.getByRole('status')).toContainText('Moves: 0'); + await expect(page.getByRole('button', { name: /^Hidden card/ })).toHaveCount(16); + } finally { + await observerContext.close(); + } +}); diff --git a/memory-match/tests/rstest/pure/server/compatibility.test.ts b/memory-match/tests/rstest/pure/server/compatibility.test.ts new file mode 100644 index 00000000..b98e7f8c --- /dev/null +++ b/memory-match/tests/rstest/pure/server/compatibility.test.ts @@ -0,0 +1,10 @@ +import path from 'node:path'; +import { expect, test } from '@rstest/core'; + +// Intentionally kept under tests/rstest to prove compatibility-root routing. +test('compatibility root receives Meteor native config context', () => { + expect(process.env.SHOWCASE_CONFIG_PHASE).toBe('native'); + expect(process.env.SHOWCASE_CONFIG_APP_ROOT).toBe( + path.resolve(import.meta.dirname, '../../../..'), + ); +}); diff --git a/memory-match/tests/setup/common.ts b/memory-match/tests/setup/common.ts new file mode 100644 index 00000000..191b611d --- /dev/null +++ b/memory-match/tests/setup/common.ts @@ -0,0 +1,7 @@ +import { afterEach, rs } from '@rstest/core'; + +afterEach(() => { + rs.restoreAllMocks(); + rs.unstubAllEnvs(); + rs.unstubAllGlobals(); +}); diff --git a/memory-match/tests/setup/dom.ts b/memory-match/tests/setup/dom.ts new file mode 100644 index 00000000..f3e005e5 --- /dev/null +++ b/memory-match/tests/setup/dom.ts @@ -0,0 +1,15 @@ +if (typeof window !== 'undefined' && !window.matchMedia) { + Object.defineProperty(window, 'matchMedia', { + configurable: true, + value: (query: string) => ({ + matches: false, + media: query, + onchange: null, + addEventListener() {}, + removeEventListener() {}, + addListener() {}, + removeListener() {}, + dispatchEvent() { return false; }, + }), + }); +} diff --git a/memory-match/tests/tooling/checkout.test.mjs b/memory-match/tests/tooling/checkout.test.mjs new file mode 100644 index 00000000..bcbd7971 --- /dev/null +++ b/memory-match/tests/tooling/checkout.test.mjs @@ -0,0 +1,138 @@ +import assert from 'node:assert/strict'; +import { spawnSync } from 'node:child_process'; +import { + chmodSync, existsSync, mkdirSync, mkdtempSync, readFileSync, realpathSync, + rmSync, statSync, writeFileSync, +} from 'node:fs'; +import { tmpdir } from 'node:os'; +import path from 'node:path'; +import test from 'node:test'; + +import { + expectedBranch, patchInstalledReactRefresh, prepareLocalPackages, resolveCheckout, + withCheckoutEnvironment, writeCheckoutLauncher, +} from '../../scripts/checkout.mjs'; + +function git(root, ...args) { + const result = spawnSync('git', ['-C', root, ...args], { encoding: 'utf8' }); + assert.equal(result.status, 0, result.stderr); +} + +function temporaryRoot(t) { + // Exercise shell quoting as well as ordinary paths. + const root = mkdtempSync(path.join(tmpdir(), "memory match's ")); + t.after(() => rmSync(root, { recursive: true, force: true })); + return root; +} + +function fakeCheckout(t, branch = expectedBranch) { + const root = temporaryRoot(t); + for (const relative of [ + 'meteor', 'packages/rspack/package.js', 'packages/rstest/package.js', + 'npm-packages/meteor-rspack/package.json', 'npm-packages/meteor-rstest/package.json', + ]) { + const target = path.join(root, relative); + mkdirSync(path.dirname(target), { recursive: true }); + writeFileSync(target, 'fixture'); + } + git(root, 'init', '--initial-branch', branch); + return root; +} + +test('rejects relative checkout paths and lists missing capabilities', (t) => { + assert.throws(() => resolveCheckout({ METEOR_CHECKOUT: '../meteor' }), /must be absolute/); + const root = temporaryRoot(t); + assert.throws(() => resolveCheckout({ METEOR_CHECKOUT: root }), + /meteor.*packages\/rspack.*packages\/rstest.*meteor-rspack.*meteor-rstest/s); +}); + +test('refuses the wrong branch without changing the checkout', (t) => { + const root = fakeCheckout(t, 'capacitor-integration'); + assert.throws(() => resolveCheckout({ METEOR_CHECKOUT: root }), + /branch is capacitor-integration; expected rspack-rstest-integration/); + const checkout = resolveCheckout({ + METEOR_CHECKOUT: root, METEOR_RSTEST_BRANCH: 'capacitor-integration', + }); + assert.equal(checkout.branch, 'capacitor-integration'); +}); + +test('normalizes checkout paths and preserves custom package directories', (t) => { + const root = fakeCheckout(t); + const checkout = resolveCheckout({ METEOR_CHECKOUT: root }); + const env = withCheckoutEnvironment(checkout, { METEOR_PACKAGE_DIRS: '/custom' }); + assert.equal(checkout.root, realpathSync(root)); + assert.equal(env.METEOR_PACKAGE_DIRS, `${checkout.packagesDir}${path.delimiter}/custom`); + assert.equal(env.METEOR_RSPACK_NPM_SPEC, checkout.rspackNpmPackage); + assert.equal(env.METEOR_RSTEST_NPM_SPEC, checkout.rstestNpmPackage); +}); + +test('setup refreshes local links and copied integrations without altering the manifest', (t) => { + const checkout = resolveCheckout({ METEOR_CHECKOUT: fakeCheckout(t) }); + const root = temporaryRoot(t); + const manifest = '{"name":"fixture"}\n'; + writeFileSync(path.join(root, 'package.json'), manifest); + const installed = path.join(root, 'node_modules/@meteorjs/rstest'); + mkdirSync(installed, { recursive: true }); + writeFileSync(path.join(installed, 'old.js'), 'old checkout'); + prepareLocalPackages(checkout, root); + prepareLocalPackages(checkout, root); + assert.equal(realpathSync(path.join(root, '.meteor/local/npm/meteor-rstest')), checkout.rstestNpmPackage); + assert.equal(existsSync(installed), false); + assert.equal(readFileSync(path.join(root, 'package.json'), 'utf8'), manifest); +}); + +test('launcher preserves arguments, environment, exit status, and checks later branch changes', (t) => { + const root = fakeCheckout(t); + const projectRoot = temporaryRoot(t); + const meteorBinary = path.join(root, 'meteor'); + writeFileSync(meteorBinary, `#!/bin/sh +printf 'packageDirs=%s\\n' "$METEOR_PACKAGE_DIRS" +printf 'rspack=%s\\n' "$METEOR_RSPACK_NPM_SPEC" +printf 'rstest=%s\\n' "$METEOR_RSTEST_NPM_SPEC" +printf 'arg=%s\\n' "$@" +exit 23 +`); + chmodSync(meteorBinary, 0o755); + const checkout = resolveCheckout({ METEOR_CHECKOUT: root }); + const launcher = writeCheckoutLauncher({ checkout, appRoot: projectRoot }); + const args = ['test', '--test-name-pattern', "player's score", '--', '--retry', '2']; + const run = () => spawnSync(launcher, args, { + encoding: 'utf8', env: { ...process.env, METEOR_PACKAGE_DIRS: '/custom/packages' }, + }); + const result = run(); + assert.equal(result.status, 23, result.stderr); + assert.equal(result.stderr, ''); + assert(result.stdout.includes(`packageDirs=${checkout.packagesDir}:/custom/packages\n`)); + assert(result.stdout.includes(`rspack=${checkout.rspackNpmPackage}\n`)); + assert(result.stdout.includes(`rstest=${checkout.rstestNpmPackage}\n`)); + assert(result.stdout.endsWith(args.map((arg) => `arg=${arg}\n`).join(''))); + assert.equal(statSync(launcher).mode & 0o777, 0o755); + git(root, 'symbolic-ref', 'HEAD', 'refs/heads/main'); + const changed = run(); + assert.equal(changed.status, 2); + assert.match(changed.stderr, /branch is main; expected rspack-rstest-integration/); + assert.equal(changed.stdout, ''); +}); + +test('development compatibility accepts the v2 React Refresh constructor and is idempotent', (t) => { + const root = temporaryRoot(t); + const config = path.join(root, 'node_modules/@meteorjs/rspack/rspack.config.js'); + mkdirSync(path.dirname(config), { recursive: true }); + writeFileSync(config, ` + const reactRefreshModule = isReactEnabled + ? safeRequire("@rspack/plugin-react-refresh") + : null; + return reactRefreshModule ? new reactRefreshModule() : null; + `); + assert.equal(patchInstalledReactRefresh(root), true); + const patched = readFileSync(config, 'utf8'); + const run = new Function('isReactEnabled', 'safeRequire', patched); + class RefreshPlugin {} + for (const module of [{ ReactRefreshRspackPlugin: RefreshPlugin }, { default: RefreshPlugin }, RefreshPlugin]) { + assert(run(true, () => module) instanceof RefreshPlugin); + } + assert.equal(run(false, () => { throw new Error('should not load'); }), null); + assert.equal(run(true, () => null), null); + assert.equal(patchInstalledReactRefresh(root), false); + assert.equal(readFileSync(config, 'utf8'), patched); +}); diff --git a/memory-match/tests/tooling/showcase-layout.test.mjs b/memory-match/tests/tooling/showcase-layout.test.mjs new file mode 100644 index 00000000..ff176196 --- /dev/null +++ b/memory-match/tests/tooling/showcase-layout.test.mjs @@ -0,0 +1,80 @@ +import assert from 'node:assert/strict'; +import { existsSync, readFileSync, readdirSync } from 'node:fs'; +import path from 'node:path'; +import test from 'node:test'; + +const appRoot = path.resolve(import.meta.dirname, '../..'); + +const primaryExamples = { + native: 'imports/game/rules.test.ts', + browser: 'imports/ui/MemoryGame.interactions.test.tsx', + meteorShared: 'imports/api/runtime-context.test.ts', + e2e: 'tests/e2e/memory-game.test.ts', +}; + +const fallbackExamples = { + globals: 'imports/game/globals.rstest.test.ts', + dom: 'imports/ui/MemoryGame.dom.rstest.test.tsx', + meteorServer: 'imports/api/methods.server.meteor.rstest.test.ts', + meteorClient: 'imports/ui/App.client.meteor.rstest.test.tsx', + compatibility: 'tests/rstest/pure/server/compatibility.test.ts', +}; + +function source(relativePath) { + return readFileSync(path.join(appRoot, relativePath), 'utf8'); +} + +function collectTests(directory) { + if (!existsSync(directory)) return []; + return readdirSync(directory, { withFileTypes: true }).flatMap((entry) => { + const target = path.join(directory, entry.name); + return entry.isDirectory() + ? collectTests(target) + : /\.(?:test|spec)s?\.[cm]?[jt]sx?$/.test(entry.name) ? [target] : []; + }); +} + +test('dependency imports are primary showcase routing path', () => { + for (const relativePath of Object.values(primaryExamples)) { + assert.equal(existsSync(path.join(appRoot, relativePath)), true, relativePath); + assert.doesNotMatch(relativePath, /\.rstest\.(?:test|spec)/); + } + + assert.match(source(primaryExamples.native), /from ['"]@rstest\/core['"]/); + assert.match(source(primaryExamples.browser), /from ['"]@rstest\/browser['"]/); + assert.match(source(primaryExamples.meteorShared), /from ['"]@rstest\/core['"]/); + assert.match(source(primaryExamples.meteorShared), /from ['"]meteor\/meteor['"]/); + assert.match(source(primaryExamples.e2e), /from ['"]@rstest\/playwright['"]/); +}); + +test('filename and compatibility hints remain secondary fallback examples', () => { + for (const relativePath of Object.values(fallbackExamples)) { + assert.equal(existsSync(path.join(appRoot, relativePath)), true, relativePath); + } + + assert.doesNotMatch(source(fallbackExamples.globals), /from ['"]@rstest\/core['"]/); + assert.match(source(fallbackExamples.globals), /@rstest\/core\/globals/); + assert.match(source(fallbackExamples.dom), /from ['"]@rstest\/core['"]/); + assert.match(source(fallbackExamples.meteorServer), /from ['"]@rstest\/core['"]/); + assert.match(source(fallbackExamples.meteorClient), /from ['"]@rstest\/core['"]/); +}); + +test('all showcase tests use upstream Rstest declarations', () => { + const testFiles = [ + ...collectTests(path.join(appRoot, 'imports')), + ...collectTests(path.join(appRoot, 'packages')), + ...collectTests(path.join(appRoot, 'tests')), + ]; + + for (const file of testFiles) { + assert.doesNotMatch(source(path.relative(appRoot, file)), /from ['"]meteor\/rstest['"]/); + } +}); + +test('only one test remains under compatibility routing roots', () => { + const compatibilityTests = collectTests(path.join(appRoot, 'tests', 'rstest')); + assert.deepEqual( + compatibilityTests.map((file) => path.relative(appRoot, file)), + [fallbackExamples.compatibility], + ); +}); diff --git a/memory-match/tsconfig.json b/memory-match/tsconfig.json new file mode 100644 index 00000000..a4ccade5 --- /dev/null +++ b/memory-match/tsconfig.json @@ -0,0 +1,26 @@ +{ + "compilerOptions": { + "allowJs": true, + "allowSyntheticDefaultImports": true, + "baseUrl": ".", + "esModuleInterop": true, + "jsx": "react-jsx", + "lib": ["DOM", "DOM.Iterable", "ES2023"], + "module": "ESNext", + "moduleResolution": "Bundler", + "noEmit": true, + "paths": { + "meteor/*": [ + "node_modules/@types/meteor/*", + ".meteor/local/types/packages.d.ts" + ] + }, + "preserveSymlinks": true, + "resolveJsonModule": true, + "skipLibCheck": true, + "strict": true, + "target": "ES2022", + "types": ["node", "meteor", "react", "react-dom"] + }, + "include": ["client", "server", "imports", "packages", "tests", "*.config.ts"] +} diff --git a/package.json b/package.json index 8edccae9..482f13c9 100644 --- a/package.json +++ b/package.json @@ -10,6 +10,9 @@ "homepage": "https://github.com/meteor/examples#readme", "license": "MIT", "scripts": { + "setup:memory-match": "npm --prefix memory-match run setup", + "start:memory-match": "npm --prefix memory-match start", + "test:memory-match": "npm --prefix memory-match test", "update:examples": "node scripts/update-examples-json.mjs", "check:examples": "node scripts/update-examples-json.mjs --check" } From 0b060276e3f1a6ad2893535fdfaad6f6762ef58b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Wed, 30 Sep 2026 14:19:54 +0200 Subject: [PATCH 2/4] Clarify Memory Match prerelease setup --- README.md | 11 +- examples.json | 4 +- memory-match/README.md | 360 +++++++++--------------------------- memory-match/docs/RSTEST.md | 108 +++++++++++ 4 files changed, 201 insertions(+), 282 deletions(-) create mode 100644 memory-match/docs/RSTEST.md diff --git a/README.md b/README.md index df5e1edf..25901f4e 100644 --- a/README.md +++ b/README.md @@ -72,12 +72,13 @@ Each example doubles as a reference for [community packages](https://docs.meteor - Repository: [meteor/examples/memory-match](./memory-match) - Why: A cosmic card game with a live leaderboard showcasing Rstest unit, component, browser, Meteor runtime, local package, and end-to-end tests - Stack: Meteor, Rspack, React, TypeScript, MongoDB, Rstest, Testing Library, Playwright -- Last Updated At: Sep/22/2026 -- Meteor Version: Checkout (`rspack-rstest-integration`, experimental) +- Last Updated At: Sep/30/2026 +- Meteor Version: Rstest prerelease -Run this example with the Meteor source checkout on `rspack-rstest-integration`. -Its [setup guide](./memory-match/README.md) and [showcase walkthrough](./memory-match/docs/SHOWCASE.md) -cover the local integration packages and demo commands. +Rstest support is currently prerelease, so the example has a temporary Meteor +source-checkout setup. Its [setup guide](./memory-match/README.md) covers the +current commands, while [Rstest integration details](./memory-match/docs/RSTEST.md) +records the migration once the integration is published. ### Parties - Repository: [meteor/examples/parties](./parties) diff --git a/examples.json b/examples.json index b5fafd55..7e9f7a60 100644 --- a/examples.json +++ b/examples.json @@ -139,8 +139,8 @@ "Testing Library", "Playwright" ], - "lastUpdatedAt": "Sep/22/2026", - "meteorVersion": "Checkout (`rspack-rstest-integration`, experimental)" + "lastUpdatedAt": "Sep/30/2026", + "meteorVersion": "Rstest prerelease" }, { "title": "Parties", diff --git a/memory-match/README.md b/memory-match/README.md index e7095c9e..85dd6c2d 100644 --- a/memory-match/README.md +++ b/memory-match/README.md @@ -1,55 +1,52 @@ # Memory Match -Small React and TypeScript Meteor app demonstrating Meteor's Rspack/Rstest -integration through direct Meteor CLI commands. Same Memory Match code runs as -native unit tests, jsdom components, Rstest Browser Mode, real Meteor -server/client tests, Atmosphere package tests, and full-app Playwright E2E. +A real-time Memory Match game built with Meteor, React, and TypeScript. Find +eight cosmic pairs, then watch completed scores appear immediately in the shared +leaderboard. The app also demonstrates Rstest across pure game logic, React +components, real Meteor methods and publications, a local Atmosphere package, +and full-browser E2E tests. -**Experimental checkout example:** this app requires the Meteor source branch -[`rspack-rstest-integration`](https://github.com/meteor/meteor/tree/rspack-rstest-integration). -Setup loads the integration packages directly from that checkout. The examples -repository branch and the Meteor checkout branch are separate. +![A completed Memory Match board with the live leaderboard](docs/preview.png) -Play sixteen cards, find eight cosmic pairs, and watch completed scores appear -in a second browser through Meteor's live publication. Start another round with -**New game**. For a presentation, follow the [showcase walkthrough](docs/SHOWCASE.md). +> **Prerelease setup:** Rstest support is not yet in an official Meteor release. +> Until it is, this example uses a Meteor source checkout on the +> [`rspack-rstest-integration`](https://github.com/meteor/meteor/tree/rspack-rstest-integration) +> branch. `meteor-checkout` is a temporary launcher created by setup; it will be +> removed when the integration is published. After setup, commands do not need +> `METEOR_CHECKOUT` to remain exported. -![A completed Memory Match board with the live leaderboard](docs/preview.png) +## Stack -Meteor owns command parsing, Isobuild, Atmosphere compilation, MongoDB, DDP, -application/browser hosts, ports, shutdown, and result aggregation. Rstest owns -native collection plus embedded Meteor-runtime collection, Rspack test -compilation, assertions, fixtures, snapshots, and exit status. Native Rstest -also owns file workers, coverage, Browser Mode, Playwright fixtures, and -reporters. +| | | +|---|---| +| Runtime | Meteor prerelease with Rstest integration | +| Frontend | React 19 + TypeScript | +| Database | MongoDB | +| Data | Meteor methods, publications, DDP, Minimongo, and Tracker | +| Tests | Rstest, Testing Library, and Playwright | +| Build | Rspack | -Unlike a driver package, Rstest participates before Meteor build/runtime -selection. Existing Mocha and Tinytest files stay compatible with their driver -flows. Showcase tests stay beside application features. One Rspack dependency -graph uses direct and transitive imports to select native Node, Browser Mode, -external E2E, or real Meteor hosts. Filename markers handle globals, jsdom, and -explicit server/client ownership. One compatibility-root test remains on -purpose. Meteor runtime tests use real collections, methods, publications, -Minimongo, Tracker, DDP, and MongoDB rather than mocks. Every lane imports its -test API from `@rstest/core`; runtime tests import Meteor modules separately. +## Features -## Setup from a Meteor checkout +- Play a sixteen-card memory game with accessible, keyboard-friendly controls +- Reactively share completed scores through Meteor pub/sub +- Test game logic in Node, UI in jsdom and Chromium, and app behavior in a real Meteor runtime +- Run a local Atmosphere package and end-to-end browser tests through the same test runner +- Generate Istanbul coverage across app, package, and E2E test sources -This showcase declares optional capabilities it uses: jsdom, Browser Mode, -Istanbul coverage, Rstest Playwright, Testing Library, and Playwright. Meteor -integration installs only required Rstest core/Rspack adapter dependencies. +## Running it -Use Node.js 22.12 or newer and Git. A sibling Meteor checkout is detected by -default: +Use Node.js 22.12 or newer. The temporary setup expects sibling Meteor and +examples checkouts: ```text workspace/ -├── meteor/ # branch: rspack-rstest-integration +├── meteor/ # rspack-rstest-integration └── examples/ └── memory-match/ ``` -For a fresh checkout, run this from the directory containing `examples`: +From the directory containing `examples`, clone the required Meteor checkout: ```bash git clone --branch rspack-rstest-integration https://github.com/meteor/meteor.git meteor @@ -59,254 +56,67 @@ npm run setup npm start ``` -If Meteor is already elsewhere, select it explicitly: - -```bash -cd /path/to/examples/memory-match -METEOR_CHECKOUT=/absolute/path/to/meteor npm run setup -./meteor-checkout npx playwright install chromium -``` - -From the examples repository root, `npm run setup:memory-match`, -`npm run start:memory-match`, and `npm run test:memory-match` run the same scripts. -On Linux, Playwright may also need system libraries: use -`./meteor-checkout npx playwright install --with-deps chromium`. - -Setup validates the branch and checkout packages, creates ignored local package -links, installs dependencies using Meteor's bundled Node/npm, generates -Atmosphere declarations through `zodern:types`, then writes ignored executable -`./meteor-checkout`. The launcher checks the branch on every invocation, -exports checkout-local package paths, and executes checkout Meteor directly. -It does not switch the checkout's branch. To use a compatible development branch, -set `METEOR_RSTEST_BRANCH=your-branch` when running setup. - -The two unpublished npm integrations use stable `file:.meteor/local/npm/...` -specs. Run setup before `npm install` or `npm ci` on a fresh clone so those links -exist. `install-links=true` installs package copies whose dependencies resolve -inside this app. Machine-specific paths stay in ignored files. - -The current checkout's development config expects React Refresh's older default -export. Setup applies a small compatibility fix to the installed -`@meteorjs/rspack` copy to accept the v2 `ReactRefreshRspackPlugin` export. -The Meteor source checkout is unchanged. This workaround is in -`scripts/checkout.mjs` and can be removed when the integration branch includes -the export fix. Rerun setup after reinstalling npm dependencies. - -After setup, `METEOR_CHECKOUT` no longer needs exporting for normal commands. -Checkout wrapper source edits are used directly through internal mirror paths. -Rerun setup after changing checkout location, package contents consumed through -normal app imports, or local package dependency metadata. - -The checkout's first run may download its development bundle and Atmosphere -dependencies. No global Meteor installation is needed. Generated builds, -Mongo data, reports, and coverage are ignored. The external recordings project -and local integration design notes are not needed to run this example. - -Equivalent direct use: - -```bash -./meteor-checkout test --once --server-only \ - --project meteor-pure-server \ - --project showcase-in-source -``` - -## Run application - -```bash -npm start -npm start -- --port 4100 -``` - -Open `http://localhost:3000` (or the selected port). Leave another browser window -on the starting screen to watch the leaderboard update after a completed game. - -## Test commands - -Every retained script shows complete Meteor command in `package.json`. - -| Command | Distinct execution model | -| --- | --- | -| `npm run test:unit` | Native Node unit tests, module mocks, snapshots, and `import.meta.rstest` | -| `npm run test:watch` | Same native projects in watch mode | -| `npm run test:component` | React components in jsdom | -| `npm run test:browser` | Rstest Browser Mode in Chromium | -| `npm run test:integration` | Combined real Meteor server/client runtime | -| `npm run test:package` | Local Atmosphere package harness | -| `npm run test:e2e` | Full Meteor app driven through Rstest Playwright | -| `npm run test:coverage` | One Istanbul report across native, real Meteor server/client, local package, and full-app E2E lanes | -| `npm run test:parallel:native` | Rstest file workers | -| `npm run test:parallel:meteor` | Isolated Meteor server-runtime workers | -| `npm run test:tooling` | Checkout setup and launcher checks without starting Meteor | -| `npm run typecheck` | TypeScript checks after setup generates Meteor declarations | - -`npm test` runs same direct command as `test:unit`. - -The [GitHub Actions workflow](../.github/workflows/memory-match.yml) checks out -the same Meteor integration branch, runs the test modes sequentially, and saves -coverage and failure artifacts. It also starts the normal development server -and checks its Mongo-backed health endpoint. It runs for changes to this example and can -also be started manually. The experimental Meteor branch can evolve; the npm -lockfile pins this app's external dependencies. - -Normal Meteor/Rstest arguments append without wrapper translation: - -```bash -npm run test:unit -- --test-name-pattern deck -npm run test:unit -- --test-file imports/game/score.test.ts -npm run test:package -- --server-only -npm run test:package -- --test-name-pattern "package export" -``` - -Watch mode is activated by omitting `--once`, not by passing unsupported -`--watch` to Rstest: - -```bash -npm run test:watch -``` - -Stop with Ctrl+C. - -## How execution is inferred - -Folders describe application domains, not runner lanes. Dependency analysis is -the default: Meteor asks Rspack for each test's direct and transitive imports, -then selects the required executor. - -| Test kind | Example | Dependency signal | Execution | Command | -| --- | --- | --- | --- | --- | -| Native Node | `imports/game/snapshots.test.ts` | `@rstest/core` | Upstream Rstest in Node | `npm run test:unit` | -| Browser Mode | `imports/ui/MemoryGame.interactions.test.tsx` | `@rstest/browser` | Upstream Rstest in Chromium | `npm run test:browser` | -| Meteor runtime | `imports/api/runtime-context.test.ts` | Direct or transitive `meteor/*` imports | Real Meteor server and browser hosts | `npm run test:integration` | -| External E2E | `tests/e2e/memory-game.test.ts` | `@rstest/playwright` | Playwright against Meteor-owned full app | `npm run test:e2e` | -| Atmosphere package | `packages/memory-match-engine` | `Package.onTest` strongly uses `rstest` | Real `local-test:*` package harness | `npm run test:package` | - -Snapshots, coverage, mocking, parameterization, and concurrency are Rstest -features inside these execution types. They do not create separate routing -lanes. For example, `imports/game/snapshots.test.ts` is inferred as native Node -because it imports `@rstest/core`; snapshot assertions then run within that -project. - -### Explicit fallbacks - -Filename markers stay available when dependency imports cannot express enough -information. They are fallback hints, not default organization: - -| Ambiguity | Example | Fallback signal | Result | -| --- | --- | --- | --- | -| Global Rstest APIs provide no import edge | `imports/game/globals.rstest.test.ts` | `.rstest.test` | Native Node ownership | -| `@rstest/core` alone cannot distinguish jsdom from Node | `imports/ui/MemoryGame.dom.rstest.test.tsx` | `.dom.rstest.test` | jsdom project | -| `meteor/*` can run on both architectures | `imports/api/methods.server.meteor.rstest.test.ts` | `.server.meteor.rstest.test` | Server-only Meteor host | -| `meteor/*` can run on both architectures | `imports/ui/App.client.meteor.rstest.test.tsx` | `.client.meteor.rstest.test` | Client-only Meteor host | -| Existing integration layout needs gradual migration | `tests/rstest/pure/server/compatibility.test.ts` | Compatibility root | Native Node project | - -In-source tests remain explicit Rstest configuration: `imports/game/shuffle.ts` -uses `import.meta.rstest` and belongs to the `showcase-in-source` project in -`rstest.config.ts`. - -Native game tests also cover deterministic shuffle, scoring, hooks, -parameterization, spies, snapshots, module mocking, and concurrency. React -tests cover jsdom and real-browser behavior. Meteor server/client tests cover -methods, publications, MongoDB, DDP, Minimongo, Tracker, package exports, and -isolated runtime workers. - -`imports/game/score-mocking.test.ts` uses upstream Rstest `rs.mock` and `rs.fn`; -mock hoisting happens during native Rspack compilation. -`imports/api/methods-spy.server.meteor.rstest.test.ts` uses upstream -`rs.spyOn` only to observe `Games.insertAsync` while real `Meteor.callAsync`, -method code, collection, and MongoDB keep running. Runtime `rs.mock` may replace -app/npm modules in the Rspack graph, but Meteor and Atmosphere modules cannot be -replaced. +Visit `http://localhost:3000/`. Open a second browser tab before completing a +game to see its leaderboard entry arrive without a page refresh. -## Useful one-off options - -Keep flag variations visible instead of adding npm aliases: +If the checkout is elsewhere, set `METEOR_CHECKOUT` during setup: ```bash -# Update selected snapshots -./meteor-checkout test --once --server-only \ - --project meteor-pure-server \ - --test-file imports/game/snapshots.test.ts \ - --update-snapshots - -# Visible Browser Mode or E2E -SHOWCASE_HEADED=1 npm run test:browser -SHOWCASE_HEADED=1 npm run test:e2e - -# Detailed test rows without generic Meteor --verbose diagnostics -npm run test:integration -- -- --reporters=verbose - -# Native reporter and CI shard -npm run test:unit -- --reporters=verbose -npm run test:unit -- --shard 1/2 - -# Native Rstest passthrough -npm run test:unit -- -- --retry 2 -npm run test:unit -- -- --trace -npm run test:unit -- -- --detectAsyncLeaks +METEOR_CHECKOUT=/absolute/path/to/meteor npm run setup ``` -`npm run test:coverage` is one `--once --coverage --full-app` selection. It -keeps the tests' ordinary `@rstest/core` and `@rstest/playwright` imports, while -collecting native tests, real Meteor server/client runtime tests, the loaded -local `memory-match-engine` package, and Rstest Playwright fixture pages into -one Istanbul report. The coverage include list deliberately contains the -package source root, so the report contains the physical -`packages/memory-match-engine/engine.ts` path as well as app sources. Meteor, -MongoDB, DDP, Atmosphere packages, and browser hosts remain real; no Meteor -mocks are introduced. - -Coverage writes `coverage/index.html` and -`coverage/coverage-summary.json`. Failure screenshots go under -`reports/failures`; E2E traces are retained on failure. Native-only selections -may use upstream Istanbul or V8 coverage, but any selection containing Meteor -uses Istanbul. Meteor watch generations are not aggregated; included sources -that no selected host loads do not get zero-hit entries; and custom-compiler -package sources are not covered. Standard local `ecmascript` and `typescript` -packages are supported. - -## Parallelism +The setup script validates the required branch, links the checkout's unpublished +packages into this app, installs dependencies, generates Meteor declarations, +and creates `meteor-checkout`. On Linux, use +`./meteor-checkout npx playwright install --with-deps chromium` to install +Chromium system dependencies. Rerun setup after changing the checkout branch or +reinstalling dependencies. + +## Test suite + +| Command | What it does | +|---|---| +| `npm test` | Native game tests in Node | +| `npm run test:watch` | Watch the native game tests | +| `npm run test:component` | React component tests in jsdom | +| `npm run test:browser` | Browser Mode tests in Chromium | +| `npm run test:integration` | Real Meteor server and client tests | +| `npm run test:package` | Local Atmosphere package tests | +| `npm run test:e2e` | Full app E2E tests with Playwright | +| `npm run test:coverage` | Combined Istanbul coverage report | +| `npm run test:parallel:native` | Native Rstest workers | +| `npm run test:parallel:meteor` | Isolated Meteor runtime workers | +| `npm run typecheck` | TypeScript checks | +| `npm run test:tooling` | Temporary checkout setup and launcher checks | + +Run `./meteor-checkout npx playwright install chromium` once before Browser Mode +or E2E tests. Full-app test commands manage their own Meteor app and MongoDB, so +you do not need to start the game first. + +## How it is structured -`test:parallel:native` forwards -`--pool.type threads --pool.maxWorkers 4` to native Rstest. One coordinator -runs test files across Node workers; no extra Meteor host starts. Inside each -file, `test.concurrent` and `describe.concurrent` use `maxConcurrency: 2` from -`rstest.config.ts`; explicit `.sequential` cases form ordering barriers. - -`test:parallel:meteor` passes `--runtime-workers 2` to Meteor. Meteor -partitions server runtime files across isolated hosts with separate local build -directories, ports, Mongo databases, and aggregated results. Within each host, -Meteor-runtime `.concurrent` cases use same bounded scheduler and share that -host's Meteor process and Mongo database. - -These are separate scheduling layers. CI sharding remains an ordinary -`--shard index/count` option rather than another project script. - -Run same-file concurrency examples directly: - -```bash -npm run test:unit -- \ - --test-file imports/game/concurrency.test.ts \ - -- --reporters=verbose - -./meteor-checkout test --once --server-only \ - --project meteor-runtime-server \ - --test-file imports/api/concurrency.server.meteor.rstest.test.ts \ - -- --reporters=verbose +```text +imports/ + api/ # Collection, methods, and publications + game/ # Game rules, scoring, deterministic shuffle, and unit tests + ui/ # React game and leaderboard components with UI tests +packages/ + memory-match-engine/ # Local Atmosphere package and its Rstest tests +tests/ + e2e/ # Playwright against the complete Meteor application + tooling/ # Checkout and routing checks +rstest.config.ts # Browser, coverage, and test project configuration ``` -## Configuration boundaries +The ordinary test sources use `@rstest/core`. Tests that import `meteor/*` run +inside real Meteor hosts; pure tests use Rstest's Node, jsdom, or browser +projects. See [Rstest integration details](docs/RSTEST.md) for the routing rules, +coverage behavior, parallel execution, and the publication checklist. -`rstest.config.ts` uses `defineConfig` from `@meteorjs/rstest`. Dynamic -Meteor context supplies roots, sides, lifecycle phase, and protected generated -projects with exact import-inferred file manifests. App config adds shared -setup, timeouts, Browser Mode, coverage, in-source project, and app-specific -Rspack adjustments. Shared setup stays environment-neutral because it loads in -native and Meteor-runtime lanes. +For a narrated demo, use the [showcase walkthrough](docs/SHOWCASE.md). -`rspack.config.ts` uses `defineConfig` from `@meteorjs/rspack` and adds -only application behavior. Meteor aliases, externals, entries, lifecycle -plugins, and Atmosphere package handling stay integration-owned. +## Links -Optional npm capabilities remain project-owned. E2E imports -`@rstest/playwright` directly while Meteor supplies managed application URL -and lifecycle. +- [Meteor docs](https://docs.meteor.com/) · [Meteor guide](https://guide.meteor.com/) +- [React docs](https://react.dev/) +- [Rstest](https://rstest.rs/) · [Testing Library](https://testing-library.com/) · [Playwright](https://playwright.dev/) diff --git a/memory-match/docs/RSTEST.md b/memory-match/docs/RSTEST.md new file mode 100644 index 00000000..b9a59801 --- /dev/null +++ b/memory-match/docs/RSTEST.md @@ -0,0 +1,108 @@ +# Rstest integration details + +Memory Match is a release-readiness showcase for the Meteor Rstest integration. +The main [README](../README.md) explains how to run the app. This document +explains what the test suite demonstrates and records the temporary checkout +setup that will disappear after publication. + +## Current prerelease arrangement + +`@meteorjs/rstest` and the matching Rspack integration are loaded from the +Meteor checkout on `rspack-rstest-integration`. `npm run setup` validates the +checkout, links the two local packages through ignored paths under +`.meteor/local/npm`, installs the app dependencies, and writes the temporary +`meteor-checkout` launcher. The launcher preserves normal Meteor arguments and +adds the local package paths required by this branch. + +The project intentionally does not pretend that released packages are available. +Its published-version migration should happen in the release PR, after the +Meteor release and npm packages exist: + +1. Replace `file:.meteor/local/npm/...` dependencies with the published, + compatible `@meteorjs/rspack` and `@meteorjs/rstest` versions. +2. Replace `meteor-checkout` scripts with ordinary `meteor` commands and remove + the temporary setup/launcher code and its tests. +3. Change CI from a source checkout to the released Meteor version, then run the + complete test matrix before merging. +4. Remove the prerelease note in the README and record the released Meteor + version in the examples index. + +Until then, the checkout requirement is a short, explicit warning in the README +instead of the example's permanent identity. + +## Test execution + +Meteor continues to own application and runtime concerns: command parsing, +Isobuild, Atmosphere compilation, MongoDB, DDP, application hosts, ports, +shutdown, and aggregated results. Rstest owns collection, Rspack test +compilation, assertions, fixtures, snapshots, coverage, Browser Mode, +Playwright fixtures, and native workers. + +Tests are organized with their app domain. Dependency analysis selects an +executor, and filename markers settle the cases where imports cannot describe +the necessary host: + +| Test kind | Example | Signal | Execution | +|---|---|---|---| +| Native unit | `imports/game/snapshots.test.ts` | `@rstest/core` | Rstest in Node | +| Browser Mode | `imports/ui/MemoryGame.interactions.test.tsx` | `@rstest/browser` | Rstest in Chromium | +| Meteor runtime | `imports/api/runtime-context.test.ts` | `meteor/*` import | Real Meteor server/client hosts | +| External E2E | `tests/e2e/memory-game.test.ts` | `@rstest/playwright` | Playwright against a Meteor-owned app | +| Atmosphere package | `packages/memory-match-engine` | `Package.onTest` uses `rstest` | Real local package harness | + +Fallback markers demonstrate the remaining explicit ownership cases: + +| Need | Example | Marker | +|---|---|---| +| Global Rstest APIs | `imports/game/globals.rstest.test.ts` | `.rstest.test` | +| jsdom instead of Node | `imports/ui/MemoryGame.dom.rstest.test.tsx` | `.dom.rstest.test` | +| Server-only Meteor host | `imports/api/methods.server.meteor.rstest.test.ts` | `.server.meteor.rstest.test` | +| Client-only Meteor host | `imports/ui/App.client.meteor.rstest.test.tsx` | `.client.meteor.rstest.test` | + +`imports/game/shuffle.ts` also demonstrates an in-source test through +`import.meta.rstest`. The one test below `tests/rstest/pure` remains as a +compatibility-root example. + +## Useful options + +Pass standard Rstest filtering and reporting options through the existing npm +scripts: + +```bash +npm run test:unit -- --test-name-pattern deck +npm run test:unit -- --test-file imports/game/score.test.ts +npm run test:unit -- --reporters=verbose +npm run test:unit -- --shard 1/2 + +SHOWCASE_HEADED=1 npm run test:browser +SHOWCASE_HEADED=1 npm run test:e2e +``` + +Update a snapshot with the direct Meteor command: + +```bash +./meteor-checkout test --once --server-only \ + --project meteor-pure-server \ + --test-file imports/game/snapshots.test.ts \ + --update-snapshots +``` + +## Coverage and parallel execution + +`npm run test:coverage` combines native tests, real Meteor server/client +tests, the local package, and Playwright E2E into one Istanbul report. It writes +`coverage/index.html` and `coverage/coverage-summary.json`. Failure screenshots +go to `reports/failures`, and E2E traces are retained on failure. + +`test:parallel:native` uses Rstest file workers. `test:parallel:meteor` starts +two isolated Meteor server-runtime workers, each with its own build directory, +port, and MongoDB. The latter is intentionally an explicit command rather than +the default because runtime workers are a different scheduling layer. + +## Configuration boundaries + +`rstest.config.ts` uses `defineConfig` from `@meteorjs/rstest`. Meteor supplies +the runtime context and generated file manifests; the app adds common setup, +timeouts, Browser Mode, coverage, an in-source project, and test-safe Rspack +adjustments. `rspack.config.ts` only adds application behavior. Meteor aliases, +entries, lifecycle plugins, and Atmosphere handling remain integration-owned. From 0f5fb1cade5c2f4eecd5949f13a782d470b52135 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Wed, 30 Sep 2026 16:35:51 +0200 Subject: [PATCH 3/4] Run Memory Match checks locally by default --- .github/workflows/memory-match.yml | 9 --------- memory-match/README.md | 3 ++- memory-match/scripts/checkout.mjs | 2 ++ memory-match/tests/tooling/checkout.test.mjs | 5 ++++- 4 files changed, 8 insertions(+), 11 deletions(-) diff --git a/.github/workflows/memory-match.yml b/.github/workflows/memory-match.yml index bd77c323..abe93d6d 100644 --- a/.github/workflows/memory-match.yml +++ b/.github/workflows/memory-match.yml @@ -2,15 +2,6 @@ name: Memory Match (Rstest checkout) on: workflow_dispatch: - pull_request: - paths: - - "memory-match/**" - - ".github/workflows/memory-match.yml" - push: - branches: [main] - paths: - - "memory-match/**" - - ".github/workflows/memory-match.yml" permissions: contents: read diff --git a/memory-match/README.md b/memory-match/README.md index 85dd6c2d..fe23275f 100644 --- a/memory-match/README.md +++ b/memory-match/README.md @@ -36,7 +36,8 @@ and full-browser E2E tests. ## Running it -Use Node.js 22.12 or newer. The temporary setup expects sibling Meteor and +Use Node.js 22.12 or newer. No global Meteor installation is needed. Run setup +before `npm install` or `npm ci`. The temporary setup expects sibling Meteor and examples checkouts: ```text diff --git a/memory-match/scripts/checkout.mjs b/memory-match/scripts/checkout.mjs index 7fe5ce8b..c8eedc84 100644 --- a/memory-match/scripts/checkout.mjs +++ b/memory-match/scripts/checkout.mjs @@ -65,6 +65,7 @@ export function resolveCheckout(env = process.env) { export function withCheckoutEnvironment(checkout, env = process.env) { return { ...env, + PATH: [checkout.root, env.PATH].filter(Boolean).join(path.delimiter), METEOR_CHECKOUT: checkout.root, METEOR_PACKAGE_DIRS: [checkout.packagesDir, env.METEOR_PACKAGE_DIRS].filter(Boolean).join(path.delimiter), METEOR_RSPACK_NPM_SPEC: checkout.rspackNpmPackage, @@ -140,6 +141,7 @@ export function renderCheckoutLauncher(checkout) { ' printf "Meteor checkout branch is %s; expected %s. Rerun npm run setup with a compatible checkout.\\n" "${current:-detached HEAD}" "$expected" >&2', ' exit 2', 'fi', + 'export PATH="$checkout:$PATH"', 'export METEOR_CHECKOUT="$checkout"', 'export METEOR_PACKAGE_DIRS="$checkout/packages${METEOR_PACKAGE_DIRS:+:$METEOR_PACKAGE_DIRS}"', 'export METEOR_RSPACK_NPM_SPEC="$checkout/npm-packages/meteor-rspack"', diff --git a/memory-match/tests/tooling/checkout.test.mjs b/memory-match/tests/tooling/checkout.test.mjs index bcbd7971..14fc08f9 100644 --- a/memory-match/tests/tooling/checkout.test.mjs +++ b/memory-match/tests/tooling/checkout.test.mjs @@ -59,8 +59,9 @@ test('refuses the wrong branch without changing the checkout', (t) => { test('normalizes checkout paths and preserves custom package directories', (t) => { const root = fakeCheckout(t); const checkout = resolveCheckout({ METEOR_CHECKOUT: root }); - const env = withCheckoutEnvironment(checkout, { METEOR_PACKAGE_DIRS: '/custom' }); + const env = withCheckoutEnvironment(checkout, { PATH: '/usr/bin', METEOR_PACKAGE_DIRS: '/custom' }); assert.equal(checkout.root, realpathSync(root)); + assert.equal(env.PATH, `${checkout.root}${path.delimiter}/usr/bin`); assert.equal(env.METEOR_PACKAGE_DIRS, `${checkout.packagesDir}${path.delimiter}/custom`); assert.equal(env.METEOR_RSPACK_NPM_SPEC, checkout.rspackNpmPackage); assert.equal(env.METEOR_RSTEST_NPM_SPEC, checkout.rstestNpmPackage); @@ -86,6 +87,7 @@ test('launcher preserves arguments, environment, exit status, and checks later b const projectRoot = temporaryRoot(t); const meteorBinary = path.join(root, 'meteor'); writeFileSync(meteorBinary, `#!/bin/sh +printf 'meteor=%s\\n' "$(command -v meteor)" printf 'packageDirs=%s\\n' "$METEOR_PACKAGE_DIRS" printf 'rspack=%s\\n' "$METEOR_RSPACK_NPM_SPEC" printf 'rstest=%s\\n' "$METEOR_RSTEST_NPM_SPEC" @@ -102,6 +104,7 @@ exit 23 const result = run(); assert.equal(result.status, 23, result.stderr); assert.equal(result.stderr, ''); + assert(result.stdout.includes(`meteor=${checkout.meteorBinary}\n`)); assert(result.stdout.includes(`packageDirs=${checkout.packagesDir}:/custom/packages\n`)); assert(result.stdout.includes(`rspack=${checkout.rspackNpmPackage}\n`)); assert(result.stdout.includes(`rstest=${checkout.rstestNpmPackage}\n`)); From 965aff4a4d87eb959a17b26a01660b307866e08d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Nacho=20Codo=C3=B1er?= Date: Wed, 30 Sep 2026 16:55:05 +0200 Subject: [PATCH 4/4] Clarify Memory Match contributor workflow --- memory-match/README.md | 19 ++++++++++++------- memory-match/docs/RSTEST.md | 27 +++++++++++++++++++++++---- memory-match/docs/SHOWCASE.md | 21 +-------------------- 3 files changed, 36 insertions(+), 31 deletions(-) diff --git a/memory-match/README.md b/memory-match/README.md index fe23275f..09665e87 100644 --- a/memory-match/README.md +++ b/memory-match/README.md @@ -47,9 +47,12 @@ workspace/ └── memory-match/ ``` -From the directory containing `examples`, clone the required Meteor checkout: +From an empty workspace, clone both feature branches as siblings: ```bash +mkdir memory-match-workspace +cd memory-match-workspace +git clone --branch feat/memory-match-rstest https://github.com/meteor/examples.git examples git clone --branch rspack-rstest-integration https://github.com/meteor/meteor.git meteor cd examples/memory-match npm run setup @@ -60,7 +63,8 @@ npm start Visit `http://localhost:3000/`. Open a second browser tab before completing a game to see its leaderboard entry arrive without a page refresh. -If the checkout is elsewhere, set `METEOR_CHECKOUT` during setup: +If you already have this examples branch, place the Meteor checkout beside it. +If the Meteor checkout is elsewhere, set `METEOR_CHECKOUT` during setup: ```bash METEOR_CHECKOUT=/absolute/path/to/meteor npm run setup @@ -91,8 +95,8 @@ reinstalling dependencies. | `npm run test:tooling` | Temporary checkout setup and launcher checks | Run `./meteor-checkout npx playwright install chromium` once before Browser Mode -or E2E tests. Full-app test commands manage their own Meteor app and MongoDB, so -you do not need to start the game first. +or E2E tests. Stop `npm start` before running tests that use Meteor; they share +the default ports. Full-app test commands manage their own app and MongoDB. ## How it is structured @@ -111,10 +115,11 @@ rstest.config.ts # Browser, coverage, and test project configuration The ordinary test sources use `@rstest/core`. Tests that import `meteor/*` run inside real Meteor hosts; pure tests use Rstest's Node, jsdom, or browser -projects. See [Rstest integration details](docs/RSTEST.md) for the routing rules, -coverage behavior, parallel execution, and the publication checklist. +projects. See [Rstest integration details](docs/RSTEST.md) for how to add tests, +the routing rules, coverage behavior, parallel execution, and the publication +checklist. -For a narrated demo, use the [showcase walkthrough](docs/SHOWCASE.md). +For a guided tour, use the [showcase walkthrough](docs/SHOWCASE.md). ## Links diff --git a/memory-match/docs/RSTEST.md b/memory-match/docs/RSTEST.md index b9a59801..4f5d73aa 100644 --- a/memory-match/docs/RSTEST.md +++ b/memory-match/docs/RSTEST.md @@ -63,15 +63,34 @@ Fallback markers demonstrate the remaining explicit ownership cases: `import.meta.rstest`. The one test below `tests/rstest/pure` remains as a compatibility-root example. +## Adding a feature or test + +Keep new behavior and its tests together. Choose the lightest test environment +that exercises the behavior: + +| Change | Add tests in | Run | +|---|---|---| +| Game rules or scoring | `imports/game/`, importing `@rstest/core` | `npm run test:unit` | +| React component behavior | `imports/ui/`, with a `.dom.rstest.test.tsx` marker for jsdom or an `@rstest/browser` import for Chromium | `npm run test:component` or `npm run test:browser` | +| Methods, publications, or subscriptions | `imports/api/`, importing real `meteor/*` modules and using a server/client marker when needed | `npm run test:integration` | +| Complete user journey | `tests/e2e/`, importing `@rstest/playwright` | `npm run test:e2e` | +| Local Atmosphere package | `packages/`, with a strong `rstest` dependency in `Package.onTest` | `npm run test:package` | + +Use `npm run typecheck` and the relevant test command while working; run +`npm run test:coverage` when a change crosses several layers. If a new test +needs its own project, give it a distinct name in `rstest.config.ts` and verify +the project selection with a focused run. + ## Useful options -Pass standard Rstest filtering and reporting options through the existing npm -scripts: +Filter by name or shard through the npm shortcut. Select one project for a +single-file run; `test:unit` also selects the in-source project. Native Rstest +reporter options go after a second `--`, which tells Meteor to pass them through: ```bash npm run test:unit -- --test-name-pattern deck -npm run test:unit -- --test-file imports/game/score.test.ts -npm run test:unit -- --reporters=verbose +./meteor-checkout test --once --server-only --project meteor-pure-server --test-file imports/game/score.test.ts +npm run test:unit -- -- --reporters=verbose npm run test:unit -- --shard 1/2 SHOWCASE_HEADED=1 npm run test:browser diff --git a/memory-match/docs/SHOWCASE.md b/memory-match/docs/SHOWCASE.md index 882ebf93..ad955398 100644 --- a/memory-match/docs/SHOWCASE.md +++ b/memory-match/docs/SHOWCASE.md @@ -19,7 +19,7 @@ npm run test:e2e ``` Run these sequentially; some Meteor commands share default ports. Complete the -first build and browser installation before recording or presenting. +first build and browser installation before presenting. ## A five-minute demo @@ -57,22 +57,3 @@ first build and browser installation before recording or presenting. In watch mode, change an assertion, show the failure, restore it, then stop with Ctrl+C. Coverage includes the game, UI, and local package across selected native, Meteor, and full-app E2E tests. Configuration is in `rstest.config.ts`. - -## Existing recording tools - -The separate `meteor-rstest-recordings` project can target this example without -copying recordings or adding recorder dependencies to the app. From that -project, set the example path for setup and recording: - -```bash -export SHOWCASE_DIR=/absolute/path/to/examples/memory-match -npm run setup -npm run record -- unit -npm run record -- integration -npm run record:all -``` - -Its README covers asciinema/agg installation and rendering. Casts and GIFs stay -in that project's `recordings/` and `gifs/` directories. Browser failure -screenshots from this example go in `reports/failures/`; E2E retains traces on -failure. Run `SHOWCASE_HEADED=1 npm run test:e2e` for a visible browser demo.