From 1b0badbf90f395f1177e2d5b5dad7bfce5572063 Mon Sep 17 00:00:00 2001 From: kevinccbsg Date: Tue, 21 Apr 2026 12:51:59 +0200 Subject: [PATCH 01/10] chore: update dependencies (openapi-mock-validator 0.2.0, twd-js 1.7.2, puppeteer 24.42.0) Co-Authored-By: Claude Opus 4.7 (1M context) --- package-lock.json | 69 +++++++++++++++-------------------------------- package.json | 6 ++--- 2 files changed, 25 insertions(+), 50 deletions(-) diff --git a/package-lock.json b/package-lock.json index a9b358c..217c3ca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,9 +9,9 @@ "version": "1.1.9", "license": "ISC", "dependencies": { - "openapi-mock-validator": "^0.1.4", - "puppeteer": "^24.41.0", - "twd-js": "^1.7.1" + "openapi-mock-validator": "^0.2.0", + "puppeteer": "^24.42.0", + "twd-js": "^1.7.2" }, "bin": { "twd-cli": "bin/twd-cli.js" @@ -155,31 +155,6 @@ } } }, - "node_modules/@emnapi/core": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", - "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "@emnapi/wasi-threads": "1.2.1", - "tslib": "^2.4.0" - } - }, - "node_modules/@emnapi/runtime": { - "version": "1.9.2", - "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", - "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", - "dev": true, - "license": "MIT", - "optional": true, - "peer": true, - "dependencies": { - "tslib": "^2.4.0" - } - }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", @@ -1048,18 +1023,18 @@ } }, "node_modules/bare-url": { - "version": "2.4.0", - "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.0.tgz", - "integrity": "sha512-NSTU5WN+fy/L0DDenfE8SXQna4voXuW0FHM7wH8i3/q9khUSchfPbPezO4zSFMnDGIf9YE+mt/RWhZgNRKRIXA==", + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/bare-url/-/bare-url-2.4.2.tgz", + "integrity": "sha512-/9a2j4ac6ckpmAHvod/ob7x439OAHst/drc2Clnq+reRYd/ovddwcF4LfoxHyNk5AuGBnPg+HqFjmE/Zpq6v0A==", "license": "Apache-2.0", "dependencies": { "bare-path": "^3.0.0" } }, "node_modules/basic-ftp": { - "version": "5.2.2", - "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.2.2.tgz", - "integrity": "sha512-1tDrzKsdCg70WGvbFss/ulVAxupNauGnOlgpyjKzeQxzyllBLS0CGLV7tjIXTK3ZQA9/FBEm9qyFFN1bciA6pw==", + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/basic-ftp/-/basic-ftp-5.3.0.tgz", + "integrity": "sha512-5K9eNNn7ywHPsYnFwjKgYH8Hf8B5emh7JKcPaVjjrMJFQQwGpwowEnZNEtHs7DfR7hCZsmaK3VA4HUK0YarT+w==", "license": "MIT", "engines": { "node": ">=10.0.0" @@ -2208,9 +2183,9 @@ } }, "node_modules/openapi-mock-validator": { - "version": "0.1.4", - "resolved": "https://registry.npmjs.org/openapi-mock-validator/-/openapi-mock-validator-0.1.4.tgz", - "integrity": "sha512-iQELUkb3aGKoyokSvi7/kkRsedTc0wpGQc5gzIvitz5aCkTQ/PdSkYGTMoKBmNLJX7NBukNhcgOpQz0InB5M5w==", + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/openapi-mock-validator/-/openapi-mock-validator-0.2.0.tgz", + "integrity": "sha512-7ssYWUFaDmGDlKLd6ARFDLgs81a0NzDSUhI1jFvi3MrOsRhqc5Q2X7xxB8mvWzL2Cj5Ywzkl265EdZ2hPdRAAg==", "license": "MIT", "dependencies": { "@apidevtools/json-schema-ref-parser": "^15.3.4", @@ -2434,9 +2409,9 @@ } }, "node_modules/puppeteer": { - "version": "24.41.0", - "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.41.0.tgz", - "integrity": "sha512-W6Fk0J3TPjjtwjXOyR/qf+YaL0H/Uq8HIgHcXG4mNM/IgbKMCH/HPyK0Fi2qbTU/QpSl9bCte2yBpGHKejTpIw==", + "version": "24.42.0", + "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-24.42.0.tgz", + "integrity": "sha512-94MoPfFp2eY3eYIMdINkez4IOP5TMHntlZbVx06fHlQTtiQiYgaY0L2Zzfod8PVUkPqP7m3Qlre2v8YS8cudPA==", "hasInstallScript": true, "license": "Apache-2.0", "dependencies": { @@ -2444,7 +2419,7 @@ "chromium-bidi": "14.0.0", "cosmiconfig": "^9.0.0", "devtools-protocol": "0.0.1595872", - "puppeteer-core": "24.41.0", + "puppeteer-core": "24.42.0", "typed-query-selector": "^2.12.1" }, "bin": { @@ -2455,9 +2430,9 @@ } }, "node_modules/puppeteer-core": { - "version": "24.41.0", - "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.41.0.tgz", - "integrity": "sha512-rLIUri7E/NQ3APSEYCCozaSJx0u8Tu9wxO6BJwnvXmIgILSK3L0TombaVh3izp1njAGrO6H2ru0hcIrLF+gWLw==", + "version": "24.42.0", + "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-24.42.0.tgz", + "integrity": "sha512-T4zXokk/izH01fYPhyyev1A4piWiOKrYq7CUFpdoYQxmOnXoV6YjUabmfIjCYkNspSoAXIxRid3Tw+Vg0fthYg==", "license": "Apache-2.0", "dependencies": { "@puppeteer/browsers": "2.13.0", @@ -2840,9 +2815,9 @@ "license": "0BSD" }, "node_modules/twd-js": { - "version": "1.7.1", - "resolved": "https://registry.npmjs.org/twd-js/-/twd-js-1.7.1.tgz", - "integrity": "sha512-wQWzwQ4xXGu+En8rVqwIOJ77UVakDQ3rNvuqksclxByvqBwjBvc2iof97GtHQ7LNwE+Z7REA6R5fGPLndqKS6Q==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/twd-js/-/twd-js-1.7.2.tgz", + "integrity": "sha512-e6syq8ZdMUdpf0fZSincADy5gwa9hYL7sFZ4+rLUM+NTncxG56FwQwA/kosk5yVeUVtWjtC8HW7104uqRkdoRw==", "license": "MIT", "dependencies": { "@testing-library/dom": "^10.4.1", diff --git a/package.json b/package.json index 2d6cbb4..144faba 100644 --- a/package.json +++ b/package.json @@ -23,9 +23,9 @@ "author": "", "license": "ISC", "dependencies": { - "openapi-mock-validator": "^0.1.4", - "puppeteer": "^24.41.0", - "twd-js": "^1.7.1" + "openapi-mock-validator": "^0.2.0", + "puppeteer": "^24.42.0", + "twd-js": "^1.7.2" }, "engines": { "node": ">=18.0.0" From 2139aaa976d65bf702ab94a2f36c2b8bda0e1aba Mon Sep 17 00:00:00 2001 From: kevinccbsg Date: Tue, 21 Apr 2026 12:52:58 +0200 Subject: [PATCH 02/10] test: add image/* photo endpoint to petstore fixture --- tests/fixtures/petstore-3.0.json | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/tests/fixtures/petstore-3.0.json b/tests/fixtures/petstore-3.0.json index 16d97a1..d967537 100644 --- a/tests/fixtures/petstore-3.0.json +++ b/tests/fixtures/petstore-3.0.json @@ -82,6 +82,28 @@ } } } + }, + "/v1/pets/{petId}/photo": { + "get": { + "parameters": [ + { + "name": "petId", + "in": "path", + "required": true, + "schema": { "type": "string" } + } + ], + "responses": { + "200": { + "description": "Pet photo", + "content": { + "image/*": { + "schema": { "type": "string", "format": "binary" } + } + } + } + } + } } } } From 37e720fe3d39b93aae6ad23aa4e8056a0ddb09b0 Mon Sep 17 00:00:00 2001 From: kevinccbsg Date: Tue, 21 Apr 2026 12:54:04 +0200 Subject: [PATCH 03/10] test: add failing test for Content-Type forwarding --- tests/contracts.test.js | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/contracts.test.js b/tests/contracts.test.js index f447943..55f1d01 100644 --- a/tests/contracts.test.js +++ b/tests/contracts.test.js @@ -256,3 +256,36 @@ describe('validateMocks with testId and occurrence', () => { expect(output.results[1].validation.valid).toBe(true); }); }); + +describe('validateMocks — Content-Type forwarding', () => { + let loadedContracts; + + beforeEach(async () => { + loadedContracts = await loadContracts( + [{ source: './tests/fixtures/petstore-3.0.json', baseUrl: '/api' }], + path.resolve(__dirname, '..'), + ); + }); + + it('forwards Content-Type from responseHeaders so image/* endpoints match', () => { + const mocks = new Map(); + mocks.set('getPetPhoto', { + alias: 'getPetPhoto', + url: '/api/v1/pets/123/photo', + method: 'GET', + status: 200, + response: 'fake-binary-data', + urlRegex: false, + responseHeaders: { 'Content-Type': 'image/png' }, + }); + + const output = validateMocks(mocks, loadedContracts); + + expect(output.results).toHaveLength(1); + const missingSchema = output.results[0].validation.warnings.filter( + w => w.type === 'MISSING_SCHEMA' + ); + expect(missingSchema).toHaveLength(0); + expect(output.results[0].validation.errors).toHaveLength(0); + }); +}); From 818999170e61378e9eee506651da9c21a5066151 Mon Sep 17 00:00:00 2001 From: kevinccbsg Date: Tue, 21 Apr 2026 12:54:56 +0200 Subject: [PATCH 04/10] fix: forward mock Content-Type to contract validator --- src/contracts.js | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/contracts.js b/src/contracts.js index 415d917..dc30969 100644 --- a/src/contracts.js +++ b/src/contracts.js @@ -2,6 +2,14 @@ import fs from 'fs'; import path from 'path'; import { OpenAPIMockValidator } from 'openapi-mock-validator'; +function readContentType(responseHeaders) { + if (!responseHeaders) return 'application/json'; + for (const [key, value] of Object.entries(responseHeaders)) { + if (key.toLowerCase() === 'content-type') return value; + } + return 'application/json'; +} + export async function loadContracts(contracts, workingDir) { const loaded = []; @@ -67,12 +75,13 @@ export function validateMocks(collectedMocks, contracts) { continue; } + const contentType = readContentType(mock.responseHeaders); const validation = contract.validator.validateResponse( pathMatch.path, mock.method, mock.status, mock.response, - { strict: contract.strict }, + { strict: contract.strict, contentType }, ); results.push({ From 5075458b247f961a3d858087cd47b1aff09e4756 Mon Sep 17 00:00:00 2001 From: kevinccbsg Date: Tue, 21 Apr 2026 12:55:56 +0200 Subject: [PATCH 05/10] test: add case-insensitivity and default tests for Content-Type --- tests/contracts.test.js | 60 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/tests/contracts.test.js b/tests/contracts.test.js index 55f1d01..1c4e8dd 100644 --- a/tests/contracts.test.js +++ b/tests/contracts.test.js @@ -288,4 +288,64 @@ describe('validateMocks — Content-Type forwarding', () => { expect(missingSchema).toHaveLength(0); expect(output.results[0].validation.errors).toHaveLength(0); }); + + it('resolves Content-Type when header key is lowercase', () => { + const mocks = new Map(); + mocks.set('getPetPhoto', { + alias: 'getPetPhoto', + url: '/api/v1/pets/123/photo', + method: 'GET', + status: 200, + response: 'fake-binary-data', + urlRegex: false, + responseHeaders: { 'content-type': 'image/png' }, + }); + const output = validateMocks(mocks, loadedContracts); + expect(output.results[0].validation.warnings.some(w => w.type === 'MISSING_SCHEMA')).toBe(false); + }); + + it('resolves Content-Type when header key is upper-case', () => { + const mocks = new Map(); + mocks.set('getPetPhoto', { + alias: 'getPetPhoto', + url: '/api/v1/pets/123/photo', + method: 'GET', + status: 200, + response: 'fake-binary-data', + urlRegex: false, + responseHeaders: { 'CONTENT-TYPE': 'image/png' }, + }); + const output = validateMocks(mocks, loadedContracts); + expect(output.results[0].validation.warnings.some(w => w.type === 'MISSING_SCHEMA')).toBe(false); + }); + + it('defaults to application/json when responseHeaders is missing', () => { + const mocks = new Map(); + mocks.set('getPets', { + alias: 'getPets', + url: '/api/v1/pets', + method: 'GET', + status: 200, + response: [{ id: 1, name: 'Fido' }], + urlRegex: false, + }); + const output = validateMocks(mocks, loadedContracts); + expect(output.results[0].validation.valid).toBe(true); + expect(output.results[0].validation.errors).toHaveLength(0); + }); + + it('defaults to application/json when responseHeaders has no Content-Type entry', () => { + const mocks = new Map(); + mocks.set('getPets', { + alias: 'getPets', + url: '/api/v1/pets', + method: 'GET', + status: 200, + response: [{ id: 1, name: 'Fido' }], + urlRegex: false, + responseHeaders: { 'X-Request-Id': 'abc123' }, + }); + const output = validateMocks(mocks, loadedContracts); + expect(output.results[0].validation.valid).toBe(true); + }); }); From d0db6a4a13169bd4f06c664ff314bf755f5e0646 Mon Sep 17 00:00:00 2001 From: kevinccbsg Date: Tue, 21 Apr 2026 12:57:11 +0200 Subject: [PATCH 06/10] test: assert mock collector preserves responseHeaders Co-Authored-By: Claude Sonnet 4.6 --- tests/runTests.test.js | 53 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/tests/runTests.test.js b/tests/runTests.test.js index 527e7e5..16e38e4 100644 --- a/tests/runTests.test.js +++ b/tests/runTests.test.js @@ -191,4 +191,57 @@ describe("runTests", () => { expect(result).toBe(true); }); + + it("preserves responseHeaders through the __twdCollectMock spread", async () => { + const testStatus = [{ id: 't-1', status: 'pass' }]; + const handlers = [{ id: 't-1', name: 'test1', type: 'test' }]; + + const page = { + goto: vi.fn(), + waitForSelector: vi.fn(), + exposeFunction: vi.fn(), + // Drive the registered __twdCollectMock callback from inside page.evaluate, + // mirroring how a real browser test would trigger it. + evaluate: vi.fn().mockImplementation(async () => { + const exposed = page.exposeFunction.mock.calls.find( + (c) => c[0] === '__twdCollectMock' + ); + expect(exposed).toBeDefined(); + const collectMock = exposed[1]; + await collectMock({ + alias: 'getPhoto', + url: '/v1/photo', + method: 'GET', + status: 200, + response: 'bin', + testId: 't-1', + responseHeaders: { 'Content-Type': 'image/png' }, + }); + return { handlers, testStatus }; + }), + }; + const browser = createMockBrowser(page); + vi.mocked(puppeteer.launch).mockResolvedValue(browser); + vi.mocked(loadConfig).mockReturnValue({ + ...defaultMockConfig, + contracts: [{ source: './openapi.json' }], + }); + vi.mocked(loadContracts).mockResolvedValue([{ /* sentinel contract */ }]); + + let capturedMocks; + vi.mocked(validateMocks).mockImplementation((mocks) => { + capturedMocks = mocks; + return { results: [], skipped: [] }; + }); + vi.mocked(printContractReport).mockReturnValue(false); + + await runTests(); + + expect(capturedMocks).toBeDefined(); + const entries = Array.from(capturedMocks.values()); + expect(entries).toHaveLength(1); + expect(entries[0].responseHeaders).toEqual({ 'Content-Type': 'image/png' }); + expect(entries[0].alias).toBe('getPhoto'); + expect(entries[0].occurrence).toBe(1); + }); }); From cfbdb4506abbe2c3623ddc6723454fe22d0978ed Mon Sep 17 00:00:00 2001 From: kevinccbsg Date: Tue, 21 Apr 2026 12:58:14 +0200 Subject: [PATCH 07/10] chore: update version to v1.1.10 --- CHANGELOG.md | 4 ++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e39ba92..59d4130 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,7 @@ +## 1.1.10 (2026-04-21) + +* fix: forward mock Content-Type to contract validator (avoids false-positive `MISSING_SCHEMA` for binary mocks) + ## 1.1.9 (2026-04-15) * chore: update twd-js to 1.7.1 diff --git a/package-lock.json b/package-lock.json index 217c3ca..c74c6df 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "twd-cli", - "version": "1.1.9", + "version": "1.1.10", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "twd-cli", - "version": "1.1.9", + "version": "1.1.10", "license": "ISC", "dependencies": { "openapi-mock-validator": "^0.2.0", diff --git a/package.json b/package.json index 144faba..6f1ef26 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "twd-cli", - "version": "1.1.9", + "version": "1.1.10", "description": "CLI tool for running TWD tests with Puppeteer", "type": "module", "main": "src/index.js", From 5ee01b72a90e631f157dee4a4383a9b6a60a9312 Mon Sep 17 00:00:00 2001 From: kevinccbsg Date: Tue, 21 Apr 2026 13:09:47 +0200 Subject: [PATCH 08/10] chore(test-example-app): bump twd-js to 1.7.2 for smoke testing Co-Authored-By: Claude Opus 4.7 (1M context) --- test-example-app/package-lock.json | 16 ++++++++-------- test-example-app/package.json | 2 +- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/test-example-app/package-lock.json b/test-example-app/package-lock.json index 30bba69..5d6295e 100644 --- a/test-example-app/package-lock.json +++ b/test-example-app/package-lock.json @@ -17,7 +17,7 @@ "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", "babel-plugin-react-compiler": "^1.0.0", - "twd-js": "^1.6.5", + "twd-js": "^1.7.2", "typescript": "~6.0.2", "vite": "^8.0.3" } @@ -1016,9 +1016,9 @@ } }, "node_modules/preact": { - "version": "10.29.0", - "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.0.tgz", - "integrity": "sha512-wSAGyk2bYR1c7t3SZ3jHcM6xy0lcBcDel6lODcs9ME6Th++Dx2KU+6D3HD8wMMKGA8Wpw7OMd3/4RGzYRpzwRg==", + "version": "10.29.1", + "resolved": "https://registry.npmjs.org/preact/-/preact-10.29.1.tgz", + "integrity": "sha512-gQCLc/vWroE8lIpleXtdJhTFDogTdZG9AjMUpVkDf2iTCNwYNWA+u16dL41TqUDJO4gm2IgrcMv3uTpjd4Pwmg==", "dev": true, "license": "MIT", "funding": { @@ -1154,9 +1154,9 @@ "optional": true }, "node_modules/twd-js": { - "version": "1.6.5", - "resolved": "https://registry.npmjs.org/twd-js/-/twd-js-1.6.5.tgz", - "integrity": "sha512-LNTX7uOPxH8vf1XJ3FA9vVKD+2xxOXxvliQ3NtfDZTTN2mQg0d9u8Ajd3UfMzoUgoloFG3IcApizAx7mN1ILoA==", + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/twd-js/-/twd-js-1.7.2.tgz", + "integrity": "sha512-e6syq8ZdMUdpf0fZSincADy5gwa9hYL7sFZ4+rLUM+NTncxG56FwQwA/kosk5yVeUVtWjtC8HW7104uqRkdoRw==", "dev": true, "license": "MIT", "dependencies": { @@ -1164,7 +1164,7 @@ "@testing-library/user-event": "^14.6.1", "@types/chai": "^5.2.3", "chai": "^6.2.2", - "preact": "^10.29.0" + "preact": "^10.29.1" }, "bin": { "twd-js": "dist/cli.js" diff --git a/test-example-app/package.json b/test-example-app/package.json index 82f7d25..2c4cdb2 100644 --- a/test-example-app/package.json +++ b/test-example-app/package.json @@ -18,7 +18,7 @@ "@types/react-dom": "^19.2.3", "@vitejs/plugin-react": "^6.0.1", "babel-plugin-react-compiler": "^1.0.0", - "twd-js": "^1.6.5", + "twd-js": "^1.7.2", "typescript": "~6.0.2", "vite": "^8.0.3" } From b593054e03728efc7cdca88a7a78864a6f6de45c Mon Sep 17 00:00:00 2001 From: kevinccbsg Date: Tue, 21 Apr 2026 13:21:46 +0200 Subject: [PATCH 09/10] test(test-example-app): add binary Content-Type smoke tests MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adds /products/{id}/thumbnail endpoint (image/*) to products-3.0.json - Adds 4 mocks exercising the new Content-Type forwarding: - image/png and image/jpeg against image/* spec → should validate cleanly - application/xml against JSON-only /api/products → should warn (MISSING_SCHEMA) - No responseHeaders against image-only endpoint → should warn (defaults to JSON, no match) All four endpoints use contract mode 'warn' so CI does not fail on the intentional negative cases. Co-Authored-By: Claude Opus 4.7 (1M context) --- test-example-app/contracts/products-3.0.json | 23 +++++++++++ test-example-app/src/App.twd.test.ts | 43 ++++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/test-example-app/contracts/products-3.0.json b/test-example-app/contracts/products-3.0.json index b999949..34f6111 100644 --- a/test-example-app/contracts/products-3.0.json +++ b/test-example-app/contracts/products-3.0.json @@ -74,6 +74,29 @@ } } }, + "/products/{productId}/thumbnail": { + "get": { + "operationId": "getProductThumbnail", + "parameters": [ + { + "name": "productId", + "in": "path", + "required": true, + "schema": { "type": "string", "format": "uuid" } + } + ], + "responses": { + "200": { + "description": "Product thumbnail image", + "content": { + "image/*": { + "schema": { "type": "string", "format": "binary" } + } + } + } + } + } + }, "/settings": { "get": { "operationId": "getSettings", diff --git a/test-example-app/src/App.twd.test.ts b/test-example-app/src/App.twd.test.ts index 3804065..5612de8 100644 --- a/test-example-app/src/App.twd.test.ts +++ b/test-example-app/src/App.twd.test.ts @@ -897,3 +897,46 @@ describe("Contract Validation - Events Mismatches (OpenAPI 3.1 — error mode)", }); }); }); + +// ── Content-Type forwarding — binary mocks vs image/* spec ─────────── + +describe("Contract Validation - Content-Type forwarding (Products API)", () => { + it("should match image/png mock against image/* spec entry", async () => { + twd.mockRequest("getProductThumbnailPng", { + method: "GET", + url: "/api/products/550e8400-e29b-41d4-a716-446655440000/thumbnail", + status: 200, + response: "fake-png-bytes", + responseHeaders: { "Content-Type": "image/png" }, + }); + }); + + it("should match image/jpeg mock against image/* spec entry", async () => { + twd.mockRequest("getProductThumbnailJpeg", { + method: "GET", + url: "/api/products/550e8400-e29b-41d4-a716-446655440001/thumbnail", + status: 200, + response: "fake-jpeg-bytes", + responseHeaders: { "content-type": "image/jpeg" }, + }); + }); + + it("should warn when non-binary Content-Type has no matching spec entry", async () => { + twd.mockRequest("getProductsAsXml", { + method: "GET", + url: "/api/products", + status: 200, + response: "", + responseHeaders: { "Content-Type": "application/xml" }, + }); + }); + + it("should warn when mock has no responseHeaders against image-only endpoint", async () => { + twd.mockRequest("getProductThumbnailNoHeader", { + method: "GET", + url: "/api/products/550e8400-e29b-41d4-a716-446655440002/thumbnail", + status: 200, + response: "fake-bytes", + }); + }); +}); From a8d64ece94357b9b1915c412f853dcf3ccace406 Mon Sep 17 00:00:00 2001 From: kevinccbsg Date: Tue, 21 Apr 2026 13:27:07 +0200 Subject: [PATCH 10/10] fix(lockfile): regenerate package-lock.json to restore @emnapi entries CI was failing with `npm ci` errors because the previous dep-bump commit's lockfile was missing top-level @emnapi/core and @emnapi/runtime entries that are required by transitive peers of @napi-rs/wasm-runtime. Regenerating via a fresh `npm install` restores them. All 177 tests pass and `npm ci` now succeeds locally. Co-Authored-By: Claude Opus 4.7 (1M context) --- package-lock.json | 337 +++++++++++++++++++++++++--------------------- 1 file changed, 181 insertions(+), 156 deletions(-) diff --git a/package-lock.json b/package-lock.json index c74c6df..f54e12c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -129,9 +129,9 @@ } }, "node_modules/@conventional-changelog/git-client": { - "version": "2.6.0", - "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.6.0.tgz", - "integrity": "sha512-T+uPDciKf0/ioNNDpMGc8FDsehJClZP0yR3Q5MN6wE/Y/1QZ7F+80OgznnTCOlMEG4AV0LvH2UJi3C/nBnaBUg==", + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/@conventional-changelog/git-client/-/git-client-2.7.0.tgz", + "integrity": "sha512-j7A8/LBEQ+3rugMzPXoKYzyUPpw/0CBQCyvtTR7Lmu4olG4yRC/Tfkq79Mr3yuPs0SUitlO2HwGP3gitMJnRFw==", "dev": true, "license": "MIT", "dependencies": { @@ -144,7 +144,7 @@ }, "peerDependencies": { "conventional-commits-filter": "^5.0.0", - "conventional-commits-parser": "^6.3.0" + "conventional-commits-parser": "^6.4.0" }, "peerDependenciesMeta": { "conventional-commits-filter": { @@ -155,6 +155,31 @@ } } }, + "node_modules/@emnapi/core": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.9.2.tgz", + "integrity": "sha512-UC+ZhH3XtczQYfOlu3lNEkdW/p4dsJ1r/bP7H8+rhao3TTTMO1ATq/4DdIi23XuGoFY+Cz0JmCbdVl0hz9jZcA==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "@emnapi/wasi-threads": "1.2.1", + "tslib": "^2.4.0" + } + }, + "node_modules/@emnapi/runtime": { + "version": "1.9.2", + "resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.9.2.tgz", + "integrity": "sha512-3U4+MIWHImeyu1wnmVygh5WlgfYDtyf0k8AbLhMFxOipihf6nrWC4syIm/SwEeec0mNSafiiNnMJwbza/Is6Lw==", + "dev": true, + "license": "MIT", + "optional": true, + "peer": true, + "dependencies": { + "tslib": "^2.4.0" + } + }, "node_modules/@emnapi/wasi-threads": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.2.1.tgz", @@ -195,9 +220,9 @@ } }, "node_modules/@napi-rs/wasm-runtime": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.3.tgz", - "integrity": "sha512-xK9sGVbJWYb08+mTJt3/YV24WxvxpXcXtP6B172paPZ+Ts69Re9dAr7lKwJoeIx8OoeuimEiRZ7umkiUVClmmQ==", + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.1.4.tgz", + "integrity": "sha512-3NQNNgA1YSlJb/kMH1ildASP9HW7/7kYnRI2szWJaofaS1hWmbGI4H+d3+22aGzXXN9IJ+n+GiFVcGipJP18ow==", "dev": true, "license": "MIT", "optional": true, @@ -214,9 +239,9 @@ } }, "node_modules/@oxc-project/types": { - "version": "0.124.0", - "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.124.0.tgz", - "integrity": "sha512-VBFWMTBvHxS11Z5Lvlr3IWgrwhMTXV+Md+EQF0Xf60+wAdsGFTBx7X7K/hP4pi8N7dcm1RvcHwDxZ16Qx8keUg==", + "version": "0.126.0", + "resolved": "https://registry.npmjs.org/@oxc-project/types/-/types-0.126.0.tgz", + "integrity": "sha512-oGfVtjAgwQVVpfBrbtk4e1XDyWHRFta6BS3GWVzrF8xYBT2VGQAk39yJS/wFSMrZqoiCU4oghT3Ch0HaHGIHcQ==", "dev": true, "license": "MIT", "funding": { @@ -245,9 +270,9 @@ } }, "node_modules/@rolldown/binding-android-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-YYe6aWruPZDtHNpwu7+qAHEMbQ/yRl6atqb/AhznLTnD3UY99Q1jE7ihLSahNWkF4EqRPVC4SiR4O0UkLK02tA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-android-arm64/-/binding-android-arm64-1.0.0-rc.16.tgz", + "integrity": "sha512-rhY3k7Bsae9qQfOtph2Pm2jZEA+s8Gmjoz4hhmx70K9iMQ/ddeae+xhRQcM5IuVx5ry1+bGfkvMn7D6MJggVSA==", "cpu": [ "arm64" ], @@ -262,9 +287,9 @@ } }, "node_modules/@rolldown/binding-darwin-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-oArR/ig8wNTPYsXL+Mzhs0oxhxfuHRfG7Ikw7jXsw8mYOtk71W0OkF2VEVh699pdmzjPQsTjlD1JIOoHkLP1Fg==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-arm64/-/binding-darwin-arm64-1.0.0-rc.16.tgz", + "integrity": "sha512-rNz0yK078yrNn3DrdgN+PKiMOW8HfQ92jQiXxwX8yW899ayV00MLVdaCNeVBhG/TbH3ouYVObo8/yrkiectkcQ==", "cpu": [ "arm64" ], @@ -279,9 +304,9 @@ } }, "node_modules/@rolldown/binding-darwin-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-YzeVqOqjPYvUbJSWJ4EDL8ahbmsIXQpgL3JVipmN+MX0XnXMeWomLN3Fb+nwCmP/jfyqte5I3XRSm7OfQrbyxw==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-darwin-x64/-/binding-darwin-x64-1.0.0-rc.16.tgz", + "integrity": "sha512-r/OmdR00HmD4i79Z//xO06uEPOq5hRXdhw7nzkxQxwSavs3PSHa1ijntdpOiZ2mzOQ3fVVu8C1M19FoNM+dMUQ==", "cpu": [ "x64" ], @@ -296,9 +321,9 @@ } }, "node_modules/@rolldown/binding-freebsd-x64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.15.tgz", - "integrity": "sha512-9Erhx956jeQ0nNTyif1+QWAXDRD38ZNjr//bSHrt6wDwB+QkAfl2q6Mn1k6OBPerznjRmbM10lgRb1Pli4xZPw==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-freebsd-x64/-/binding-freebsd-x64-1.0.0-rc.16.tgz", + "integrity": "sha512-KcRE5w8h0OnjUatG8pldyD14/CQ5Phs1oxfR+3pKDjboHRo9+MkqQaiIZlZRpsxC15paeXme/I127tUa9TXJ6g==", "cpu": [ "x64" ], @@ -313,9 +338,9 @@ } }, "node_modules/@rolldown/binding-linux-arm-gnueabihf": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.15.tgz", - "integrity": "sha512-cVwk0w8QbZJGTnP/AHQBs5yNwmpgGYStL88t4UIaqcvYJWBfS0s3oqVLZPwsPU6M0zlW4GqjP0Zq5MnAGwFeGA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm-gnueabihf/-/binding-linux-arm-gnueabihf-1.0.0-rc.16.tgz", + "integrity": "sha512-bT0guA1bpxEJ/ZhTRniQf7rNF8ybvXOuWbNIeLABaV5NGjx4EtOWBTSRGWFU9ZWVkPOZ+HNFP8RMcBokBiZ0Kg==", "cpu": [ "arm" ], @@ -330,9 +355,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-eBZ/u8iAK9SoHGanqe/jrPnY0JvBN6iXbVOsbO38mbz+ZJsaobExAm1Iu+rxa4S1l2FjG0qEZn4Rc6X8n+9M+w==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-+tHktCHWV8BDQSjemUqm/Jl/TPk3QObCTIjmdDy/nlupcujZghmKK2962LYrqFpWu+ai01AN/REOH3NEpqvYQg==", "cpu": [ "arm64" ], @@ -347,9 +372,9 @@ } }, "node_modules/@rolldown/binding-linux-arm64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-ZvRYMGrAklV9PEkgt4LQM6MjQX2P58HPAuecwYObY2DhS2t35R0I810bKi0wmaYORt6m/2Sm+Z+nFgb0WhXNcQ==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.0.0-rc.16.tgz", + "integrity": "sha512-3fPzdREH806oRLxpTWW1Gt4tQHs0TitZFOECB2xzCFLPKnSOy90gwA7P29cksYilFO6XVRY1kzga0cL2nRjKPg==", "cpu": [ "arm64" ], @@ -364,9 +389,9 @@ } }, "node_modules/@rolldown/binding-linux-ppc64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-VDpgGBzgfg5hLg+uBpCLoFG5kVvEyafmfxGUV0UHLcL5irxAK7PKNeC2MwClgk6ZAiNhmo9FLhRYgvMmedLtnQ==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-ppc64-gnu/-/binding-linux-ppc64-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-EKwI1tSrLs7YVw+JPJT/G2dJQ1jl9qlTTTEG0V2Ok/RdOenRfBw2PQdLPyjhIu58ocdBfP7vIRN/pvMsPxs/AQ==", "cpu": [ "ppc64" ], @@ -381,9 +406,9 @@ } }, "node_modules/@rolldown/binding-linux-s390x-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-y1uXY3qQWCzcPgRJATPSOUP4tCemh4uBdY7e3EZbVwCJTY3gLJWnQABgeUetvED+bt1FQ01OeZwvhLS2bpNrAQ==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-s390x-gnu/-/binding-linux-s390x-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-Uknladnb3Sxqu6SEcqBldQyJUpk8NleooZEc0MbRBJ4inEhRYWZX0NJu12vNf2mqAq7gsofAxHrGghiUYjhaLQ==", "cpu": [ "s390x" ], @@ -398,9 +423,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-gnu": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.15.tgz", - "integrity": "sha512-023bTPBod7J3Y/4fzAN6QtpkSABR0rigtrwaP+qSEabUh5zf6ELr9Nc7GujaROuPY3uwdSIXWrvhn1KxOvurWA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.0.0-rc.16.tgz", + "integrity": "sha512-FIb8+uG49sZBtLTn+zt1AJ20TqVcqWeSIyoVt0or7uAWesgKaHbiBh6OpA/k9v0LTt+PTrb1Lao133kP4uVxkg==", "cpu": [ "x64" ], @@ -415,9 +440,9 @@ } }, "node_modules/@rolldown/binding-linux-x64-musl": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.15.tgz", - "integrity": "sha512-witB2O0/hU4CgfOOKUoeFgQ4GktPi1eEbAhaLAIpgD6+ZnhcPkUtPsoKKHRzmOoWPZue46IThdSgdo4XneOLYw==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-linux-x64-musl/-/binding-linux-x64-musl-1.0.0-rc.16.tgz", + "integrity": "sha512-RuERhF9/EgWxZEXYWCOaViUWHIboceK4/ivdtQ3R0T44NjLkIIlGIAVAuCddFxsZ7vnRHtNQUrt2vR2n2slB2w==", "cpu": [ "x64" ], @@ -432,9 +457,9 @@ } }, "node_modules/@rolldown/binding-openharmony-arm64": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.15.tgz", - "integrity": "sha512-UCL68NJ0Ud5zRipXZE9dF5PmirzJE4E4BCIOOssEnM7wLDsxjc6Qb0sGDxTNRTP53I6MZpygyCpY8Aa8sPfKPg==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-openharmony-arm64/-/binding-openharmony-arm64-1.0.0-rc.16.tgz", + "integrity": "sha512-mXcXnvd9GpazCxeUCCnZ2+YF7nut+ZOEbE4GtaiPtyY6AkhZWbK70y1KK3j+RDhjVq5+U8FySkKRb/+w0EeUwA==", "cpu": [ "arm64" ], @@ -449,9 +474,9 @@ } }, "node_modules/@rolldown/binding-wasm32-wasi": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.15.tgz", - "integrity": "sha512-ApLruZq/ig+nhaE7OJm4lDjayUnOHVUa77zGeqnqZ9pn0ovdVbbNPerVibLXDmWeUZXjIYIT8V3xkT58Rm9u5Q==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-wasm32-wasi/-/binding-wasm32-wasi-1.0.0-rc.16.tgz", + "integrity": "sha512-3Q2KQxnC8IJOLqXmUMoYwyIPZU9hzRbnHaoV3Euz+VVnjZKcY8ktnNP8T9R4/GGQtb27C/UYKABxesKWb8lsvQ==", "cpu": [ "wasm32" ], @@ -461,16 +486,16 @@ "dependencies": { "@emnapi/core": "1.9.2", "@emnapi/runtime": "1.9.2", - "@napi-rs/wasm-runtime": "^1.1.3" + "@napi-rs/wasm-runtime": "^1.1.4" }, "engines": { - "node": ">=14.0.0" + "node": "^20.19.0 || >=22.12.0" } }, "node_modules/@rolldown/binding-win32-arm64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-KmoUoU7HnN+Si5YWJigfTws1jz1bKBYDQKdbLspz0UaqjjFkddHsqorgiW1mxcAj88lYUE6NC/zJNwT+SloqtA==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.0.0-rc.16.tgz", + "integrity": "sha512-tj7XRemQcOcFwv7qhpUxMTBbI5mWMlE4c1Omhg5+h8GuLXzyj8HviYgR+bB2DMDgRqUE+jiDleqSCRjx4aYk/Q==", "cpu": [ "arm64" ], @@ -485,9 +510,9 @@ } }, "node_modules/@rolldown/binding-win32-x64-msvc": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.15.tgz", - "integrity": "sha512-3P2A8L+x75qavWLe/Dll3EYBJLQmtkJN8rfh+U/eR3MqMgL/h98PhYI+JFfXuDPgPeCB7iZAKiqii5vqOvnA0g==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.0.0-rc.16.tgz", + "integrity": "sha512-PH5DRZT+F4f2PTXRXR8uJxnBq2po/xFtddyabTJVJs/ZYVHqXPEgNIr35IHTEa6bpa0Q8Awg+ymkTaGnKITw4g==", "cpu": [ "x64" ], @@ -502,9 +527,9 @@ } }, "node_modules/@rolldown/pluginutils": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.15.tgz", - "integrity": "sha512-UromN0peaE53IaBRe9W7CjrZgXl90fqGpK+mIZbA3qSTeYqg3pqpROBdIPvOG3F5ereDHNwoHBI2e50n1BDr1g==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/@rolldown/pluginutils/-/pluginutils-1.0.0-rc.16.tgz", + "integrity": "sha512-45+YtqxLYKDWQouLKCrpIZhke+nXxhsw+qAHVzHDVwttyBlHNBVs2K25rDXrZzhpTp9w1FlAlvweV1H++fdZoA==", "dev": true, "license": "MIT" }, @@ -644,13 +669,13 @@ "peer": true }, "node_modules/@types/node": { - "version": "25.5.0", - "resolved": "https://registry.npmjs.org/@types/node/-/node-25.5.0.tgz", - "integrity": "sha512-jp2P3tQMSxWugkCUKLRPVUpGaL5MVFwF8RDuSRztfwgN1wmqJeMSbKlnEtQqU8UrhTmzEmZdu2I6v2dpp7XIxw==", + "version": "25.6.0", + "resolved": "https://registry.npmjs.org/@types/node/-/node-25.6.0.tgz", + "integrity": "sha512-+qIYRKdNYJwY3vRCZMdJbPLJAtGjQBudzZzdzwQYkEPQd+PJGixUL5QfvCLDaULoLv+RhT3LDkwEfKaAkgSmNQ==", "license": "MIT", "optional": true, "dependencies": { - "undici-types": "~7.18.0" + "undici-types": "~7.19.0" } }, "node_modules/@types/normalize-package-data": { @@ -671,15 +696,15 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.4.tgz", - "integrity": "sha512-x7FptB5oDruxNPDNY2+S8tCh0pcq7ymCe1gTHcsp733jYjrJl8V1gMUlVysuCD9Kz46Xz9t1akkv08dPcYDs1w==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-4.1.5.tgz", + "integrity": "sha512-38C0/Ddb7HcRG0Z4/DUem8x57d2p9jYgp18mkaYswEOQBGsI1CG4f/hjm0ZCeaJfWhSZ4k7jgs29V1Zom7Ki9A==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "@bcoe/v8-coverage": "^1.0.2", - "@vitest/utils": "4.1.4", + "@vitest/utils": "4.1.5", "ast-v8-to-istanbul": "^1.0.0", "istanbul-lib-coverage": "^3.2.2", "istanbul-lib-report": "^3.0.1", @@ -693,8 +718,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "4.1.4", - "vitest": "4.1.4" + "@vitest/browser": "4.1.5", + "vitest": "4.1.5" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -703,16 +728,16 @@ } }, "node_modules/@vitest/expect": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.4.tgz", - "integrity": "sha512-iPBpra+VDuXmBFI3FMKHSFXp3Gx5HfmSCE8X67Dn+bwephCnQCaB7qWK2ldHa+8ncN8hJU8VTMcxjPpyMkUjww==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-4.1.5.tgz", + "integrity": "sha512-PWBaRY5JoKuRnHlUHfpV/KohFylaDZTupcXN1H9vYryNLOnitSw60Mw9IAE2r67NbwwzBw/Cc/8q9BK3kIX8Kw==", "dev": true, "license": "MIT", "dependencies": { "@standard-schema/spec": "^1.1.0", "@types/chai": "^5.2.2", - "@vitest/spy": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", "chai": "^6.2.2", "tinyrainbow": "^3.1.0" }, @@ -721,13 +746,13 @@ } }, "node_modules/@vitest/mocker": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.4.tgz", - "integrity": "sha512-R9HTZBhW6yCSGbGQnDnH3QHfJxokKN4KB+Yvk9Q1le7eQNYwiCyKxmLmurSpFy6BzJanSLuEUDrD+j97Q+ZLPg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-4.1.5.tgz", + "integrity": "sha512-/x2EmFC4mT4NNzqvC3fmesuV97w5FC903KPmey4gsnJiMQ3Be1IlDKVaDaG8iqaLFHqJ2FVEkxZk5VmeLjIItw==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/spy": "4.1.4", + "@vitest/spy": "4.1.5", "estree-walker": "^3.0.3", "magic-string": "^0.30.21" }, @@ -748,9 +773,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.4.tgz", - "integrity": "sha512-ddmDHU0gjEUyEVLxtZa7xamrpIefdEETu3nZjWtHeZX4QxqJ7tRxSteHVXJOcr8jhiLoGAhkK4WJ3WqBpjx42A==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-4.1.5.tgz", + "integrity": "sha512-7I3q6l5qr03dVfMX2wCo9FxwSJbPdwKjy2uu/YPpU3wfHvIL4QHwVRp57OfGrDFeUJ8/8QdfBKIV12FTtLn00g==", "dev": true, "license": "MIT", "dependencies": { @@ -761,13 +786,13 @@ } }, "node_modules/@vitest/runner": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.4.tgz", - "integrity": "sha512-xTp7VZ5aXP5ZJrn15UtJUWlx6qXLnGtF6jNxHepdPHpMfz/aVPx+htHtgcAL2mDXJgKhpoo2e9/hVJsIeFbytQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-4.1.5.tgz", + "integrity": "sha512-2D+o7Pr82IEO46YPpoA/YU0neeyr6FTerQb5Ro7BUnBuv6NQtT/kmVnczngiMEBhzgqz2UZYl5gArejsyERDSQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/utils": "4.1.4", + "@vitest/utils": "4.1.5", "pathe": "^2.0.3" }, "funding": { @@ -775,14 +800,14 @@ } }, "node_modules/@vitest/snapshot": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.4.tgz", - "integrity": "sha512-MCjCFgaS8aZz+m5nTcEcgk/xhWv0rEH4Yl53PPlMXOZ1/Ka2VcZU6CJ+MgYCZbcJvzGhQRjVrGQNZqkGPttIKw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-4.1.5.tgz", + "integrity": "sha512-zypXEt4KH/XgKGPUz4eC2AvErYx0My5hfL8oDb1HzGFpEk1P62bxSohdyOmvz+d9UJwanI68MKwr2EquOaOgMQ==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/pretty-format": "4.1.5", + "@vitest/utils": "4.1.5", "magic-string": "^0.30.21", "pathe": "^2.0.3" }, @@ -791,9 +816,9 @@ } }, "node_modules/@vitest/spy": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.4.tgz", - "integrity": "sha512-XxNdAsKW7C+FLydqFJLb5KhJtl3PGCMmYwFRfhvIgxJvLSXhhVI1zM8f1qD3Zg7RCjTSzDVyct6sghs9UEgBEQ==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-4.1.5.tgz", + "integrity": "sha512-2lNOsh6+R2Idnf1TCZqSwYlKN2E/iDlD8sgU59kYVl+OMDmvldO1VDk39smRfpUNwYpNRVn3w4YfuC7KfbBnkQ==", "dev": true, "license": "MIT", "funding": { @@ -801,13 +826,13 @@ } }, "node_modules/@vitest/utils": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.4.tgz", - "integrity": "sha512-13QMT+eysM5uVGa1rG4kegGYNp6cnQcsTc67ELFbhNLQO+vgsygtYJx2khvdt4gVQqSSpC/KT5FZZxUpP3Oatw==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-4.1.5.tgz", + "integrity": "sha512-76wdkrmfXfqGjueGgnb45ITPyUi1ycZ4IHgC2bhPDUfWHklY/q3MdLOAB+TF1e6xfl8NxNY0ZYaPCFNWSsw3Ug==", "dev": true, "license": "MIT", "dependencies": { - "@vitest/pretty-format": "4.1.4", + "@vitest/pretty-format": "4.1.5", "convert-source-map": "^2.0.0", "tinyrainbow": "^3.1.0" }, @@ -2303,9 +2328,9 @@ } }, "node_modules/postcss": { - "version": "8.5.9", - "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.9.tgz", - "integrity": "sha512-7a70Nsot+EMX9fFU3064K/kdHWZqGVY+BADLyXc8Dfv+mTLLVl6JzJpPaCZ2kQL9gIJvKXSLMHhqdRRjwQeFtw==", + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.5.10.tgz", + "integrity": "sha512-pMMHxBOZKFU6HgAZ4eyGnwXF/EvPGGqUr0MnZ5+99485wwW41kW91A4LOGxSHhgugZmSChL5AlElNdwlNgcnLQ==", "dev": true, "funding": [ { @@ -2448,9 +2473,9 @@ } }, "node_modules/react": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react/-/react-19.2.4.tgz", - "integrity": "sha512-9nfp2hYpCwOjAN+8TZFGhtWEwgvWHXqESH8qT89AT/lWklpLON22Lc8pEtnpsZz7VmawabSU0gCjnj8aC0euHQ==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react/-/react-19.2.5.tgz", + "integrity": "sha512-llUJLzz1zTUBrskt2pwZgLq59AemifIftw4aB7JxOqf1HY2FDaGDxgwpAPVzHU1kdWabH7FauP4i1oEeer2WCA==", "license": "MIT", "peer": true, "engines": { @@ -2458,16 +2483,16 @@ } }, "node_modules/react-dom": { - "version": "19.2.4", - "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.4.tgz", - "integrity": "sha512-AXJdLo8kgMbimY95O2aKQqsz2iWi9jMgKJhRBAxECE4IFxfcazB2LmzloIoibJI3C12IlY20+KFaLv+71bUJeQ==", + "version": "19.2.5", + "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-19.2.5.tgz", + "integrity": "sha512-J5bAZz+DXMMwW/wV3xzKke59Af6CHY7G4uYLN1OvBcKEsWOs4pQExj86BBKamxl/Ik5bx9whOrvBlSDfWzgSag==", "license": "MIT", "peer": true, "dependencies": { "scheduler": "^0.27.0" }, "peerDependencies": { - "react": "^19.2.4" + "react": "^19.2.5" } }, "node_modules/react-is": { @@ -2504,14 +2529,14 @@ } }, "node_modules/rolldown": { - "version": "1.0.0-rc.15", - "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.15.tgz", - "integrity": "sha512-Ff31guA5zT6WjnGp0SXw76X6hzGRk/OQq2hE+1lcDe+lJdHSgnSX6nK3erbONHyCbpSj9a9E+uX/OvytZoWp2g==", + "version": "1.0.0-rc.16", + "resolved": "https://registry.npmjs.org/rolldown/-/rolldown-1.0.0-rc.16.tgz", + "integrity": "sha512-rzi5WqKzEZw3SooTt7cgm4eqIoujPIyGcJNGFL7iPEuajQw7vxMHUkXylu4/vhCkJGXsgRmxqMKXUpT6FEgl0g==", "dev": true, "license": "MIT", "dependencies": { - "@oxc-project/types": "=0.124.0", - "@rolldown/pluginutils": "1.0.0-rc.15" + "@oxc-project/types": "=0.126.0", + "@rolldown/pluginutils": "1.0.0-rc.16" }, "bin": { "rolldown": "bin/cli.mjs" @@ -2520,21 +2545,21 @@ "node": "^20.19.0 || >=22.12.0" }, "optionalDependencies": { - "@rolldown/binding-android-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-arm64": "1.0.0-rc.15", - "@rolldown/binding-darwin-x64": "1.0.0-rc.15", - "@rolldown/binding-freebsd-x64": "1.0.0-rc.15", - "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.15", - "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.15", - "@rolldown/binding-linux-x64-musl": "1.0.0-rc.15", - "@rolldown/binding-openharmony-arm64": "1.0.0-rc.15", - "@rolldown/binding-wasm32-wasi": "1.0.0-rc.15", - "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.15", - "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.15" + "@rolldown/binding-android-arm64": "1.0.0-rc.16", + "@rolldown/binding-darwin-arm64": "1.0.0-rc.16", + "@rolldown/binding-darwin-x64": "1.0.0-rc.16", + "@rolldown/binding-freebsd-x64": "1.0.0-rc.16", + "@rolldown/binding-linux-arm-gnueabihf": "1.0.0-rc.16", + "@rolldown/binding-linux-arm64-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-arm64-musl": "1.0.0-rc.16", + "@rolldown/binding-linux-ppc64-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-s390x-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-x64-gnu": "1.0.0-rc.16", + "@rolldown/binding-linux-x64-musl": "1.0.0-rc.16", + "@rolldown/binding-openharmony-arm64": "1.0.0-rc.16", + "@rolldown/binding-wasm32-wasi": "1.0.0-rc.16", + "@rolldown/binding-win32-arm64-msvc": "1.0.0-rc.16", + "@rolldown/binding-win32-x64-msvc": "1.0.0-rc.16" } }, "node_modules/scheduler": { @@ -2664,9 +2689,9 @@ "license": "MIT" }, "node_modules/std-env": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.0.0.tgz", - "integrity": "sha512-zUMPtQ/HBY3/50VbpkupYHbRroTRZJPRLvreamgErJVys0ceuzMkD44J/QjqhHjOzK42GQ3QZIeFG1OYfOtKqQ==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/std-env/-/std-env-4.1.0.tgz", + "integrity": "sha512-Rq7ybcX2RuC55r9oaPVEW7/xu3tj8u4GeBYHBWCychFtzMIr86A7e3PPEBPT37sHStKX3+TiX/Fr/ACmJLVlLQ==", "dev": true, "license": "MIT" }, @@ -2858,9 +2883,9 @@ } }, "node_modules/undici-types": { - "version": "7.18.2", - "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.18.2.tgz", - "integrity": "sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==", + "version": "7.19.2", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.19.2.tgz", + "integrity": "sha512-qYVnV5OEm2AW8cJMCpdV20CDyaN3g0AjDlOGf1OW4iaDEx8MwdtChUp4zu4H0VP3nDRF/8RKWH+IPp9uW0YGZg==", "license": "MIT", "optional": true }, @@ -2876,18 +2901,18 @@ } }, "node_modules/vite": { - "version": "8.0.8", - "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.8.tgz", - "integrity": "sha512-dbU7/iLVa8KZALJyLOBOQ88nOXtNG8vxKuOT4I2mD+Ya70KPceF4IAmDsmU0h1Qsn5bPrvsY9HJstCRh3hG6Uw==", + "version": "8.0.9", + "resolved": "https://registry.npmjs.org/vite/-/vite-8.0.9.tgz", + "integrity": "sha512-t7g7GVRpMXjNpa67HaVWI/8BWtdVIQPCL2WoozXXA7LBGEFK4AkkKkHx2hAQf5x1GZSlcmEDPkVLSGahxnEEZw==", "dev": true, "license": "MIT", "peer": true, "dependencies": { "lightningcss": "^1.32.0", "picomatch": "^4.0.4", - "postcss": "^8.5.8", - "rolldown": "1.0.0-rc.15", - "tinyglobby": "^0.2.15" + "postcss": "^8.5.10", + "rolldown": "1.0.0-rc.16", + "tinyglobby": "^0.2.16" }, "bin": { "vite": "bin/vite.js" @@ -2955,20 +2980,20 @@ } }, "node_modules/vitest": { - "version": "4.1.4", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.4.tgz", - "integrity": "sha512-tFuJqTxKb8AvfyqMfnavXdzfy3h3sWZRWwfluGbkeR7n0HUev+FmNgZ8SDrRBTVrVCjgH5cA21qGbCffMNtWvg==", + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-4.1.5.tgz", + "integrity": "sha512-9Xx1v3/ih3m9hN+SbfkUyy0JAs72ap3r7joc87XL6jwF0jGg6mFBvQ1SrwaX+h8BlkX6Hz9shdd1uo6AF+ZGpg==", "dev": true, "license": "MIT", "peer": true, "dependencies": { - "@vitest/expect": "4.1.4", - "@vitest/mocker": "4.1.4", - "@vitest/pretty-format": "4.1.4", - "@vitest/runner": "4.1.4", - "@vitest/snapshot": "4.1.4", - "@vitest/spy": "4.1.4", - "@vitest/utils": "4.1.4", + "@vitest/expect": "4.1.5", + "@vitest/mocker": "4.1.5", + "@vitest/pretty-format": "4.1.5", + "@vitest/runner": "4.1.5", + "@vitest/snapshot": "4.1.5", + "@vitest/spy": "4.1.5", + "@vitest/utils": "4.1.5", "es-module-lexer": "^2.0.0", "expect-type": "^1.3.0", "magic-string": "^0.30.21", @@ -2996,12 +3021,12 @@ "@edge-runtime/vm": "*", "@opentelemetry/api": "^1.9.0", "@types/node": "^20.0.0 || ^22.0.0 || >=24.0.0", - "@vitest/browser-playwright": "4.1.4", - "@vitest/browser-preview": "4.1.4", - "@vitest/browser-webdriverio": "4.1.4", - "@vitest/coverage-istanbul": "4.1.4", - "@vitest/coverage-v8": "4.1.4", - "@vitest/ui": "4.1.4", + "@vitest/browser-playwright": "4.1.5", + "@vitest/browser-preview": "4.1.5", + "@vitest/browser-webdriverio": "4.1.5", + "@vitest/coverage-istanbul": "4.1.5", + "@vitest/coverage-v8": "4.1.5", + "@vitest/ui": "4.1.5", "happy-dom": "*", "jsdom": "*", "vite": "^6.0.0 || ^7.0.0 || ^8.0.0"