diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b2fb818..d1844a0 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -37,3 +37,11 @@ jobs: run: yarn test:coverage env: LOG_SILENT: 'true' + + - name: Upload coverage report + if: always() + uses: actions/upload-artifact@v4 + with: + name: coverage-node-${{ matrix.node-version }} + path: coverage/ + if-no-files-found: warn diff --git a/.gitignore b/.gitignore index 865f5e1..a8825bb 100644 --- a/.gitignore +++ b/.gitignore @@ -134,3 +134,11 @@ dist # Compiled browser SDK for the edge-replica example (build with: yarn build:browser) examples/edge-replica/lib/ + +# Claude Code tooling (agent worktrees, local state) +.claude/ + +# Stryker mutation testing output +reports/ +.stryker-tmp/ +stryker.log diff --git a/docs/TEST_COVERAGE.md b/docs/TEST_COVERAGE.md index f0f0c4b..3710949 100644 --- a/docs/TEST_COVERAGE.md +++ b/docs/TEST_COVERAGE.md @@ -6,6 +6,42 @@ This is an assessment of where the test suite is strong, where it is thin, and a prioritized list of concrete additions. Numbers come from `npx jest --coverage` (Istanbul) over `src/`. +## Follow-up round 2 — deeper hardening + +A second pass (after the round-1 work below) took the suite from **273 → 347 +tests** and coverage to **~90.4% stmt / 76.7% branch / 90.7% func / 92.3% line**: + +- **Edge stream-source internals** (`tests/edgeStreamSource.test.ts`): drives + `HttpStreamSource` against a stub SSE server and `EventSourceStreamSource` via + an injected double — frame parsing, split frames, malformed payloads, auth/non- + 200 responses, and every termination path. `httpStreamSource` 75→100% stmt, + `eventSourceStreamSource` 80→100% stmt. This surfaced a **real bug**: an abrupt + socket reset emitted `aborted`/`close` (not `end`), which the source ignored — + so the replica silently stalled instead of reconnecting. Fixed in + `src/edge/httpStreamSource.ts` (listen for `aborted`/`close`, single-fire guard). +- **Runtime unit tests** (`tests/runtime/{canonical,shardRouter,keyedModule,projection}Unit.test.ts`): + drove `canonical.ts`, `shardRouter.ts`, `keyedModule.ts`, `projection.ts` to + **100%** statements and branches (from 76/74/78/64%). +- **Generative consensus safety suite** (`tests/consensusProperties.test.ts`): + seeded (mulberry32, no new deps) randomized command streams + leader-crash + churn over LocalTransport clusters, asserting the Raft safety triple — state + convergence, committed-log agreement up to the shared commit index, and + determinism of replay. Reproducible via `SEED=`. +- **CI**: coverage is now emitted as lcov + an uploaded artifact per Node leg, and + the global threshold floor was ratcheted to 88/74/88/90. +- **Mutation testing (opt-in)**: `yarn test:mutation` runs Stryker (dev-only, + scoped, not in the CI gate) to measure test *effectiveness*, not just reach. The + initial `canonical.ts` run scored ~94%. See [ADR-0024](./adr/0024-opt-in-mutation-testing.md). + +**Known remaining gap (intentional):** the 2s `READ_BARRIER_TIMEOUT` branch in +`RaftNode.waitForApplied` is still not unit-tested. `lastApplied` is incremented +*before* `apply()` (raftNode.ts), so `commitIndex` can't be held ahead of +`lastApplied` via a throwing state machine; the only trigger is a precisely-timed +partition of a lagging follower right after it receives a ReadIndex, which is +inherently racy. The adjacent fail-closed paths are covered in +`followerReads.test.ts`/`readBarrier.test.ts`. Forcing this branch cleanly would +need a test-only seam in `src` — deferred rather than shipping a flaky timing test. + ## Resolution — all six areas addressed Every gap below has been worked through (commits on this branch). Result: the diff --git a/docs/adr/0024-opt-in-mutation-testing.md b/docs/adr/0024-opt-in-mutation-testing.md new file mode 100644 index 0000000..5f0727e --- /dev/null +++ b/docs/adr/0024-opt-in-mutation-testing.md @@ -0,0 +1,50 @@ +# 0024. Opt-in mutation testing (Stryker), dev-only + +- Status: Accepted +- Date: 2026-06-22 + +## Context + +Line/branch coverage tells us which code *ran* under test, not whether the tests +would actually *catch a regression* in it. After raising coverage to ~90% the +natural next question is test strength: a file at 100% line coverage can still +have assertions weak enough that a real bug slips through. Mutation testing +answers this by introducing small faults ("mutants") and checking the suite +fails — a killed mutant means the tests caught it. + +The established tool for the TypeScript/Jest stack is **Stryker**, which is a +heavyweight dev toolchain (100+ transitive packages) and runs the suite many +times. [ADR-0013](./0013-minimal-dependencies.md) is explicit about keeping +dependencies minimal — but it scopes that rule to *runtime* primitives +(consensus, RPC, metrics, persistence), which must stay visible and in-house. + +## Decision + +Add Stryker as a **dev-only, opt-in** tool, not part of the default `yarn test` +or the CI gate: + +- `@stryker-mutator/core` + `@stryker-mutator/jest-runner` as **devDependencies** + (they never ship in the library surface; runtime deps are unchanged). +- `stryker.conf.json` reuses the existing `jest.config.js` and uses + `coverageAnalysis: "perTest"` so only the tests covering a mutant run. +- A `yarn test:mutation` script. `mutate` is scoped narrowly by default (a single + pure module) so a run is fast on a POC; widen it ad hoc to assess other code. +- `thresholds.break` is `null` — mutation score is a **diagnostic**, never a hard + gate, so it can't make CI flaky or slow. + +This honors ADR-0013's intent (no new *runtime* weight, the core stays in-house) +while gaining a sharper test-quality signal on demand. + +## Consequences + +- We can measure test *effectiveness*, not just reach. The initial scoped run + (`src/runtime/canonical.ts`) scored ~94%, surfacing a few survived mutants in + the `'drop'`-mode branch — concrete, actionable test-strengthening targets that + coverage alone could not reveal. +- No impact on the default workflow: `yarn test`/`test:coverage` and CI are + unchanged; mutation runs are explicit and local. +- The dev dependency footprint grows, accepted as dev-only and reversible + (delete the two devDeps + `stryker.conf.json` + the script). Stryker output + (`reports/`, `.stryker-tmp/`) is git-ignored. +- For production hardening, widen `mutate` to the consensus core and treat + surviving mutants as a backlog of weak assertions to fix. diff --git a/docs/adr/README.md b/docs/adr/README.md index 500a106..cd68b75 100644 --- a/docs/adr/README.md +++ b/docs/adr/README.md @@ -36,6 +36,7 @@ supersedes the old one rather than editing history. | [0021](./0021-pluggable-bft-consensus-seam.md) | Pluggable BFT consensus — the seam, and why it is not built | Proposed | | [0022](./0022-joint-consensus-membership.md) | Dynamic cluster membership via joint consensus | Accepted | | [0023](./0023-edge-read-replicas-in-the-browser.md) | Edge read replicas in the browser | Accepted | +| [0024](./0024-opt-in-mutation-testing.md) | Opt-in mutation testing (Stryker), dev-only | Accepted | ## Template diff --git a/jest.config.js b/jest.config.js index 0e640b5..a3d7ba6 100644 --- a/jest.config.js +++ b/jest.config.js @@ -7,7 +7,16 @@ module.exports = { }, moduleDirectories: ['node_modules', 'src'], testMatch: ['**/*.test.ts'], + // Never discover tests inside git worktrees the tooling parks under .claude/ + // (they contain a full copy of this suite, which would multiply discovery). + testPathIgnorePatterns: ['/node_modules/', '/.claude/'], + modulePathIgnorePatterns: ['/.claude/'], verbose: true, + // Reporters used when --coverage is passed: a concise summary for CI logs, + // the per-file table, and lcov (coverage/lcov.info + an HTML report) which CI + // uploads as an artifact. + coverageReporters: ['text-summary', 'text', 'lcov'], + coverageDirectory: 'coverage', // What coverage is measured over (only when --coverage is passed). Exclude // pure type/wiring entry points that carry no testable logic of their own. collectCoverageFrom: [ @@ -18,17 +27,21 @@ module.exports = { '!src/moduleServer.ts', '!src/edge/browser.ts', ], - // Floor to stop coverage from regressing. Set just below the current numbers - // so it ratchets up over time rather than blocking on day one. Sandboxed - // reducer bodies run inside a vm and are not seen by the instrumenter (their - // injected counters are no-op'd — see src/runtime/sandbox.ts), so global - // line/branch figures sit a little lower than the bulk of the per-file ones. + // Floor to stop coverage from regressing, set just below the current aggregate + // (stmts ~90.4 / branches ~76.7 / funcs ~90.7 / lines ~92.3). A single global + // bucket is deliberate: jest's per-path/glob thresholds SUBTRACT their files + // from the global bucket, so adding directory floors would shift the global + // number unpredictably as code moves — a tightened global floor is the robust + // regression guard. Sandboxed reducer bodies run inside a vm and are invisible + // to the instrumenter (their injected counters are no-op'd — see + // src/runtime/sandbox.ts), which holds the global figures a touch below the + // bulk of the per-file ones. coverageThreshold: { global: { - statements: 86, - branches: 71, - functions: 86, - lines: 88, + statements: 88, + branches: 74, + functions: 88, + lines: 90, }, }, }; diff --git a/package.json b/package.json index d1508f2..13184dd 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ "mint-token": "node scripts/mint-token.js", "start": "tsc && node dist/server.js", "test": "jest --detectOpenHandles --runInBand --forceExit", - "test:coverage": "jest --coverage --runInBand --forceExit" + "test:coverage": "jest --coverage --runInBand --forceExit", + "test:mutation": "stryker run" }, "repository": { "type": "git", @@ -35,6 +36,8 @@ "express": "^4.18.2" }, "devDependencies": { + "@stryker-mutator/core": "^9.6.1", + "@stryker-mutator/jest-runner": "^9.6.1", "@types/cors": "^2.8.13", "@types/express": "^4.17.17", "@types/jest": "^29.5.1", diff --git a/src/edge/httpStreamSource.ts b/src/edge/httpStreamSource.ts index 8ed3e5e..3c9951e 100644 --- a/src/edge/httpStreamSource.ts +++ b/src/edge/httpStreamSource.ts @@ -35,8 +35,17 @@ export class HttpStreamSource implements LogS const client = url.protocol === 'https:' ? https : http; let closed = false; + let streamDone = false; let buffer = ''; + // Report stream termination exactly once (until an intentional close()), + // regardless of which of end/aborted/close/error fires first or repeats. + const fail = (err: Error): void => { + if (closed || streamDone) return; + streamDone = true; + handlers.onError(err); + }; + const headers: Record = { Accept: 'text/event-stream' }; if (this.token) headers.Authorization = `Bearer ${this.token}`; @@ -46,12 +55,12 @@ export class HttpStreamSource implements LogS (res) => { if (res.statusCode === 401 || res.statusCode === 403) { res.resume(); - if (!closed) handlers.onError(new Error(`stream unauthorized (HTTP ${res.statusCode})`)); + fail(new Error(`stream unauthorized (HTTP ${res.statusCode})`)); return; } if (res.statusCode !== 200) { res.resume(); // drain - if (!closed) handlers.onError(new Error(`stream HTTP ${res.statusCode}`)); + fail(new Error(`stream HTTP ${res.statusCode}`)); return; } handlers.onOpen?.(); @@ -66,15 +75,21 @@ export class HttpStreamSource implements LogS dispatchFrame(frame, handlers); } }); - res.on('end', () => { - if (!closed) handlers.onError(new Error('stream ended')); - }); + // Surface every way the stream can terminate so the EdgeReplica can + // reconnect. A clean server close emits `end`; an abrupt reset + // (RST / socket.destroy) emits `aborted`/`close` WITHOUT `end`. We + // must report the abrupt case too, or the replica silently stalls. + // `aborted` is deprecated since Node 17 but still fires; `close` + // covers the abrupt path on newer runtimes — `fail()` collapses the + // overlap (and a late `close` after `end`) to a single onError, and + // is a no-op after an intentional `close()`. + res.on('end', () => fail(new Error('stream ended'))); + res.on('aborted', () => fail(new Error('stream aborted'))); + res.on('close', () => fail(new Error('stream closed'))); }, ); - req.on('error', (err) => { - if (!closed) handlers.onError(err); - }); + req.on('error', (err) => fail(err)); return () => { closed = true; diff --git a/stryker.conf.json b/stryker.conf.json new file mode 100644 index 0000000..de47132 --- /dev/null +++ b/stryker.conf.json @@ -0,0 +1,21 @@ +{ + "$schema": "./node_modules/@stryker-mutator/core/schema/stryker-schema.json", + "_comment": "Opt-in mutation testing (ADR-0024). NOT part of the default test/CI gate. Run: `yarn test:mutation`. Scoped narrowly by default to keep runs fast on a POC; widen `mutate` to assess other modules. `coverageAnalysis: perTest` only runs the tests that cover each mutant.", + "packageManager": "yarn", + "testRunner": "jest", + "jest": { + "projectType": "custom", + "configFile": "jest.config.js" + }, + "coverageAnalysis": "perTest", + "tsconfigFile": "tsconfig.json", + "mutate": [ + "src/runtime/canonical.ts" + ], + "reporters": ["clear-text", "progress"], + "thresholds": { + "high": 90, + "low": 75, + "break": null + } +} diff --git a/tests/consensusProperties.test.ts b/tests/consensusProperties.test.ts new file mode 100644 index 0000000..d2997e4 --- /dev/null +++ b/tests/consensusProperties.test.ts @@ -0,0 +1,281 @@ +import { RaftNode, NotLeaderError } from '../src/consensus/raftNode'; +import { isControlCommand } from '../src/consensus/types'; +import type { Command } from '../src/consensus/types'; +import { + buildAddCommand, + buildBorrowCommand, + buildReturnCommand, + buildUpdateCommand, + buildDeleteCommand, + BookCommand, + Book, +} from '../src/models/book'; +import { BookNode, BookStateMachine } from '../src/models/bookStateMachine'; +import { buildCluster, leaders, waitFor } from './helpers'; + +/** + * Property-based / generative safety tests for the consensus core. + * + * Each iteration builds a fresh in-process LocalTransport book cluster, drives a + * randomized sequence of valid book commands through the current leader (re-finding + * it each step and tolerating transient NotLeader), periodically crashes/restarts a + * node or the leader to force re-elections, then — after the cluster re-settles — + * asserts the Raft SAFETY invariants: + * + * 1. State convergence — every live node's app.getAll() is deep-equal. + * 2. Log agreement — committed entries are identical across nodes up to the + * shared (minimum) commit index; no divergence below the commit point. + * 3. Determinism — replaying the committed command sequence into a fresh + * BookStateMachine reproduces the converged state exactly. + * + * Randomness is a hand-rolled seeded mulberry32 PRNG (no new deps), and every + * iteration prints its seed up front so any failure is reproducible: re-run with + * SEED= to replay a single failing case. + */ + +// ---- seeded PRNG (mulberry32) — deterministic, reproducible ---- + +function mulberry32(seed: number): () => number { + let a = seed >>> 0; + return () => { + a |= 0; + a = (a + 0x6d2b79f5) | 0; + let t = Math.imul(a ^ (a >>> 15), 1 | a); + t = (t + Math.imul(t ^ (t >>> 7), 61 | t)) ^ t; + return ((t ^ (t >>> 14)) >>> 0) / 4294967296; + }; +} + +class Rng { + constructor(private readonly next: () => number) {} + float(): number { + return this.next(); + } + int(maxExclusive: number): number { + return Math.floor(this.next() * maxExclusive); + } + pick(items: T[]): T { + return items[this.int(items.length)]; + } + bool(p = 0.5): boolean { + return this.next() < p; + } +} + +// ---- helpers ---- + +const liveLeader = (nodes: BookNode[]): BookNode | undefined => leaders(nodes)[0]; + +/** + * Submit `cmd` to whichever live node is currently leader, retrying across + * transient NotLeader / re-election windows. Returns true if it committed. + */ +async function submitToLeader(nodes: BookNode[], cmd: BookCommand): Promise { + for (let attempt = 0; attempt < 40; attempt++) { + const leader = liveLeader(nodes); + if (leader) { + try { + await leader.submit(cmd); + return true; + } catch (err) { + // Transient under churn: the leader stepped down mid-submit + // (NotLeaderError) or the leader we awaited was crashed (its pending + // entries reject with 'node stopped'). Re-find the leader and retry. + // Any OTHER error is a real failure and must surface — never let a + // genuine regression hide as a silently-retried low-commit run. + if (!(err instanceof NotLeaderError) && (err as Error).message !== 'node stopped') { + throw err; + } + } + } + await new Promise((r) => setTimeout(r, 15)); + } + return false; +} + +/** Pick a valid, well-typed book command given the leader's current state. */ +function nextCommand(rng: Rng, leader: BookNode, isbnCounter: { n: number }): BookCommand { + const books = leader.app.getAll(); + // With no books yet, the only sensible command is ADD. + if (books.length === 0 || rng.bool(0.45)) { + const isbn = `ISBN-${isbnCounter.n++}`; + return buildAddCommand({ + title: `Title ${isbn}`, + author: rng.pick(['Lamport', 'Ongaro', 'Tanenbaum', 'Lampson']), + publisher: rng.pick(['ACM', 'USENIX', 'Pearson']), + isbn, + copies: 1 + rng.int(3), + }); + } + + const book: Book = rng.pick(books); + const choice = rng.int(4); + switch (choice) { + case 0: + return buildUpdateCommand(book.id, { title: `Retitled ${rng.int(1000)}` }); + case 1: + // BORROW may legitimately fail (no copies) — still a valid log entry. + return buildBorrowCommand(book.id, rng.pick(['alice', 'bob', 'carol'])); + case 2: + // RETURN may legitimately fail (nothing borrowed) — still valid. + return buildReturnCommand(book.id); + default: + return buildDeleteCommand(book.id); + } +} + +/** Committed application (non-control) commands from a node, in log order. */ +function committedAppCommands(node: BookNode): BookCommand[] { + const out: BookCommand[] = []; + for (const { entry } of node.getCommittedEntries(0)) { + const command = entry.command as Command; + if (!isControlCommand(command)) out.push(command as BookCommand); + } + return out; +} + +/** Stable, order-independent comparison key for a set of books. */ +function bookKey(books: Book[]): string { + return JSON.stringify([...books].sort((a, b) => a.id.localeCompare(b.id))); +} + +// ---- invariant assertions ---- + +function assertConvergence(live: BookNode[], seed: number): void { + if (live.length < 2) return; + const reference = bookKey(live[0].app.getAll()); + for (const node of live.slice(1)) { + expect({ seed, node: node.id, state: bookKey(node.app.getAll()) }).toEqual({ + seed, + node: node.id, + state: reference, + }); + } +} + +function assertLogAgreement(live: BookNode[], seed: number): void { + if (live.length < 2) return; + // Compare committed entries up to the SHARED (minimum) commit index: no two + // nodes may disagree on any committed entry below the commit point. + const minCommit = Math.min(...live.map((n) => n.getCommitIndex())); + const serialize = (node: BookNode): string[] => { + const rows: string[] = []; + for (const { index, entry } of node.getCommittedEntries(0)) { + if (index > minCommit) break; + rows.push(`${index}:${entry.term}:${JSON.stringify(entry.command)}`); + } + return rows; + }; + const reference = serialize(live[0]); + for (const node of live.slice(1)) { + expect({ seed, node: node.id, log: serialize(node) }).toEqual({ + seed, + node: node.id, + log: reference, + }); + } +} + +function assertDeterminism(live: BookNode[], seed: number): void { + // Replaying the converged node's committed command sequence into a fresh state + // machine must reproduce the same state, confirming apply() is a pure function + // of the committed log. + const reference = live[0]; + const replay = new BookStateMachine(); + for (const cmd of committedAppCommands(reference)) replay.apply(cmd); + expect({ seed, state: bookKey(replay.getAll()) }).toEqual({ + seed, + state: bookKey(reference.app.getAll()), + }); +} + +// ---- the generative scenario ---- + +async function runScenario(seed: number, size: number): Promise { + const rng = new Rng(mulberry32(seed)); + const nodes = buildCluster(size); + nodes.forEach((n) => n.start()); + const stopped = new Set(); + const live = () => nodes.filter((n) => !stopped.has(n)); + + try { + await waitFor(() => leaders(nodes).length === 1, 3000); + + const isbnCounter = { n: 0 }; + const steps = 6 + rng.int(6); // 6..11 commands per iteration + + for (let step = 0; step < steps; step++) { + const leader = liveLeader(live()); + if (!leader) { + await waitFor(() => leaders(live()).length === 1, 3000).catch(() => undefined); + continue; + } + const cmd = nextCommand(rng, leader, isbnCounter); + await submitToLeader(live(), cmd); + + // Periodically induce churn: crash a node (often the leader) to force a + // re-election, or a second one on a 5-node cluster. A 3-node cluster + // tolerates exactly one failure, so never stop more than one there. + if (rng.bool(0.35)) { + if (stopped.size === 0) { + const victim = rng.bool(0.6) ? liveLeader(nodes) ?? rng.pick(nodes) : rng.pick(nodes); + victim.stop(); + stopped.add(victim); + await waitFor(() => leaders(live()).length === 1, 3000).catch(() => undefined); + } else if (size >= 5 && stopped.size < size - 3 && rng.bool(0.4)) { + // Only a 5-node cluster can afford a second concurrent failure + // (5 tolerates 2). Bounded so a quorum always remains. + const candidate = live().find((n) => !n.isLeader()); + if (candidate) { + candidate.stop(); + stopped.add(candidate); + await waitFor(() => leaders(live()).length === 1, 3000).catch(() => undefined); + } + } + } + } + + // Restart every crashed node so the cluster heals to full membership. + for (const node of [...stopped]) { + node.start(); + stopped.delete(node); + } + + // Wait for the healed cluster to re-settle: one leader, and every node + // caught up to the leader's commit index (so convergence is a fair check). + await waitFor(() => leaders(nodes).length === 1, 4000); + const targetCommit = liveLeader(nodes)!.getCommitIndex(); + await waitFor(() => nodes.every((n) => n.getCommitIndex() >= targetCommit), 4000); + // Give the apply loop a beat to drain lastApplied up to commitIndex everywhere. + await waitFor(() => nodes.every((n) => n.status().lastApplied >= targetCommit), 4000); + + // ---- SAFETY INVARIANTS ---- + assertLogAgreement(nodes, seed); + assertConvergence(nodes, seed); + assertDeterminism(nodes, seed); + } finally { + nodes.forEach((n) => n.stop()); + } +} + +describe('Consensus safety invariants (generative)', () => { + // Generous headroom: an iteration can chain several 3-4s settle waits, and CI + // boxes are slower than dev. The real timing is bounded by the fast test timers. + jest.setTimeout(45000); + + // A fixed base seed keeps CI runs reproducible while still covering many + // distinct randomized scenarios. Override with SEED= to replay one case. + const BASE_SEED = process.env.SEED ? Number(process.env.SEED) : 0xc0ffee; + const ITERATIONS = process.env.SEED ? 1 : 10; + + for (let i = 0; i < ITERATIONS; i++) { + const seed = (BASE_SEED + i * 0x9e3779b1) >>> 0; + const size = i % 3 === 2 ? 5 : 3; // mix in 5-node clusters + + it(`converges and stays consistent under churn [seed=${seed}, ${size} nodes]`, async () => { + // eslint-disable-next-line no-console + console.log(`[consensusProperties] iteration ${i} seed=${seed} size=${size}`); + await runScenario(seed, size); + }); + } +}); diff --git a/tests/edgeStreamSource.test.ts b/tests/edgeStreamSource.test.ts new file mode 100644 index 0000000..1385cec --- /dev/null +++ b/tests/edgeStreamSource.test.ts @@ -0,0 +1,493 @@ +import http from 'http'; +import { Server } from 'http'; +import { AddressInfo } from 'net'; +import { HttpStreamSource } from '../src/edge/httpStreamSource'; +import { + EventSourceStreamSource, + EventSourceCtor, + EventSourceLike, + MessageEventLike, +} from '../src/edge/eventSourceStreamSource'; +import { StreamHandlers, StreamSnapshot, StreamEntry } from '../src/edge/types'; +import { AppCommand } from '../src/consensus/types'; +import { waitFor } from './helpers'; + +/** + * Unit-level coverage for the edge stream-source internals that the HTTP-backed + * EdgeReplica integration suites don't exercise directly: SSE frame parsing, + * malformed-payload handling, mid-stream disconnect -> onError, the close() + * teardown contract for {@link HttpStreamSource}, and the open/message/error/ + * close paths of {@link EventSourceStreamSource} via an injected double. + */ + +jest.setTimeout(15000); + +interface Cmd extends AppCommand { + type: string; +} + +/** A recording StreamHandlers: every callback pushes onto an ordered event log. */ +function recordingHandlers(): { + handlers: StreamHandlers; + events: string[]; + snapshots: StreamSnapshot[]; + entries: StreamEntry[]; + caughtUp: number[]; + errors: Error[]; +} { + const events: string[] = []; + const snapshots: StreamSnapshot[] = []; + const entries: StreamEntry[] = []; + const caughtUp: number[] = []; + const errors: Error[] = []; + const handlers: StreamHandlers = { + onOpen() { + events.push('open'); + }, + onSnapshot(snap) { + events.push('snapshot'); + snapshots.push(snap); + }, + onEntry(item) { + events.push('entry'); + entries.push(item); + }, + onCaughtUp(index) { + events.push('caughtup'); + caughtUp.push(index); + }, + onError(err) { + events.push('error'); + errors.push(err); + }, + }; + return { handlers, events, snapshots, entries, caughtUp, errors }; +} + +const sse = (event: string, data: unknown): string => `event: ${event}\ndata: ${JSON.stringify(data)}\n\n`; + +describe('HttpStreamSource (Node SSE client)', () => { + let server: Server; + let baseUrl: string; + const sockets = new Set(); + // Per-test hook: receives the request + response so each test scripts the stream. + let onRequest: (req: http.IncomingMessage, res: http.ServerResponse) => void; + + beforeEach(async () => { + onRequest = (_req, res) => res.end(); + server = http.createServer((req, res) => onRequest(req, res)); + // Track live sockets so teardown can force-close any held-open SSE stream; + // otherwise server.close() would block on the long-lived connection. + server.on('connection', (s) => { + sockets.add(s); + s.on('close', () => sockets.delete(s)); + }); + await new Promise((r) => server.listen(0, '127.0.0.1', () => r())); + baseUrl = `http://127.0.0.1:${(server.address() as AddressInfo).port}`; + }); + + afterEach(async () => { + for (const s of sockets) s.destroy(); + sockets.clear(); + await new Promise((r) => server.close(() => r())); + }); + + it('parses a snapshot -> entry -> caughtup sequence in order and decodes payloads', async () => { + const snapshot: StreamSnapshot = { + lastIncludedIndex: 5, + lastIncludedTerm: 2, + members: [{ id: 'n1', url: 'http://n1' }], + data: { state: { count: 7 } }, + }; + const streamEntry: StreamEntry = { index: 6, entry: { term: 2, command: { type: 'op' } } }; + + onRequest = (req, res) => { + // The fromIndex query is propagated onto the URL. + expect(req.url).toContain('fromIndex=5'); + res.writeHead(200, { 'Content-Type': 'text/event-stream' }); + res.write(': keepalive comment\n\n'); + res.write(sse('snapshot', snapshot)); + res.write(sse('entry', streamEntry)); + res.write(sse('caughtup', { index: 6 })); + // Leave the connection open; close() will tear it down. + }; + + const source = new HttpStreamSource(baseUrl); + const rec = recordingHandlers(); + const close = source.connect(5, rec.handlers); + + await waitFor(() => rec.caughtUp.length === 1, 5000); + close(); + + expect(rec.events).toEqual(['open', 'snapshot', 'entry', 'caughtup']); + expect(rec.snapshots[0]).toEqual(snapshot); + expect(rec.entries[0]).toEqual(streamEntry); + expect(rec.caughtUp[0]).toBe(6); + expect(rec.errors).toHaveLength(0); + }); + + it('handles a frame split across multiple TCP chunks', async () => { + const streamEntry: StreamEntry = { index: 1, entry: { term: 1, command: { type: 'op' } } }; + const full = sse('entry', streamEntry); + const mid = Math.floor(full.length / 2); + + onRequest = (_req, res) => { + res.writeHead(200, { 'Content-Type': 'text/event-stream' }); + res.write(full.slice(0, mid)); + setTimeout(() => res.write(full.slice(mid)), 20); + }; + + const source = new HttpStreamSource(baseUrl); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + + await waitFor(() => rec.entries.length === 1, 5000); + close(); + expect(rec.entries[0]).toEqual(streamEntry); + expect(rec.errors).toHaveLength(0); + }); + + it('surfaces a malformed (non-JSON) data frame via onError without crashing', async () => { + onRequest = (_req, res) => { + res.writeHead(200, { 'Content-Type': 'text/event-stream' }); + res.write('event: entry\ndata: {not valid json}\n\n'); + // A valid frame after the bad one still gets dispatched -> consumer survives. + res.write(sse('caughtup', { index: 3 })); + }; + + const source = new HttpStreamSource(baseUrl); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + + await waitFor(() => rec.caughtUp.length === 1, 5000); + close(); + + expect(rec.errors).toHaveLength(1); + expect(rec.caughtUp[0]).toBe(3); + }); + + it('ignores a comment-only frame and an unknown event type (forward-compatible)', async () => { + onRequest = (_req, res) => { + res.writeHead(200, { 'Content-Type': 'text/event-stream' }); + res.write(': just a comment\n\n'); + res.write('event: futurething\ndata: {"hello":"world"}\n\n'); + res.write('event: entry\n\n'); // no data line -> ignored + res.write(sse('caughtup', { index: 1 })); + }; + + const source = new HttpStreamSource(baseUrl); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + + await waitFor(() => rec.caughtUp.length === 1, 5000); + close(); + + // Only open + caughtup; the comment/unknown/empty frames produced nothing. + expect(rec.events).toEqual(['open', 'caughtup']); + expect(rec.errors).toHaveLength(0); + }); + + it('reports onError when the server disconnects mid-stream (after delivering entries)', async () => { + onRequest = (_req, res) => { + res.writeHead(200, { 'Content-Type': 'text/event-stream' }); + res.write(sse('entry', { index: 1, entry: { term: 1, command: { type: 'op' } } })); + // The server tears the stream down after the first frame; the client sees + // end-of-response and surfaces it as an error for the replica to reconnect. + setTimeout(() => res.end(), 20); + }; + + const source = new HttpStreamSource(baseUrl); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + + await waitFor(() => rec.errors.length === 1, 5000); + close(); + expect(rec.entries).toHaveLength(1); + expect(rec.errors[0]).toBeInstanceOf(Error); + expect(rec.errors[0].message).toMatch(/stream ended/); + }); + + it('reports onError on an abrupt socket reset so the replica can reconnect', async () => { + onRequest = (_req, res) => { + res.writeHead(200, { 'Content-Type': 'text/event-stream' }); + res.write(sse('entry', { index: 1, entry: { term: 1, command: { type: 'op' } } })); + // Abrupt RST: Node fires 'aborted'/'close' on the response, NOT 'end' on + // the response nor 'error' on the request. The source listens for these + // so the drop surfaces as onError (single fire) instead of stalling. + setTimeout(() => res.socket?.destroy(), 20); + }; + + const source = new HttpStreamSource(baseUrl); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + + await waitFor(() => rec.entries.length === 1, 5000); + await waitFor(() => rec.events.includes('error'), 5000); + close(); + expect(rec.entries).toHaveLength(1); + // Exactly one termination signal, despite aborted + close both firing. + expect(rec.errors).toHaveLength(1); + }); + + it('reports onError when the server ends the stream cleanly', async () => { + onRequest = (_req, res) => { + res.writeHead(200, { 'Content-Type': 'text/event-stream' }); + res.end(sse('caughtup', { index: 1 })); + }; + + const source = new HttpStreamSource(baseUrl); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + + await waitFor(() => rec.errors.length === 1, 5000); + close(); + // The clean end still surfaces as an error: the consumer (EdgeReplica) decides + // whether to reconnect. + expect(rec.caughtUp[0]).toBe(1); + expect(rec.errors[0].message).toMatch(/stream ended/); + }); + + it('reports onError on a non-200 status (e.g. 500)', async () => { + onRequest = (_req, res) => { + res.writeHead(500); + res.end('boom'); + }; + + const source = new HttpStreamSource(baseUrl); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + + await waitFor(() => rec.errors.length === 1, 5000); + close(); + expect(rec.events).not.toContain('open'); + expect(rec.errors[0].message).toMatch(/HTTP 500/); + }); + + it('reports an unauthorized stream (401/403) distinctly and does not open', async () => { + onRequest = (req, res) => { + // The bearer token rides the Authorization header. + expect(req.headers.authorization).toBe('Bearer secret-tok'); + res.writeHead(403); + res.end(); + }; + + const source = new HttpStreamSource(baseUrl, { token: 'secret-tok' }); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + + await waitFor(() => rec.errors.length === 1, 5000); + close(); + expect(rec.events).not.toContain('open'); + expect(rec.errors[0].message).toMatch(/unauthorized.*403/); + }); + + it('close() stops the stream: no events fire after teardown', async () => { + let res!: http.ServerResponse; + const opened = new Promise((resolve) => { + onRequest = (_req, r) => { + res = r; + res.writeHead(200, { 'Content-Type': 'text/event-stream' }); + // Flush a keepalive comment so the response headers reach the client and + // onOpen fires (writeHead alone may buffer under keep-alive). + res.write(': open\n\n'); + resolve(); + }; + }); + + const source = new HttpStreamSource(baseUrl); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + + await opened; + await waitFor(() => rec.events.includes('open'), 5000); + close(); + + // After close(), a server-side end must NOT surface as an error (closed guard). + res.end(sse('caughtup', { index: 1 })); + // Give any in-flight 'end'/'error' callbacks a chance to (wrongly) fire. + await new Promise((r) => setTimeout(r, 50)); + + expect(rec.events).toEqual(['open']); + expect(rec.errors).toHaveLength(0); + expect(rec.caughtUp).toHaveLength(0); + }); + + it('routes to https for an https:// base URL (connection fails fast, no crash)', async () => { + // We don't stand up TLS; we only assert the https branch is taken and the + // resulting connection error is surfaced through onError (not thrown). + const source = new HttpStreamSource('https://127.0.0.1:1/'); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + await waitFor(() => rec.errors.length === 1, 5000); + close(); + // The connection error is surfaced (not thrown). Assert on shape rather than + // `instanceof Error`, which can fail across the https module's internal realm. + expect(typeof rec.errors[0].message).toBe('string'); + expect(rec.events).not.toContain('open'); + }); +}); + +/** + * A fully in-memory EventSource double. Unlike the socket-backed polyfill in + * eventSourceSource.test.ts, this lets us drive open/message/error directly so we + * can exercise EventSourceStreamSource's branches (parse failure, post-close + * suppression, close() idempotency) deterministically. + */ +class FakeEventSource implements EventSourceLike { + static last: FakeEventSource | null = null; + onopen: ((ev: unknown) => void) | null = null; + onerror: ((ev: unknown) => void) | null = null; + closed = 0; + readonly url: string; + private readonly listeners = new Map void)[]>(); + + constructor(url: string) { + this.url = url; + FakeEventSource.last = this; + } + + addEventListener(type: string, listener: (ev: MessageEventLike) => void): void { + const arr = this.listeners.get(type) ?? []; + arr.push(listener); + this.listeners.set(type, arr); + } + + close(): void { + this.closed += 1; + } + + // --- test drivers --- + emitOpen(): void { + this.onopen?.({}); + } + emit(type: string, data: unknown): void { + for (const cb of this.listeners.get(type) ?? []) cb({ data: JSON.stringify(data) }); + } + emitRaw(type: string, data: string): void { + for (const cb of this.listeners.get(type) ?? []) cb({ data }); + } + emitError(): void { + this.onerror?.({}); + } +} + +describe('EventSourceStreamSource (browser path) via an injected double', () => { + const ctor = FakeEventSource as unknown as EventSourceCtor; + + beforeEach(() => { + FakeEventSource.last = null; + }); + + it('builds the stream URL with fromIndex and a token query param', () => { + const source = new EventSourceStreamSource('http://node:3001/', ctor, { token: 'tok 1' }); + const rec = recordingHandlers(); + const close = source.connect(7, rec.handlers); + + const es = FakeEventSource.last!; + expect(es.url).toBe('http://node:3001/raft/stream?fromIndex=7&token=tok%201'); + close(); + }); + + it('uses & as the query separator when baseUrl already has a query string', () => { + const source = new EventSourceStreamSource('http://node:3001/?x=1', ctor); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + expect(FakeEventSource.last!.url).toBe('http://node:3001/?x=1/raft/stream&fromIndex=0'); + close(); + }); + + it('dispatches open/snapshot/entry/caughtup and decodes payloads', () => { + const source = new EventSourceStreamSource('http://node', ctor); + const rec = recordingHandlers(); + source.connect(0, rec.handlers); + const es = FakeEventSource.last!; + + const snapshot: StreamSnapshot = { + lastIncludedIndex: 3, + lastIncludedTerm: 1, + members: [], + data: { state: { count: 1 } }, + }; + const streamEntry: StreamEntry = { index: 4, entry: { term: 1, command: { type: 'op' } } }; + + es.emitOpen(); + es.emit('snapshot', snapshot); + es.emit('entry', streamEntry); + es.emit('caughtup', { index: 4 }); + + expect(rec.events).toEqual(['open', 'snapshot', 'entry', 'caughtup']); + expect(rec.snapshots[0]).toEqual(snapshot); + expect(rec.entries[0]).toEqual(streamEntry); + expect(rec.caughtUp[0]).toBe(4); + }); + + it('surfaces a malformed message payload via onError and skips dispatch', () => { + const source = new EventSourceStreamSource('http://node', ctor); + const rec = recordingHandlers(); + source.connect(0, rec.handlers); + const es = FakeEventSource.last!; + + es.emitRaw('entry', '{bad json'); + + expect(rec.entries).toHaveLength(0); + expect(rec.errors).toHaveLength(1); + expect(rec.errors[0].message).toMatch(/bad SSE payload/); + }); + + it('on error: closes the EventSource and reports exactly once', () => { + const source = new EventSourceStreamSource('http://node', ctor); + const rec = recordingHandlers(); + source.connect(0, rec.handlers); + const es = FakeEventSource.last!; + + es.emitError(); + es.emitError(); // second error after self-close is suppressed + + expect(rec.errors).toHaveLength(1); + expect(rec.errors[0].message).toMatch(/EventSource error/); + expect(es.closed).toBe(1); + }); + + it('close() closes the EventSource and suppresses a later error', () => { + const source = new EventSourceStreamSource('http://node', ctor); + const rec = recordingHandlers(); + const close = source.connect(0, rec.handlers); + const es = FakeEventSource.last!; + + close(); + expect(es.closed).toBe(1); + + // An error arriving after an explicit close must not reach the handler. + es.emitError(); + expect(rec.errors).toHaveLength(0); + }); + + it('throws when no EventSource is available and none is injected', () => { + const g = globalThis as unknown as { EventSource?: unknown }; + const had = 'EventSource' in g; + const prev = g.EventSource; + delete g.EventSource; + try { + expect(() => new EventSourceStreamSource('http://node')).toThrow(/No EventSource/); + } finally { + if (had) g.EventSource = prev; + } + }); + + it('falls back to a global EventSource when no ctor is passed', () => { + const g = globalThis as unknown as { EventSource?: unknown }; + const had = 'EventSource' in g; + const prev = g.EventSource; + g.EventSource = FakeEventSource; + try { + const source = new EventSourceStreamSource('http://node'); + const rec = recordingHandlers(); + source.connect(0, rec.handlers); + FakeEventSource.last!.emitOpen(); + expect(rec.events).toEqual(['open']); + } finally { + if (had) g.EventSource = prev; + else delete g.EventSource; + } + }); +}); diff --git a/tests/runtime/canonicalUnit.test.ts b/tests/runtime/canonicalUnit.test.ts new file mode 100644 index 0000000..01f5393 --- /dev/null +++ b/tests/runtime/canonicalUnit.test.ts @@ -0,0 +1,100 @@ +import { canonicalJson } from '../../src/runtime/canonical'; + +/** + * Direct unit coverage of the shared canonical-JSON serializer (`canonical.ts`). + * `determinism.test.ts` exercises it only via `canonicalBytes` (drop mode, size + * bound); these tests hit the serializer's own branches head-on: the default + * `'throw'` undefined mode (hash-preimage path), the lenient `'drop'` mode, nested + * structures, and key-order independence — the determinism linchpin the module + * exists to guarantee. + */ +describe('canonicalJson: undefined handling', () => { + describe("'throw' mode (default — hash preimages)", () => { + it('throws on a bare top-level undefined', () => { + expect(() => canonicalJson(undefined)).toThrow(/undefined is not serializable/); + }); + + it('throws on an undefined-valued object property (would be silently dropped)', () => { + expect(() => canonicalJson({ a: 1, b: undefined })).toThrow(/undefined is not serializable/); + }); + + it('throws on an undefined array element', () => { + expect(() => canonicalJson([1, undefined, 3])).toThrow(/undefined is not serializable/); + }); + + it('throws on a nested undefined deep in the structure', () => { + expect(() => canonicalJson({ outer: { inner: [{ x: undefined }] } })).toThrow( + /undefined is not serializable/, + ); + }); + + it('is the default when opts is omitted or onUndefined is unset', () => { + expect(() => canonicalJson(undefined, {})).toThrow(/undefined/); + }); + }); + + describe("'drop' mode (lenient — size bound)", () => { + it('returns null for a bare top-level undefined (matches JSON.stringify(null))', () => { + expect(canonicalJson(undefined, { onUndefined: 'drop' })).toBe('null'); + }); + + it('omits undefined-valued object properties, mirroring JSON.stringify', () => { + expect(canonicalJson({ a: 1, b: undefined, c: 3 }, { onUndefined: 'drop' })).toBe('{"a":1,"c":3}'); + expect(canonicalJson({ a: 1, b: undefined, c: 3 }, { onUndefined: 'drop' })).toBe( + JSON.stringify({ a: 1, c: 3 }), + ); + }); + + it('normalizes an undefined array element to null, mirroring JSON.stringify', () => { + expect(canonicalJson([1, undefined, 3], { onUndefined: 'drop' })).toBe('[1,null,3]'); + expect(canonicalJson([1, undefined, 3], { onUndefined: 'drop' })).toBe(JSON.stringify([1, undefined, 3])); + }); + + it('drops nested undefined object props but keeps the surrounding structure', () => { + const v = { keep: 'yes', gone: undefined, nested: { a: undefined, b: 2 } }; + expect(canonicalJson(v, { onUndefined: 'drop' })).toBe('{"keep":"yes","nested":{"b":2}}'); + }); + }); +}); + +describe('canonicalJson: primitives and structure', () => { + it('serializes scalars exactly like JSON.stringify', () => { + expect(canonicalJson(null)).toBe('null'); + expect(canonicalJson(42)).toBe('42'); + expect(canonicalJson(true)).toBe('true'); + expect(canonicalJson('hi')).toBe('"hi"'); + expect(canonicalJson('a "quoted" \n value')).toBe(JSON.stringify('a "quoted" \n value')); + }); + + it('serializes an empty object and empty array', () => { + expect(canonicalJson({})).toBe('{}'); + expect(canonicalJson([])).toBe('[]'); + }); + + it('quotes object keys (including keys needing escaping)', () => { + expect(canonicalJson({ 'a"b': 1 })).toBe('{"a\\"b":1}'); + }); + + it('serializes nested objects and arrays recursively', () => { + const v = { z: [1, { q: 2 }], a: { b: { c: [3, 4] } } }; + expect(canonicalJson(v)).toBe('{"a":{"b":{"c":[3,4]}},"z":[1,{"q":2}]}'); + }); +}); + +describe('canonicalJson: key-order independence (determinism linchpin)', () => { + it('produces identical bytes regardless of object key insertion order', () => { + expect(canonicalJson({ a: 1, b: 2, c: 3 })).toBe(canonicalJson({ c: 3, a: 1, b: 2 })); + }); + + it('sorts keys recursively at every depth', () => { + const a = { outer: { z: 1, a: 2 }, list: [{ y: 1, x: 2 }] }; + const b = { list: [{ x: 2, y: 1 }], outer: { a: 2, z: 1 } }; + expect(canonicalJson(a)).toBe(canonicalJson(b)); + expect(canonicalJson(a)).toBe('{"list":[{"x":2,"y":1}],"outer":{"a":2,"z":1}}'); + }); + + it('preserves array element order (arrays are positional, not sorted)', () => { + expect(canonicalJson([3, 1, 2])).toBe('[3,1,2]'); + expect(canonicalJson([3, 1, 2])).not.toBe(canonicalJson([1, 2, 3])); + }); +}); diff --git a/tests/runtime/keyedModuleUnit.test.ts b/tests/runtime/keyedModuleUnit.test.ts new file mode 100644 index 0000000..d3cf097 --- /dev/null +++ b/tests/runtime/keyedModuleUnit.test.ts @@ -0,0 +1,110 @@ +import { defineKeyedModule } from '../../src/runtime/keyedModule'; +import { StoreView } from '../../src/runtime/stateStore'; + +/** + * Unit coverage of `defineKeyedModule`'s VALIDATION branches. `keyedStore.test.ts` + * exercises keyed modules end-to-end through `ModuleHost` (and the strict-default + * lint via Date.now), but not the definition-time guards themselves: empty name, + * the `__`-reserved-name rejection, the no-commands / empty-command-name guards, + * and the non-strict `{ strict: false }` path that records `__lint` instead of + * throwing. + */ + +/** A trivially clean keyed reducer (passes the determinism lint). */ +const ok = (store: StoreView, input: unknown) => { + store.put('k', input); + return {}; +}; + +describe('defineKeyedModule: name validation', () => { + it('rejects an empty name', () => { + expect(() => defineKeyedModule({ name: '', commands: { go: ok } })).toThrow(/non-empty name/); + }); + + it('rejects a whitespace-only name', () => { + expect(() => defineKeyedModule({ name: ' ', commands: { go: ok } })).toThrow(/non-empty name/); + }); + + it('rejects a "__"-prefixed name (reserved for runtime internals)', () => { + expect(() => defineKeyedModule({ name: '__outbox', commands: { go: ok } })).toThrow( + /reserved.*"__"|"__".*reserved/, + ); + }); +}); + +describe('defineKeyedModule: command validation', () => { + it('rejects a module with no commands', () => { + expect(() => defineKeyedModule({ name: 'empty', commands: {} })).toThrow( + /must define at least one command/, + ); + }); + + it('rejects a command with an empty name', () => { + expect(() => defineKeyedModule({ name: 'bad-cmd', commands: { '': ok } })).toThrow( + /command with an empty name/, + ); + }); + + it('treats an entirely absent commands map as no commands', () => { + // `commands` omitted: the `?? {}` default yields zero command names. + expect(() => defineKeyedModule({ name: 'no-commands-field' } as never)).toThrow( + /must define at least one command/, + ); + }); +}); + +describe('defineKeyedModule: success', () => { + it('stamps kind: "keyed" and returns the definition for a valid module', () => { + const mod = defineKeyedModule({ + name: 'good', + version: '1', + commands: { go: ok }, + queries: { count: (store) => store.size() }, + }); + expect(mod.name).toBe('good'); + expect(mod.kind).toBe('keyed'); + expect(mod.version).toBe('1'); + expect(mod.__lint).toBeUndefined(); + expect(Object.keys(mod.commands)).toEqual(['go']); + }); + + it('accepts an explicit kind: "keyed" without complaint', () => { + const mod = defineKeyedModule({ name: 'explicit', kind: 'keyed', commands: { go: ok } }); + expect(mod.kind).toBe('keyed'); + }); +}); + +describe('defineKeyedModule: determinism lint', () => { + it('throws on a non-deterministic reducer under the strict default', () => { + expect(() => + defineKeyedModule({ + name: 'bad-random', + commands: { + go: (store) => { + store.put('k', Math.random()); + return {}; + }, + }, + }), + ).toThrow(/determinism lint/); + }); + + it('records violations under __lint instead of throwing when strict: false', () => { + const mod = defineKeyedModule( + { + name: 'vetted-keyed', + commands: { + go: (store) => { + store.put('t', Date.now()); + return {}; + }, + }, + }, + { strict: false }, + ); + expect(mod.name).toBe('vetted-keyed'); + expect(mod.kind).toBe('keyed'); + expect(mod.__lint).toBeDefined(); + expect(mod.__lint!.some((v) => /Date\.now/.test(v))).toBe(true); + }); +}); diff --git a/tests/runtime/projectionUnit.test.ts b/tests/runtime/projectionUnit.test.ts new file mode 100644 index 0000000..d156a2f --- /dev/null +++ b/tests/runtime/projectionUnit.test.ts @@ -0,0 +1,66 @@ +import { defineProjection, ProjectionDefinition, ProjectionEvent } from '../../src/runtime/projection'; + +/** + * Unit coverage of `defineProjection`'s VALIDATION branches. `projection.test.ts` + * drives a pre-built projection (`noteIndex`) through `ProjectionHost`, but never + * exercises the definition-time guards in `projection.ts`: empty name, a missing + * `init()` factory, a missing `on()` fold, and the no-queries guard. A valid + * definition is returned as-is (identity with light validation). + */ + +type View = { total: number }; + +const validDef = (over: Partial> = {}): ProjectionDefinition => ({ + name: 'p', + init: () => ({ total: 0 }), + on: (view, _event: ProjectionEvent) => view, + queries: { total: (view) => view.total }, + ...over, +}); + +describe('defineProjection: name validation', () => { + it('rejects an empty name', () => { + expect(() => defineProjection(validDef({ name: '' }))).toThrow(/non-empty name/); + }); + + it('rejects a whitespace-only name', () => { + expect(() => defineProjection(validDef({ name: ' ' }))).toThrow(/non-empty name/); + }); +}); + +describe('defineProjection: shape validation', () => { + it('rejects a definition missing the init() factory', () => { + expect(() => defineProjection(validDef({ init: undefined as unknown as () => View }))).toThrow( + /requires an init\(\) factory/, + ); + }); + + it('rejects a definition missing the on() fold', () => { + expect(() => + defineProjection(validDef({ on: undefined as unknown as ProjectionDefinition['on'] })), + ).toThrow(/requires an on\(\) fold/); + }); + + it('rejects a definition with no queries', () => { + expect(() => defineProjection(validDef({ queries: {} }))).toThrow(/must define at least one query/); + }); + + it('treats an entirely absent queries map as no queries', () => { + // `queries` omitted: the `?? {}` default yields zero query names. + const def = validDef(); + delete (def as { queries?: unknown }).queries; + expect(() => defineProjection(def)).toThrow(/must define at least one query/); + }); +}); + +describe('defineProjection: success', () => { + it('returns a valid definition unchanged (identity)', () => { + const def = validDef(); + const result = defineProjection(def); + expect(result).toBe(def); + expect(result.name).toBe('p'); + // The returned fold/init/queries are the same callables it was given. + expect(result.init()).toEqual({ total: 0 }); + expect(Object.keys(result.queries)).toEqual(['total']); + }); +}); diff --git a/tests/runtime/shardRouterUnit.test.ts b/tests/runtime/shardRouterUnit.test.ts new file mode 100644 index 0000000..274d164 --- /dev/null +++ b/tests/runtime/shardRouterUnit.test.ts @@ -0,0 +1,174 @@ +import { ApplyResult, CommandMeta } from '../../src/consensus/types'; +import { MetricsRegistry } from '../../src/platform/metrics'; +import { NoShardLeaderError, ShardNode, ShardRouter } from '../../src/runtime/shardRouter'; + +/** + * Unit coverage of `ShardRouter` over FAKE shard nodes. `sharding.test.ts` drives + * the router with real `buildModuleCluster` shards (the happy path), but its error + * and edge branches — empty-shard guard, an out-of-range shard index, the + * no-known-leader rejection, and `collectMetrics` when a shard has NO leader — are + * easier and faster to pin down with stubbed `{ isLeader, submit }` handles. No + * sockets, no timers, no teardown needed. + */ + +interface FakeNode extends ShardNode { + leader: boolean; + submitted: Array<{ command: any; meta?: CommandMeta }>; +} + +/** A stub shard node whose leadership is a settable flag. */ +function fakeNode(leader: boolean): FakeNode { + const submitted: Array<{ command: any; meta?: CommandMeta }> = []; + return { + leader, + submitted, + isLeader() { + return this.leader; + }, + async submit(command: any, meta?: CommandMeta): Promise> { + submitted.push({ command, meta }); + return { status: 200, result: { ok: true } } as ApplyResult; + }, + }; +} + +const META: CommandMeta = { actor: 'tester', requestId: 'req-1' }; + +describe('ShardRouter construction', () => { + it('rejects an empty shard list', () => { + expect(() => new ShardRouter([])).toThrow(/at least one shard/); + }); + + it('exposes shardCount equal to the number of handles', () => { + const router = new ShardRouter([{ nodes: [fakeNode(true)] }, { nodes: [fakeNode(false)] }]); + expect(router.shardCount).toBe(2); + + const single = new ShardRouter([{ nodes: [fakeNode(true)] }]); + expect(single.shardCount).toBe(1); + }); +}); + +describe('ShardRouter.shardFor (deterministic routing)', () => { + it('maps a key into [0, shardCount) and is stable across instances', () => { + const mk = () => + new ShardRouter([{ nodes: [fakeNode(true)] }, { nodes: [fakeNode(true)] }, { nodes: [fakeNode(true)] }]); + const a = mk(); + const b = mk(); + for (let i = 0; i < 50; i++) { + const key = `k-${i}`; + const shard = a.shardFor(key); + expect(shard).toBeGreaterThanOrEqual(0); + expect(shard).toBeLessThan(3); + expect(b.shardFor(key)).toBe(shard); // pure function of key + count + } + }); + + it('a single-shard router always routes to shard 0', () => { + const router = new ShardRouter([{ nodes: [fakeNode(true)] }]); + for (const key of ['a', 'b', 'anything']) { + expect(router.shardFor(key)).toBe(0); + } + }); +}); + +describe('ShardRouter.leaderOf', () => { + it('returns the current leader node when one exists', () => { + const follower = fakeNode(false); + const leader = fakeNode(true); + const router = new ShardRouter([{ nodes: [follower, leader] }]); + expect(router.leaderOf(0)).toBe(leader); + }); + + it('returns null when the shard has no known leader', () => { + const router = new ShardRouter([{ nodes: [fakeNode(false), fakeNode(false)] }]); + expect(router.leaderOf(0)).toBeNull(); + }); + + it('throws RangeError for an out-of-range shard index', () => { + const router = new ShardRouter([{ nodes: [fakeNode(true)] }]); + expect(() => router.leaderOf(5)).toThrow(RangeError); + expect(() => router.leaderOf(5)).toThrow(/no such shard: 5/); + }); +}); + +describe('ShardRouter.submit', () => { + it("routes a command to the owning shard's leader and resolves its ApplyResult", async () => { + // Two shards, each with a distinct leader; find a key landing on each. + const leaderA = fakeNode(true); + const leaderB = fakeNode(true); + const router = new ShardRouter([{ nodes: [leaderA] }, { nodes: [leaderB] }]); + + let keyA: string | undefined; + let keyB: string | undefined; + for (let i = 0; i < 1000 && (keyA === undefined || keyB === undefined); i++) { + const key = `acct-${i}`; + const shard = router.shardFor(key); + if (shard === 0 && keyA === undefined) keyA = key; + if (shard === 1 && keyB === undefined) keyB = key; + } + expect(keyA).toBeDefined(); + expect(keyB).toBeDefined(); + + const resA = await router.submit(keyA!, { type: 'X' } as any, META); + expect(resA.status).toBe(200); + // The command reached ONLY the owning shard's leader. + expect(leaderA.submitted).toHaveLength(1); + expect(leaderA.submitted[0].command).toEqual({ type: 'X' }); + expect(leaderA.submitted[0].meta).toBe(META); + expect(leaderB.submitted).toHaveLength(0); + + await router.submit(keyB!, { type: 'Y' } as any, META); + expect(leaderB.submitted).toHaveLength(1); + expect(leaderA.submitted).toHaveLength(1); // unchanged + }); + + it('rejects with NoShardLeaderError when the owning shard has no leader', async () => { + // Every node is a follower => no leader on any shard. + const router = new ShardRouter([{ nodes: [fakeNode(false), fakeNode(false)] }]); + await expect(router.submit('any-key', { type: 'X' } as any, META)).rejects.toBeInstanceOf(NoShardLeaderError); + await expect(router.submit('any-key', { type: 'X' } as any, META)).rejects.toMatchObject({ shard: 0 }); + }); + + it('NoShardLeaderError carries the shard number and a descriptive message', () => { + const err = new NoShardLeaderError(3); + expect(err.shard).toBe(3); + expect(err.name).toBe('NoShardLeaderError'); + expect(err.message).toMatch(/shard 3 has no known leader/); + expect(err).toBeInstanceOf(Error); + }); +}); + +describe('ShardRouter.collectMetrics', () => { + it('sets shard_count and shard_has_leader=1 for every shard that has a leader', () => { + const metrics = new MetricsRegistry(); + const router = new ShardRouter([{ nodes: [fakeNode(true)] }, { nodes: [fakeNode(true)] }]); + router.collectMetrics(metrics); + + const text = metrics.expose(); + expect(sampleValue(text, 'shard_count ')).toBe(2); + expect(sampleValue(text, 'shard_has_leader{shard="0"}')).toBe(1); + expect(sampleValue(text, 'shard_has_leader{shard="1"}')).toBe(1); + }); + + it('sets shard_has_leader=0 for a shard mid-election (no known leader)', () => { + const metrics = new MetricsRegistry(); + // Shard 0 has a leader; shard 1 is leaderless (both followers). + const router = new ShardRouter([ + { nodes: [fakeNode(true)] }, + { nodes: [fakeNode(false), fakeNode(false)] }, + ]); + router.collectMetrics(metrics); + + const text = metrics.expose(); + expect(sampleValue(text, 'shard_count ')).toBe(2); + expect(sampleValue(text, 'shard_has_leader{shard="0"}')).toBe(1); + expect(sampleValue(text, 'shard_has_leader{shard="1"}')).toBe(0); + }); +}); + +/** Parse a single Prometheus sample line's value by exact `name{labels}` prefix. */ +function sampleValue(text: string, prefix: string): number | undefined { + const line = text.split('\n').find((l) => l.startsWith(prefix)); + if (!line) return undefined; + return Number(line.slice(line.lastIndexOf(' ') + 1)); +} diff --git a/yarn.lock b/yarn.lock index 6ff8ca2..b891dca 100644 --- a/yarn.lock +++ b/yarn.lock @@ -17,11 +17,25 @@ dependencies: "@babel/highlight" "^7.18.6" +"@babel/code-frame@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.29.7.tgz#f2fbbfea87c44a21590ec515b778b2c26d8866e7" + integrity sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw== + dependencies: + "@babel/helper-validator-identifier" "^7.29.7" + js-tokens "^4.0.0" + picocolors "^1.1.1" + "@babel/compat-data@^7.21.4": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.21.4.tgz#457ffe647c480dff59c2be092fc3acf71195c87f" integrity sha512-/DYyDpeCfaVinT40FPGdkkb+lYSKvsVuMjDAG7jPOWWiM1ibOaB9CXJAlc4d1QpP/U2q2P9jbrSlClKSErd55g== +"@babel/compat-data@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/compat-data/-/compat-data-7.29.7.tgz#6f0237f0f36d2e51c0570a636faed9d2d0efe629" + integrity sha512-locTkQyKvwIEgBzVrn8693ebc97F2U8ZHjbXwDXJ5Fn2TCpNwTlKcaKLkdHop5c/icOFE7qt7Q9JC5hnKNa6Gg== + "@babel/core@^7.11.6", "@babel/core@^7.12.3": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.21.4.tgz#c6dc73242507b8e2a27fd13a9c1814f9fa34a659" @@ -43,6 +57,27 @@ json5 "^2.2.2" semver "^6.3.0" +"@babel/core@~7.29.0": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.29.7.tgz#80c10b17248082968b57a857b91640971f2070f7" + integrity sha512-RgHBCvtjbOK2gXSNBNIkNoEc9qoVEtau3hj8gEqKQuL3HZAibKarWFEI3Lfm6EYKkLalOh8eSrj9b+ch9H/VBA== + 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" + "@babel/generator@^7.21.4", "@babel/generator@^7.7.2": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.21.4.tgz#64a94b7448989f421f919d5239ef553b37bb26bc" @@ -53,6 +88,24 @@ "@jridgewell/trace-mapping" "^0.3.17" jsesc "^2.5.1" +"@babel/generator@^7.29.7", "@babel/generator@~7.29.0": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.29.7.tgz#cca0b8827e6bcf3ba176788e7f3b180ad6db2fa3" + integrity sha512-DkXD5OJQaAQIdZ1bt3UZdEnHAn9Imd3IVBdX03UFe+ony9Ojw5pzr9YVKGDY1jt+Gcn/FnGkNf8r+Vj5NOJWtQ== + dependencies: + "@babel/parser" "^7.29.7" + "@babel/types" "^7.29.7" + "@jridgewell/gen-mapping" "^0.3.12" + "@jridgewell/trace-mapping" "^0.3.28" + jsesc "^3.0.2" + +"@babel/helper-annotate-as-pure@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.29.7.tgz#c70fe3c6ecbdc3fd2dd1b0f498428b88b82ce47f" + integrity sha512-OoK6239jHPuSQOoS0kfTVKn0b/rVTk0seKq4Gd2UMLtmOVLjDC0ki3e+c90Trqv2gMfvJFqkiljrr568+qddiw== + dependencies: + "@babel/types" "^7.29.7" + "@babel/helper-compilation-targets@^7.21.4": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.21.4.tgz#770cd1ce0889097ceacb99418ee6934ef0572656" @@ -64,6 +117,30 @@ lru-cache "^5.1.1" semver "^6.3.0" +"@babel/helper-compilation-targets@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-compilation-targets/-/helper-compilation-targets-7.29.7.tgz#7a1def704302401c47f64fa85589e974ae217042" + integrity sha512-wem6WaBj4NaVYVdNhLPPVacES6ZJ+KBBfSkTMD3YZxbP3rm3Di85tJU5ljaUNhaOynt+Aj0xruhYuzQBt8n71g== + 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" + +"@babel/helper-create-class-features-plugin@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.29.7.tgz#6eddf286f2ec418f740c91d60a83347c55838ddd" + integrity sha512-IY3ZD9Tmooqr3TUhc3DUWxiuo8xx1DWLhd5M7hQ+ZWJamqM2BbalrBJb2MisSLoYorOj75U03qULCxQTY9r3hg== + dependencies: + "@babel/helper-annotate-as-pure" "^7.29.7" + "@babel/helper-member-expression-to-functions" "^7.29.7" + "@babel/helper-optimise-call-expression" "^7.29.7" + "@babel/helper-replace-supers" "^7.29.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.29.7" + "@babel/traverse" "^7.29.7" + semver "^6.3.1" + "@babel/helper-environment-visitor@^7.18.9": version "7.18.9" resolved "https://registry.yarnpkg.com/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz#0c0cee9b35d2ca190478756865bb3528422f51be" @@ -77,6 +154,11 @@ "@babel/template" "^7.20.7" "@babel/types" "^7.21.0" +"@babel/helper-globals@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-globals/-/helper-globals-7.29.7.tgz#f04a96fbd8473241b1079243f5b3f03a3010ab7b" + integrity sha512-3nQVUAtvkKH9zahfWgw96Jc/uFOmjACE1kQz82E2lqWmHBgjzbNlsC22nuQTfahmWeQtTq5nQ/4Nnd2A1wj4zA== + "@babel/helper-hoist-variables@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz#d4d2c8fb4baeaa5c68b99cc8245c56554f926678" @@ -84,6 +166,14 @@ dependencies: "@babel/types" "^7.18.6" +"@babel/helper-member-expression-to-functions@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.29.7.tgz#8dbdb3ce0b5c487e1aec10e13c9a43a500814df8" + integrity sha512-j+7JYmk1JYDtACIGj0QJqqWZjoUpMoEikQGADMaHgCMCSDqd2+P32rfcibUNrGOMWrlzK1WJBdxrB3JJQZwWtg== + dependencies: + "@babel/traverse" "^7.29.7" + "@babel/types" "^7.29.7" + "@babel/helper-module-imports@^7.18.6": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.21.4.tgz#ac88b2f76093637489e718a90cec6cf8a9b029af" @@ -91,6 +181,14 @@ dependencies: "@babel/types" "^7.21.4" +"@babel/helper-module-imports@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.29.7.tgz#ef25048a518e828d7393fac5882ddd73921d7396" + integrity sha512-ejHwrQQYcm9xnTivShn2IDOlIzInN34AXskvq9QicvCtEzq1Vzclu/tKF8Jq1Cg8JG2GL6/EmjgsCT7lXepE3g== + dependencies: + "@babel/traverse" "^7.29.7" + "@babel/types" "^7.29.7" + "@babel/helper-module-transforms@^7.21.2": version "7.21.2" resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.21.2.tgz#160caafa4978ac8c00ac66636cb0fa37b024e2d2" @@ -105,11 +203,41 @@ "@babel/traverse" "^7.21.2" "@babel/types" "^7.21.2" +"@babel/helper-module-transforms@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.29.7.tgz#b062747a5997ba138637201328bbff77960574ae" + integrity sha512-UPUVSyXbOh627KiCIGQSgwWzGeBKLkaJ9PJEdrngIwMSzxLR4jS4+f1f1jb7VzBbg8nFLaYotvVPFCTqdrmTAg== + dependencies: + "@babel/helper-module-imports" "^7.29.7" + "@babel/helper-validator-identifier" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/helper-optimise-call-expression@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.29.7.tgz#77b0b5b94f1997fa9d6e3125f445227b1faf9d85" + integrity sha512-+kmGVjcT9RGYzoDwdwEqEvGgKe3BYq+O1iGzjFubaNgZHwYHP6lsF2Yghf4kEuv9BV7tYDZ913aBW9am6YKong== + dependencies: + "@babel/types" "^7.29.7" + "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.4", "@babel/helper-plugin-utils@^7.12.13", "@babel/helper-plugin-utils@^7.14.5", "@babel/helper-plugin-utils@^7.20.2", "@babel/helper-plugin-utils@^7.8.0": version "7.20.2" resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz#d1b9000752b18d0877cff85a5c376ce5c3121629" integrity sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ== +"@babel/helper-plugin-utils@^7.27.1", "@babel/helper-plugin-utils@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.29.7.tgz#c0a0766f1a13617d8a17407d7ab8f9d486225ea4" + integrity sha512-G7sHYigPY17oO5SYWnfD/0MTBwVR781S/JI643e/JhUYgVgWE/61SoW3NH9KWUKyKq5LVh3npif99Wkt6j86Jw== + +"@babel/helper-replace-supers@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.29.7.tgz#bc3c3964329043c79112e513c1b198f16589ac21" + integrity sha512-atfGXWSeCiF4DnKZIfmJfQRkSw9b9gNNXR1kqKjbhG4pGYCOnkp8OcTB8E3NXjBu8NpheSnOeNKz8KT7UNFTmQ== + dependencies: + "@babel/helper-member-expression-to-functions" "^7.29.7" + "@babel/helper-optimise-call-expression" "^7.29.7" + "@babel/traverse" "^7.29.7" + "@babel/helper-simple-access@^7.20.2": version "7.20.2" resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.20.2.tgz#0ab452687fe0c2cfb1e2b9e0015de07fc2d62dd9" @@ -117,6 +245,14 @@ dependencies: "@babel/types" "^7.20.2" +"@babel/helper-skip-transparent-expression-wrappers@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.29.7.tgz#50c95c7e4c4f54936cfa0116428edc559862d551" + integrity sha512-brcMGQaVzIeUb+6/bs1Av0f8YuNNjKY2JyvfRCsFuFsdKccEQ5Ges2y74D74NZ1Rz8lKJ9ksJkfqwQFJ/iNEyQ== + dependencies: + "@babel/traverse" "^7.29.7" + "@babel/types" "^7.29.7" + "@babel/helper-split-export-declaration@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz#7367949bc75b20c6d5a5d4a97bba2824ae8ef075" @@ -129,16 +265,31 @@ resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz#38d3acb654b4701a9b77fb0615a96f775c3a9e63" integrity sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw== +"@babel/helper-string-parser@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-string-parser/-/helper-string-parser-7.29.7.tgz#7f0871d99824d23137d60f86fcf6130fd5a1b51f" + integrity sha512-Pb5ijPrZ89GDH8223L4UP8i6QApWxs04RbPQJTeWDV0/keR2E36MeKnyr6LYmUUvqRRI+Iv87SuF1W6ErINzYw== + "@babel/helper-validator-identifier@^7.18.6", "@babel/helper-validator-identifier@^7.19.1": version "7.19.1" resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz#7eea834cf32901ffdc1a7ee555e2f9c27e249ca2" integrity sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w== +"@babel/helper-validator-identifier@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.29.7.tgz#bd87084ced0c796ec46bda492de6e83d29e89fc2" + integrity sha512-qehxGkRj55h/ff8EMaJ+cYhyaKlHIxqYDn682wQD7RNp9UujOQsHog2uS0r2vzr4pW+sXf90NeeayjcNaX3fFg== + "@babel/helper-validator-option@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.21.0.tgz#8224c7e13ace4bafdc4004da2cf064ef42673180" integrity sha512-rmL/B8/f0mKS2baE9ZpyTcTavvEuWhTTW8amjzXNvYG4AwBsqTLikfXsEofsJEfKHf+HQVQbFOHy6o+4cnC/fQ== +"@babel/helper-validator-option@^7.27.1", "@babel/helper-validator-option@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helper-validator-option/-/helper-validator-option-7.29.7.tgz#cf315be940213b354eb4abcc0bd01ebe3f73bc2a" + integrity sha512-N9ZErrD+yW5geCDtBqnOoxmR8+tNKiGuxKlDpuJxfsqpa2dFcexaziGAE/qoHLiDDreVNMupxGmSoNlyvsA3gw== + "@babel/helpers@^7.21.0": version "7.21.0" resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.21.0.tgz#9dd184fb5599862037917cdc9eecb84577dc4e7e" @@ -148,6 +299,14 @@ "@babel/traverse" "^7.21.0" "@babel/types" "^7.21.0" +"@babel/helpers@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.29.7.tgz#45abfde7548997e34376c3e69feb475cffb4a607" + integrity sha512-1k2lAGRMfHTcwuNYcCNUmaUffmQv8KWMfh2iJUUeRlwlwH4FdNG7mfPI10NPfLHJFThE4Tyr4mv7kTNZOiPuBg== + dependencies: + "@babel/template" "^7.29.7" + "@babel/types" "^7.29.7" + "@babel/highlight@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.18.6.tgz#81158601e93e2563795adcbfbdf5d64be3f2ecdf" @@ -162,6 +321,22 @@ resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.21.4.tgz#94003fdfc520bbe2875d4ae557b43ddb6d880f17" integrity sha512-alVJj7k7zIxqBZ7BTRhz0IqJFxW1VJbm6N8JbcYhQ186df9ZBPbZBmWSqAMXwHGsCJdYks7z/voa3ibiS5bCIw== +"@babel/parser@^7.29.7", "@babel/parser@~7.29.0": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.29.7.tgz#837b87387cbf5ec5530cb634b3c622f68edb9334" + integrity sha512-hnORnjP/1P/zFEndoeX+n+t1RwWRJiJpM/jO7FW32Kn9r5+sJB2JWOdYo4L6k78j15eCwY3Gm/7364B1EMwtNg== + dependencies: + "@babel/types" "^7.29.7" + +"@babel/plugin-proposal-decorators@~7.29.0": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-proposal-decorators/-/plugin-proposal-decorators-7.29.7.tgz#ebc57bd4d711df920a553de8a456a3a020ce0d72" + integrity sha512-EtU0Hi3GvrTqD56xKmZvV/uCXK2ZbwVNPNLAquVItcAZpUhkXwWlo3Fmj0c2LxgSf2I8IDULeAepwNP1OefLXg== + dependencies: + "@babel/helper-create-class-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/plugin-syntax-decorators" "^7.29.7" + "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" @@ -183,6 +358,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.12.13" +"@babel/plugin-syntax-decorators@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-decorators/-/plugin-syntax-decorators-7.29.7.tgz#9a23ab91fb8e61d142684108bca6f343ceee88f6" + integrity sha512-9MTTLbF39X6sqM92JPEsoI7++26hjZvzkxKZy64aMhWLH2mPkJ/Q3AV4QLmls3R14FpSpkOwQQfUh962JGQxxg== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz#ee601348c370fa334d2207be158777496521fd51" @@ -197,6 +379,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.8.0" +"@babel/plugin-syntax-jsx@^7.27.1": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.29.7.tgz#622c16f9ad63782fe6e83dadc7e40330744b7f1e" + integrity sha512-TSu8+mHCoEaaCDEZ0I3+6mvTBYR4PCxQwf2z9/r5Tbztv6NaLR3B9thGTTxX2WGuGHJqRiAbKPeGTJ5XWXVg6A== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/plugin-syntax-jsx@^7.7.2": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz#f264ed7bf40ffc9ec239edabc17a50c4f5b6fea2" @@ -253,6 +442,13 @@ dependencies: "@babel/helper-plugin-utils" "^7.14.5" +"@babel/plugin-syntax-typescript@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.29.7.tgz#7c29388932313ed58413a0343048d75d92fb5b24" + integrity sha512-ngr+82Sh0xMz25TPCZi+nC2iTzjfCdWS2ONXTp/PtSCHCgaCNBpdMqgvJ2ccdLlClVZ7sisIgB914j/JFe+RZA== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/plugin-syntax-typescript@^7.7.2": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz#2751948e9b7c6d771a8efa59340c15d4a2891ff8" @@ -260,6 +456,52 @@ dependencies: "@babel/helper-plugin-utils" "^7.20.2" +"@babel/plugin-transform-destructuring@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.29.7.tgz#5781ec6947852e27b64c1165f0db431f408090e4" + integrity sha512-iPX8aD6H9zV5s7ZsqTdNocPN/MGQ5sSMnElKrktxjJRMnB2jN/1p2+R7GkfD6CAYoVFqy5A4XnSIUeGgJzIWpg== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/traverse" "^7.29.7" + +"@babel/plugin-transform-explicit-resource-management@^7.28.0": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-explicit-resource-management/-/plugin-transform-explicit-resource-management-7.29.7.tgz#65c8b9f76ec915b02a0e1df703125a0fca58abaa" + integrity sha512-Rstj7coNz8sE+7Ju7ihpHLI564lsK5pUpNNlvptCIC/16E/S5hbl6n3kESPKdNRmqEWlpn5xpS5Q2dvXBsySLw== + dependencies: + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/plugin-transform-destructuring" "^7.29.7" + +"@babel/plugin-transform-modules-commonjs@^7.27.1": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.29.7.tgz#70e6835abf2663dafbe94b8ef1f51de7351ef135" + integrity sha512-j0vCldybPC5b5dwCQOJ21uKtHzt7hxLygJTg9eF1ScfaikEDNfzn94XoW5Fi+seBR0nCyL23xaBFFkq7dTM8XQ== + dependencies: + "@babel/helper-module-transforms" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + +"@babel/plugin-transform-typescript@^7.28.5": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/plugin-transform-typescript/-/plugin-transform-typescript-7.29.7.tgz#f0449c3df7037bbe232043476851c38f5e4a7615" + integrity sha512-jK52h8LaLc7JarhQV2ofeFMts4H7vnOXnqZNA6fYglBTZewRBE51KWt3BUltW1P+KoPsYkHoJeXePuz4zo2LMw== + dependencies: + "@babel/helper-annotate-as-pure" "^7.29.7" + "@babel/helper-create-class-features-plugin" "^7.29.7" + "@babel/helper-plugin-utils" "^7.29.7" + "@babel/helper-skip-transparent-expression-wrappers" "^7.29.7" + "@babel/plugin-syntax-typescript" "^7.29.7" + +"@babel/preset-typescript@~7.28.0": + version "7.28.5" + resolved "https://registry.yarnpkg.com/@babel/preset-typescript/-/preset-typescript-7.28.5.tgz#540359efa3028236958466342967522fd8f2a60c" + integrity sha512-+bQy5WOI2V6LJZpPVxY+yp66XdZ2yifu0Mc1aP5CQKgjn4QM5IN2i5fAZ4xKop47pr8rpVhiAeu+nDQa12C8+g== + dependencies: + "@babel/helper-plugin-utils" "^7.27.1" + "@babel/helper-validator-option" "^7.27.1" + "@babel/plugin-syntax-jsx" "^7.27.1" + "@babel/plugin-transform-modules-commonjs" "^7.27.1" + "@babel/plugin-transform-typescript" "^7.28.5" + "@babel/template@^7.20.7", "@babel/template@^7.3.3": version "7.20.7" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.20.7.tgz#a15090c2839a83b02aa996c0b4994005841fd5a8" @@ -269,6 +511,15 @@ "@babel/parser" "^7.20.7" "@babel/types" "^7.20.7" +"@babel/template@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.29.7.tgz#4d9d4004f645cdd304de958c725162784ecac700" + integrity sha512-puq+Gf35oI24FeN11LkoUQFqv9uwNeWpxXZi/Ji3rRIoKAzKnxRaZ+Gkj0vKS9ZCiTESfng1N9LyOyXvo+m+Gg== + dependencies: + "@babel/code-frame" "^7.29.7" + "@babel/parser" "^7.29.7" + "@babel/types" "^7.29.7" + "@babel/traverse@^7.21.0", "@babel/traverse@^7.21.2", "@babel/traverse@^7.21.4", "@babel/traverse@^7.7.2": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.21.4.tgz#a836aca7b116634e97a6ed99976236b3282c9d36" @@ -285,6 +536,19 @@ debug "^4.1.0" globals "^11.1.0" +"@babel/traverse@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.29.7.tgz#c47b07a41b95da0907d026b5dd894d98de7d2f2d" + integrity sha512-EhlfNQtZ+NK22w5BM61ciuiq1m58ed33Wr1Xan//ZRTy6hgjnwyCffRYwzsGXdASJSUJ1guZILsErh1eQcl+zw== + dependencies: + "@babel/code-frame" "^7.29.7" + "@babel/generator" "^7.29.7" + "@babel/helper-globals" "^7.29.7" + "@babel/parser" "^7.29.7" + "@babel/template" "^7.29.7" + "@babel/types" "^7.29.7" + debug "^4.3.1" + "@babel/types@^7.0.0", "@babel/types@^7.18.6", "@babel/types@^7.20.2", "@babel/types@^7.20.7", "@babel/types@^7.21.0", "@babel/types@^7.21.2", "@babel/types@^7.21.4", "@babel/types@^7.3.0", "@babel/types@^7.3.3": version "7.21.4" resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.21.4.tgz#2d5d6bb7908699b3b416409ffd3b5daa25b030d4" @@ -294,11 +558,158 @@ "@babel/helper-validator-identifier" "^7.19.1" to-fast-properties "^2.0.0" +"@babel/types@^7.29.7": + version "7.29.7" + resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.29.7.tgz#8005e31d82712ee7adaef6e23c63b71a62770a92" + integrity sha512-4zBIxpPzowiZpusoFkyGVwakdRJUyuH5PxQ/PrqghfdFWWasvnCdPfQXHrenDai+gyLARulZjZowCOj6fjT4pA== + dependencies: + "@babel/helper-string-parser" "^7.29.7" + "@babel/helper-validator-identifier" "^7.29.7" + "@bcoe/v8-coverage@^0.2.3": version "0.2.3" resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== +"@inquirer/ansi@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@inquirer/ansi/-/ansi-2.0.7.tgz#86de22810cac3ed406ec10f8d66016815b8226b4" + integrity sha512-3eTuUO1vH2cZm2ZKHeQxnOqlTi9EfZDGgIe3BL3I4u+rJHocr9Fz86M4fjYABPvFnQG/gGK551HqDiIcETwU6Q== + +"@inquirer/checkbox@^5.2.1": + version "5.2.1" + resolved "https://registry.yarnpkg.com/@inquirer/checkbox/-/checkbox-5.2.1.tgz#7f148b3153a776cee202015b10f9a985068d188d" + integrity sha512-b6xmA/VlTe0ZgDQHDui+Nav470u7u49nRd8/iuhOcQPO9Ch7lGuogydhi2VOmNlZ+zXcM8IcPuNSwQcdJaF/kw== + dependencies: + "@inquirer/ansi" "^2.0.7" + "@inquirer/core" "^11.2.1" + "@inquirer/figures" "^2.0.7" + "@inquirer/type" "^4.0.7" + +"@inquirer/confirm@^6.1.1": + version "6.1.1" + resolved "https://registry.yarnpkg.com/@inquirer/confirm/-/confirm-6.1.1.tgz#9c6a7d79c6132b2af57fdb75747f056204e55356" + integrity sha512-eb8DBZcz/2qHWQda4rk2JiQk5h9QV/cVHi1yjt0f69WFZMRFn0sJTye3EAP8icut8UDMjQPsaH5KbcOogefrFQ== + dependencies: + "@inquirer/core" "^11.2.1" + "@inquirer/type" "^4.0.7" + +"@inquirer/core@^11.2.1": + version "11.2.1" + resolved "https://registry.yarnpkg.com/@inquirer/core/-/core-11.2.1.tgz#54ccd8f7d47852140b6066cbd77d63b2c2b168fd" + integrity sha512-Qd6GJT1yVyrZZCfN8W2qKF5ApmqryXRhRKCuip8h01x2w/esJQ2XIYc6f9abMIHgKQdBfFTSOdbHRLAhuM09UA== + dependencies: + "@inquirer/ansi" "^2.0.7" + "@inquirer/figures" "^2.0.7" + "@inquirer/type" "^4.0.7" + cli-width "^4.1.0" + fast-wrap-ansi "^0.2.0" + mute-stream "^3.0.0" + signal-exit "^4.1.0" + +"@inquirer/editor@^5.2.2": + version "5.2.2" + resolved "https://registry.yarnpkg.com/@inquirer/editor/-/editor-5.2.2.tgz#7c73e2fc0e7bd4c40cfd38a180ae5bbd24d32b90" + integrity sha512-ZRVd/oD+sYsUd5zVm0NflqEzlqfYCyHNsqkHl2oWXEUHs12tCbcSFi+wVFEvD8+LGRaMUsVrE7qeo6lSG/S1Vg== + dependencies: + "@inquirer/core" "^11.2.1" + "@inquirer/external-editor" "^3.0.3" + "@inquirer/type" "^4.0.7" + +"@inquirer/expand@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@inquirer/expand/-/expand-5.1.1.tgz#e2afeac247d97dd64ee18aa81e902bdd1fe0ea70" + integrity sha512-YmQpenjbFSHAK3sOd44puHh3V1KXXr+JiNpUztoSQ4drLh2rTVzTap/YtlAVu/5xavifIlBfNEzJ/neZJ1a/1g== + dependencies: + "@inquirer/core" "^11.2.1" + "@inquirer/type" "^4.0.7" + +"@inquirer/external-editor@^3.0.3": + version "3.0.3" + resolved "https://registry.yarnpkg.com/@inquirer/external-editor/-/external-editor-3.0.3.tgz#d79e772542cf8d340642e9dabd3a1ea7f5a30104" + integrity sha512-6thf5I8q7lZwzGLAxPaaGEREEkZ3nyePPDQ1oyobblxmEE8mqTLguScP7pDjUTAibiyb4hfXl+qjUEJ+di/aNA== + dependencies: + chardet "^2.1.1" + iconv-lite "^0.7.2" + +"@inquirer/figures@^2.0.7": + version "2.0.7" + resolved "https://registry.yarnpkg.com/@inquirer/figures/-/figures-2.0.7.tgz#f5cc5843732a81304d06a0db4b53cc7dbda15541" + integrity sha512-aJ8TBPOGB6f/2qziPfElISTCEd5XOYTFckA2SGjhNmiKzfK/u4ot3v0DUzGVdUnKjN10EqnnEPck36BkyfLnJw== + +"@inquirer/input@^5.1.2": + version "5.1.2" + resolved "https://registry.yarnpkg.com/@inquirer/input/-/input-5.1.2.tgz#9305cb170dfc3a5323e5eac885a945e7cddd5c4b" + integrity sha512-9K/DDBSQpOyZSkt6sOVP9Vo0TR7atX2kuILsUu0x3wVcVbe97lJwIJKMLdMw25tDYuXl/qp6erT0Xs1rfmcfZg== + dependencies: + "@inquirer/core" "^11.2.1" + "@inquirer/type" "^4.0.7" + +"@inquirer/number@^4.1.1": + version "4.1.1" + resolved "https://registry.yarnpkg.com/@inquirer/number/-/number-4.1.1.tgz#b133668d8e0e099b4133abb915221501e0ff75d7" + integrity sha512-XF4IXAbPnGPgw0wsbC/i2tPcyfdZgDpUlhsqU0SfT4IRIGWha6Xm9VRgN5yYxJq+jnyXlfXI/nQ3ulfk0iEICA== + dependencies: + "@inquirer/core" "^11.2.1" + "@inquirer/type" "^4.0.7" + +"@inquirer/password@^5.1.1": + version "5.1.1" + resolved "https://registry.yarnpkg.com/@inquirer/password/-/password-5.1.1.tgz#f21efb614da9c905095262f51781fd2a721fceac" + integrity sha512-3XBfF7DAsp5qeDsvN5Rd1HmbNokVvEQoUM0QLrRcybC9nX96w3Pbmu7qUsb3IT3J3jBvs2+mTXaKHOUsgHMLzg== + dependencies: + "@inquirer/ansi" "^2.0.7" + "@inquirer/core" "^11.2.1" + "@inquirer/type" "^4.0.7" + +"@inquirer/prompts@^8.0.0": + version "8.5.2" + resolved "https://registry.yarnpkg.com/@inquirer/prompts/-/prompts-8.5.2.tgz#09c0132ada2bbba94c91d341115e1e41cb3f1525" + integrity sha512-IYR/3C/paEVVQYQvdDlFZVjRCJVYHHON0XXMH91KO9GSxs0TdKYWlUdvfQl2EfAHDxUaN3IBffkE/BDTh5nJ6g== + dependencies: + "@inquirer/checkbox" "^5.2.1" + "@inquirer/confirm" "^6.1.1" + "@inquirer/editor" "^5.2.2" + "@inquirer/expand" "^5.1.1" + "@inquirer/input" "^5.1.2" + "@inquirer/number" "^4.1.1" + "@inquirer/password" "^5.1.1" + "@inquirer/rawlist" "^5.3.1" + "@inquirer/search" "^4.2.1" + "@inquirer/select" "^5.2.1" + +"@inquirer/rawlist@^5.3.1": + version "5.3.1" + resolved "https://registry.yarnpkg.com/@inquirer/rawlist/-/rawlist-5.3.1.tgz#66f6b8e6aa82d47399c433b8262128e7c1a4f9ce" + integrity sha512-QqdTqQddL3qPX/PPrjobpsO25NZ4dWXgTLenrR445L2ptLEYE6Z+PD5c5CNDJNx4ugRgELAIpSIJxZaO2jJ2Og== + dependencies: + "@inquirer/core" "^11.2.1" + "@inquirer/type" "^4.0.7" + +"@inquirer/search@^4.2.1": + version "4.2.1" + resolved "https://registry.yarnpkg.com/@inquirer/search/-/search-4.2.1.tgz#c8f4b78ab3f866fdf0503fac0cd08c4a6661c11e" + integrity sha512-xJj8QWKRSrfKoBIITLZK61dD3zwo0Rz11fgDImku30/Oe81zMdIdGgrLY2h6RkJ+KZ/GhNYIRMKnH/62qBTA5g== + dependencies: + "@inquirer/core" "^11.2.1" + "@inquirer/figures" "^2.0.7" + "@inquirer/type" "^4.0.7" + +"@inquirer/select@^5.2.1": + version "5.2.1" + resolved "https://registry.yarnpkg.com/@inquirer/select/-/select-5.2.1.tgz#3a05e76e58d9e1bb095e912c3e7093aa04cd4604" + integrity sha512-FlDndEUww8m7BfukO2nJa25vhD+H5jxxCv4oGioKqzyWz3nPHhhw4LKdYRSlXuAx7DsdWia7iyaBPKKS95Evfw== + dependencies: + "@inquirer/ansi" "^2.0.7" + "@inquirer/core" "^11.2.1" + "@inquirer/figures" "^2.0.7" + "@inquirer/type" "^4.0.7" + +"@inquirer/type@^4.0.7": + version "4.0.7" + resolved "https://registry.yarnpkg.com/@inquirer/type/-/type-4.0.7.tgz#9c6f0d857fe6ad549a3a932343b64e76acb34b10" + integrity sha512-t28inv14nMQ1PhKpsJPY+kEs/c00qzeCOS2gTNRyTjG5d6qsVA2fItxW4hkvGZ5lvanGLdtCzVIx5dwdRpN1+g== + "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" @@ -516,11 +927,32 @@ "@jridgewell/sourcemap-codec" "^1.4.10" "@jridgewell/trace-mapping" "^0.3.9" +"@jridgewell/gen-mapping@^0.3.12", "@jridgewell/gen-mapping@^0.3.5": + version "0.3.13" + resolved "https://registry.yarnpkg.com/@jridgewell/gen-mapping/-/gen-mapping-0.3.13.tgz#6342a19f44347518c93e43b1ac69deb3c4656a1f" + integrity sha512-2kkt/7niJ6MgEPxF0bYdQ6etZaA+fQvDcLKckhy1yIQOzaoKjBBjSj63/aLVjYE3qhRt5dvM+uUyfCg6UKCBbA== + dependencies: + "@jridgewell/sourcemap-codec" "^1.5.0" + "@jridgewell/trace-mapping" "^0.3.24" + +"@jridgewell/remapping@^2.3.5": + version "2.3.5" + resolved "https://registry.yarnpkg.com/@jridgewell/remapping/-/remapping-2.3.5.tgz#375c476d1972947851ba1e15ae8f123047445aa1" + integrity sha512-LI9u/+laYG4Ds1TDKSJW2YPrIlcVYOwi2fUC6xB43lueCjgxV4lffOCZCtYFiH6TNOX+tQKXx97T4IKHbhyHEQ== + dependencies: + "@jridgewell/gen-mapping" "^0.3.5" + "@jridgewell/trace-mapping" "^0.3.24" + "@jridgewell/resolve-uri@3.1.0": version "3.1.0" resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz#2203b118c157721addfe69d47b70465463066d78" integrity sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w== +"@jridgewell/resolve-uri@^3.1.0": + version "3.1.2" + resolved "https://registry.yarnpkg.com/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz#7a0ee601f60f99a20c7c7c5ff0c80388c1189bd6" + integrity sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw== + "@jridgewell/set-array@^1.0.1": version "1.1.2" resolved "https://registry.yarnpkg.com/@jridgewell/set-array/-/set-array-1.1.2.tgz#7c6cf998d6d20b914c0a55a91ae928ff25965e72" @@ -536,6 +968,11 @@ resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz#d7c6e6755c78567a951e04ab52ef0fd26de59f32" integrity sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg== +"@jridgewell/sourcemap-codec@^1.4.14", "@jridgewell/sourcemap-codec@^1.5.0": + version "1.5.5" + resolved "https://registry.yarnpkg.com/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.5.tgz#6912b00d2c631c0d15ce1a7ab57cd657f2a8f8ba" + integrity sha512-cYQ9310grqxueWbl+WuIUIaiUaDcj7WOq5fVhEljNVgRfOUhY9fy2zTvfoqWsnebh8Sl70VScFbICvJnLKB0Og== + "@jridgewell/trace-mapping@^0.3.12", "@jridgewell/trace-mapping@^0.3.15", "@jridgewell/trace-mapping@^0.3.17", "@jridgewell/trace-mapping@^0.3.9": version "0.3.18" resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz#25783b2086daf6ff1dcb53c9249ae480e4dd4cd6" @@ -544,11 +981,29 @@ "@jridgewell/resolve-uri" "3.1.0" "@jridgewell/sourcemap-codec" "1.4.14" +"@jridgewell/trace-mapping@^0.3.24", "@jridgewell/trace-mapping@^0.3.28": + version "0.3.31" + resolved "https://registry.yarnpkg.com/@jridgewell/trace-mapping/-/trace-mapping-0.3.31.tgz#db15d6781c931f3a251a3dac39501c98a6082fd0" + integrity sha512-zzNR+SdQSDJzc8joaeP8QQoCQr8NuYx2dIIytl1QeBEZHJ9uW6hebsrYgbz8hJwUQao3TWCMtmfV8Nu1twOLAw== + dependencies: + "@jridgewell/resolve-uri" "^3.1.0" + "@jridgewell/sourcemap-codec" "^1.4.14" + +"@sec-ant/readable-stream@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz#60de891bb126abfdc5410fdc6166aca065f10a0c" + integrity sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg== + "@sinclair/typebox@^0.25.16": version "0.25.24" resolved "https://registry.yarnpkg.com/@sinclair/typebox/-/typebox-0.25.24.tgz#8c7688559979f7079aacaf31aa881c3aa410b718" integrity sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ== +"@sindresorhus/merge-streams@^4.0.0": + version "4.0.0" + resolved "https://registry.yarnpkg.com/@sindresorhus/merge-streams/-/merge-streams-4.0.0.tgz#abb11d99aeb6d27f1b563c38147a72d50058e339" + integrity sha512-tlqY9xq5ukxTUZBmoOp+m61cqwQD5pHJtFY3Mn8CA8ps6yghLH/Hw8UPdqg4OLmFW3IFlcXnQNmo/dh8HzXYIQ== + "@sinonjs/commons@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-2.0.0.tgz#fd4ca5b063554307e8327b4564bd56d3b73924a3" @@ -563,6 +1018,81 @@ dependencies: "@sinonjs/commons" "^2.0.0" +"@stryker-mutator/api@9.6.1": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@stryker-mutator/api/-/api-9.6.1.tgz#df8072cb268a6fd8dec2994cc64b477978fa3d69" + integrity sha512-g8VNoFWQWbx0pdal3Vt8jVCZW+v3sc3gi94iI0GVtVgUGTqphAjJF6EAruPTx0lqvtonsaAxn5TD36hcG1d6Wg== + dependencies: + mutation-testing-metrics "3.7.3" + mutation-testing-report-schema "3.7.3" + tslib "~2.8.0" + typed-inject "~5.0.0" + +"@stryker-mutator/core@^9.6.1": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@stryker-mutator/core/-/core-9.6.1.tgz#c149d80754b9fc73c11f6282ec199af24be535f4" + integrity sha512-WMgnvf+Wyh/yiruhNZwc8w8DlzmmjXhPjSn5MR8RhAXzlnWji8TQrUYgBUkHk9bEgSaIlB3KZHm37iiU5Q2cLQ== + dependencies: + "@inquirer/prompts" "^8.0.0" + "@stryker-mutator/api" "9.6.1" + "@stryker-mutator/instrumenter" "9.6.1" + "@stryker-mutator/util" "9.6.1" + ajv "~8.18.0" + chalk "~5.6.0" + commander "~14.0.0" + diff-match-patch "1.0.5" + emoji-regex "~10.6.0" + execa "~9.6.0" + json-rpc-2.0 "^1.7.0" + lodash.groupby "~4.6.0" + minimatch "~10.2.4" + mutation-server-protocol "~0.4.0" + mutation-testing-elements "3.7.3" + mutation-testing-metrics "3.7.3" + mutation-testing-report-schema "3.7.3" + npm-run-path "~6.0.0" + progress "~2.0.3" + rxjs "~7.8.1" + semver "^7.6.3" + source-map "~0.7.4" + tree-kill "~1.2.2" + tslib "2.8.1" + typed-inject "~5.0.0" + typed-rest-client "~2.3.0" + +"@stryker-mutator/instrumenter@9.6.1": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@stryker-mutator/instrumenter/-/instrumenter-9.6.1.tgz#97e0e03da440712fac29a52c82f5cc0945183480" + integrity sha512-5K8wH4Pthly25c2uKKik4Dfcoeou7sbJdFS6u3QIYHlulgFVDJwtEMWTZGkZfs7IiUEXIDNa0keRACq5jn5AvA== + dependencies: + "@babel/core" "~7.29.0" + "@babel/generator" "~7.29.0" + "@babel/parser" "~7.29.0" + "@babel/plugin-proposal-decorators" "~7.29.0" + "@babel/plugin-transform-explicit-resource-management" "^7.28.0" + "@babel/preset-typescript" "~7.28.0" + "@stryker-mutator/api" "9.6.1" + "@stryker-mutator/util" "9.6.1" + angular-html-parser "~10.4.0" + semver "~7.7.0" + tslib "2.8.1" + weapon-regex "~1.3.2" + +"@stryker-mutator/jest-runner@^9.6.1": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@stryker-mutator/jest-runner/-/jest-runner-9.6.1.tgz#e30ef75112b2d09f168ab74ce4b0310a6d2d0f41" + integrity sha512-nIrIndfWwdweYkIcxJmyBTpl84nrXs9AE6A8vzEwwzUGvDb9kVvwBPfpEajtdAkjwPceH0pPuVrPkotvqcgYqQ== + dependencies: + "@stryker-mutator/api" "9.6.1" + "@stryker-mutator/util" "9.6.1" + semver "~7.7.0" + tslib "~2.8.0" + +"@stryker-mutator/util@9.6.1": + version "9.6.1" + resolved "https://registry.yarnpkg.com/@stryker-mutator/util/-/util-9.6.1.tgz#f4ce5cb3a5379002c56b742b70dfdc96d392acc0" + integrity sha512-Lk/ALVctJjFv1vvwR+CFoKzDCWvsBlq7flDUnmnpuwTrGbm156EdZD1Jjq4o8KdOap0ezUZqQNE9OAI1m2+pUQ== + "@types/babel__core@^7.1.14": version "7.20.0" resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.20.0.tgz#61bc5a4cae505ce98e1e36c5445e4bee060d8891" @@ -763,6 +1293,21 @@ accepts@~1.3.8: mime-types "~2.1.34" negotiator "0.6.3" +ajv@~8.18.0: + version "8.18.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.18.0.tgz#8864186b6738d003eb3a933172bb3833e10cefbc" + integrity sha512-PlXPeEWMXMZ7sPYOHqmDyCJzcfNrUr3fGNKtezX14ykXOEIvyK81d+qydx89KY5O71FKMPaQ2vBfBFI5NHR63A== + dependencies: + fast-deep-equal "^3.1.3" + fast-uri "^3.0.1" + json-schema-traverse "^1.0.0" + require-from-string "^2.0.2" + +angular-html-parser@~10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/angular-html-parser/-/angular-html-parser-10.4.0.tgz#1f22bc19b466a4411b5dcaa6c0e508fe553e2306" + integrity sha512-++nLNyZwRfHqFh7akH5Gw/JYizoFlMRz0KRigfwfsLqV8ZqlcVRb1LkPEWdYvEKDnbktknM2J4BXaYUGrQZPww== + ansi-escapes@^4.2.1: version "4.3.2" resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.2.tgz#6b2291d1db7d98b6521d5f1efa42d0f3a9feb65e" @@ -889,6 +1434,16 @@ balanced-match@^1.0.0: resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee" integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw== +balanced-match@^4.0.2: + version "4.0.4" + resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a" + integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA== + +baseline-browser-mapping@^2.10.38: + version "2.10.38" + resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.38.tgz#c84d093c4bf7325c5053c279d90f153c66526042" + integrity sha512-31/02mVB4yuQU6adKk5SlY6m+mxDwUq5KZkyYgnLrrKl7TEm1+3PyDtDBz2kOv/wxZz41GHsvV1A/u6RmiyBvw== + body-parser@1.20.1: version "1.20.1" resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.1.tgz#b1812a8912c195cd371a3ee5e66faa2338a5c668" @@ -915,6 +1470,13 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" +brace-expansion@^5.0.5: + version "5.0.6" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-5.0.6.tgz#ec68fe0a641a29d8711579caf641d05bae1f2285" + integrity sha512-kLpxurY4Z4r9sgMsyG0Z9uzsBlgiU/EFKhj/h91/8yHu0edo7XuixOIH3VcJ8kkxs6/jPzoI6U9Vj3WqbMQ94g== + dependencies: + balanced-match "^4.0.2" + braces@^3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" @@ -932,6 +1494,17 @@ browserslist@^4.21.3: node-releases "^2.0.8" update-browserslist-db "^1.0.10" +browserslist@^4.24.0: + version "4.28.4" + resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.4.tgz#dd8b8167a32845ff5f8cd6ce13f5abba16cd04c9" + integrity sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw== + dependencies: + baseline-browser-mapping "^2.10.38" + caniuse-lite "^1.0.30001799" + electron-to-chromium "^1.5.376" + node-releases "^2.0.48" + update-browserslist-db "^1.2.3" + bs-logger@0.x: version "0.2.6" resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" @@ -956,6 +1529,14 @@ bytes@3.1.2: resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.2.tgz#8b0beeb98605adf1b128fa4386403c009e0221a5" integrity sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg== +call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz#4b5428c222be985d79c3d82657479dbe0b59b2d6" + integrity sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ== + dependencies: + es-errors "^1.3.0" + function-bind "^1.1.2" + call-bind@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.2.tgz#b1d4e89e688119c3c9a903ad30abb2f6a919be3c" @@ -964,6 +1545,14 @@ call-bind@^1.0.0: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-bound@^1.0.2: + version "1.0.4" + resolved "https://registry.yarnpkg.com/call-bound/-/call-bound-1.0.4.tgz#238de935d2a2a692928c538c7ccfa91067fd062a" + integrity sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg== + dependencies: + call-bind-apply-helpers "^1.0.2" + get-intrinsic "^1.3.0" + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -984,6 +1573,11 @@ caniuse-lite@^1.0.30001449: resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001481.tgz#f58a717afe92f9e69d0e35ff64df596bfad93912" integrity sha512-KCqHwRnaa1InZBtqXzP98LPg0ajCVujMKjqKDhZEthIpAsJl/YEIa3YvXjGXPVqzZVguccuu7ga9KOE1J9rKPQ== +caniuse-lite@^1.0.30001799: + version "1.0.30001799" + resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001799.tgz#5c909138c27f1a61219d3e092071c1cc7d32dc55" + integrity sha512-hG1bReV+OUU+MOqK4t/ZWI0tZOyz3rqS9XuhOUz1cIcbwBKjOyJEJuw9ER5JuNyqxNk8u/JUVbGibBOL1yrjFw== + chalk@^2.0.0: version "2.4.2" resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" @@ -1001,11 +1595,21 @@ chalk@^4.0.0: ansi-styles "^4.1.0" supports-color "^7.1.0" +chalk@~5.6.0: + version "5.6.2" + resolved "https://registry.yarnpkg.com/chalk/-/chalk-5.6.2.tgz#b1238b6e23ea337af71c7f8a295db5af0c158aea" + integrity sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA== + char-regex@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== +chardet@^2.1.1: + version "2.2.0" + resolved "https://registry.yarnpkg.com/chardet/-/chardet-2.2.0.tgz#005d664f2cbd4961888d2e2c32c5a69e59d8eec4" + integrity sha512-rddelWYNPRrXq6PtNEN2S3f6t9ILzvqaN5pVgi4kqt9jHQaXIial9PznB5iSPVlQSLNaaH22ItWz3EJtQ10+OA== + ci-info@^3.2.0: version "3.8.0" resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-3.8.0.tgz#81408265a5380c929f0bc665d62256628ce9ef91" @@ -1016,6 +1620,11 @@ cjs-module-lexer@^1.0.0: resolved "https://registry.yarnpkg.com/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz#9f84ba3244a512f3a54e5277e8eef4c489864e40" integrity sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA== +cli-width@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-4.1.0.tgz#42daac41d3c254ef38ad8ac037672130173691c5" + integrity sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ== + cliui@^8.0.1: version "8.0.1" resolved "https://registry.yarnpkg.com/cliui/-/cliui-8.0.1.tgz#0c04b075db02cbfe60dc8e6cf2f5486b1a3608aa" @@ -1066,6 +1675,11 @@ combined-stream@^1.0.8: dependencies: delayed-stream "~1.0.0" +commander@~14.0.0: + version "14.0.3" + resolved "https://registry.yarnpkg.com/commander/-/commander-14.0.3.tgz#425d79b48f9af82fcd9e4fc1ea8af6c5ec07bbc2" + integrity sha512-H+y0Jo/T1RZ9qPP4Eh1pkcQcLRglraJaSLoyOtHxu6AapkjWVCy2Sit1QQ4x3Dng8qDlSsZEet7g5Pq06MvTgw== + component-emitter@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" @@ -1130,6 +1744,15 @@ cross-spawn@^7.0.3: shebang-command "^2.0.0" which "^2.0.1" +cross-spawn@^7.0.6: + version "7.0.6" + resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.6.tgz#8a58fe78f00dcd70c370451759dfbfaf03e8ee9f" + integrity sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA== + dependencies: + path-key "^3.1.0" + shebang-command "^2.0.0" + which "^2.0.1" + debug@2.6.9: version "2.6.9" resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" @@ -1144,6 +1767,13 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.4: dependencies: ms "2.1.2" +debug@^4.3.1: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + dedent@^0.7.0: version "0.7.0" resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" @@ -1164,6 +1794,14 @@ depd@2.0.0: resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df" integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw== +des.js@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.1.0.tgz#1d37f5766f3bbff4ee9638e871a8768c173b81da" + integrity sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg== + dependencies: + inherits "^2.0.1" + minimalistic-assert "^1.0.0" + destroy@1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015" @@ -1182,6 +1820,11 @@ dezalgo@^1.0.4: asap "^2.0.0" wrappy "1" +diff-match-patch@1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/diff-match-patch/-/diff-match-patch-1.0.5.tgz#abb584d5f10cd1196dfc55aa03701592ae3f7b37" + integrity sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw== + diff-sequences@^29.4.3: version "29.4.3" resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-29.4.3.tgz#9314bc1fabe09267ffeca9cbafc457d8499a13f2" @@ -1192,6 +1835,15 @@ dotenv@^16.0.3: resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== +dunder-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/dunder-proto/-/dunder-proto-1.0.1.tgz#d7ae667e1dc83482f8b70fd0f6eefc50da30f58a" + integrity sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A== + dependencies: + call-bind-apply-helpers "^1.0.1" + es-errors "^1.3.0" + gopd "^1.2.0" + ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -1202,6 +1854,11 @@ electron-to-chromium@^1.4.284: resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.371.tgz#393983ef087268a20c926a89be30e9f0bfc803b0" integrity sha512-jlBzY4tFcJaiUjzhRTCWAqRvTO/fWzjA3Bls0mykzGZ7zvcMP7h05W6UcgzfT9Ca1SW2xyKDOFRyI0pQeRNZGw== +electron-to-chromium@^1.5.376: + version "1.5.376" + resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.376.tgz#16a9d4b72cb16c416aa73a879d92b047b96797ac" + integrity sha512-cUVA7/RvbFTEuw/i3obUwDTRIXojaxkResf+ibByPFxjc6XK3VNtcQXV0NSbAlJ0FMjcJGgftVVB4Qo184EXvA== + emittery@^0.13.1: version "0.13.1" resolved "https://registry.yarnpkg.com/emittery/-/emittery-0.13.1.tgz#c04b8c3457490e0847ae51fced3af52d338e3dad" @@ -1212,6 +1869,11 @@ emoji-regex@^8.0.0: resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== +emoji-regex@~10.6.0: + version "10.6.0" + resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-10.6.0.tgz#bf3d6e8f7f8fd22a65d9703475bc0147357a6b0d" + integrity sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A== + encodeurl@~1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" @@ -1224,11 +1886,33 @@ error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +es-define-property@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.1.tgz#983eb2f9a6724e9303f61addf011c72e09e0b0fa" + integrity sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g== + +es-errors@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f" + integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw== + +es-object-atoms@^1.0.0, es-object-atoms@^1.1.1: + version "1.1.2" + resolved "https://registry.yarnpkg.com/es-object-atoms/-/es-object-atoms-1.1.2.tgz#a2d0b373205724dfa525d23b0c3e1b1ca582c99b" + integrity sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw== + dependencies: + es-errors "^1.3.0" + escalade@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== +escalade@^3.2.0: + version "3.2.0" + resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.2.0.tgz#011a3f69856ba189dffa7dc8fcce99d2a87903e5" + integrity sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA== + escape-html@~1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" @@ -1269,6 +1953,24 @@ execa@^5.0.0: signal-exit "^3.0.3" strip-final-newline "^2.0.0" +execa@~9.6.0: + version "9.6.1" + resolved "https://registry.yarnpkg.com/execa/-/execa-9.6.1.tgz#5b90acedc6bdc0fa9b9a6ddf8f9cbb0c75a7c471" + integrity sha512-9Be3ZoN4LmYR90tUoVu2te2BsbzHfhJyfEiAVfz7N5/zv+jduIfLrV2xdQXOHbaD6KgpGdO9PRPM1Y4Q9QkPkA== + 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" + exit@^0.1.2: version "0.1.2" resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" @@ -1322,6 +2024,11 @@ express@^4.18.2: utils-merge "1.0.1" vary "~1.1.2" +fast-deep-equal@^3.1.3: + version "3.1.3" + resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== + fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" @@ -1332,6 +2039,30 @@ fast-safe-stringify@^2.1.1: resolved "https://registry.yarnpkg.com/fast-safe-stringify/-/fast-safe-stringify-2.1.1.tgz#c406a83b6e70d9e35ce3b30a81141df30aeba884" integrity sha512-W+KJc2dmILlPplD/H4K9l9LcAHAfPtP6BY84uVLXQ6Evcz9Lcg33Y2z1IVblT6xdY54PXYVHEv+0Wpq8Io6zkA== +fast-string-truncated-width@^3.0.2: + version "3.0.3" + resolved "https://registry.yarnpkg.com/fast-string-truncated-width/-/fast-string-truncated-width-3.0.3.tgz#23afe0da67d752ca0727538f1e6967759728ce49" + integrity sha512-0jjjIEL6+0jag3l2XWWizO64/aZVtpiGE3t0Zgqxv0DPuxiMjvB3M24fCyhZUO4KomJQPj3LTSUnDP3GpdwC0g== + +fast-string-width@^3.0.2: + version "3.0.2" + resolved "https://registry.yarnpkg.com/fast-string-width/-/fast-string-width-3.0.2.tgz#16dbabb491ce5585b5ecb675b65c165d71688eeb" + integrity sha512-gX8LrtNEI5hq8DVUfRQMbr5lpaS4nMIWV+7XEbXk2b8kiQIizgnlr12B4dA3ZEx3308ze0O4Q1R+cHts8kyUJg== + dependencies: + fast-string-truncated-width "^3.0.2" + +fast-uri@^3.0.1: + version "3.1.2" + resolved "https://registry.yarnpkg.com/fast-uri/-/fast-uri-3.1.2.tgz#8af3d4fc9d3e71b11572cc2673b514a7d1a8c8ec" + integrity sha512-rVjf7ArG3LTk+FS6Yw81V1DLuZl1bRbNrev6Tmd/9RaroeeRRJhAt7jg/6YFxbvAQXUCavSoZhPPj6oOx+5KjQ== + +fast-wrap-ansi@^0.2.0: + version "0.2.2" + resolved "https://registry.yarnpkg.com/fast-wrap-ansi/-/fast-wrap-ansi-0.2.2.tgz#95e952a0145bce3f59ad56e179f84c48d4072935" + integrity sha512-7F2Fl+TjRSenLqlU3UjSH0iyqopqoZIu7eZVpEirP2g1GtWa2G/ecEmBdgz31+Mxr+ELclgg6sokpSFIQiZ02Q== + dependencies: + fast-string-width "^3.0.2" + fb-watchman@^2.0.0: version "2.0.2" resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.2.tgz#e9524ee6b5c77e9e5001af0f85f3adbb8623255c" @@ -1339,6 +2070,13 @@ fb-watchman@^2.0.0: dependencies: bser "2.1.1" +figures@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/figures/-/figures-6.1.0.tgz#935479f51865fa7479f6fa94fc6fc7ac14e62c4a" + integrity sha512-d+l3qxjSesT4V7v2fh+QnmFnUWv9lSpjarhShNTgBOfA0ttejbQUAlHLitbjkoRiDulW0OPoQPYIGhIC8ohejg== + dependencies: + is-unicode-supported "^2.0.0" + fill-range@^7.0.1: version "7.0.1" resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" @@ -1411,6 +2149,11 @@ function-bind@^1.1.1: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== +function-bind@^1.1.2: + version "1.1.2" + resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" + integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== + gensync@^1.0.0-beta.2: version "1.0.0-beta.2" resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0" @@ -1430,16 +2173,48 @@ get-intrinsic@^1.0.2: has "^1.0.3" has-symbols "^1.0.3" +get-intrinsic@^1.2.5, get-intrinsic@^1.3.0: + version "1.3.0" + resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.3.0.tgz#743f0e3b6964a93a5491ed1bffaae054d7f98d01" + integrity sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ== + dependencies: + call-bind-apply-helpers "^1.0.2" + es-define-property "^1.0.1" + es-errors "^1.3.0" + es-object-atoms "^1.1.1" + function-bind "^1.1.2" + get-proto "^1.0.1" + gopd "^1.2.0" + has-symbols "^1.1.0" + hasown "^2.0.2" + math-intrinsics "^1.1.0" + get-package-type@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== +get-proto@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/get-proto/-/get-proto-1.0.1.tgz#150b3f2743869ef3e851ec0c49d15b1d14d00ee1" + integrity sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g== + dependencies: + dunder-proto "^1.0.1" + es-object-atoms "^1.0.0" + get-stream@^6.0.0: version "6.0.1" resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== +get-stream@^9.0.0: + version "9.0.1" + resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-9.0.1.tgz#95157d21df8eb90d1647102b63039b1df60ebd27" + integrity sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA== + dependencies: + "@sec-ant/readable-stream" "^0.4.1" + is-stream "^4.0.1" + glob@^7.1.3, glob@^7.1.4: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" @@ -1457,6 +2232,11 @@ globals@^11.1.0: resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== +gopd@^1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.2.0.tgz#89f56b8217bdbc8802bd299df6d7f1081d7e51a1" + integrity sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg== + graceful-fs@^4.2.9: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" @@ -1477,6 +2257,11 @@ has-symbols@^1.0.3: resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8" integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A== +has-symbols@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.1.0.tgz#fc9c6a783a084951d0b971fe1018de813707a338" + integrity sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ== + has@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" @@ -1484,6 +2269,13 @@ has@^1.0.3: dependencies: function-bind "^1.1.1" +hasown@^2.0.2: + version "2.0.4" + resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.4.tgz#8c62d8cb90beb2aad5d0a5b67581ad9854c3f003" + integrity sha512-T2UbfbBEF32wiepXIsMlTW9+dDYC6wMh/t/vYA4tuOMKqWz/n3vr1NFSxQiyP+zk2mXsoMA/i/7qV6LKut1t1A== + dependencies: + function-bind "^1.1.2" + hexoid@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/hexoid/-/hexoid-1.0.0.tgz#ad10c6573fb907de23d9ec63a711267d9dc9bc18" @@ -1510,6 +2302,11 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +human-signals@^8.0.1: + version "8.0.1" + resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-8.0.1.tgz#f08bb593b6d1db353933d06156cedec90abe51fb" + integrity sha512-eKCa6bwnJhvxj14kZk5NCPc6Hb6BdsU9DZcOnmQKSnO1VKrfV0zCvtttPZUsBvjmNDn8rpcJfpwSYnHBjc95MQ== + iconv-lite@0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -1517,6 +2314,13 @@ iconv-lite@0.4.24: dependencies: safer-buffer ">= 2.1.2 < 3" +iconv-lite@^0.7.2: + version "0.7.2" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.7.2.tgz#d0bdeac3f12b4835b7359c2ad89c422a4d1cc72e" + integrity sha512-im9DjEDQ55s9fL4EYzOAv0yMqmMBSZp6G0VvFyTMPKWxiSBHUj9NW/qqLmXUwXrrM7AvqSlTCfvqRb0cM8yYqw== + dependencies: + safer-buffer ">= 2.1.2 < 3.0.0" + import-local@^3.0.2: version "3.1.0" resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.1.0.tgz#b4479df8a5fd44f6cdce24070675676063c95cb4" @@ -1538,7 +2342,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4: +inherits@2, inherits@2.0.4, inherits@^2.0.1: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -1575,11 +2379,26 @@ is-number@^7.0.0: resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== +is-plain-obj@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-4.1.0.tgz#d65025edec3657ce032fd7db63c97883eaed71f0" + integrity sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg== + is-stream@^2.0.0: version "2.0.1" resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.1.tgz#fac1e3d53b97ad5a9d0ae9cef2389f5810a5c077" integrity sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg== +is-stream@^4.0.1: + version "4.0.1" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-4.0.1.tgz#375cf891e16d2e4baec250b85926cffc14720d9b" + integrity sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A== + +is-unicode-supported@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-2.1.0.tgz#09f0ab0de6d3744d48d265ebb98f65d11f2a9b3a" + integrity sha512-mE00Gnza5EEB3Ds0HfMyllZzbBrmLOX3vfWoj9A9PEnTfratQ/BcaJOuMhnkhjXvb2+FkY3VuHqtAGpTPmglFQ== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -1988,6 +2807,11 @@ jest@^29.5.0: import-local "^3.0.2" jest-cli "^29.5.0" +js-md4@^0.3.2: + version "0.3.2" + resolved "https://registry.yarnpkg.com/js-md4/-/js-md4-0.3.2.tgz#cd3b3dc045b0c404556c81ddb5756c23e59d7cf5" + integrity sha512-/GDnfQYsltsjRswQhN9fhv3EMw2sCpUdrdxyWDOUK7eyD++r3gRhzgiQgc/x4MAv2i1iuQ4lxO5mvqM3vj4bwA== + js-tokens@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" @@ -2006,11 +2830,26 @@ jsesc@^2.5.1: resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== +jsesc@^3.0.2: + version "3.1.0" + resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-3.1.0.tgz#74d335a234f67ed19907fdadfac7ccf9d409825d" + integrity sha512-/sM3dO2FOzXjKQhJuo0Q173wf2KOo8t4I8vHy6lF9poUp7bKT0/NHE8fPX23PwfhnykfqnC2xRxOnVw5XuGIaA== + json-parse-even-better-errors@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== +json-rpc-2.0@^1.7.0: + version "1.7.1" + resolved "https://registry.yarnpkg.com/json-rpc-2.0/-/json-rpc-2.0-1.7.1.tgz#f4a5095d0a7e51701bffe153ce19087a8b13418e" + integrity sha512-JqZjhjAanbpkXIzFE7u8mE/iFblawwlXtONaCvRqI+pyABVz7B4M1EUNpyVW+dZjqgQ2L5HFmZCmOCgUKm00hg== + +json-schema-traverse@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz#ae7bcb3656ab77a73ba5c49bf654f38e6b6860e2" + integrity sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug== + json5@^2.2.2, json5@^2.2.3: version "2.2.3" resolved "https://registry.yarnpkg.com/json5/-/json5-2.2.3.tgz#78cd6f1a19bdc12b73db5ad0c61efd66c1e29283" @@ -2038,6 +2877,11 @@ locate-path@^5.0.0: dependencies: p-locate "^4.1.0" +lodash.groupby@~4.6.0: + version "4.6.0" + resolved "https://registry.yarnpkg.com/lodash.groupby/-/lodash.groupby-4.6.0.tgz#0b08a1dcf68397c397855c3239783832df7403d1" + integrity sha512-5dcWxm23+VAoz+awKmBaiBvzox8+RqMgFhi7UvX9DHZr2HdxHXM/Wrf8cfKpsW37RNrvtPn6hSwNqurSILbmJw== + lodash.memoize@4.x: version "4.1.2" resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" @@ -2076,6 +2920,11 @@ makeerror@1.0.12: dependencies: tmpl "1.0.5" +math-intrinsics@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/math-intrinsics/-/math-intrinsics-1.1.0.tgz#a0dd74be81e2aa5c2f27e65ce283605ee4e2b7f9" + integrity sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g== + media-typer@0.3.0: version "0.3.0" resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" @@ -2131,6 +2980,11 @@ mimic-fn@^2.1.0: resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== +minimalistic-assert@^1.0.0: + version "1.0.1" + resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== + minimatch@^3.0.4, minimatch@^3.1.1: version "3.1.2" resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.1.2.tgz#19cd194bfd3e428f049a70817c038d89ab4be35b" @@ -2138,6 +2992,13 @@ minimatch@^3.0.4, minimatch@^3.1.1: dependencies: brace-expansion "^1.1.7" +minimatch@~10.2.4: + version "10.2.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-10.2.5.tgz#bd48687a0be38ed2961399105600f832095861d1" + integrity sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg== + dependencies: + brace-expansion "^5.0.5" + ms@2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" @@ -2148,11 +3009,40 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -ms@2.1.3: +ms@2.1.3, ms@^2.1.3: version "2.1.3" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== +mutation-server-protocol@~0.4.0: + version "0.4.1" + resolved "https://registry.yarnpkg.com/mutation-server-protocol/-/mutation-server-protocol-0.4.1.tgz#1109b1cdf615d944429281a5c2461453ecfabdf0" + integrity sha512-SBGK0j8hLDne7bktgThKI8kGvGTx3rY3LAeQTmOKZ5bVnL/7TorLMvcVF7dIPJCu5RNUWhkkuF53kurygYVt3g== + dependencies: + zod "^4.1.12" + +mutation-testing-elements@3.7.3: + version "3.7.3" + resolved "https://registry.yarnpkg.com/mutation-testing-elements/-/mutation-testing-elements-3.7.3.tgz#ae53b36dec076fd1146e2cc473f5a872f924a9a7" + integrity sha512-SMeIPxngJpfjfNYctFpYQQtlBlZaVO0aoB3FKdwrI8Ee/2bkyUuCZzAOCLv1U9fnmfA37dPFq0Owduoxs2XgGQ== + +mutation-testing-metrics@3.7.3: + version "3.7.3" + resolved "https://registry.yarnpkg.com/mutation-testing-metrics/-/mutation-testing-metrics-3.7.3.tgz#6958a1a154fcbfb28a1cdc7764db56cb65a6b68d" + integrity sha512-B8QrP0ZomErzTPNlhrzKWPNBln+3afwBZPHv0Q7N8wZZTYxMptzb/Gdm3ExXVmioVYrtZAtsDs7W/T/b2AixOQ== + dependencies: + mutation-testing-report-schema "3.7.3" + +mutation-testing-report-schema@3.7.3: + version "3.7.3" + resolved "https://registry.yarnpkg.com/mutation-testing-report-schema/-/mutation-testing-report-schema-3.7.3.tgz#f3a42f9084e1eb324494b87c9464df0b6d0f802d" + integrity sha512-BHm3MYq+ckO+t5CtlG8zpqxc75rdJCkxVlE+fGuGJM3F7tNCQ/OW2N+TQVHN3BHsYa84+BFc6g3AwDYkUsw2MA== + +mute-stream@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-3.0.0.tgz#cd8014dd2acb72e1e91bb67c74f0019e620ba2d1" + integrity sha512-dkEJPVvun4FryqBmZ5KhDo0K9iDXAwn08tMLDinNdRBNPcYEDiWYysLcc6k3mjTMlbP9KyylvRpd4wFtwrT9rw== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -2168,6 +3058,11 @@ node-int64@^0.4.0: resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" integrity sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw== +node-releases@^2.0.48: + version "2.0.48" + resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.48.tgz#4da73d040ada751fc9959d993f27de48792e3b7d" + integrity sha512-1uz8041X6LoI6ZSdZacM9lVY28vuzDlSKitnpbSNK0RfKoIJkX29NBPVEFXhnuSuEOA9Ww0xnPJ+ILWbGAv8DA== + node-releases@^2.0.8: version "2.0.10" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.10.tgz#c311ebae3b6a148c89b1813fd7c4d3c024ef537f" @@ -2185,11 +3080,24 @@ npm-run-path@^4.0.1: dependencies: path-key "^3.0.0" +npm-run-path@^6.0.0, npm-run-path@~6.0.0: + version "6.0.0" + resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-6.0.0.tgz#25cfdc4eae04976f3349c0b1afc089052c362537" + integrity sha512-9qny7Z9DsQU8Ou39ERsPU4OZQlSTP47ShQzuKZ6PRXpYLtIFgl/DEBYEXKlvcEa+9tHVcK8CF81Y2V72qaZhWA== + dependencies: + path-key "^4.0.0" + unicorn-magic "^0.3.0" + object-assign@^4: version "4.1.1" resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" integrity sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg== +object-inspect@^1.13.3, object-inspect@^1.13.4: + version "1.13.4" + resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.4.tgz#8375265e21bc20d0fa582c22e1b13485d6e00213" + integrity sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew== + object-inspect@^1.9.0: version "1.12.3" resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.12.3.tgz#ba62dffd67ee256c8c086dfae69e016cd1f198b9" @@ -2252,6 +3160,11 @@ parse-json@^5.2.0: json-parse-even-better-errors "^2.3.0" lines-and-columns "^1.1.6" +parse-ms@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/parse-ms/-/parse-ms-4.0.0.tgz#c0c058edd47c2a590151a718990533fd62803df4" + integrity sha512-TXfryirbmq34y8QBwgqCVLi+8oA3oWx2eAnSn62ITyEhEYaWRlVZ2DvMM9eZbMs/RfxPu/PK/aBLyGj4IrqMHw== + parseurl@~1.3.3: version "1.3.3" resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" @@ -2272,6 +3185,11 @@ path-key@^3.0.0, path-key@^3.1.0: resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== +path-key@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/path-key/-/path-key-4.0.0.tgz#295588dc3aee64154f877adb9d780b81c554bf18" + integrity sha512-haREypq7xkM7ErfgIyA0z+Bj4AGKlMSdlQE2jvJo6huWD1EdkKYV+G/T4nq0YEF2vgTT8kqMFKo1uHn950r4SQ== + path-parse@^1.0.7: version "1.0.7" resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" @@ -2287,6 +3205,11 @@ picocolors@^1.0.0: resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" integrity sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ== +picocolors@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.1.1.tgz#3d321af3eab939b083c8f929a1d12cda81c26b6b" + integrity sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA== + picomatch@^2.0.4, picomatch@^2.2.3, picomatch@^2.3.1: version "2.3.1" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" @@ -2313,6 +3236,18 @@ pretty-format@^29.0.0, pretty-format@^29.5.0: ansi-styles "^5.0.0" react-is "^18.0.0" +pretty-ms@^9.2.0: + version "9.3.0" + resolved "https://registry.yarnpkg.com/pretty-ms/-/pretty-ms-9.3.0.tgz#dd2524fcb3c326b4931b2272dfd1e1a8ed9a9f5a" + integrity sha512-gjVS5hOP+M3wMm5nmNOucbIrqudzs9v/57bWRHQWLYklXqoXKrVfYW2W9+glfGsqtPgpiz5WwyEEB+ksXIx3gQ== + dependencies: + parse-ms "^4.0.0" + +progress@~2.0.3: + version "2.0.3" + resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== + prompts@^2.0.1: version "2.4.2" resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" @@ -2341,6 +3276,13 @@ qs@6.11.0: dependencies: side-channel "^1.0.4" +qs@6.15.1: + version "6.15.1" + resolved "https://registry.yarnpkg.com/qs/-/qs-6.15.1.tgz#bdb55aed06bfac257a90c44a446a73fba5575c8f" + integrity sha512-6YHEFRL9mfgcAvql/XhwTvf5jKcOiiupt2FiJxHkiX1z4j7WL8J/jRHYLluORvc1XxB5rV20KoeK00gVJamspg== + dependencies: + side-channel "^1.1.0" + qs@^6.11.0: version "6.11.1" resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.1.tgz#6c29dff97f0c0060765911ba65cbc9764186109f" @@ -2373,6 +3315,11 @@ require-directory@^2.1.1: resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" integrity sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q== +require-from-string@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/require-from-string/-/require-from-string-2.0.2.tgz#89a7fdd938261267318eafe14f9c32e598c36909" + integrity sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw== + resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -2399,12 +3346,19 @@ resolve@^1.20.0: path-parse "^1.0.7" supports-preserve-symlinks-flag "^1.0.0" +rxjs@~7.8.1: + version "7.8.2" + resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-7.8.2.tgz#955bc473ed8af11a002a2be52071bf475638607b" + integrity sha512-dhKf903U/PQZY6boNNtAGdWbG85WAbjT/1xYoZIC7FAY0yWapOBQVsVrDl58W86//e1VpMNBtRV4MaXfdMySFA== + dependencies: + tslib "^2.1.0" + safe-buffer@5.2.1: version "5.2.1" resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== -"safer-buffer@>= 2.1.2 < 3": +"safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0": version "2.1.2" resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== @@ -2421,6 +3375,21 @@ semver@^6.0.0, semver@^6.3.0: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@^6.3.1: + version "6.3.1" + resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" + integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== + +semver@^7.6.3: + version "7.8.5" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.8.5.tgz#39b646037dd50c14fb451e7e4cac58ed8b863f69" + integrity sha512-Y7/KDsb8LjooZpwaqGyulO6DQlksgCncchHGk+sZIY4SBvUocMBEFH5Ur1fI4dV+Jvl0w6cjvucaIi40puRioA== + +semver@~7.7.0: + version "7.7.4" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.4.tgz#28464e36060e991fa7a11d0279d2d3f3b57a7e8a" + integrity sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA== + send@0.18.0: version "0.18.0" resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be" @@ -2467,6 +3436,35 @@ shebang-regex@^3.0.0: resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== +side-channel-list@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-list/-/side-channel-list-1.0.1.tgz#c2e0b5a14a540aebee3bbc6c3f8666cc9b509127" + integrity sha512-mjn/0bi/oUURjc5Xl7IaWi/OJJJumuoJFQJfDDyO46+hBWsfaVM65TBHq2eoZBhzl9EchxOijpkbRC8SVBQU0w== + dependencies: + es-errors "^1.3.0" + object-inspect "^1.13.4" + +side-channel-map@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/side-channel-map/-/side-channel-map-1.0.1.tgz#d6bb6b37902c6fef5174e5f533fab4c732a26f42" + integrity sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA== + dependencies: + call-bound "^1.0.2" + es-errors "^1.3.0" + get-intrinsic "^1.2.5" + object-inspect "^1.13.3" + +side-channel-weakmap@^1.0.2: + version "1.0.2" + resolved "https://registry.yarnpkg.com/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz#11dda19d5368e40ce9ec2bdc1fb0ecbc0790ecea" + integrity sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A== + 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" + side-channel@^1.0.4: version "1.0.4" resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.4.tgz#efce5c8fdc104ee751b25c58d4290011fa5ea2cf" @@ -2476,11 +3474,27 @@ side-channel@^1.0.4: get-intrinsic "^1.0.2" object-inspect "^1.9.0" +side-channel@^1.1.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.1.1.tgz#ea02c62e05dc4bea67d4442f0fb71ee192f8e0ab" + integrity sha512-6x6dK6zJdpTzF4sQeNYxwtvBzf6Eg4GtlesS94HOvTudUeyK2WXAaIfmDgsyslYrRBeFIlsi54AYsFGUuhmvrQ== + 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" + signal-exit@^3.0.3, signal-exit@^3.0.7: version "3.0.7" resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.7.tgz#a9a1767f8af84155114eaabd73f99273c8f59ad9" integrity sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ== +signal-exit@^4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-4.1.0.tgz#952188c1cbd546070e2dd20d0f41c0ae0530cb04" + integrity sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw== + sisteransi@^1.0.5: version "1.0.5" resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" @@ -2504,6 +3518,11 @@ source-map@^0.6.0, source-map@^0.6.1: resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== +source-map@~0.7.4: + version "0.7.6" + resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.6.tgz#a3658ab87e5b6429c8a1f3ba0083d4c61ca3ef02" + integrity sha512-i5uvt8C3ikiWeNZSVZNWcfZPItFQOsYTUAOkcUPGd8DqDy1uOUikjt5dG+uRlwyvR108Fb9DOd4GvXfT0N2/uQ== + sprintf-js@~1.0.2: version "1.0.3" resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" @@ -2555,6 +3574,11 @@ strip-final-newline@^2.0.0: resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== +strip-final-newline@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-4.0.0.tgz#35a369ec2ac43df356e3edd5dcebb6429aa1fa5c" + integrity sha512-aulFJcD6YK8V1G7iRB5tigAP4TsHBZZrOV8pjV++zdUwmeV8uzbY7yn6h9MswN62adStNZFuCIx4haBnRuMDaw== + strip-json-comments@^3.1.1: version "3.1.1" resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-3.1.1.tgz#31f1281b3832630434831c310c01cccda8cbe006" @@ -2641,6 +3665,11 @@ toidentifier@1.0.1: resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.1.tgz#3be34321a88a820ed1bd80dfaa33e479fbb8dd35" integrity sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA== +tree-kill@~1.2.2: + version "1.2.2" + resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc" + integrity sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A== + ts-jest@^29.1.0: version "29.1.0" resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-29.1.0.tgz#4a9db4104a49b76d2b368ea775b6c9535c603891" @@ -2655,6 +3684,16 @@ ts-jest@^29.1.0: semver "7.x" yargs-parser "^21.0.1" +tslib@2.8.1, tslib@^2.1.0, tslib@~2.8.0: + version "2.8.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.8.1.tgz#612efe4ed235d567e8aba5f2a5fab70280ade83f" + integrity sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w== + +tunnel@0.0.6: + version "0.0.6" + resolved "https://registry.yarnpkg.com/tunnel/-/tunnel-0.0.6.tgz#72f1314b34a5b192db012324df2cc587ca47f92c" + integrity sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg== + type-detect@4.0.8: version "4.0.8" resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" @@ -2673,16 +3712,42 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" +typed-inject@~5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/typed-inject/-/typed-inject-5.0.0.tgz#03e19e41188ec6a05496a5d37dc307d649aa7e87" + integrity sha512-0Ql2ORqBORLMdAW89TQKZsb1PQkFGImFfVmncXWe7a+AA3+7dh7Se9exxZowH4kbnlvKEFkMxUYdHUpjYWFJaA== + +typed-rest-client@~2.3.0: + version "2.3.1" + resolved "https://registry.yarnpkg.com/typed-rest-client/-/typed-rest-client-2.3.1.tgz#8a7e488da15da381e82d5cbbdedd0b08828e897d" + integrity sha512-k4kX5Up6qA68D0Cby2AK+6+vM5k3qTxe+/3FqhnHRExjY5cfbOnzjQZbP/LXleF8hVoDvDqxlgk9KK83HoBZlQ== + dependencies: + des.js "^1.1.0" + js-md4 "^0.3.2" + qs "6.15.1" + tunnel "0.0.6" + underscore "^1.13.8" + typescript@^5.0.4: version "5.0.4" resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.0.4.tgz#b217fd20119bd61a94d4011274e0ab369058da3b" integrity sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw== +underscore@^1.13.8: + version "1.13.8" + resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.8.tgz#a93a21186c049dbf0e847496dba72b7bd8c1e92b" + integrity sha512-DXtD3ZtEQzc7M8m4cXotyHR+FAS18C64asBYY5vqZexfYryNNnDc02W4hKg3rdQuqOYas1jkseX0+nZXjTXnvQ== + undici-types@~6.21.0: version "6.21.0" resolved "https://registry.yarnpkg.com/undici-types/-/undici-types-6.21.0.tgz#691d00af3909be93a7faa13be61b3a5b50ef12cb" integrity sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ== +unicorn-magic@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/unicorn-magic/-/unicorn-magic-0.3.0.tgz#4efd45c85a69e0dd576d25532fbfa22aa5c8a104" + integrity sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA== + unpipe@1.0.0, unpipe@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" @@ -2696,6 +3761,14 @@ update-browserslist-db@^1.0.10: escalade "^3.1.1" picocolors "^1.0.0" +update-browserslist-db@^1.2.3: + version "1.2.3" + resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d" + integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w== + dependencies: + escalade "^3.2.0" + picocolors "^1.1.1" + utils-merge@1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" @@ -2722,6 +3795,11 @@ walker@^1.0.8: dependencies: makeerror "1.0.12" +weapon-regex@~1.3.2: + version "1.3.6" + resolved "https://registry.yarnpkg.com/weapon-regex/-/weapon-regex-1.3.6.tgz#e2248700d2516581093e77739d821883418f6ddf" + integrity sha512-wsf1m1jmMrso5nhwVFJJHSubEBf3+pereGd7+nBKtYJ18KoB/PWJOHS3WRkwS04VrOU0iJr2bZU+l1QaTJ+9nA== + which@^2.0.1: version "2.0.2" resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" @@ -2788,3 +3866,13 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== + +yoctocolors@^2.1.1: + version "2.1.2" + resolved "https://registry.yarnpkg.com/yoctocolors/-/yoctocolors-2.1.2.tgz#d795f54d173494e7d8db93150cec0ed7f678c83a" + integrity sha512-CzhO+pFNo8ajLM2d2IW/R93ipy99LWjtwblvC1RsoSUMZgyLbYFr221TnSNT7GjGdYui6P459mw9JH/g/zW2ug== + +zod@^4.1.12: + version "4.4.3" + resolved "https://registry.yarnpkg.com/zod/-/zod-4.4.3.tgz#b680f172885d18bbebf21a834ea25e55a1bbf356" + integrity sha512-ytENFjIJFl2UwYglde2jchW2Hwm4GJFLDiSXWdTrJQBIN9Fcyp7n4DhxJEiWNAJMV1/BqWfW/kkg71UDcHJyTQ==