From 8459c91447a15e1cefad140c13bed1f85cd8cbd3 Mon Sep 17 00:00:00 2001 From: Paulius Krutkis Date: Fri, 26 Jun 2026 07:58:36 +0300 Subject: [PATCH 1/4] Fix CLI exit codes for validation and API-level scrape failures Map plain 400/422 API errors to the documented VALIDATION exit code (4) instead of NETWORK (7), so scripts can distinguish permanent input errors from transient network failures. Detect server-side scrape failures (failed content envelopes and HTTP error statuses) and exit non-zero with the API message on stderr, instead of printing the failure body to stdout and exiting 0. --- src/output/errors/scrape-failed-error.ts | 9 ++ src/output/services/detect-scrape-failure.ts | 68 +++++++++++++++ src/output/services/write-scrape-response.ts | 6 ++ src/platform/services/handle-cli-error.ts | 8 ++ .../output/errors/scrape-failed-error.test.ts | 19 +++++ .../services/detect-scrape-failure.test.ts | 84 +++++++++++++++++++ .../services/write-scrape-response.test.ts | 30 +++++++ .../services/handle-cli-error.test.ts | 23 +++++ 8 files changed, 247 insertions(+) create mode 100644 src/output/errors/scrape-failed-error.ts create mode 100644 src/output/services/detect-scrape-failure.ts create mode 100644 tests/output/errors/scrape-failed-error.test.ts create mode 100644 tests/output/services/detect-scrape-failure.test.ts diff --git a/src/output/errors/scrape-failed-error.ts b/src/output/errors/scrape-failed-error.ts new file mode 100644 index 0000000..5b4b81b --- /dev/null +++ b/src/output/errors/scrape-failed-error.ts @@ -0,0 +1,9 @@ +export class ScrapeFailedError extends Error { + readonly statusCode: number | undefined; + + constructor(message: string, statusCode?: number) { + super(message); + this.name = "ScrapeFailedError"; + this.statusCode = statusCode; + } +} diff --git a/src/output/services/detect-scrape-failure.ts b/src/output/services/detect-scrape-failure.ts new file mode 100644 index 0000000..77a5e7d --- /dev/null +++ b/src/output/services/detect-scrape-failure.ts @@ -0,0 +1,68 @@ +import type { ResultEntry, SyncResponse } from "@decodo/sdk-ts"; +import { ScrapeFailedError } from "../errors/scrape-failed-error.js"; + +const HTTP_ERROR_THRESHOLD = 400; + +function readString( + source: Record, + key: string +): string | undefined { + const value = source[key]; + return typeof value === "string" && value.length > 0 ? value : undefined; +} + +function readNumber( + source: Record, + key: string +): number | undefined { + const value = source[key]; + return typeof value === "number" ? value : undefined; +} + +function failureFromContent(content: unknown): ScrapeFailedError | undefined { + if (typeof content !== "object" || content === null) { + return; + } + + const envelope = content as Record; + if (envelope.status !== "failed") { + return; + } + + const statusCode = readNumber(envelope, "status_code"); + const message = + readString(envelope, "message") ?? + (statusCode === undefined + ? "Scrape failed." + : `Scrape failed with status ${statusCode}.`); + + return new ScrapeFailedError(message, statusCode); +} + +function failureFromStatus(entry: ResultEntry): ScrapeFailedError | undefined { + const { status_code: statusCode } = entry; + if (typeof statusCode !== "number" || statusCode < HTTP_ERROR_THRESHOLD) { + return; + } + + const message = + (typeof entry.content === "object" && entry.content !== null + ? readString(entry.content as Record, "message") + : undefined) ?? `Scrape request returned status ${statusCode}.`; + + return new ScrapeFailedError(message, statusCode); +} + +export function detectScrapeFailure( + response: SyncResponse +): ScrapeFailedError | undefined { + for (const entry of response.results) { + const failure = + failureFromContent(entry.content) ?? failureFromStatus(entry); + if (failure) { + return failure; + } + } + + return; +} diff --git a/src/output/services/write-scrape-response.ts b/src/output/services/write-scrape-response.ts index 7f682c4..7f6ac24 100644 --- a/src/output/services/write-scrape-response.ts +++ b/src/output/services/write-scrape-response.ts @@ -3,6 +3,7 @@ import { writeBinaryOutput } from "../../platform/services/write-binary.js"; import { extractPngFromResponse } from "../../scrape/services/extract-png.js"; import { defaultScreenshotFilename } from "../../scrape/services/screenshot-output-filename.js"; import type { WriteScrapeResponseContext } from "../types/write-scrape-response.js"; +import { detectScrapeFailure } from "./detect-scrape-failure.js"; import { extractPayload } from "./extract-payload.js"; import { renderPayload } from "./render-output.js"; import { resolvePrettyIndent } from "./resolve-pretty.js"; @@ -15,6 +16,11 @@ export function writeScrapeResponse( ): void { const { options } = context; + const failure = detectScrapeFailure(response); + if (failure) { + throw failure; + } + if (context.binary?.kind === "png") { writeBinaryOutput(extractPngFromResponse(response), { output: options.output, diff --git a/src/platform/services/handle-cli-error.ts b/src/platform/services/handle-cli-error.ts index a5789dd..f5c45bd 100644 --- a/src/platform/services/handle-cli-error.ts +++ b/src/platform/services/handle-cli-error.ts @@ -7,6 +7,7 @@ import { } from "@decodo/sdk-ts"; import { PLAYGROUND_URL } from "../../auth/constants.js"; import { AuthRequiredError } from "../../auth/errors/auth-required-error.js"; +import { ScrapeFailedError } from "../../output/errors/scrape-failed-error.js"; import { EXIT } from "../constants.js"; import { CliUsageError } from "../errors/cli-usage-error.js"; @@ -63,7 +64,14 @@ export function resolveCliExitCode(err: unknown): number { return EXIT.TIMEOUT; } + if (err instanceof ScrapeFailedError) { + return EXIT.NETWORK; + } + if (err instanceof DecodoError) { + if (err.statusCode === 400 || err.statusCode === 422) { + return EXIT.VALIDATION; + } return EXIT.NETWORK; } diff --git a/tests/output/errors/scrape-failed-error.test.ts b/tests/output/errors/scrape-failed-error.test.ts new file mode 100644 index 0000000..3d0ce4e --- /dev/null +++ b/tests/output/errors/scrape-failed-error.test.ts @@ -0,0 +1,19 @@ +import { describe, expect, it } from "vitest"; +import { ScrapeFailedError } from "../../../src/output/errors/scrape-failed-error.js"; + +describe("ScrapeFailedError", () => { + it("sets name, message, and status code", () => { + const err = new ScrapeFailedError("scrape failed", 613); + + expect(err).toBeInstanceOf(Error); + expect(err.name).toBe("ScrapeFailedError"); + expect(err.message).toBe("scrape failed"); + expect(err.statusCode).toBe(613); + }); + + it("leaves status code undefined when omitted", () => { + const err = new ScrapeFailedError("scrape failed"); + + expect(err.statusCode).toBeUndefined(); + }); +}); diff --git a/tests/output/services/detect-scrape-failure.test.ts b/tests/output/services/detect-scrape-failure.test.ts new file mode 100644 index 0000000..4ee0d5e --- /dev/null +++ b/tests/output/services/detect-scrape-failure.test.ts @@ -0,0 +1,84 @@ +import type { SyncResponse } from "@decodo/sdk-ts"; +import { describe, expect, it } from "vitest"; +import { detectScrapeFailure } from "../../../src/output/services/detect-scrape-failure.js"; + +describe("detectScrapeFailure", () => { + it("returns undefined for a successful response", () => { + const response = { + results: [{ content: { items: [1] }, status_code: 200 }], + } as SyncResponse; + + expect(detectScrapeFailure(response)).toBeUndefined(); + }); + + it("flags a failed content envelope and surfaces its message", () => { + const response = { + results: [ + { + content: { + status: "failed", + status_code: 613, + message: "Trends request was rejected", + }, + }, + ], + } as unknown as SyncResponse; + + const failure = detectScrapeFailure(response); + + expect(failure?.message).toBe("Trends request was rejected"); + expect(failure?.statusCode).toBe(613); + }); + + it("flags a failed envelope without a message using its status code", () => { + const response = { + results: [{ content: { status: "failed", status_code: 12_002 } }], + } as unknown as SyncResponse; + + const failure = detectScrapeFailure(response); + + expect(failure?.message).toContain("12002"); + expect(failure?.statusCode).toBe(12_002); + }); + + it("flags an entry whose status code is an HTTP error", () => { + const response = { + results: [ + { + content: { results: [], _warnings: ["not found"] }, + status_code: 404, + }, + ], + } as unknown as SyncResponse; + + const failure = detectScrapeFailure(response); + + expect(failure?.message).toContain("404"); + expect(failure?.statusCode).toBe(404); + }); + + it("ignores entries that omit a status code", () => { + const response = { + results: [{ content: { ok: true } }], + } as SyncResponse; + + expect(detectScrapeFailure(response)).toBeUndefined(); + }); + + it("returns the first failure across multiple results", () => { + const response = { + results: [ + { content: { ok: true }, status_code: 200 }, + { + content: { + status: "failed", + status_code: 613, + message: "second failed", + }, + }, + ], + } as unknown as SyncResponse; + + expect(detectScrapeFailure(response)?.message).toBe("second failed"); + }); +}); diff --git a/tests/output/services/write-scrape-response.test.ts b/tests/output/services/write-scrape-response.test.ts index ad686b6..dfb4736 100644 --- a/tests/output/services/write-scrape-response.test.ts +++ b/tests/output/services/write-scrape-response.test.ts @@ -133,6 +133,36 @@ describe("writeScrapeResponse", () => { expect(stderr).toEqual([]); }); + it("throws on a failed content envelope without writing to stdout", () => { + const response = { + results: [ + { + content: { + status: "failed", + status_code: 12_002, + message: "blocked", + }, + }, + ], + } as unknown as SyncResponse; + + expect(() => writeScrapeResponse(response, { options: {} })).toThrow( + "blocked" + ); + expect(written).toBeUndefined(); + }); + + it("throws on an HTTP error status even with --full", () => { + const response = { + results: [{ content: { results: [] }, status_code: 404 }], + } as unknown as SyncResponse; + + expect(() => + writeScrapeResponse(response, { options: { full: true } }) + ).toThrow("404"); + expect(written).toBeUndefined(); + }); + it("refuses TTY stdout for binary png without -o", () => { Object.defineProperty(process.stdout, "isTTY", { value: true, diff --git a/tests/platform/services/handle-cli-error.test.ts b/tests/platform/services/handle-cli-error.test.ts index f83f7e3..b0ca8b1 100644 --- a/tests/platform/services/handle-cli-error.test.ts +++ b/tests/platform/services/handle-cli-error.test.ts @@ -7,6 +7,7 @@ import { } from "@decodo/sdk-ts"; import { afterEach, beforeEach, describe, expect, it, vi } from "vitest"; import { AuthRequiredError } from "../../../src/auth/errors/auth-required-error.js"; +import { ScrapeFailedError } from "../../../src/output/errors/scrape-failed-error.js"; import { CliUsageError } from "../../../src/platform/errors/cli-usage-error.js"; import { handleCliError } from "../../../src/platform/services/handle-cli-error.js"; @@ -88,6 +89,28 @@ describe("handleCliError", () => { expect(exitCode).toBe(7); }); + it("maps 400 Decodo errors to exit code 4 (validation)", () => { + const err = new DecodoError("Validation failed, see documentation", 400); + + expect(() => handleCliError(err)).toThrow("process.exit:4"); + expect(exitCode).toBe(4); + }); + + it("maps 422 Decodo errors to exit code 4 (validation)", () => { + const err = new DecodoError("Unprocessable entity", 422); + + expect(() => handleCliError(err)).toThrow("process.exit:4"); + expect(exitCode).toBe(4); + }); + + it("maps scrape failures to exit code 7 with the API message", () => { + const err = new ScrapeFailedError("Trends request was rejected", 613); + + expect(() => handleCliError(err)).toThrow("process.exit:7"); + expect(exitCode).toBe(7); + expect(stderr.join("\n")).toContain("Trends request was rejected"); + }); + it("maps syscall-coded network failures in the cause chain to exit code 7", () => { const cause = Object.assign( new Error("getaddrinfo ENOTFOUND api.decodo.com"), From 74fcc25f91f355eef4647685c6e095b8e5c65be8 Mon Sep 17 00:00:00 2001 From: Paulius Krutkis Date: Fri, 26 Jun 2026 08:59:28 +0300 Subject: [PATCH 2/4] Add detectDegradedStatus function and enhance scrape failure detection Introduced a new function, detectDegradedStatus, to identify HTTP errors that still return usable content. Updated the detectScrapeFailure function to utilize this new logic. Enhanced writeScrapeResponse to log warnings for degraded statuses. Added corresponding tests to ensure correct behavior for both functions, including scenarios where HTTP errors return valid content. --- src/output/services/detect-scrape-failure.ts | 45 +++++++++++++++++++ src/output/services/write-scrape-response.ts | 12 ++++- .../services/detect-scrape-failure.test.ts | 39 +++++++++++++++- .../services/write-scrape-response.test.ts | 11 +++++ 4 files changed, 105 insertions(+), 2 deletions(-) diff --git a/src/output/services/detect-scrape-failure.ts b/src/output/services/detect-scrape-failure.ts index 77a5e7d..d3fc70b 100644 --- a/src/output/services/detect-scrape-failure.ts +++ b/src/output/services/detect-scrape-failure.ts @@ -39,12 +39,40 @@ function failureFromContent(content: unknown): ScrapeFailedError | undefined { return new ScrapeFailedError(message, statusCode); } +function hasUsableContent(content: unknown): boolean { + if (content === undefined || content === null) { + return false; + } + + if (typeof content === "string") { + return content.trim().length > 0; + } + + if (Array.isArray(content)) { + return content.length > 0; + } + + if (typeof content === "object") { + const envelope = content as Record; + if (Array.isArray(envelope.results)) { + return envelope.results.length > 0; + } + return Object.keys(envelope).length > 0; + } + + return true; +} + function failureFromStatus(entry: ResultEntry): ScrapeFailedError | undefined { const { status_code: statusCode } = entry; if (typeof statusCode !== "number" || statusCode < HTTP_ERROR_THRESHOLD) { return; } + if (hasUsableContent(entry.content)) { + return; + } + const message = (typeof entry.content === "object" && entry.content !== null ? readString(entry.content as Record, "message") @@ -66,3 +94,20 @@ export function detectScrapeFailure( return; } + +export function detectDegradedStatus( + response: SyncResponse +): number | undefined { + for (const entry of response.results) { + const { status_code: statusCode } = entry; + if ( + typeof statusCode === "number" && + statusCode >= HTTP_ERROR_THRESHOLD && + hasUsableContent(entry.content) + ) { + return statusCode; + } + } + + return; +} diff --git a/src/output/services/write-scrape-response.ts b/src/output/services/write-scrape-response.ts index 7f6ac24..2be4d04 100644 --- a/src/output/services/write-scrape-response.ts +++ b/src/output/services/write-scrape-response.ts @@ -3,7 +3,10 @@ import { writeBinaryOutput } from "../../platform/services/write-binary.js"; import { extractPngFromResponse } from "../../scrape/services/extract-png.js"; import { defaultScreenshotFilename } from "../../scrape/services/screenshot-output-filename.js"; import type { WriteScrapeResponseContext } from "../types/write-scrape-response.js"; -import { detectScrapeFailure } from "./detect-scrape-failure.js"; +import { + detectDegradedStatus, + detectScrapeFailure, +} from "./detect-scrape-failure.js"; import { extractPayload } from "./extract-payload.js"; import { renderPayload } from "./render-output.js"; import { resolvePrettyIndent } from "./resolve-pretty.js"; @@ -21,6 +24,13 @@ export function writeScrapeResponse( throw failure; } + const degradedStatus = detectDegradedStatus(response); + if (degradedStatus !== undefined) { + console.error( + `Warning: target returned HTTP ${degradedStatus}; emitting the content it returned` + ); + } + if (context.binary?.kind === "png") { writeBinaryOutput(extractPngFromResponse(response), { output: options.output, diff --git a/tests/output/services/detect-scrape-failure.test.ts b/tests/output/services/detect-scrape-failure.test.ts index 4ee0d5e..f39a05a 100644 --- a/tests/output/services/detect-scrape-failure.test.ts +++ b/tests/output/services/detect-scrape-failure.test.ts @@ -1,6 +1,9 @@ import type { SyncResponse } from "@decodo/sdk-ts"; import { describe, expect, it } from "vitest"; -import { detectScrapeFailure } from "../../../src/output/services/detect-scrape-failure.js"; +import { + detectDegradedStatus, + detectScrapeFailure, +} from "../../../src/output/services/detect-scrape-failure.js"; describe("detectScrapeFailure", () => { it("returns undefined for a successful response", () => { @@ -65,6 +68,14 @@ describe("detectScrapeFailure", () => { expect(detectScrapeFailure(response)).toBeUndefined(); }); + it("does not flag an HTTP error that still returned a body", () => { + const response = { + results: [{ content: "404 Not Found", status_code: 404 }], + } as unknown as SyncResponse; + + expect(detectScrapeFailure(response)).toBeUndefined(); + }); + it("returns the first failure across multiple results", () => { const response = { results: [ @@ -82,3 +93,29 @@ describe("detectScrapeFailure", () => { expect(detectScrapeFailure(response)?.message).toBe("second failed"); }); }); + +describe("detectDegradedStatus", () => { + it("returns undefined for a successful response", () => { + const response = { + results: [{ content: "ok", status_code: 200 }], + } as unknown as SyncResponse; + + expect(detectDegradedStatus(response)).toBeUndefined(); + }); + + it("returns the status code when an HTTP error still returned a body", () => { + const response = { + results: [{ content: "404 Not Found", status_code: 404 }], + } as unknown as SyncResponse; + + expect(detectDegradedStatus(response)).toBe(404); + }); + + it("returns undefined when an HTTP error returned no usable content", () => { + const response = { + results: [{ content: { results: [] }, status_code: 404 }], + } as unknown as SyncResponse; + + expect(detectDegradedStatus(response)).toBeUndefined(); + }); +}); diff --git a/tests/output/services/write-scrape-response.test.ts b/tests/output/services/write-scrape-response.test.ts index dfb4736..879bd86 100644 --- a/tests/output/services/write-scrape-response.test.ts +++ b/tests/output/services/write-scrape-response.test.ts @@ -163,6 +163,17 @@ describe("writeScrapeResponse", () => { expect(written).toBeUndefined(); }); + it("emits content and warns when an HTTP error still returned a body", () => { + const response = { + results: [{ content: "404 Not Found", status_code: 404 }], + } as unknown as SyncResponse; + + writeScrapeResponse(response, { options: {} }); + + expect(written).toBe("404 Not Found\n"); + expect(stderr.join("\n")).toContain("HTTP 404"); + }); + it("refuses TTY stdout for binary png without -o", () => { Object.defineProperty(process.stdout, "isTTY", { value: true, From 583c257e6818d2da02702ddde0fe92383c08f8b9 Mon Sep 17 00:00:00 2001 From: Paulius Krutkis Date: Fri, 26 Jun 2026 10:14:01 +0300 Subject: [PATCH 3/4] Detect top-level scrape failure envelope and guard missing results Target 5xx responses come back as a top-level { status: "failed" } envelope with no results array. detectScrapeFailure now inspects the response itself for that envelope before iterating, so the failure surfaces as a ScrapeFailedError (exit 7) with the API's guidance instead of crashing with "results is not iterable". Both detectScrapeFailure and detectDegradedStatus now read results through a guard, so a missing or non-array results never throws. --- src/output/services/detect-scrape-failure.ts | 21 ++++++++++----- .../services/detect-scrape-failure.test.ts | 26 +++++++++++++++++++ 2 files changed, 41 insertions(+), 6 deletions(-) diff --git a/src/output/services/detect-scrape-failure.ts b/src/output/services/detect-scrape-failure.ts index d3fc70b..46d598f 100644 --- a/src/output/services/detect-scrape-failure.ts +++ b/src/output/services/detect-scrape-failure.ts @@ -19,12 +19,12 @@ function readNumber( return typeof value === "number" ? value : undefined; } -function failureFromContent(content: unknown): ScrapeFailedError | undefined { - if (typeof content !== "object" || content === null) { +function failureFromEnvelope(value: unknown): ScrapeFailedError | undefined { + if (typeof value !== "object" || value === null) { return; } - const envelope = content as Record; + const envelope = value as Record; if (envelope.status !== "failed") { return; } @@ -81,12 +81,21 @@ function failureFromStatus(entry: ResultEntry): ScrapeFailedError | undefined { return new ScrapeFailedError(message, statusCode); } +function readResults(response: SyncResponse): ResultEntry[] { + return Array.isArray(response.results) ? response.results : []; +} + export function detectScrapeFailure( response: SyncResponse ): ScrapeFailedError | undefined { - for (const entry of response.results) { + const topLevelFailure = failureFromEnvelope(response); + if (topLevelFailure) { + return topLevelFailure; + } + + for (const entry of readResults(response)) { const failure = - failureFromContent(entry.content) ?? failureFromStatus(entry); + failureFromEnvelope(entry.content) ?? failureFromStatus(entry); if (failure) { return failure; } @@ -98,7 +107,7 @@ export function detectScrapeFailure( export function detectDegradedStatus( response: SyncResponse ): number | undefined { - for (const entry of response.results) { + for (const entry of readResults(response)) { const { status_code: statusCode } = entry; if ( typeof statusCode === "number" && diff --git a/tests/output/services/detect-scrape-failure.test.ts b/tests/output/services/detect-scrape-failure.test.ts index f39a05a..100f5c8 100644 --- a/tests/output/services/detect-scrape-failure.test.ts +++ b/tests/output/services/detect-scrape-failure.test.ts @@ -92,6 +92,26 @@ describe("detectScrapeFailure", () => { expect(detectScrapeFailure(response)?.message).toBe("second failed"); }); + + it("flags a top-level failure envelope that omits results", () => { + const response = { + status: "failed", + status_code: 613, + message: "We were not able to scrape the target.", + task_id: "7476155848721478657", + } as unknown as SyncResponse; + + const failure = detectScrapeFailure(response); + + expect(failure?.message).toBe("We were not able to scrape the target."); + expect(failure?.statusCode).toBe(613); + }); + + it("does not throw when results is missing", () => { + const response = {} as unknown as SyncResponse; + + expect(detectScrapeFailure(response)).toBeUndefined(); + }); }); describe("detectDegradedStatus", () => { @@ -118,4 +138,10 @@ describe("detectDegradedStatus", () => { expect(detectDegradedStatus(response)).toBeUndefined(); }); + + it("does not throw when results is missing", () => { + const response = {} as unknown as SyncResponse; + + expect(detectDegradedStatus(response)).toBeUndefined(); + }); }); From 786dcac1aeb97d13dca7804b77a0deee55c9a353 Mon Sep 17 00:00:00 2001 From: Paulius Krutkis Date: Fri, 26 Jun 2026 10:36:24 +0300 Subject: [PATCH 4/4] Bump vite and esbuild to patched versions Pin vite to ^7.3.5 and esbuild to ^0.28.1 via pnpm overrides to clear the Dependabot advisories (vite server.fs.deny bypass and launch-editor NTLM disclosure, esbuild dev-server file read). Both are transitive dev-only deps via vitest and never ship in the CLI bundle. --- package.json | 6 ++ pnpm-lock.yaml | 238 +++++++++++++++++++++++++------------------------ 2 files changed, 127 insertions(+), 117 deletions(-) diff --git a/package.json b/package.json index 23c128d..c75190c 100644 --- a/package.json +++ b/package.json @@ -47,5 +47,11 @@ "typescript": "^5.3.3", "ultracite": "7.7.0", "vitest": "^3.2.0" + }, + "pnpm": { + "overrides": { + "vite": "^7.3.5", + "esbuild": "^0.28.1" + } } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8e0cb2a..0146088 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -4,6 +4,10 @@ settings: autoInstallPeers: true excludeLinksFromLockfile: false +overrides: + vite: ^7.3.5 + esbuild: ^0.28.1 + importers: .: @@ -105,158 +109,158 @@ packages: resolution: {integrity: sha512-V/SdHS0DV9L8gBJc5ljQbTmbgV7C8Cn7V91qn3JfnHKgvSmuUq2kLH27UPgCbAa0T2ZVXOkBzbIog5ZnOzAUMg==} engines: {node: '>=18.0.0'} - '@esbuild/aix-ppc64@0.27.7': - resolution: {integrity: sha512-EKX3Qwmhz1eMdEJokhALr0YiD0lhQNwDqkPYyPhiSwKrh7/4KRjQc04sZ8db+5DVVnZ1LmbNDI1uAMPEUBnQPg==} + '@esbuild/aix-ppc64@0.28.1': + resolution: {integrity: sha512-Svl7tq8k/08+p6CXPpRjQ1fKX+1odH/BQbb48fV6fj3CWHhsoIOoY87w1oHXm0qEpkIK3ZfVgp0hed3XBXzXMQ==} engines: {node: '>=18'} cpu: [ppc64] os: [aix] - '@esbuild/android-arm64@0.27.7': - resolution: {integrity: sha512-62dPZHpIXzvChfvfLJow3q5dDtiNMkwiRzPylSCfriLvZeq0a1bWChrGx/BbUbPwOrsWKMn8idSllklzBy+dgQ==} + '@esbuild/android-arm64@0.28.1': + resolution: {integrity: sha512-34EGEbCIAgosYz6goLcopX6Mo7NyGv9tfwEM2/7Ce2VcVRk568iSvniGWcUXIy7wEDR1wzolcxcriFVrWYcwBg==} engines: {node: '>=18'} cpu: [arm64] os: [android] - '@esbuild/android-arm@0.27.7': - resolution: {integrity: sha512-jbPXvB4Yj2yBV7HUfE2KHe4GJX51QplCN1pGbYjvsyCZbQmies29EoJbkEc+vYuU5o45AfQn37vZlyXy4YJ8RQ==} + '@esbuild/android-arm@0.28.1': + resolution: {integrity: sha512-0k2F129Xdio1TdJfzJ8sy1Q47vUD2NnwdhiAf7drUN1EBTfPf4hsFCtmMgu/6m8JSzsBrlmVjudMBQqOfG8usQ==} engines: {node: '>=18'} cpu: [arm] os: [android] - '@esbuild/android-x64@0.27.7': - resolution: {integrity: sha512-x5VpMODneVDb70PYV2VQOmIUUiBtY3D3mPBG8NxVk5CogneYhkR7MmM3yR/uMdITLrC1ml/NV1rj4bMJuy9MCg==} + '@esbuild/android-x64@0.28.1': + resolution: {integrity: sha512-dbwY7ltSMDWsRatcRpCnES4F+im88OCUgGZjy52shC7GqHRE/cYlxNbB4Z4UpJswpcc4Qxd2oE/ufM0p61IKng==} engines: {node: '>=18'} cpu: [x64] os: [android] - '@esbuild/darwin-arm64@0.27.7': - resolution: {integrity: sha512-5lckdqeuBPlKUwvoCXIgI2D9/ABmPq3Rdp7IfL70393YgaASt7tbju3Ac+ePVi3KDH6N2RqePfHnXkaDtY9fkw==} + '@esbuild/darwin-arm64@0.28.1': + resolution: {integrity: sha512-TZbWkQY7kvTAXbXUT7uVACR5cMHsDiSz9z7ZKAX/RTq/WJEk3QyRr0wZpNhBDX+/0CtdqUIJlOiodQcta6tY3Q==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] - '@esbuild/darwin-x64@0.27.7': - resolution: {integrity: sha512-rYnXrKcXuT7Z+WL5K980jVFdvVKhCHhUwid+dDYQpH+qu+TefcomiMAJpIiC2EM3Rjtq0sO3StMV/+3w3MyyqQ==} + '@esbuild/darwin-x64@0.28.1': + resolution: {integrity: sha512-zfdzgK9ACBNZLI/CyHTOx81SyNbM6YXn7rxSgX97VjyiPl9W1i4Ka4fgKECEoFCKGpvBj5qArWIGgQjOwkgskQ==} engines: {node: '>=18'} cpu: [x64] os: [darwin] - '@esbuild/freebsd-arm64@0.27.7': - resolution: {integrity: sha512-B48PqeCsEgOtzME2GbNM2roU29AMTuOIN91dsMO30t+Ydis3z/3Ngoj5hhnsOSSwNzS+6JppqWsuhTp6E82l2w==} + '@esbuild/freebsd-arm64@0.28.1': + resolution: {integrity: sha512-wG2EA8ENdEI0qhkSZMjfqrdY+ziCYCPMmtZjjIwOmXFjmyzEHn+UUxk5of+SYsjtfs3VpnlC7QLzSI5hY/rOAw==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] - '@esbuild/freebsd-x64@0.27.7': - resolution: {integrity: sha512-jOBDK5XEjA4m5IJK3bpAQF9/Lelu/Z9ZcdhTRLf4cajlB+8VEhFFRjWgfy3M1O4rO2GQ/b2dLwCUGpiF/eATNQ==} + '@esbuild/freebsd-x64@0.28.1': + resolution: {integrity: sha512-i7dZ9vQgnvSCzi/rYCXNgtF/U+eKZNJBzu3eTQbRgHnM7tNSizLOkRFAl3qzVc/Op/u5YkHHa4pf/3DOYHthLQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] - '@esbuild/linux-arm64@0.27.7': - resolution: {integrity: sha512-RZPHBoxXuNnPQO9rvjh5jdkRmVizktkT7TCDkDmQ0W2SwHInKCAV95GRuvdSvA7w4VMwfCjUiPwDi0ZO6Nfe9A==} + '@esbuild/linux-arm64@0.28.1': + resolution: {integrity: sha512-yHs+0uc8+nvEAfAfxrWQKK5peSNzBc4PegcMO0EJ2hT71uA7vB8Ihg2e77R2P7SG5uYjPbHlLLmve4LLLRCf0g==} engines: {node: '>=18'} cpu: [arm64] os: [linux] - '@esbuild/linux-arm@0.27.7': - resolution: {integrity: sha512-RkT/YXYBTSULo3+af8Ib0ykH8u2MBh57o7q/DAs3lTJlyVQkgQvlrPTnjIzzRPQyavxtPtfg0EopvDyIt0j1rA==} + '@esbuild/linux-arm@0.28.1': + resolution: {integrity: sha512-qVXBOHQS+d5Y722GwJzJUtOLlX7km3CraOaGormF1pDtPd2C/l1SHRPgjLunLGe51Sh5YYWKMFDyV4SxgMQYTQ==} engines: {node: '>=18'} cpu: [arm] os: [linux] - '@esbuild/linux-ia32@0.27.7': - resolution: {integrity: sha512-GA48aKNkyQDbd3KtkplYWT102C5sn/EZTY4XROkxONgruHPU72l+gW+FfF8tf2cFjeHaRbWpOYa/uRBz/Xq1Pg==} + '@esbuild/linux-ia32@0.28.1': + resolution: {integrity: sha512-d1z4ZuP0ajrfz/FhGT4vv278rX8KnPPJx8i5+AtK7TYbx9Le9F1hyzurZpkEyjkGa9dUGhQow4C1NmeGvqxN2w==} engines: {node: '>=18'} cpu: [ia32] os: [linux] - '@esbuild/linux-loong64@0.27.7': - resolution: {integrity: sha512-a4POruNM2oWsD4WKvBSEKGIiWQF8fZOAsycHOt6JBpZ+JN2n2JH9WAv56SOyu9X5IqAjqSIPTaJkqN8F7XOQ5Q==} + '@esbuild/linux-loong64@0.28.1': + resolution: {integrity: sha512-M5sRjUVZrkm1OAPR3dlOYzNmN+loZKGVi1VUQGrwuqLcbR6qeAz+famMhjASeH3YVKvZz+zT1jlh/keC3Rj/lg==} engines: {node: '>=18'} cpu: [loong64] os: [linux] - '@esbuild/linux-mips64el@0.27.7': - resolution: {integrity: sha512-KabT5I6StirGfIz0FMgl1I+R1H73Gp0ofL9A3nG3i/cYFJzKHhouBV5VWK1CSgKvVaG4q1RNpCTR2LuTVB3fIw==} + '@esbuild/linux-mips64el@0.28.1': + resolution: {integrity: sha512-mRObBZeHh2OxcBFPWE/FjylkRgZdYuiTR3vaTozquCGOH14iP9oN4x4Ge81CoIDYQrXmIxpFumJBu5MtZpnQJQ==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] - '@esbuild/linux-ppc64@0.27.7': - resolution: {integrity: sha512-gRsL4x6wsGHGRqhtI+ifpN/vpOFTQtnbsupUF5R5YTAg+y/lKelYR1hXbnBdzDjGbMYjVJLJTd2OFmMewAgwlQ==} + '@esbuild/linux-ppc64@0.28.1': + resolution: {integrity: sha512-slScBsMAb3GFDcdrCgLwZtPYRoH2H/youv10QiZyRjmsP48fznoveWytSgCI/R0ZcUgpc0ZhIUEx6LHts8yrfQ==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] - '@esbuild/linux-riscv64@0.27.7': - resolution: {integrity: sha512-hL25LbxO1QOngGzu2U5xeXtxXcW+/GvMN3ejANqXkxZ/opySAZMrc+9LY/WyjAan41unrR3YrmtTsUpwT66InQ==} + '@esbuild/linux-riscv64@0.28.1': + resolution: {integrity: sha512-kw0owk1o0GFETUJyW0jc0G4Yzs0BHZn0JDZ8JRT088vjJYX777BAs1fDGxAC+q831qOs2DTC96mNsG2opdfyyQ==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] - '@esbuild/linux-s390x@0.27.7': - resolution: {integrity: sha512-2k8go8Ycu1Kb46vEelhu1vqEP+UeRVj2zY1pSuPdgvbd5ykAw82Lrro28vXUrRmzEsUV0NzCf54yARIK8r0fdw==} + '@esbuild/linux-s390x@0.28.1': + resolution: {integrity: sha512-/lAIjX8aYFRByhh6L5rYtPEDRqa9de/4V/juOXcta5frjvzXO4/sqEtyytse0g3zZFuWu5cDN0MkLz2qRDD2Ag==} engines: {node: '>=18'} cpu: [s390x] os: [linux] - '@esbuild/linux-x64@0.27.7': - resolution: {integrity: sha512-hzznmADPt+OmsYzw1EE33ccA+HPdIqiCRq7cQeL1Jlq2gb1+OyWBkMCrYGBJ+sxVzve2ZJEVeePbLM2iEIZSxA==} + '@esbuild/linux-x64@0.28.1': + resolution: {integrity: sha512-u/anNYF2mmVOEDwLtnQ1wOr3EZ9sTNGLWrsYGYwHWzGA3Si84IOkHXlbWTD1NB+9/1lcnweYKO54uhxZydNzfA==} engines: {node: '>=18'} cpu: [x64] os: [linux] - '@esbuild/netbsd-arm64@0.27.7': - resolution: {integrity: sha512-b6pqtrQdigZBwZxAn1UpazEisvwaIDvdbMbmrly7cDTMFnw/+3lVxxCTGOrkPVnsYIosJJXAsILG9XcQS+Yu6w==} + '@esbuild/netbsd-arm64@0.28.1': + resolution: {integrity: sha512-oks0DYbLwWMmaakTsCb+zL4E+aHRVLom9IJZOAthMQEPiQmydXHkziYEsGYRx0uNV/IjEKGAV941JzH02pflqw==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] - '@esbuild/netbsd-x64@0.27.7': - resolution: {integrity: sha512-OfatkLojr6U+WN5EDYuoQhtM+1xco+/6FSzJJnuWiUw5eVcicbyK3dq5EeV/QHT1uy6GoDhGbFpprUiHUYggrw==} + '@esbuild/netbsd-x64@0.28.1': + resolution: {integrity: sha512-aeL6lAnN89Hz43Mlh1G8ARasbuoYvSITDEx0tHh5b7jJnHcssqgjy9Yx430GDpmCa6OyrKoS0aNRjKundRizGg==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] - '@esbuild/openbsd-arm64@0.27.7': - resolution: {integrity: sha512-AFuojMQTxAz75Fo8idVcqoQWEHIXFRbOc1TrVcFSgCZtQfSdc1RXgB3tjOn/krRHENUB4j00bfGjyl2mJrU37A==} + '@esbuild/openbsd-arm64@0.28.1': + resolution: {integrity: sha512-MEFJe5C3R8pwXdZ5Y21oo6m7ePiS0d9pWucn99O/wvyJZChoIQKrQDxKrGeW8F5+T0okTHesAmDeiHDTIq0V/Q==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] - '@esbuild/openbsd-x64@0.27.7': - resolution: {integrity: sha512-+A1NJmfM8WNDv5CLVQYJ5PshuRm/4cI6WMZRg1by1GwPIQPCTs1GLEUHwiiQGT5zDdyLiRM/l1G0Pv54gvtKIg==} + '@esbuild/openbsd-x64@0.28.1': + resolution: {integrity: sha512-i/ZLIOafE0Z8cI/XANJAixoJL/uRAoS2xOA3rb0xN+KK0K177cMAsQYkzHtBrtMXAKuAc7HGgcWiZ/sRC1Nxgw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] - '@esbuild/openharmony-arm64@0.27.7': - resolution: {integrity: sha512-+KrvYb/C8zA9CU/g0sR6w2RBw7IGc5J2BPnc3dYc5VJxHCSF1yNMxTV5LQ7GuKteQXZtspjFbiuW5/dOj7H4Yw==} + '@esbuild/openharmony-arm64@0.28.1': + resolution: {integrity: sha512-ge+Z7EXFNt2BO1oAMsVpiQ8EwndV9i1xXerAeTIK7AtPs3bKFXQM7nlRxDSIUIMeueR1CNXxqztLzdNeReKBJg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] - '@esbuild/sunos-x64@0.27.7': - resolution: {integrity: sha512-ikktIhFBzQNt/QDyOL580ti9+5mL/YZeUPKU2ivGtGjdTYoqz6jObj6nOMfhASpS4GU4Q/Clh1QtxWAvcYKamA==} + '@esbuild/sunos-x64@0.28.1': + resolution: {integrity: sha512-BEjgtECkL3vY+SaSQ6nzVfiALUeFxpawyp8Jmf5PtYhf1Ug40N1h/hxlhts+f1FvSvarEigdxS3BlSMI2PJLcQ==} engines: {node: '>=18'} cpu: [x64] os: [sunos] - '@esbuild/win32-arm64@0.27.7': - resolution: {integrity: sha512-7yRhbHvPqSpRUV7Q20VuDwbjW5kIMwTHpptuUzV+AA46kiPze5Z7qgt6CLCK3pWFrHeNfDd1VKgyP4O+ng17CA==} + '@esbuild/win32-arm64@0.28.1': + resolution: {integrity: sha512-lCv9eK/H6ZJWbE7bh2nw54CZ9M2nupBxJcTsdk/QQnWkdSjKGuxmmH8/GWrlT1eMmZfn4dGcCjRte397WqfQXA==} engines: {node: '>=18'} cpu: [arm64] os: [win32] - '@esbuild/win32-ia32@0.27.7': - resolution: {integrity: sha512-SmwKXe6VHIyZYbBLJrhOoCJRB/Z1tckzmgTLfFYOfpMAx63BJEaL9ExI8x7v0oAO3Zh6D/Oi1gVxEYr5oUCFhw==} + '@esbuild/win32-ia32@0.28.1': + resolution: {integrity: sha512-zvb/mB2bSCoJOpoCBgYKKpX6YM6mJBlBUVUtVj41DlZJVEB6/0CKlRYxP5wWl1C1ILiCoAU5wZZ4q1P3qeS6Eg==} engines: {node: '>=18'} cpu: [ia32] os: [win32] - '@esbuild/win32-x64@0.27.7': - resolution: {integrity: sha512-56hiAJPhwQ1R4i+21FVF7V8kSD5zZTdHcVuRFMW0hn753vVfQN8xlx4uOPT4xoGH0Z/oVATuR82AiqSTDIpaHg==} + '@esbuild/win32-x64@0.28.1': + resolution: {integrity: sha512-bm4Mowrv+GXMlpWX++EcXw/iLyd1o3+bJkC2DkWXYVvgZCqD/bSj9ctZeAMC3cIxgjRVR2Dufaiu4YPxr5gW1A==} engines: {node: '>=18'} cpu: [x64] os: [win32] @@ -549,7 +553,7 @@ packages: resolution: {integrity: sha512-EZOrpDbkKotFAP7wPAQV1UIyoGOk4oX7ynWhBhLB7v+meMHbQhU16oPpIYGTTe4oFlhpryGpgpcZP/sin3hYuw==} peerDependencies: msw: ^2.4.9 - vite: ^5.0.0 || ^6.0.0 || ^7.0.0-0 + vite: ^7.3.5 peerDependenciesMeta: msw: optional: true @@ -626,8 +630,8 @@ packages: es-module-lexer@1.7.0: resolution: {integrity: sha512-jEQoCwk8hyb2AZziIOLhDqpm5+2ww5uIE6lkO/6jcOCusfk6LhMHpXXfBLXTZ7Ydyt0j4VoUQv6uGNYbdW+kBA==} - esbuild@0.27.7: - resolution: {integrity: sha512-IxpibTjyVnmrIQo5aqNpCgoACA/dTKLTlhMHihVHhdkxKyPO1uBBthumT0rdHmcsk9uMonIWS0m4FljWzILh3w==} + esbuild@0.28.1: + resolution: {integrity: sha512-HrJrvZv5ayxBzPfwphOoNzkzOIIlifzk0KJrGK2c8R4+LKpMtpYLQeUdjnwjWv/LZlkH2laZk+4w78pi99D4Vw==} engines: {node: '>=18'} hasBin: true @@ -824,8 +828,8 @@ packages: engines: {node: ^18.0.0 || ^20.0.0 || >=22.0.0} hasBin: true - vite@7.3.3: - resolution: {integrity: sha512-/4XH147Ui7OGTjg3HbdWe5arnZQSbfuRzdr9Ec7TQi5I7R+ir0Rlc9GIvD4v0XZurELqA035KVXJXpR61xhiTA==} + vite@7.3.6: + resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: @@ -963,82 +967,82 @@ snapshots: dependencies: zod: 4.4.3 - '@esbuild/aix-ppc64@0.27.7': + '@esbuild/aix-ppc64@0.28.1': optional: true - '@esbuild/android-arm64@0.27.7': + '@esbuild/android-arm64@0.28.1': optional: true - '@esbuild/android-arm@0.27.7': + '@esbuild/android-arm@0.28.1': optional: true - '@esbuild/android-x64@0.27.7': + '@esbuild/android-x64@0.28.1': optional: true - '@esbuild/darwin-arm64@0.27.7': + '@esbuild/darwin-arm64@0.28.1': optional: true - '@esbuild/darwin-x64@0.27.7': + '@esbuild/darwin-x64@0.28.1': optional: true - '@esbuild/freebsd-arm64@0.27.7': + '@esbuild/freebsd-arm64@0.28.1': optional: true - '@esbuild/freebsd-x64@0.27.7': + '@esbuild/freebsd-x64@0.28.1': optional: true - '@esbuild/linux-arm64@0.27.7': + '@esbuild/linux-arm64@0.28.1': optional: true - '@esbuild/linux-arm@0.27.7': + '@esbuild/linux-arm@0.28.1': optional: true - '@esbuild/linux-ia32@0.27.7': + '@esbuild/linux-ia32@0.28.1': optional: true - '@esbuild/linux-loong64@0.27.7': + '@esbuild/linux-loong64@0.28.1': optional: true - '@esbuild/linux-mips64el@0.27.7': + '@esbuild/linux-mips64el@0.28.1': optional: true - '@esbuild/linux-ppc64@0.27.7': + '@esbuild/linux-ppc64@0.28.1': optional: true - '@esbuild/linux-riscv64@0.27.7': + '@esbuild/linux-riscv64@0.28.1': optional: true - '@esbuild/linux-s390x@0.27.7': + '@esbuild/linux-s390x@0.28.1': optional: true - '@esbuild/linux-x64@0.27.7': + '@esbuild/linux-x64@0.28.1': optional: true - '@esbuild/netbsd-arm64@0.27.7': + '@esbuild/netbsd-arm64@0.28.1': optional: true - '@esbuild/netbsd-x64@0.27.7': + '@esbuild/netbsd-x64@0.28.1': optional: true - '@esbuild/openbsd-arm64@0.27.7': + '@esbuild/openbsd-arm64@0.28.1': optional: true - '@esbuild/openbsd-x64@0.27.7': + '@esbuild/openbsd-x64@0.28.1': optional: true - '@esbuild/openharmony-arm64@0.27.7': + '@esbuild/openharmony-arm64@0.28.1': optional: true - '@esbuild/sunos-x64@0.27.7': + '@esbuild/sunos-x64@0.28.1': optional: true - '@esbuild/win32-arm64@0.27.7': + '@esbuild/win32-arm64@0.28.1': optional: true - '@esbuild/win32-ia32@0.27.7': + '@esbuild/win32-ia32@0.28.1': optional: true - '@esbuild/win32-x64@0.27.7': + '@esbuild/win32-x64@0.28.1': optional: true '@jridgewell/sourcemap-codec@1.5.5': {} @@ -1200,13 +1204,13 @@ snapshots: chai: 5.3.3 tinyrainbow: 2.0.0 - '@vitest/mocker@3.2.6(vite@7.3.3(@types/node@25.9.1)(yaml@2.9.0))': + '@vitest/mocker@3.2.6(vite@7.3.6(@types/node@25.9.1)(yaml@2.9.0))': dependencies: '@vitest/spy': 3.2.6 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 7.3.3(@types/node@25.9.1)(yaml@2.9.0) + vite: 7.3.6(@types/node@25.9.1)(yaml@2.9.0) '@vitest/pretty-format@3.2.6': dependencies: @@ -1274,34 +1278,34 @@ snapshots: es-module-lexer@1.7.0: {} - esbuild@0.27.7: + esbuild@0.28.1: optionalDependencies: - '@esbuild/aix-ppc64': 0.27.7 - '@esbuild/android-arm': 0.27.7 - '@esbuild/android-arm64': 0.27.7 - '@esbuild/android-x64': 0.27.7 - '@esbuild/darwin-arm64': 0.27.7 - '@esbuild/darwin-x64': 0.27.7 - '@esbuild/freebsd-arm64': 0.27.7 - '@esbuild/freebsd-x64': 0.27.7 - '@esbuild/linux-arm': 0.27.7 - '@esbuild/linux-arm64': 0.27.7 - '@esbuild/linux-ia32': 0.27.7 - '@esbuild/linux-loong64': 0.27.7 - '@esbuild/linux-mips64el': 0.27.7 - '@esbuild/linux-ppc64': 0.27.7 - '@esbuild/linux-riscv64': 0.27.7 - '@esbuild/linux-s390x': 0.27.7 - '@esbuild/linux-x64': 0.27.7 - '@esbuild/netbsd-arm64': 0.27.7 - '@esbuild/netbsd-x64': 0.27.7 - '@esbuild/openbsd-arm64': 0.27.7 - '@esbuild/openbsd-x64': 0.27.7 - '@esbuild/openharmony-arm64': 0.27.7 - '@esbuild/sunos-x64': 0.27.7 - '@esbuild/win32-arm64': 0.27.7 - '@esbuild/win32-ia32': 0.27.7 - '@esbuild/win32-x64': 0.27.7 + '@esbuild/aix-ppc64': 0.28.1 + '@esbuild/android-arm': 0.28.1 + '@esbuild/android-arm64': 0.28.1 + '@esbuild/android-x64': 0.28.1 + '@esbuild/darwin-arm64': 0.28.1 + '@esbuild/darwin-x64': 0.28.1 + '@esbuild/freebsd-arm64': 0.28.1 + '@esbuild/freebsd-x64': 0.28.1 + '@esbuild/linux-arm': 0.28.1 + '@esbuild/linux-arm64': 0.28.1 + '@esbuild/linux-ia32': 0.28.1 + '@esbuild/linux-loong64': 0.28.1 + '@esbuild/linux-mips64el': 0.28.1 + '@esbuild/linux-ppc64': 0.28.1 + '@esbuild/linux-riscv64': 0.28.1 + '@esbuild/linux-s390x': 0.28.1 + '@esbuild/linux-x64': 0.28.1 + '@esbuild/netbsd-arm64': 0.28.1 + '@esbuild/netbsd-x64': 0.28.1 + '@esbuild/openbsd-arm64': 0.28.1 + '@esbuild/openbsd-x64': 0.28.1 + '@esbuild/openharmony-arm64': 0.28.1 + '@esbuild/sunos-x64': 0.28.1 + '@esbuild/win32-arm64': 0.28.1 + '@esbuild/win32-ia32': 0.28.1 + '@esbuild/win32-x64': 0.28.1 estree-walker@3.0.3: dependencies: @@ -1498,7 +1502,7 @@ snapshots: debug: 4.4.3 es-module-lexer: 1.7.0 pathe: 2.0.3 - vite: 7.3.3(@types/node@25.9.1)(yaml@2.9.0) + vite: 7.3.6(@types/node@25.9.1)(yaml@2.9.0) transitivePeerDependencies: - '@types/node' - jiti @@ -1513,9 +1517,9 @@ snapshots: - tsx - yaml - vite@7.3.3(@types/node@25.9.1)(yaml@2.9.0): + vite@7.3.6(@types/node@25.9.1)(yaml@2.9.0): dependencies: - esbuild: 0.27.7 + esbuild: 0.28.1 fdir: 6.5.0(picomatch@4.0.4) picomatch: 4.0.4 postcss: 8.5.15 @@ -1530,7 +1534,7 @@ snapshots: dependencies: '@types/chai': 5.2.3 '@vitest/expect': 3.2.6 - '@vitest/mocker': 3.2.6(vite@7.3.3(@types/node@25.9.1)(yaml@2.9.0)) + '@vitest/mocker': 3.2.6(vite@7.3.6(@types/node@25.9.1)(yaml@2.9.0)) '@vitest/pretty-format': 3.2.6 '@vitest/runner': 3.2.6 '@vitest/snapshot': 3.2.6 @@ -1548,7 +1552,7 @@ snapshots: tinyglobby: 0.2.16 tinypool: 1.1.1 tinyrainbow: 2.0.0 - vite: 7.3.3(@types/node@25.9.1)(yaml@2.9.0) + vite: 7.3.6(@types/node@25.9.1)(yaml@2.9.0) vite-node: 3.2.4(@types/node@25.9.1)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: