From 7b70ba4708ac8e719d947e07f325c4e73e2f9674 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 13:07:32 +0000 Subject: [PATCH 1/2] chore: benchmark the downgraders with CodSpeed Mirror middleapi/standard-server: `pnpm bench` runs Vitest benchmarks through the CodSpeed plugin, and a CodSpeed workflow runs them in simulation mode on pushes to main and on pull requests, so a performance change shows up on the pull request that causes it. The benches in packages/downgrader/benches cover both spec and schema converters of each step, plus the chained 3.2 to 3.0 path, on: - the official corpus the tests validate against - a generated CRUD API at 10 and 100 resources that uses every feature each step rewrites (removed parts to inline, $defs, $id, webhooks, query operations, item schemas, ...) - the shared and cyclic reference graphs that once made conversion exponential, so a regression there costs orders of magnitude READMEs gain the CodSpeed badge, the bench command, and a short performance section for the downgrader. Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LjCihASFt61Eqjq9jfAoE5 --- .github/workflows/codspeed.yaml | 29 + README.md | 6 + package.json | 2 + packages/downgrader/README.md | 9 + packages/downgrader/benches/__shared__/api.ts | 334 ++++++++ .../downgrader/benches/__shared__/graphs.ts | 104 +++ .../downgrader/benches/__shared__/schemas.ts | 99 +++ packages/downgrader/benches/chained.bench.ts | 27 + .../downgrader/benches/v3.1-to-v3.0.bench.ts | 55 ++ .../downgrader/benches/v3.2-to-v3.1.bench.ts | 50 ++ packages/downgrader/tsconfig.json | 1 + packages/types/README.md | 3 + packages/types/tsconfig.json | 1 + pnpm-lock.yaml | 771 +++++++++++++----- vitest.config.ts | 6 + 15 files changed, 1300 insertions(+), 197 deletions(-) create mode 100644 .github/workflows/codspeed.yaml create mode 100644 packages/downgrader/benches/__shared__/api.ts create mode 100644 packages/downgrader/benches/__shared__/graphs.ts create mode 100644 packages/downgrader/benches/__shared__/schemas.ts create mode 100644 packages/downgrader/benches/chained.bench.ts create mode 100644 packages/downgrader/benches/v3.1-to-v3.0.bench.ts create mode 100644 packages/downgrader/benches/v3.2-to-v3.1.bench.ts diff --git a/.github/workflows/codspeed.yaml b/.github/workflows/codspeed.yaml new file mode 100644 index 0000000..de63dc4 --- /dev/null +++ b/.github/workflows/codspeed.yaml @@ -0,0 +1,29 @@ +name: CodSpeed + +on: + push: + branches: [main] + pull_request: + branches: [main] + # `workflow_dispatch` allows CodSpeed to trigger backtest + # performance analysis in order to generate initial data. + workflow_dispatch: + +permissions: + contents: read + id-token: write + +jobs: + benchmarks: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v7 + + - uses: pnpm/action-setup@v6 + + - run: pnpm i + + - uses: CodSpeedHQ/action@v4 + with: + mode: simulation + run: pnpm run bench diff --git a/README.md b/README.md index a27cbe6..f610a99 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,9 @@ weekly downloads + + CodSpeed + MIT License @@ -32,8 +35,11 @@ pnpm install pnpm test pnpm lint pnpm type:check +pnpm bench ``` +`pnpm bench` runs the benchmarks in [`packages/downgrader/benches`](https://github.com/middleapi/openapi-spec/tree/main/packages/downgrader/benches). [CodSpeed](https://app.codspeed.io/middleapi/openapi-spec) runs them on every push to `main` and every pull request, and reports any change in performance on the pull request. + ## Sponsors Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going through [GitHub Sponsors](https://github.com/sponsors/dinwwwh) or [Open Collective](https://opencollective.com/middleapi). Every bit helps! 🚀 diff --git a/package.json b/package.json index 8eae86b..fac837d 100644 --- a/package.json +++ b/package.json @@ -8,6 +8,7 @@ "type:check": "pnpm run -r type:check && tsc", "test": "vitest run", "test:coverage": "vitest run --coverage", + "bench": "vitest bench --run", "lint": "eslint .", "lint:fix": "eslint --fix .", "repo:fix": "sherif --fix", @@ -15,6 +16,7 @@ }, "devDependencies": { "@antfu/eslint-config": "^9.5.1", + "@codspeed/vitest-plugin": "^5.7.1", "@seriousme/openapi-schema-validator": "^2.9.1", "@types/node": "^26.4.0", "@vitest/coverage-v8": "^4.1.11", diff --git a/packages/downgrader/README.md b/packages/downgrader/README.md index 21b9f33..967a7b9 100644 --- a/packages/downgrader/README.md +++ b/packages/downgrader/README.md @@ -7,6 +7,9 @@ weekly downloads + + CodSpeed + MIT License @@ -247,6 +250,12 @@ A schema is _loosened_ when the conversion removes a restriction from it or a su - A schema without `type` that has `contentEncoding: base64`, or `contentMediaType` without `contentEncoding`, gains `type: string`, so non-string values the original accepts are rejected. - Non-standard keywords are kept, although the official 3.0 schema forbids them. +## Performance + +An object reached through many `$ref`s or shared references is converted once and reused, so the work grows with the size of the document, not with the number of paths through its references, even where they form cycles. + +[Benchmarks](https://github.com/middleapi/openapi-spec/tree/main/packages/downgrader/benches) cover each converter on the official example documents, generated APIs, and worst-case reference graphs. [CodSpeed](https://app.codspeed.io/middleapi/openapi-spec) runs them on every pull request to catch regressions. + ## Sponsors Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going through [GitHub Sponsors](https://github.com/sponsors/dinwwwh) or [Open Collective](https://opencollective.com/middleapi). Every bit helps! 🚀 diff --git a/packages/downgrader/benches/__shared__/api.ts b/packages/downgrader/benches/__shared__/api.ts new file mode 100644 index 0000000..22c41e2 --- /dev/null +++ b/packages/downgrader/benches/__shared__/api.ts @@ -0,0 +1,334 @@ +import type * as OpenAPIV3_1 from '@openapi-spec/types/v3.1' +import type * as OpenAPIV3_2 from '@openapi-spec/types/v3.2' + +// A CRUD API the way a framework would emit it: one tag, three schemas, and +// a few paths and a webhook per resource, around shared schemas, parameters, +// responses, and security schemes. It uses what each step has to rewrite: +// 3.1 schemas with `null` in `type`, `const`, numeric exclusive bounds, +// `examples`, `$defs`, and an `$id`; Path Items reused from +// `components.pathItems`; webhooks; mutual TLS; and, in 3.2 only, `$self`, +// the `query` method, streamed `itemSchema`s, reusable Media Type Objects, +// Server `name`, Tag `summary`, `parent`, and `kind`, Response `summary`, +// `dataValue` examples, and the device authorization flow. +// +// Every call builds a fresh tree that shares no objects, like a document +// parsed from JSON, so a conversion walks every node. + +type Document = Omit + +function ref(pointer: string): OpenAPIV3_2.ReferenceObject { + return { $ref: pointer } +} + +function schemaRef(name: string): OpenAPIV3_2.SchemaObject { + return { $ref: `#/components/schemas/${name}` } +} + +function json(schema: OpenAPIV3_2.SchemaObject): Record { + return { 'application/json': { schema } } +} + +function errorResponse(v32: boolean): OpenAPIV3_2.ReferenceObject | OpenAPIV3_2.ResponseObject { + return ref(`#/components/responses/${v32 ? 'Problem' : 'Error'}`) +} + +function sharedSchemas(): Record { + return { + Status: { + type: 'string', + enum: ['active', 'archived', 'deleted'], + default: 'active', + }, + Address: { + $id: 'https://api.example.com/schemas/address', + type: 'object', + required: ['line1', 'country'], + properties: { + line1: { type: 'string' }, + line2: { type: ['string', 'null'] }, + postalCode: { type: 'string', pattern: '^[0-9A-Z -]{3,10}$' }, + country: { $ref: '#/$defs/Country' }, + }, + $defs: { + Country: { type: 'string', minLength: 2, maxLength: 2, examples: ['US'] }, + }, + }, + User: { + type: 'object', + required: ['id', 'email'], + properties: { + id: { type: 'string', format: 'uuid', readOnly: true }, + email: { type: 'string', format: 'email' }, + name: { type: ['string', 'null'] }, + address: schemaRef('Address'), + }, + }, + Error: { + type: 'object', + required: ['type', 'title', 'status'], + properties: { + type: { type: 'string', format: 'uri' }, + title: { type: 'string' }, + status: { type: 'integer', minimum: 400, exclusiveMaximum: 600 }, + detail: { type: ['string', 'null'] }, + errors: { + type: 'array', + items: { + type: 'object', + required: ['path', 'message'], + properties: { path: { type: 'string' }, message: { type: 'string' } }, + }, + }, + }, + }, + } +} + +function resourceSchemas(name: string, parent: string | undefined): Record { + const fields = (): Record => ({ + name: { type: 'string', minLength: 1, maxLength: 120 }, + description: { type: ['string', 'null'], maxLength: 2000 }, + price: { type: 'number', exclusiveMinimum: 0, examples: [9.99] }, + quantity: { type: 'integer', minimum: 0, default: 0 }, + tags: { type: 'array', items: { type: 'string' }, uniqueItems: true, maxItems: 20 }, + metadata: { type: 'object', additionalProperties: { type: ['string', 'number', 'boolean', 'null'] } }, + dimensions: schemaRef(`${name}/$defs/Dimensions`), + }) + return { + [name]: { + type: 'object', + description: `A ${name} as the API returns it.`, + required: ['id', 'kind', 'name', 'status', 'createdAt'], + properties: { + id: { type: 'string', format: 'uuid', readOnly: true }, + kind: { const: name }, + status: schemaRef('Status'), + ...fields(), + owner: schemaRef('User'), + parent: parent === undefined ? { type: 'null' } : { anyOf: [schemaRef(parent), { type: 'null' }] }, + createdAt: { type: 'string', format: 'date-time', readOnly: true }, + updatedAt: { type: ['string', 'null'], format: 'date-time', readOnly: true }, + }, + $defs: { + Dimensions: { + type: 'object', + required: ['width', 'height'], + properties: { + width: { type: 'number', exclusiveMinimum: 0 }, + height: { type: 'number', exclusiveMinimum: 0 }, + unit: { type: 'string', enum: ['cm', 'in'], default: 'cm' }, + }, + }, + }, + }, + [`${name}Input`]: { + type: 'object', + required: ['name'], + properties: fields(), + additionalProperties: false, + }, + [`${name}Page`]: { + type: 'object', + required: ['items'], + properties: { + items: { type: 'array', items: schemaRef(name) }, + nextCursor: { type: ['string', 'null'] }, + }, + }, + } +} + +function build(resources: number, v32: boolean): Document { + const tags: OpenAPIV3_2.TagObject[] = v32 ? [{ name: 'resources', summary: 'Resources', kind: 'nav' }] : [] + const paths: OpenAPIV3_2.PathsObject = {} + const webhooks: Record = {} + const schemas = sharedSchemas() + const examples: Record = {} + const pathItems: Record = {} + + for (let index = 0; index < resources; index++) { + const name = `Resource${index}` + const path = `/resources-${index}` as const + const tag = `resource-${index}` + const success = (status: string, schema: OpenAPIV3_2.SchemaObject): OpenAPIV3_2.ResponsesObject => ({ + [status]: { description: `The ${name}.`, ...(v32 && { summary: name }), content: json(schema) }, + default: errorResponse(v32), + }) + + tags.push({ name: tag, description: `Operations on ${name}.`, ...(v32 && { summary: name, parent: 'resources', kind: 'nav' }) }) + Object.assign(schemas, resourceSchemas(name, index === 0 ? undefined : `Resource${index - 1}`)) + examples[name] = { + summary: `A sample ${name}.`, + [v32 ? 'dataValue' : 'value']: { id: '3fa85f64-5717-4562-b3fc-2c963f66afa6', kind: name, name: 'Sample', status: 'active', createdAt: '2026-01-01T00:00:00Z' }, + } + + paths[path] = { + get: { + operationId: `list${name}`, + tags: [tag], + parameters: [ref('#/components/parameters/Cursor'), ref('#/components/parameters/Limit'), { name: 'status', in: 'query', schema: schemaRef('Status') }], + responses: success('200', schemaRef(`${name}Page`)), + }, + post: { + operationId: `create${name}`, + tags: [tag], + requestBody: { required: true, content: json(schemaRef(`${name}Input`)) }, + responses: success('201', schemaRef(name)), + callbacks: { + created: { + '{$request.header.X-Callback-Url}': { + post: { requestBody: { content: json(schemaRef(name)) }, responses: { 204: { description: 'Received.' } } }, + }, + }, + }, + }, + ...(v32 && { + query: { + operationId: `search${name}`, + tags: [tag], + requestBody: { content: json({ type: 'object', properties: { text: { type: 'string' }, status: schemaRef('Status') } }) }, + responses: success('200', schemaRef(`${name}Page`)), + }, + }), + } + paths[`${path}/{id}`] = { $ref: `#/components/pathItems/${name}` } + paths[`${path}/{id}/attachments`] = { + post: { + operationId: `attach${name}`, + tags: [tag], + parameters: [ref('#/components/parameters/Id')], + requestBody: { + content: { + 'multipart/form-data': { + schema: { + type: 'object', + required: ['file'], + properties: { + file: { type: 'string', contentMediaType: 'application/octet-stream' }, + caption: { type: ['string', 'null'] }, + }, + }, + }, + }, + }, + responses: { 204: { description: 'Attached.' }, default: errorResponse(v32) }, + }, + } + if (v32) { + paths[`${path}/events`] = { + get: { + operationId: `stream${name}`, + tags: [tag], + responses: { + 200: { description: `A stream of ${name} changes.`, content: { 'application/jsonl': { itemSchema: schemaRef(name) } } }, + default: errorResponse(v32), + }, + }, + } + } + + pathItems[name] = { + parameters: [ref('#/components/parameters/Id')], + get: { + operationId: `get${name}`, + tags: [tag], + responses: { + 200: { description: `The ${name}.`, content: { 'application/json': { schema: schemaRef(name), examples: { sample: ref(`#/components/examples/${name}`) } } } }, + 404: ref('#/components/responses/NotFound'), + default: errorResponse(v32), + }, + }, + patch: { + operationId: `update${name}`, + tags: [tag], + requestBody: { content: { 'application/merge-patch+json': { schema: schemaRef(`${name}Input`) } } }, + responses: success('200', schemaRef(name)), + }, + delete: { + operationId: `delete${name}`, + tags: [tag], + security: [{ oauth2: ['write'] }, { mtls: [] }], + responses: { 204: { description: 'Deleted.' }, default: errorResponse(v32) }, + }, + } + webhooks[`${tag}.updated`] = { + post: { + requestBody: { content: json(schemaRef(name)) }, + responses: { 200: { description: 'Received.' } }, + }, + } + } + + return { + ...(v32 && { $self: 'https://api.example.com/openapi.json' }), + info: { + title: 'Example API', + summary: 'A CRUD API to benchmark conversions with.', + version: '1.0.0', + license: { name: 'MIT', identifier: 'MIT' }, + }, + jsonSchemaDialect: v32 ? 'https://spec.openapis.org/oas/3.2/dialect/2025-09-17' : 'https://spec.openapis.org/oas/3.1/dialect/base', + servers: [ + { url: 'https://api.example.com/v1', description: 'Production', ...(v32 && { name: 'production' }) }, + { + url: 'https://{region}.api.example.com/v1', + description: 'Regional', + variables: { region: { default: 'us', enum: ['us', 'eu'] } }, + ...(v32 && { name: 'regional' }), + }, + ], + security: [{ bearer: [] }, { oauth2: ['read'] }], + tags, + paths, + webhooks, + components: { + schemas, + parameters: { + Id: { name: 'id', in: 'path', required: true, schema: { type: 'string', format: 'uuid' } }, + Cursor: { name: 'cursor', in: 'query', schema: { type: ['string', 'null'] } }, + Limit: { name: 'limit', in: 'query', schema: { type: 'integer', minimum: 1, maximum: 100, default: 20 } }, + }, + responses: { + NotFound: { description: 'Not found.', content: { 'application/problem+json': { schema: schemaRef('Error') } } }, + ...(v32 + ? { Problem: { summary: 'Problem', description: 'A problem.', content: { 'application/problem+json': ref('#/components/mediaTypes/Problem') } } } + : { Error: { description: 'A problem.', content: { 'application/problem+json': { schema: schemaRef('Error') } } } }), + }, + examples, + pathItems, + securitySchemes: { + bearer: { type: 'http', scheme: 'bearer', bearerFormat: 'JWT' }, + apiKey: { type: 'apiKey', name: 'X-API-Key', in: 'header' }, + mtls: { type: 'mutualTLS' }, + oauth2: { + type: 'oauth2', + flows: { + authorizationCode: { + authorizationUrl: 'https://auth.example.com/authorize', + tokenUrl: 'https://auth.example.com/token', + scopes: { read: 'Read resources.', write: 'Change resources.' }, + }, + ...(v32 && { + deviceAuthorization: { + deviceAuthorizationUrl: 'https://auth.example.com/device', + tokenUrl: 'https://auth.example.com/token', + scopes: { read: 'Read resources.', write: 'Change resources.' }, + }, + }), + }, + }, + }, + ...(v32 && { mediaTypes: { Problem: { description: 'A problem.', schema: schemaRef('Error') } } }), + }, + } +} + +/** A 3.1 API with `resources` resources. */ +export function createApiV31(resources: number): OpenAPIV3_1.OpenAPIObject { + return { openapi: '3.1.2', ...build(resources, false) } as OpenAPIV3_1.OpenAPIObject +} + +/** A 3.2 API with `resources` resources. */ +export function createApiV32(resources: number): OpenAPIV3_2.OpenAPIObject { + return { openapi: '3.2.0', ...build(resources, true) } +} diff --git a/packages/downgrader/benches/__shared__/graphs.ts b/packages/downgrader/benches/__shared__/graphs.ts new file mode 100644 index 0000000..2d4db28 --- /dev/null +++ b/packages/downgrader/benches/__shared__/graphs.ts @@ -0,0 +1,104 @@ +import type * as OpenAPIV3_1 from '@openapi-spec/types/v3.1' +import type * as OpenAPIV3_2 from '@openapi-spec/types/v3.2' + +// Small inputs that reach the same objects along exponentially many paths, +// or around cycles. Converting each object once keeps the work linear, so a +// regression here costs orders of magnitude, not percent. The tests that +// count this work are the ones named "... once". + +function info(): OpenAPIV3_2.InfoObject { + return { title: 'Graph', version: '1.0.0' } +} + +/** + * `depth` nested objects whose two properties share one child, as a + * dereferencing parser leaves them: 2^depth paths reach the leaf. + */ +export function schemaDiamond(depth: number): OpenAPIV3_2.SchemaObject { + let node: OpenAPIV3_2.SchemaObject = { type: ['string', 'null'] } + for (let level = 0; level < depth; level++) { + node = { type: 'object', properties: { left: node, right: node } } + } + return node +} + +function diamondLevel(level: number, depth: number, pointer: (level: number) => string): OpenAPIV3_2.SchemaObject { + return level === depth + ? { type: ['string', 'null'] } + : { type: 'object', properties: { left: { $ref: pointer(level + 1) }, right: { $ref: pointer(level + 1) } } } +} + +/** + * A diamond like `schemaDiamond`, but each level is a schema in the webhooks, + * which 3.0 lacks, and its two properties reach the next level through + * `$ref`s. Every level has to be inlined. + */ +export function referenceDiamondV31(depth: number): OpenAPIV3_1.OpenAPIObject { + const pointer = (level: number): string => `#/webhooks/w${level}/post/requestBody/content/application~1json/schema` + const webhooks: Record = {} + for (let level = 0; level <= depth; level++) { + webhooks[`w${level}`] = { post: { requestBody: { content: { 'application/json': { schema: diamondLevel(level, depth, pointer) } } } } } + } + return { openapi: '3.1.2', info: info(), components: { schemas: { Root: { $ref: pointer(0) } } }, webhooks } +} + +/** + * A diamond like `referenceDiamondV31`, with each level in + * `components.mediaTypes`, which 3.1 lacks. + */ +export function referenceDiamondV32(depth: number): OpenAPIV3_2.OpenAPIObject { + const pointer = (level: number): string => `#/components/mediaTypes/M${level}/schema` + const mediaTypes: Record = {} + for (let level = 0; level <= depth; level++) { + mediaTypes[`M${level}`] = { schema: diamondLevel(level, depth, pointer) } + } + return { openapi: '3.2.0', info: info(), components: { mediaTypes, schemas: { Root: { $ref: pointer(0) } } } } +} + +/** + * Path Items `base` and `h0` … `h`, where every `h` has a `$ref` to + * `base` and callbacks to every `h`, itself included, so about k! paths + * run through them. `pointer` says where they live. + */ +function cyclicCallbackGraph(k: number, pointer: (name: string) => string): Record { + const items: Record = { base: { get: { responses: { 200: { description: 'ok' } } } } } + for (let i = 0; i < k; i++) { + const callbacks = Object.fromEntries(Array.from({ length: k }, (_, j) => [`c${j}`, { '{$request.body#/url}': { $ref: pointer(`h${j}`) } }])) + items[`h${i}`] = { $ref: pointer('base'), post: { callbacks, responses: { 200: { description: 'ok' } } } } + } + return items +} + +/** A cyclic callback graph in the webhooks, which 3.0 lacks, entered from a path. */ +export function callbackGraphV31(k: number): OpenAPIV3_1.OpenAPIObject { + const webhooks = cyclicCallbackGraph(k, name => `#/webhooks/${name}`) as Record + return { openapi: '3.1.2', info: info(), paths: { '/a': { $ref: '#/webhooks/h0' } }, webhooks } +} + +/** A cyclic callback graph in a `query` operation, which 3.1 lacks, entered from a path. */ +export function callbackGraphV32(k: number): OpenAPIV3_2.OpenAPIObject { + const graph = cyclicCallbackGraph(k, name => `#/paths/~1q/query/callbacks/cb/${name}`) + return { + openapi: '3.2.0', + info: info(), + paths: { + '/a': { $ref: '#/paths/~1q/query/callbacks/cb/h0' }, + '/q': { query: { callbacks: { cb: graph }, responses: { 200: { description: 'ok' } } } }, + }, + } +} + +/** + * `length` Path Items in `components.pathItems`, which 3.0 lacks, each a + * `$ref` to the next, with a path entering the chain at every one of them. + */ +export function pathItemChainV31(length: number): OpenAPIV3_1.OpenAPIObject { + const pointer = (index: number): string => `#/components/pathItems/P${index}` + const pathItems: Record = { [`P${length}`]: { get: { responses: { 200: { description: 'ok' } } } } } + const paths: OpenAPIV3_1.PathsObject = {} + for (let index = 0; index < length; index++) { + pathItems[`P${index}`] = { $ref: pointer(index + 1) } + paths[`/p${index}`] = { $ref: pointer(index) } + } + return { openapi: '3.1.2', info: info(), components: { pathItems }, paths } +} diff --git a/packages/downgrader/benches/__shared__/schemas.ts b/packages/downgrader/benches/__shared__/schemas.ts new file mode 100644 index 0000000..8d0c73c --- /dev/null +++ b/packages/downgrader/benches/__shared__/schemas.ts @@ -0,0 +1,99 @@ +import type * as OpenAPIV3_2 from '@openapi-spec/types/v3.2' + +// Standalone Schema Objects, in the shape a schema library emits them. The +// 3.1 and 3.2 dialects share these keywords, so both steps take the same +// inputs. + +/** One nullable property, the smallest common call. */ +export const PROPERTY_SCHEMA: OpenAPIV3_2.SchemaObject = { + type: ['string', 'null'], + format: 'email', + maxLength: 254, + examples: ['ada@example.com'], +} + +/** + * An order with its definitions in `$defs`, reached through `$ref`s from + * many places, including a recursive category tree, and the keywords 3.0 + * lacks: `const`, numeric exclusive bounds, `prefixItems`, `if`/`then`/`else`, + * `patternProperties`, `dependentRequired`, and `contentEncoding`. + */ +export const ORDER_SCHEMA: OpenAPIV3_2.SchemaObject = { + type: 'object', + required: ['id', 'status', 'customer', 'lines', 'total'], + properties: { + id: { type: 'string', format: 'uuid' }, + status: { enum: ['pending', 'paid', 'shipped', 'cancelled'] }, + customer: { + type: 'object', + required: ['email'], + properties: { + email: { type: 'string', format: 'email' }, + name: { type: ['string', 'null'] }, + billing: { $ref: '#/$defs/Address' }, + shipping: { anyOf: [{ $ref: '#/$defs/Address' }, { type: 'null' }] }, + }, + }, + lines: { type: 'array', minItems: 1, items: { $ref: '#/$defs/Line' } }, + discounts: { + type: 'array', + items: { + oneOf: [ + { type: 'object', required: ['kind', 'percent'], properties: { kind: { const: 'percent' }, percent: { type: 'number', exclusiveMinimum: 0, maximum: 100 } } }, + { type: 'object', required: ['kind', 'amount'], properties: { kind: { const: 'fixed' }, amount: { $ref: '#/$defs/Money' } } }, + ], + discriminator: { propertyName: 'kind' }, + }, + }, + total: { $ref: '#/$defs/Money' }, + location: { type: 'array', prefixItems: [{ type: 'number' }, { type: 'number' }], items: false }, + giftWrap: { type: 'boolean' }, + giftMessage: { type: ['string', 'null'], maxLength: 500 }, + invoice: { type: 'string', contentEncoding: 'base64', contentMediaType: 'application/pdf' }, + metadata: { type: 'object', patternProperties: { '^x-': { type: 'string' } } }, + createdAt: { type: 'string', format: 'date-time', examples: ['2026-01-01T00:00:00Z'] }, + }, + dependentRequired: { giftMessage: ['giftWrap'] }, + if: { properties: { status: { const: 'shipped' } } }, + then: { required: ['shippedAt'], properties: { shippedAt: { type: 'string', format: 'date-time' } } }, + else: { properties: { shippedAt: { type: 'null' } } }, + $defs: { + Money: { + type: 'object', + required: ['amount', 'currency'], + properties: { + amount: { type: 'number', minimum: 0 }, + currency: { type: 'string', pattern: '^[A-Z]{3}$', examples: ['USD'] }, + }, + }, + Address: { + type: 'object', + required: ['line1', 'country'], + properties: { + line1: { type: 'string' }, + line2: { type: ['string', 'null'] }, + postalCode: { type: ['string', 'null'] }, + country: { type: 'string', minLength: 2, maxLength: 2 }, + }, + }, + Line: { + type: 'object', + required: ['sku', 'quantity', 'price'], + properties: { + sku: { type: 'string' }, + quantity: { type: 'integer', exclusiveMinimum: 0 }, + price: { $ref: '#/$defs/Money' }, + category: { $ref: '#/$defs/Category' }, + }, + }, + Category: { + type: 'object', + required: ['name'], + properties: { + name: { type: 'string' }, + parent: { anyOf: [{ $ref: '#/$defs/Category' }, { type: 'null' }] }, + children: { type: 'array', items: { $ref: '#/$defs/Category' } }, + }, + }, + }, +} diff --git a/packages/downgrader/benches/chained.bench.ts b/packages/downgrader/benches/chained.bench.ts new file mode 100644 index 0000000..831eb70 --- /dev/null +++ b/packages/downgrader/benches/chained.bench.ts @@ -0,0 +1,27 @@ +// There is no direct 3.2 → 3.0 converter: the two steps compose (see the +// package README), and this is what that costs end to end. + +import type * as OpenAPIV3_2 from '@openapi-spec/types/v3.2' + +import { downgradeSpecV31ToV30, downgradeSpecV32ToV31 } from '@openapi-spec/downgrader' +import { bench, describe } from 'vitest' +import { corpusV32 } from '../tests/corpus' +import { createApiV32 } from './__shared__/api' + +const API_100_RESOURCES = createApiV32(100) + +function downgradeTwice(doc: OpenAPIV3_2.OpenAPIObject) { + return downgradeSpecV31ToV30(downgradeSpecV32ToV31(doc)) +} + +describe('downgradeSpecV32ToV31 + downgradeSpecV31ToV30', () => { + bench('official corpus', () => { + for (const [, doc] of corpusV32) { + downgradeTwice(doc) + } + }) + + bench('generated api, 100 resources', () => { + downgradeTwice(API_100_RESOURCES) + }) +}) diff --git a/packages/downgrader/benches/v3.1-to-v3.0.bench.ts b/packages/downgrader/benches/v3.1-to-v3.0.bench.ts new file mode 100644 index 0000000..0c2560e --- /dev/null +++ b/packages/downgrader/benches/v3.1-to-v3.0.bench.ts @@ -0,0 +1,55 @@ +import { downgradeSchemaV31ToV30, downgradeSpecV31ToV30 } from '@openapi-spec/downgrader' +import { bench, describe } from 'vitest' +import { corpusV31 } from '../tests/corpus' +import { createApiV31 } from './__shared__/api' +import { callbackGraphV31, pathItemChainV31, referenceDiamondV31, schemaDiamond } from './__shared__/graphs' +import { ORDER_SCHEMA, PROPERTY_SCHEMA } from './__shared__/schemas' + +const API_10_RESOURCES = createApiV31(10) +const API_100_RESOURCES = createApiV31(100) +const REFERENCE_DIAMOND = referenceDiamondV31(64) +const CALLBACK_GRAPH = callbackGraphV31(8) +const PATH_ITEM_CHAIN = pathItemChainV31(200) +const SCHEMA_DIAMOND = schemaDiamond(64) + +describe('downgradeSpecV31ToV30', () => { + bench('official corpus', () => { + for (const [, doc] of corpusV31) { + downgradeSpecV31ToV30(doc) + } + }) + + bench('generated api, 10 resources', () => { + downgradeSpecV31ToV30(API_10_RESOURCES) + }) + + bench('generated api, 100 resources', () => { + downgradeSpecV31ToV30(API_100_RESOURCES) + }) + + bench('reference diamond into removed webhooks, 64 levels', () => { + downgradeSpecV31ToV30(REFERENCE_DIAMOND) + }) + + bench('cyclic callback graph in removed webhooks, 8 path items', () => { + downgradeSpecV31ToV30(CALLBACK_GRAPH) + }) + + bench('path item $ref chain in removed components, 200 hops', () => { + downgradeSpecV31ToV30(PATH_ITEM_CHAIN) + }) +}) + +describe('downgradeSchemaV31ToV30', () => { + bench('property schema', () => { + downgradeSchemaV31ToV30(PROPERTY_SCHEMA) + }) + + bench('order schema with $defs', () => { + downgradeSchemaV31ToV30(ORDER_SCHEMA) + }) + + bench('dereferenced diamond, 64 levels', () => { + downgradeSchemaV31ToV30(SCHEMA_DIAMOND) + }) +}) diff --git a/packages/downgrader/benches/v3.2-to-v3.1.bench.ts b/packages/downgrader/benches/v3.2-to-v3.1.bench.ts new file mode 100644 index 0000000..ce4e25b --- /dev/null +++ b/packages/downgrader/benches/v3.2-to-v3.1.bench.ts @@ -0,0 +1,50 @@ +import { downgradeSchemaV32ToV31, downgradeSpecV32ToV31 } from '@openapi-spec/downgrader' +import { bench, describe } from 'vitest' +import { corpusV32 } from '../tests/corpus' +import { createApiV32 } from './__shared__/api' +import { callbackGraphV32, referenceDiamondV32, schemaDiamond } from './__shared__/graphs' +import { ORDER_SCHEMA, PROPERTY_SCHEMA } from './__shared__/schemas' + +const API_10_RESOURCES = createApiV32(10) +const API_100_RESOURCES = createApiV32(100) +const REFERENCE_DIAMOND = referenceDiamondV32(64) +const CALLBACK_GRAPH = callbackGraphV32(8) +const SCHEMA_DIAMOND = schemaDiamond(64) + +describe('downgradeSpecV32ToV31', () => { + bench('official corpus', () => { + for (const [, doc] of corpusV32) { + downgradeSpecV32ToV31(doc) + } + }) + + bench('generated api, 10 resources', () => { + downgradeSpecV32ToV31(API_10_RESOURCES) + }) + + bench('generated api, 100 resources', () => { + downgradeSpecV32ToV31(API_100_RESOURCES) + }) + + bench('reference diamond into removed media types, 64 levels', () => { + downgradeSpecV32ToV31(REFERENCE_DIAMOND) + }) + + bench('cyclic callback graph in a removed operation, 8 path items', () => { + downgradeSpecV32ToV31(CALLBACK_GRAPH) + }) +}) + +describe('downgradeSchemaV32ToV31', () => { + bench('property schema', () => { + downgradeSchemaV32ToV31(PROPERTY_SCHEMA) + }) + + bench('order schema with $defs', () => { + downgradeSchemaV32ToV31(ORDER_SCHEMA) + }) + + bench('dereferenced diamond, 64 levels', () => { + downgradeSchemaV32ToV31(SCHEMA_DIAMOND) + }) +}) diff --git a/packages/downgrader/tsconfig.json b/packages/downgrader/tsconfig.json index b5c68d2..0e040b5 100644 --- a/packages/downgrader/tsconfig.json +++ b/packages/downgrader/tsconfig.json @@ -9,6 +9,7 @@ "exclude": [ "**/*.test.*", "**/*.test-d.ts", + "**/*.bench.*", "**/__tests__/**", "**/__mocks__/**", "**/__snapshots__/**" diff --git a/packages/types/README.md b/packages/types/README.md index 5802be0..a788f1f 100644 --- a/packages/types/README.md +++ b/packages/types/README.md @@ -7,6 +7,9 @@ weekly downloads + + CodSpeed + MIT License diff --git a/packages/types/tsconfig.json b/packages/types/tsconfig.json index 0fb4b9f..3e0f03d 100644 --- a/packages/types/tsconfig.json +++ b/packages/types/tsconfig.json @@ -4,6 +4,7 @@ "exclude": [ "**/*.test.*", "**/*.test-d.ts", + "**/*.bench.*", "**/__tests__/**", "**/__mocks__/**", "**/__snapshots__/**" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 6643fa7..f476da5 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -169,6 +169,9 @@ importers: '@antfu/eslint-config': specifier: ^9.5.1 version: 9.5.1(@typescript-eslint/typescript-estree@8.69.0(supports-color@7.2.0)(typescript@6.0.3))(@typescript-eslint/utils@8.69.0(eslint@10.10.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(@vue/compiler-sfc@3.5.42)(eslint-plugin-format@2.0.1(eslint@10.10.0(jiti@2.7.0)(supports-color@7.2.0)))(eslint@10.10.0(jiti@2.7.0)(supports-color@7.2.0))(oxlint@1.80.0)(supports-color@7.2.0)(typescript@6.0.3)(vitest@4.1.11) + '@codspeed/vitest-plugin': + specifier: ^5.7.1 + version: 5.7.1(debug@4.4.3(supports-color@7.2.0))(supports-color@7.2.0)(tinybench@2.9.0)(vite@7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0))(vitest@4.1.11) '@seriousme/openapi-schema-validator': specifier: ^2.9.1 version: 2.9.1 @@ -207,7 +210,7 @@ importers: version: 3.6.1(typescript@6.0.3) vitest: specifier: ^4.1.11 - version: 4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(vite@8.2.2(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)) + version: 4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(vite@7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0)) packages/downgrader: dependencies: @@ -335,6 +338,16 @@ packages: resolution: {integrity: sha512-y7/yvZ2TPAnR9+jnc00klvNNLkJiXFFrQA/hlLCcxA9a2A4zQIOimyFQ9XfwYKiGD1fb5GY8vbKIIgO8d5Tb2A==} engines: {node: '>= 20.12.0'} + '@codspeed/core@5.7.1': + resolution: {integrity: sha512-7mrFkqaY14rXu3XHv3o7bK3btLK0LFRxfeK3bQC8dLduI/Ty9eq8Hv8rx04FAY/onQbRTx3rUUQg5xprYHpATQ==} + + '@codspeed/vitest-plugin@5.7.1': + resolution: {integrity: sha512-yKNqaYVxZZPJYkhVHpz30Oem4TUgcI+/IRDD9YHvcAgi0P42CL6TB/+qYjuFOWghFzTPrm3TUbNFoBsevSTbUA==} + peerDependencies: + tinybench: '>=2.9.0' + vite: ^4.2.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 + vitest: ^3.2 || ^4 + '@colordx/core@5.6.0': resolution: {integrity: sha512-EDlcg/Hmlj1WuFh/Os9YhA+A2aasB2XlgwFfGePUDuW7fVHC07HBi5AFIMx0Ct1eM8kHM9NRyOtZ0MuVYa8xvg==} @@ -376,156 +389,312 @@ packages: cpu: [ppc64] os: [aix] + '@esbuild/aix-ppc64@0.28.2': + resolution: {integrity: sha512-XExcO+dvLKvVtNTibSTBej1NCAbaGhWn9Ww1ZPx80qsahhPFe/8jgWP0IchNe0F3HwkU7n8ejhH8bjonqht8mQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [aix] + '@esbuild/android-arm64@0.25.12': resolution: {integrity: sha512-6AAmLG7zwD1Z159jCKPvAxZd4y/VTO0VkprYy+3N2FtJ8+BQWFXU+OxARIwA46c5tdD9SsKGZ/1ocqBS/gAKHg==} engines: {node: '>=18'} cpu: [arm64] os: [android] + '@esbuild/android-arm64@0.28.2': + resolution: {integrity: sha512-5YfKeeI8qWfBZIX+u2xZC3Zlb3Os/gLS2sbEKM+I4ZOcsWmHS2WLysCcQZDAFRslDUU5Oiq44gf6PYN1vGwG5A==} + engines: {node: '>=18'} + cpu: [arm64] + os: [android] + '@esbuild/android-arm@0.25.12': resolution: {integrity: sha512-VJ+sKvNA/GE7Ccacc9Cha7bpS8nyzVv0jdVgwNDaR4gDMC/2TTRc33Ip8qrNYUcpkOHUT5OZ0bUcNNVZQ9RLlg==} engines: {node: '>=18'} cpu: [arm] os: [android] + '@esbuild/android-arm@0.28.2': + resolution: {integrity: sha512-kXXoiPVVGQcnIYGOeaovwOURpniDBpSq4A03qkQ+BMQqtGG6HYap3xne9C1O1yo4TR3qxlCX5IqqmX6fFo2Lqg==} + engines: {node: '>=18'} + cpu: [arm] + os: [android] + '@esbuild/android-x64@0.25.12': resolution: {integrity: sha512-5jbb+2hhDHx5phYR2By8GTWEzn6I9UqR11Kwf22iKbNpYrsmRB18aX/9ivc5cabcUiAT/wM+YIZ6SG9QO6a8kg==} engines: {node: '>=18'} cpu: [x64] os: [android] + '@esbuild/android-x64@0.28.2': + resolution: {integrity: sha512-O387ite7SzUyCcy3JQX4P4bLtEA7bLLkx+esve5JHnyYfNTxcVpXZo9jhdB0lTKN44gztELTdU7nS8Nr16Fs1Q==} + engines: {node: '>=18'} + cpu: [x64] + os: [android] + '@esbuild/darwin-arm64@0.25.12': resolution: {integrity: sha512-N3zl+lxHCifgIlcMUP5016ESkeQjLj/959RxxNYIthIg+CQHInujFuXeWbWMgnTo4cp5XVHqFPmpyu9J65C1Yg==} engines: {node: '>=18'} cpu: [arm64] os: [darwin] + '@esbuild/darwin-arm64@0.28.2': + resolution: {integrity: sha512-n4KqkOQrraxHJcgjM1RvwbigfQKIKJVpM7xp+KsxiyUSrRdIXnt73VhrPAx0fV44hgfmIVKjxMN9J1t5jySVkw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [darwin] + '@esbuild/darwin-x64@0.25.12': resolution: {integrity: sha512-HQ9ka4Kx21qHXwtlTUVbKJOAnmG1ipXhdWTmNXiPzPfWKpXqASVcWdnf2bnL73wgjNrFXAa3yYvBSd9pzfEIpA==} engines: {node: '>=18'} cpu: [x64] os: [darwin] + '@esbuild/darwin-x64@0.28.2': + resolution: {integrity: sha512-uq6suIWYP37qzGddBKPw5QEQPi6HiLGsO7UmkpfyaYNQ3D+rN6w6WfwH+nuqcGXWvawGwxOEroO4YGnFh95azw==} + engines: {node: '>=18'} + cpu: [x64] + os: [darwin] + '@esbuild/freebsd-arm64@0.25.12': resolution: {integrity: sha512-gA0Bx759+7Jve03K1S0vkOu5Lg/85dou3EseOGUes8flVOGxbhDDh/iZaoek11Y8mtyKPGF3vP8XhnkDEAmzeg==} engines: {node: '>=18'} cpu: [arm64] os: [freebsd] + '@esbuild/freebsd-arm64@0.28.2': + resolution: {integrity: sha512-n+I0BTSRIoy+d6RPKnEVwql5UwBJolytvY4mAOIEJorKlqgPII8ix6slVVrfZ5Tnj7glIZvloylbB/EJPMWEXw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [freebsd] + '@esbuild/freebsd-x64@0.25.12': resolution: {integrity: sha512-TGbO26Yw2xsHzxtbVFGEXBFH0FRAP7gtcPE7P5yP7wGy7cXK2oO7RyOhL5NLiqTlBh47XhmIUXuGciXEqYFfBQ==} engines: {node: '>=18'} cpu: [x64] os: [freebsd] + '@esbuild/freebsd-x64@0.28.2': + resolution: {integrity: sha512-78XJTJkvPs0kz2w61301PJjXl4g7q3JqiYMZ/M/yVI73EHBrCRTgkhu9oqG7vPqq+a/yadEW8aD+agKlk5xrmg==} + engines: {node: '>=18'} + cpu: [x64] + os: [freebsd] + '@esbuild/linux-arm64@0.25.12': resolution: {integrity: sha512-8bwX7a8FghIgrupcxb4aUmYDLp8pX06rGh5HqDT7bB+8Rdells6mHvrFHHW2JAOPZUbnjUpKTLg6ECyzvas2AQ==} engines: {node: '>=18'} cpu: [arm64] os: [linux] + '@esbuild/linux-arm64@0.28.2': + resolution: {integrity: sha512-pW4AC0P3it8c7do9MVM4p51FzHzdM/TZrerurgRcHJ2WTa1VQ1CIq18xncfpBJw4ojkiZZrKW2yIBWBP92j6Ug==} + engines: {node: '>=18'} + cpu: [arm64] + os: [linux] + '@esbuild/linux-arm@0.25.12': resolution: {integrity: sha512-lPDGyC1JPDou8kGcywY0YILzWlhhnRjdof3UlcoqYmS9El818LLfJJc3PXXgZHrHCAKs/Z2SeZtDJr5MrkxtOw==} engines: {node: '>=18'} cpu: [arm] os: [linux] + '@esbuild/linux-arm@0.28.2': + resolution: {integrity: sha512-XlDnu2q5yoqems+xay6wSAcg9DDD7K9RLKZEBOMZm3ckNpJBvOX20tSfby8KfrrhINDyv9V2YVZKY/SpoGJI8w==} + engines: {node: '>=18'} + cpu: [arm] + os: [linux] + '@esbuild/linux-ia32@0.25.12': resolution: {integrity: sha512-0y9KrdVnbMM2/vG8KfU0byhUN+EFCny9+8g202gYqSSVMonbsCfLjUO+rCci7pM0WBEtz+oK/PIwHkzxkyharA==} engines: {node: '>=18'} cpu: [ia32] os: [linux] + '@esbuild/linux-ia32@0.28.2': + resolution: {integrity: sha512-CYbnj78HsIeA+DhgUKgFCfvNsTHFhMMrinUrMZpDXJXKN8T3XViTZ/+wtHeVxEWY8ewSzTFN+nRmSwO2tZaLUQ==} + engines: {node: '>=18'} + cpu: [ia32] + os: [linux] + '@esbuild/linux-loong64@0.25.12': resolution: {integrity: sha512-h///Lr5a9rib/v1GGqXVGzjL4TMvVTv+s1DPoxQdz7l/AYv6LDSxdIwzxkrPW438oUXiDtwM10o9PmwS/6Z0Ng==} engines: {node: '>=18'} cpu: [loong64] os: [linux] + '@esbuild/linux-loong64@0.28.2': + resolution: {integrity: sha512-buwkd8nsph4R+ajRvw0qM5Hja/TXQow3ptzWO2EbG/cqcIkHloRrdlBtQlshyYGTNFvfkfJ5tpPLVkY4DtsPfQ==} + engines: {node: '>=18'} + cpu: [loong64] + os: [linux] + '@esbuild/linux-mips64el@0.25.12': resolution: {integrity: sha512-iyRrM1Pzy9GFMDLsXn1iHUm18nhKnNMWscjmp4+hpafcZjrr2WbT//d20xaGljXDBYHqRcl8HnxbX6uaA/eGVw==} engines: {node: '>=18'} cpu: [mips64el] os: [linux] + '@esbuild/linux-mips64el@0.28.2': + resolution: {integrity: sha512-ZVykbDyk7519VwiNb9Lcj9m8XM6v5V9uKPvrEMkkEedVewf+0itkhahp4HDpgERXhwLRpWFypsGbG/J8s0QjJA==} + engines: {node: '>=18'} + cpu: [mips64el] + os: [linux] + '@esbuild/linux-ppc64@0.25.12': resolution: {integrity: sha512-9meM/lRXxMi5PSUqEXRCtVjEZBGwB7P/D4yT8UG/mwIdze2aV4Vo6U5gD3+RsoHXKkHCfSxZKzmDssVlRj1QQA==} engines: {node: '>=18'} cpu: [ppc64] os: [linux] + '@esbuild/linux-ppc64@0.28.2': + resolution: {integrity: sha512-CAXl+Dtd9UUuJd8pKKdwh6MLm3MUMiqMPmhZ3tTSXPqfyQ3vDl6R5hZdZ/kYojK4ofXtdfSv1tFq8XzWx3heNQ==} + engines: {node: '>=18'} + cpu: [ppc64] + os: [linux] + '@esbuild/linux-riscv64@0.25.12': resolution: {integrity: sha512-Zr7KR4hgKUpWAwb1f3o5ygT04MzqVrGEGXGLnj15YQDJErYu/BGg+wmFlIDOdJp0PmB0lLvxFIOXZgFRrdjR0w==} engines: {node: '>=18'} cpu: [riscv64] os: [linux] + '@esbuild/linux-riscv64@0.28.2': + resolution: {integrity: sha512-GeXCej4IQtU1B+QlDV8W/RRvbzI3O/Stss+/bCXv4lZls5WGRtu2a+3JkA3i4qIUlMXpcHebWpF8AkJhATowuA==} + engines: {node: '>=18'} + cpu: [riscv64] + os: [linux] + '@esbuild/linux-s390x@0.25.12': resolution: {integrity: sha512-MsKncOcgTNvdtiISc/jZs/Zf8d0cl/t3gYWX8J9ubBnVOwlk65UIEEvgBORTiljloIWnBzLs4qhzPkJcitIzIg==} engines: {node: '>=18'} cpu: [s390x] os: [linux] + '@esbuild/linux-s390x@0.28.2': + resolution: {integrity: sha512-3H1weTYZPxt/WOhByszQZybS9w5lKzUn1FDMsgEChbHWQwHYQQRfBxgCcZvPhjHfKyJjIievvMmEUawJrdY9Dg==} + engines: {node: '>=18'} + cpu: [s390x] + os: [linux] + '@esbuild/linux-x64@0.25.12': resolution: {integrity: sha512-uqZMTLr/zR/ed4jIGnwSLkaHmPjOjJvnm6TVVitAa08SLS9Z0VM8wIRx7gWbJB5/J54YuIMInDquWyYvQLZkgw==} engines: {node: '>=18'} cpu: [x64] os: [linux] + '@esbuild/linux-x64@0.28.2': + resolution: {integrity: sha512-4xTZr1FUmSoQW4XIWmit3tzQrUTZM+N3P0XV8xROKYF50XfI7xeO90+1bZvNwxIufQ9hDQVRJH5YhgPVF8A/HQ==} + engines: {node: '>=18'} + cpu: [x64] + os: [linux] + '@esbuild/netbsd-arm64@0.25.12': resolution: {integrity: sha512-xXwcTq4GhRM7J9A8Gv5boanHhRa/Q9KLVmcyXHCTaM4wKfIpWkdXiMog/KsnxzJ0A1+nD+zoecuzqPmCRyBGjg==} engines: {node: '>=18'} cpu: [arm64] os: [netbsd] + '@esbuild/netbsd-arm64@0.28.2': + resolution: {integrity: sha512-sSATRjPeDBg3pdgHoQfoYBob11Kk1FGa9lui5RIHZCoCkJa9QKlvl3/vKz2usCmYYjs7ymJR/2Nnsqe+Hjt5nw==} + engines: {node: '>=18'} + cpu: [arm64] + os: [netbsd] + '@esbuild/netbsd-x64@0.25.12': resolution: {integrity: sha512-Ld5pTlzPy3YwGec4OuHh1aCVCRvOXdH8DgRjfDy/oumVovmuSzWfnSJg+VtakB9Cm0gxNO9BzWkj6mtO1FMXkQ==} engines: {node: '>=18'} cpu: [x64] os: [netbsd] + '@esbuild/netbsd-x64@0.28.2': + resolution: {integrity: sha512-lqnzCV+mM0gIADaKihiCg6ifgfU2L3h5E33rNQBN1Y4MaVGnzryzmvvf7UHxprpQdE8hpqLolJ9Rl+SkIRDpyw==} + engines: {node: '>=18'} + cpu: [x64] + os: [netbsd] + '@esbuild/openbsd-arm64@0.25.12': resolution: {integrity: sha512-fF96T6KsBo/pkQI950FARU9apGNTSlZGsv1jZBAlcLL1MLjLNIWPBkj5NlSz8aAzYKg+eNqknrUJ24QBybeR5A==} engines: {node: '>=18'} cpu: [arm64] os: [openbsd] + '@esbuild/openbsd-arm64@0.28.2': + resolution: {integrity: sha512-AL2qJILH7lNjrDmCQDvdxMfAUIv8KMNZOvrwAQ8i8//ntL9FflhOyMJ8OZSMBb8/AWXe3/5v5S20y3zCoZWKoQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openbsd] + '@esbuild/openbsd-x64@0.25.12': resolution: {integrity: sha512-MZyXUkZHjQxUvzK7rN8DJ3SRmrVrke8ZyRusHlP+kuwqTcfWLyqMOE3sScPPyeIXN/mDJIfGXvcMqCgYKekoQw==} engines: {node: '>=18'} cpu: [x64] os: [openbsd] + '@esbuild/openbsd-x64@0.28.2': + resolution: {integrity: sha512-QtiuPytchRyC4rwUKhexJdQKvDuZ6hWloi3igqPQNUJCS1/v9EiO3UTOXR6A3FoMo4fnAKbWJdqaIwhOzh8qEw==} + engines: {node: '>=18'} + cpu: [x64] + os: [openbsd] + '@esbuild/openharmony-arm64@0.25.12': resolution: {integrity: sha512-rm0YWsqUSRrjncSXGA7Zv78Nbnw4XL6/dzr20cyrQf7ZmRcsovpcRBdhD43Nuk3y7XIoW2OxMVvwuRvk9XdASg==} engines: {node: '>=18'} cpu: [arm64] os: [openharmony] + '@esbuild/openharmony-arm64@0.28.2': + resolution: {integrity: sha512-WkhYDmpTjLvGlScA1rwjRUmhl4k8oXR3cIbtqWmELgU/dFeHHlEllxDvdWcNJV9rbzCexB5vz8gtNewWLgCT7Q==} + engines: {node: '>=18'} + cpu: [arm64] + os: [openharmony] + '@esbuild/sunos-x64@0.25.12': resolution: {integrity: sha512-3wGSCDyuTHQUzt0nV7bocDy72r2lI33QL3gkDNGkod22EsYl04sMf0qLb8luNKTOmgF/eDEDP5BFNwoBKH441w==} engines: {node: '>=18'} cpu: [x64] os: [sunos] + '@esbuild/sunos-x64@0.28.2': + resolution: {integrity: sha512-GPMSkTOtMnv2U2F8gxe4Io6qmVs+YKyp832Etqqxr0hFngmXQ3rzwytelm3GIn7T4VviRUlf3sOgBOiTdvaf7g==} + engines: {node: '>=18'} + cpu: [x64] + os: [sunos] + '@esbuild/win32-arm64@0.25.12': resolution: {integrity: sha512-rMmLrur64A7+DKlnSuwqUdRKyd3UE7oPJZmnljqEptesKM8wx9J8gx5u0+9Pq0fQQW8vqeKebwNXdfOyP+8Bsg==} engines: {node: '>=18'} cpu: [arm64] os: [win32] + '@esbuild/win32-arm64@0.28.2': + resolution: {integrity: sha512-PIhhEkE9uPBleRBrQEJpUn7MBnibZzbGzYWPmY3x+YoVg/95zbjB4CxPPOQ8l5tYYM4mMaCthF8/1DIfBQQyWQ==} + engines: {node: '>=18'} + cpu: [arm64] + os: [win32] + '@esbuild/win32-ia32@0.25.12': resolution: {integrity: sha512-HkqnmmBoCbCwxUKKNPBixiWDGCpQGVsrQfJoVGYLPT41XWF8lHuE5N6WhVia2n4o5QK5M4tYr21827fNhi4byQ==} engines: {node: '>=18'} cpu: [ia32] os: [win32] + '@esbuild/win32-ia32@0.28.2': + resolution: {integrity: sha512-YmJbfTlvU7Sdn9BB+4PRES4oB6pxgS37MAONj+hBr/cpXS1aBPKXxNnDbu+QCWPj0o9dgyxeq79g6c5P8KeuYA==} + engines: {node: '>=18'} + cpu: [ia32] + os: [win32] + '@esbuild/win32-x64@0.25.12': resolution: {integrity: sha512-alJC0uCZpTFrSL0CCDjcgleBXPnCrEAhTBILpeAp7M/OFgoqtAetfBzX0xM00MUsVVPpVjlPuMbREqnZCXaTnA==} engines: {node: '>=18'} cpu: [x64] os: [win32] + '@esbuild/win32-x64@0.28.2': + resolution: {integrity: sha512-5ebpxr3nWMzrL/rnUI755Jkuee0bHL/Gq0WTF9lvcpv73wAp5eu8MfBUgWK9bhWvZjj7yX8etf/8tI8Ney695g==} + engines: {node: '>=18'} + cpu: [x64] + os: [win32] + '@eslint-community/eslint-plugin-eslint-comments@4.7.2': resolution: {integrity: sha512-LF03qURSwEWm2dz5wtdDCzNk+7Opl0X7q6I3undsaIuNsEiNvRV3BCtqu14Q/6Pzg1tBj44LcxpW2EpSLZStZw==} engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} @@ -639,9 +808,6 @@ packages: resolution: {integrity: sha512-XRO0zi2NIUKq2lUk3T1ecFSld1fMWRKE6naRFGkgkdeosx7IslyUKNv5Dcb5PJTja9tHJoFu0v/7yEpAkrkrTg==} engines: {node: ^20.19.0 || ^22.13.0 || >=24} - '@oxc-project/types@0.147.0': - resolution: {integrity: sha512-IJ3s6ltHLp45S0bh7phkX+gJO7A1Wuz2EaqpAhb8WjqDwbzMiWKHhyyT42tskaWjEYXtHtVCPpnBJVT9+dcRLg==} - '@oxfmt/binding-android-arm-eabi@0.35.0': resolution: {integrity: sha512-BaRKlM3DyG81y/xWTsE6gZiv89F/3pHe2BqX2H4JbiB8HNVlWWtplzgATAE5IDSdwChdeuWLDTQzJ92Lglw3ZA==} engines: {node: ^20.19.0 || >=22.12.0} @@ -893,105 +1059,6 @@ packages: '@quansync/fs@1.0.0': resolution: {integrity: sha512-4TJ3DFtlf1L5LDMaM6CanJ/0lckGNtJcMjQ1NAV6zDmA0tEHKZtxNKin8EgPaVX1YzljbxckyT2tJrpQKAtngQ==} - '@rolldown/binding-android-arm-eabi@1.2.6': - resolution: {integrity: sha512-b+jTcARdTiFLI6jB4a5XjTm0RWd6KcRfQj/I2356fxUZemiho9zQLxo0RtCuMDAyKcLo6cEltkgbQp6d1+sjjQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [android] - - '@rolldown/binding-android-arm64@1.2.6': - resolution: {integrity: sha512-lkWU8ZJaRk9q3CIEY1Tc7vIFALp3Xw5NfGJo2hQg5oIqNgxWi1zI+IiDEK3r70BF5Dzol1tcXsnzsRc8NLhG+Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [android] - - '@rolldown/binding-darwin-arm64@1.2.6': - resolution: {integrity: sha512-dgR56NYnvAszm7Ob1B2/Vn0e8bUQYZH2UjVaMMtMVOCKFSfjhfLmuA/9+O+F+ajUdG6B/bSssrKW6JJYASa8jA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [darwin] - - '@rolldown/binding-darwin-x64@1.2.6': - resolution: {integrity: sha512-vpVxFvUCFioJqug7OTvqptkc4yb8UX0AwfDmJpaR/0sWz+BUmqSVAf7c8JkUgnN8YLspb4a/N6NhTyMAmdyQ7Q==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [darwin] - - '@rolldown/binding-freebsd-x64@1.2.6': - resolution: {integrity: sha512-h1wG6Y6K3JlRswxsI64qQJqBAy4vrLuHgRbc8CZMGSWTOFRY6ghMApM1NKzB2I0n5xV1fjkE18SuVl2QpLeNpA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [freebsd] - - '@rolldown/binding-linux-arm-gnueabihf@1.2.6': - resolution: {integrity: sha512-tbCiqub0q2MVWJKgF5PoAlNWCtQydiOYSLIkd8sByqK/6MMYLJRcSXSYodqYtd0O+Fw7QaVmKKlS4oL94YRZ0w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm] - os: [linux] - - '@rolldown/binding-linux-arm64-gnu@1.2.6': - resolution: {integrity: sha512-oxK9+baEBPhZG5HB4URY+uU04zJWeZlH6Tb9rB5DK4DF9XR1uXNLXt5Q5ZsugTKayNCNLhkcwz/ye74hRI98dg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-arm64-musl@1.2.6': - resolution: {integrity: sha512-muWCk27FVBEZtv0MsK8gnfSmgczA8KQ0uRVJbTABKhkRfQc38aUrcb7fhi3BNiyseFmgcRsoMfQsSNJ+DbZdSw==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [linux] - libc: [musl] - - '@rolldown/binding-linux-ppc64-gnu@1.2.6': - resolution: {integrity: sha512-eWDoSfU7Co2qj3vgB3Dt4lj1mG6CoWbcJQkRMP3XJplyCMtuaq3LHvPFjS9QIPvMGWVadJC04Xiy0IdcVPtnwQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [ppc64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-s390x-gnu@1.2.6': - resolution: {integrity: sha512-2bWNjRSIayvupRKxXUY2tWG9fYdoUlTqWywHRvE8Eq3GvuQ+f2HeIkve697fIt+IQs/PV8yFsdWuhp1aJ1PdnA==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [s390x] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-gnu@1.2.6': - resolution: {integrity: sha512-KekI0gS0wLxe1UBSQSjenBVwou/JkcQPDzBPICGZjxUv9k3RteHDPBQaiOicZUFKRIH2wKEimGwVpnJsbPzu7w==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [glibc] - - '@rolldown/binding-linux-x64-musl@1.2.6': - resolution: {integrity: sha512-TvtPnfVr+HtyGiDmPK4VWmlNm7QhNNAcK5Q9A7aOXsI8545yCyaoMaicXrFZ72JzeYjaUVk7yT243zT0jzjFKQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [linux] - libc: [musl] - - '@rolldown/binding-openharmony-arm64@1.2.6': - resolution: {integrity: sha512-iOo0VEay2XFhaCcH0sps5XIimkSuOnNaZrf6+ZkoSOQBJPKNU48RkmJv0/lSpipexu5P+ouFgafe5IGr/DiQfg==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [openharmony] - - '@rolldown/binding-win32-arm64-msvc@1.2.6': - resolution: {integrity: sha512-y5NTmmasMS455JlOCO4ZM9krIchv3Mvm1crL1iUPGOPgEzSkves9n0SdC5Sjz6+qWDFhd8/JpfWMH8NSWNHe+A==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [arm64] - os: [win32] - - '@rolldown/binding-win32-x64-msvc@1.2.6': - resolution: {integrity: sha512-np8iZSLfXlAD4kWhiyq/u0Yt8oZDtRQ8lGhQaCXo2rl37KNjeU0GjJuwr4P3oeZ++ROfofsKNBqR5LTO8aXyWQ==} - engines: {node: ^20.19.0 || >=22.12.0} - cpu: [x64] - os: [win32] - - '@rolldown/pluginutils@1.0.1': - resolution: {integrity: sha512-2j9bGt5Jh8hj+vPtgzPtl72j0yRxHAyumoo6TNfAjsLB04UtpSvPbPcDcBMxz7n+9CYB0c1GxQFxYRg2jimqGw==} - '@rollup/plugin-alias@5.1.1': resolution: {integrity: sha512-PR9zDb+rOzkRb2VD+EuKB7UC41vU5DIwZ5qqCpk0KJudcWAyi8rvYOhS7+L5aZCspw1stTViLgN5v6FF1p5cgQ==} engines: {node: '>=14.0.0'} @@ -1378,6 +1445,10 @@ packages: engines: {node: '>=0.4.0'} hasBin: true + agent-base@6.0.2: + resolution: {integrity: sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==} + engines: {node: '>= 6.0.0'} + ajv-draft-04@1.0.0: resolution: {integrity: sha512-mv00Te6nmYbRp5DCwclxtt7yV/joXJPGS7nM+97GdxvuttCOfgI3K4U25zboyeX0O+myI8ERluxQe5wljMmVIw==} peerDependencies: @@ -1422,6 +1493,9 @@ packages: ast-v8-to-istanbul@1.0.5: resolution: {integrity: sha512-UPAgKJFSEGMWSDr3LX4tqnAb4f7KGT8O40Tyx8wbYmmZ/yn58lNCm8h3svs3eXgiGd5AXxz8NDOvXWvicq+rJA==} + asynckit@0.4.0: + resolution: {integrity: sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==} + autoprefixer@10.5.4: resolution: {integrity: sha512-MaU0U/za7N3r6brxD4YB/l4NSrFzLPlANv6wEuQVaIPlD3L4W9rFcQPbL/EilY9BHhHvhfcz3gInDLrEtWT4EA==} engines: {node: ^10 || ^12 || >=14} @@ -1429,6 +1503,9 @@ packages: peerDependencies: postcss: ^8.1.0 + axios@1.20.0: + resolution: {integrity: sha512-r8aOh8j9cGKpgQAqpzrUHnSIc6a59Y3Xf/cv8sy1DrHCkZHzQGEuoq1tARk6qSyDdtQGSDgpb9kFlruzPvrgwg==} + balanced-match@4.0.4: resolution: {integrity: sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==} engines: {node: 18 || 20 || >=22} @@ -1494,6 +1571,10 @@ packages: cacheable@2.5.0: resolution: {integrity: sha512-60cyAOytib/OzBw1JNSoSV/boK1AtHryDIjvVBk7XbN4ugfkM3+Sry7fEjNgPMGgOjuaZPAp8ruZ0Cxafwyq9g==} + call-bind-apply-helpers@1.0.2: + resolution: {integrity: sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==} + engines: {node: '>= 0.4'} + caniuse-api@3.0.0: resolution: {integrity: sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw==} @@ -1544,6 +1625,10 @@ packages: colorette@2.0.20: resolution: {integrity: sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==} + combined-stream@1.0.8: + resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} + engines: {node: '>= 0.8'} + commander@11.1.0: resolution: {integrity: sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==} engines: {node: '>=16'} @@ -1673,6 +1758,10 @@ packages: defu@6.1.7: resolution: {integrity: sha512-7z22QmUWiQ/2d0KkdYmANbRUVABpZ9SNYyH5vx6PZ+nE5bcC0l7uFvEfHlyld/HcGBFTL536ClDt3DEcSlEJAQ==} + delayed-stream@1.0.0: + resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} + engines: {node: '>=0.4.0'} + dequal@2.0.3: resolution: {integrity: sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==} engines: {node: '>=6'} @@ -1716,6 +1805,10 @@ packages: resolution: {integrity: sha512-nI4U3TottKAcAD9LLud4Cb7b2QztQMUEfHbvhTH09bqXTxnSie8WnjPALV/WMCrJZ6UV/qHJ6L03OqO3LcdYZw==} engines: {node: '>=12'} + dunder-proto@1.0.1: + resolution: {integrity: sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==} + engines: {node: '>= 0.4'} + electron-to-chromium@1.5.415: resolution: {integrity: sha512-958V+Kbhtgz+SxXeEVKBjrlKRBIDAYvUJfwhjxMZ5S6ut9jAl7l9ZKBkBrvjyjZE36PabLUo2L8kEeV5O4vgJg==} @@ -1739,6 +1832,10 @@ packages: resolution: {integrity: sha512-zwfzJecQ/Uej6tusMqwAqU/6KL2XaB2VZ2Jg54Je6ahNBGNH6Ek6g3jjNCF0fG9EWQKGZNddNjU5F1ZQn/sBnA==} engines: {node: '>=20.19.0'} + es-define-property@1.0.1: + resolution: {integrity: sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==} + engines: {node: '>= 0.4'} + es-errors@1.3.0: resolution: {integrity: sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==} engines: {node: '>= 0.4'} @@ -1746,11 +1843,24 @@ packages: es-module-lexer@2.3.2: resolution: {integrity: sha512-poHGpORABojJJucnV9KbOavETW8lBVnphkW77ER5/BQ5Fz7oXSoCNek7IH3vR5nRjdsEz926ibFYX8KtLQmdyw==} + es-object-atoms@1.1.2: + resolution: {integrity: sha512-HWcBoN6NileqtSydK2FqHbS/LoDd2pqrnQHLyJzBj4kOp/ky2MWMN694xOfkK8/SnUsW2DH7EfyVlydKCsm1Zw==} + engines: {node: '>= 0.4'} + + es-set-tostringtag@2.1.0: + resolution: {integrity: sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==} + engines: {node: '>= 0.4'} + esbuild@0.25.12: resolution: {integrity: sha512-bbPBYYrtZbkt6Os6FiTLCTFxvq4tt3JKall1vRwshA3fdVztsLAatFaZobhkBC8/BrPetoa0oksYoKXoG4ryJg==} engines: {node: '>=18'} hasBin: true + esbuild@0.28.2: + resolution: {integrity: sha512-HKVLS8dvII+xoKW9kmqxbRKrnWEXfJJr/FZhhJmiqIB0e053QNYFqOBouTMO/k5sID4MvCiUCvv8b9M4h32wIA==} + engines: {node: '>=18'} + hasBin: true + escalade@3.2.0: resolution: {integrity: sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==} engines: {node: '>=6'} @@ -2038,6 +2148,10 @@ packages: resolution: {integrity: sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==} engines: {node: '>=10'} + find-up@6.3.0: + resolution: {integrity: sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + fix-dts-default-cjs-exports@1.0.1: resolution: {integrity: sha512-pVIECanWFC61Hzl2+oOCtoJ3F17kglZC/6N94eRWycFgBH35hHx0Li604ZIzhseh97mf2p0cv7vVrOZGoqhlEg==} @@ -2047,6 +2161,19 @@ packages: flatted@3.4.4: resolution: {integrity: sha512-5+ybhBZANEJxaH3X5evAFatUxLfEHSr7n6kYJ+1Qd0mUqr4eu9gIf6GDbWHf8RJijHrjjO8G+la14SlL2SeS1Q==} + follow-redirects@1.16.0: + resolution: {integrity: sha512-y5rN/uOsadFT/JfYwhxRS5R7Qce+g3zG97+JrtFZlC9klX/W5hD7iiLzScI4nZqUS7DNUdhPgw4xI8W2LuXlUw==} + engines: {node: '>=4.0'} + peerDependencies: + debug: '*' + peerDependenciesMeta: + debug: + optional: true + + form-data@4.0.6: + resolution: {integrity: sha512-vKatAh4SlVfgbv+YtmhiRjhEMJsYpsG1Y2rMQtR+SVSbytsSD1YGzDIcrAJmdFec88u/+VoGmxnl+80gL1tRCQ==} + engines: {node: '>= 6'} + format@0.2.2: resolution: {integrity: sha512-wzsgA6WOq+09wrU1tsJ09udeR/YZRaeArL9e1wPbFg3GG2yDnC2ldKpxs4xunpFF9DgqCqOIra3bc1HWrJ37Ww==} engines: {node: '>=0.4.x'} @@ -2070,6 +2197,14 @@ packages: resolution: {integrity: sha512-939eZS4gJ3htTHAldmyyuzlrD58P03fHG49v2JfFXbV6OhvZKRC9j2yAtdHw/zrp2zXHuv05zMIy40F0ge7spA==} engines: {node: '>=18'} + get-intrinsic@1.3.0: + resolution: {integrity: sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==} + engines: {node: '>= 0.4'} + + get-proto@1.0.1: + resolution: {integrity: sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==} + engines: {node: '>= 0.4'} + get-tsconfig@4.14.3: resolution: {integrity: sha512-++QEw4DIY7WGoukz+/+A/8dGYPT9l9yIadnmSgZ8Rjr3YVSVDipQSO9CdnJo9ePqFqUUqh+wk9uIaoiAwsiPkA==} @@ -2103,6 +2238,10 @@ packages: globrex@0.1.2: resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + gopd@1.2.0: + resolution: {integrity: sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==} + engines: {node: '>= 0.4'} + graceful-fs@4.2.11: resolution: {integrity: sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==} @@ -2110,6 +2249,14 @@ packages: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + has-symbols@1.1.0: + resolution: {integrity: sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==} + engines: {node: '>= 0.4'} + + has-tostringtag@1.0.2: + resolution: {integrity: sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==} + engines: {node: '>= 0.4'} + hashery@1.5.1: resolution: {integrity: sha512-iZyKG96/JwPz1N55vj2Ie2vXbhu440zfUfJvSwEqEbeLluk7NnapfGqa7LH0mOsnDxTF85Mx8/dyR6HfqcbmbQ==} engines: {node: '>=20'} @@ -2133,6 +2280,10 @@ packages: html-escaper@2.0.2: resolution: {integrity: sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==} + https-proxy-agent@5.0.1: + resolution: {integrity: sha512-dFcAjpTQFgoLMzC2VwU+C/CbS7uRL0lWmxDITmqm7C+7F0Odmj6s9l6alZc6AELXhrnggM2CeWSXHGOdX2YtwA==} + engines: {node: '>= 6'} + identifier-regex@1.1.0: resolution: {integrity: sha512-SLX4H/vtcYlYnL7XqnuJKHU7Z8517TgsW9nmQiGOgMCjQ8V/deLYu6bEmbGoXe7WMMhc9+EUGyFFneHja8KabA==} engines: {node: '>=18'} @@ -2361,6 +2512,10 @@ packages: resolution: {integrity: sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==} engines: {node: '>=10'} + locate-path@7.2.0: + resolution: {integrity: sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + lodash.memoize@4.1.2: resolution: {integrity: sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==} @@ -2387,6 +2542,10 @@ packages: markdown-table@3.0.4: resolution: {integrity: sha512-wiYz4+JrLyb/DqW2hkFJxP7Vd7JuTDm77fvbM8VfEQdmSMqcImWeeRbHwZjBjIFki/VaMK2BhFi7oUUZeM5bqw==} + math-intrinsics@1.1.0: + resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} + engines: {node: '>= 0.4'} + mdast-util-find-and-replace@3.0.2: resolution: {integrity: sha512-Tmd1Vg/m3Xz43afeNxDIhWRtFZgM2VLyaf4vSTYwudTyeuTneoL3qtWMA5jeLyz/O1vDJmmV4QuScFCA2tBPwg==} @@ -2525,6 +2684,14 @@ packages: micromark@4.0.2: resolution: {integrity: sha512-zpe98Q6kvavpCr1NPVSCMebCKfD7CA2NqZ+rykeNhONIJBpc1tFKt9hucLGwha3jNTNI8lHpctWJWoimVF4PfA==} + mime-db@1.52.0: + resolution: {integrity: sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==} + engines: {node: '>= 0.6'} + + mime-types@2.1.35: + resolution: {integrity: sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==} + engines: {node: '>= 0.6'} + minimatch@10.2.6: resolution: {integrity: sha512-vpLQEs+VLCr1nU0BXS07maYoFwlDAH0gngQuuttxIwutDFEMHq2blX+8vpgxDdK3J1PwjCJiep77OitTZ4Ll1A==} engines: {node: 18 || 20 || >=22} @@ -2595,6 +2762,10 @@ packages: node-fetch-native@1.6.7: resolution: {integrity: sha512-g9yhqoedzIUm0nTnTqAQvueMPVOuIY16bqgAJJC8XOOubYFNwz6IER9qs0Gq2Xd0+CecCKFjtdDTMA4u4xG06Q==} + node-gyp-build@4.8.4: + resolution: {integrity: sha512-LA4ZjwlnUblHVgq0oBF3Jl/6h/Nvs5fzBLwdEF4nuxnFdsfajde4WfxtJr3CaiH+F6ewcIB/q4jQ4UzPyid+CQ==} + hasBin: true + node-releases@2.0.54: resolution: {integrity: sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==} engines: {node: '>=18'} @@ -2661,10 +2832,18 @@ packages: resolution: {integrity: sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==} engines: {node: '>=10'} + p-limit@4.0.0: + resolution: {integrity: sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-locate@5.0.0: resolution: {integrity: sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==} engines: {node: '>=10'} + p-locate@6.0.0: + resolution: {integrity: sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + p-timeout@6.1.4: resolution: {integrity: sha512-MyIV3ZA/PmyBN/ud8vV9XzwTrNtR4jFrObymZYnZqMmW0zA8Z17vnT0rBgFE/TlohB+YCHqXMgZzb3Csp49vqg==} engines: {node: '>=14.16'} @@ -2686,6 +2865,10 @@ packages: resolution: {integrity: sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==} engines: {node: '>=8'} + path-exists@5.0.0: + resolution: {integrity: sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + path-key@3.1.1: resolution: {integrity: sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==} engines: {node: '>=8'} @@ -2925,6 +3108,10 @@ packages: resolution: {integrity: sha512-X+vn9z8nOFZQlxOLmfJ0iKDdMD7jYTsTW12OAlCpdoE3Igik6L37pugIZi+N3usuyp5McfgKPWi12q3zvHLeGQ==} engines: {node: '>=20'} + proxy-from-env@2.1.0: + resolution: {integrity: sha512-cJ+oHTW1VAEa8cJslgmUZrc+sjRKgAKl3Zyse6+PV38hZe/V6Z14TbCuXcan9F9ghlz4QrFr2c92TNF82UkYHA==} + engines: {node: '>=10'} + punycode@2.3.1: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} @@ -2985,11 +3172,6 @@ packages: engines: {node: '>= 0.4'} hasBin: true - rolldown@1.2.6: - resolution: {integrity: sha512-vMM4q3aixf46GiF1Kok8jDPFsEpXgFWGjUHXNkNHNm+Y2adXAG2dbX91jkti3i0ZRsOlcmbuzAz1poObSHCmUA==} - engines: {node: ^20.19.0 || >=22.12.0} - hasBin: true - rollup-plugin-dts@6.5.1: resolution: {integrity: sha512-jODTXp3H7MK/Ur/ErtsrQ0G1GvaCmc3du+y5pNrdBMf6d7HlL2Nd/N6TkEr+f75CkUj01zEoEd7y2elH0eHi1Q==} engines: {node: '>=20'} @@ -3105,6 +3287,10 @@ packages: spdx-license-ids@3.0.23: resolution: {integrity: sha512-CWLcCCH7VLu13TgOH+r8p1O/Znwhqv/dbb6lqWy67G+pT1kHmeD/+V36AVb/vq8QMIQwVShJ6Ssl5FPh0fuSdw==} + stack-trace@1.0.0-pre2: + resolution: {integrity: sha512-2ztBJRek8IVofG9DBJqdy2N5kulaacX30Nz7xmkYF6ale9WBVmIy6mFBchvGX7Vx/MyjBhx+Rcxqrj+dbOnQ6A==} + engines: {node: '>=16'} + stackback@0.0.2: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} @@ -3275,16 +3461,15 @@ packages: resolution: {integrity: sha512-sXMwN6DMHeouPfCxkxWkKAmxphWKEenHYY5H1nIBzU3PmDsmJp6kBXJdshjVdpMZuWCmL9SH7KFRx29AylpP6g==} engines: {node: '>=18.12.0'} - vite@8.2.2: - resolution: {integrity: sha512-cFKLV/PRgAUlIRm5WjMjJ86jrftzpqcgH+Us+DS8mI3CDNiH30Whrz8uHL3+MOLPAgqbMBAqWdAHAphOAM+z/Q==} + vite@7.3.6: + resolution: {integrity: sha512-4XP60spRGjSZFf1qYH+dJIkK2znL3zQfl9KkOV9MkkRR/3Dls0dxaBsQPTloEc5BLXWPL9vsOxopxyKoMmDueg==} engines: {node: ^20.19.0 || >=22.12.0} hasBin: true peerDependencies: '@types/node': ^20.19.0 || >=22.12.0 - '@vitejs/devtools': ^0.4.0 || ^0.5.0 - esbuild: ^0.27.0 || ^0.28.0 jiti: '>=1.21.0' less: ^4.0.0 + lightningcss: ^1.21.0 sass: ^1.70.0 sass-embedded: ^1.70.0 stylus: '>=0.54.8' @@ -3295,14 +3480,12 @@ packages: peerDependenciesMeta: '@types/node': optional: true - '@vitejs/devtools': - optional: true - esbuild: - optional: true jiti: optional: true less: optional: true + lightningcss: + optional: true sass: optional: true sass-embedded: @@ -3406,6 +3589,10 @@ packages: resolution: {integrity: sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==} engines: {node: '>=10'} + yocto-queue@1.2.2: + resolution: {integrity: sha512-4LCcse/U2MHZ63HAJVE+v71o7yOdIe4cZ70Wpf8D/IyjDKYQLV5GD46B+hSTjJsvV5PztjvHoU580EftxjDZFQ==} + engines: {node: '>=12.20'} + zwitch@2.0.4: resolution: {integrity: sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A==} @@ -3516,6 +3703,27 @@ snapshots: fast-wrap-ansi: 0.2.2 sisteransi: 1.0.5 + '@codspeed/core@5.7.1(debug@4.4.3(supports-color@7.2.0))(supports-color@7.2.0)': + dependencies: + axios: 1.20.0(debug@4.4.3(supports-color@7.2.0))(supports-color@7.2.0) + find-up: 6.3.0 + form-data: 4.0.6 + node-gyp-build: 4.8.4 + stack-trace: 1.0.0-pre2 + transitivePeerDependencies: + - debug + - supports-color + + '@codspeed/vitest-plugin@5.7.1(debug@4.4.3(supports-color@7.2.0))(supports-color@7.2.0)(tinybench@2.9.0)(vite@7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0))(vitest@4.1.11)': + dependencies: + '@codspeed/core': 5.7.1(debug@4.4.3(supports-color@7.2.0))(supports-color@7.2.0) + tinybench: 2.9.0 + vite: 7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0) + vitest: 4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(vite@7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0)) + transitivePeerDependencies: + - debug + - supports-color + '@colordx/core@5.6.0': {} '@dprint/formatter@0.5.1': {} @@ -3554,81 +3762,159 @@ snapshots: '@esbuild/aix-ppc64@0.25.12': optional: true + '@esbuild/aix-ppc64@0.28.2': + optional: true + '@esbuild/android-arm64@0.25.12': optional: true + '@esbuild/android-arm64@0.28.2': + optional: true + '@esbuild/android-arm@0.25.12': optional: true + '@esbuild/android-arm@0.28.2': + optional: true + '@esbuild/android-x64@0.25.12': optional: true + '@esbuild/android-x64@0.28.2': + optional: true + '@esbuild/darwin-arm64@0.25.12': optional: true + '@esbuild/darwin-arm64@0.28.2': + optional: true + '@esbuild/darwin-x64@0.25.12': optional: true + '@esbuild/darwin-x64@0.28.2': + optional: true + '@esbuild/freebsd-arm64@0.25.12': optional: true + '@esbuild/freebsd-arm64@0.28.2': + optional: true + '@esbuild/freebsd-x64@0.25.12': optional: true + '@esbuild/freebsd-x64@0.28.2': + optional: true + '@esbuild/linux-arm64@0.25.12': optional: true + '@esbuild/linux-arm64@0.28.2': + optional: true + '@esbuild/linux-arm@0.25.12': optional: true + '@esbuild/linux-arm@0.28.2': + optional: true + '@esbuild/linux-ia32@0.25.12': optional: true + '@esbuild/linux-ia32@0.28.2': + optional: true + '@esbuild/linux-loong64@0.25.12': optional: true + '@esbuild/linux-loong64@0.28.2': + optional: true + '@esbuild/linux-mips64el@0.25.12': optional: true + '@esbuild/linux-mips64el@0.28.2': + optional: true + '@esbuild/linux-ppc64@0.25.12': optional: true + '@esbuild/linux-ppc64@0.28.2': + optional: true + '@esbuild/linux-riscv64@0.25.12': optional: true + '@esbuild/linux-riscv64@0.28.2': + optional: true + '@esbuild/linux-s390x@0.25.12': optional: true + '@esbuild/linux-s390x@0.28.2': + optional: true + '@esbuild/linux-x64@0.25.12': optional: true + '@esbuild/linux-x64@0.28.2': + optional: true + '@esbuild/netbsd-arm64@0.25.12': optional: true + '@esbuild/netbsd-arm64@0.28.2': + optional: true + '@esbuild/netbsd-x64@0.25.12': optional: true + '@esbuild/netbsd-x64@0.28.2': + optional: true + '@esbuild/openbsd-arm64@0.25.12': optional: true + '@esbuild/openbsd-arm64@0.28.2': + optional: true + '@esbuild/openbsd-x64@0.25.12': optional: true + '@esbuild/openbsd-x64@0.28.2': + optional: true + '@esbuild/openharmony-arm64@0.25.12': optional: true + '@esbuild/openharmony-arm64@0.28.2': + optional: true + '@esbuild/sunos-x64@0.25.12': optional: true + '@esbuild/sunos-x64@0.28.2': + optional: true + '@esbuild/win32-arm64@0.25.12': optional: true + '@esbuild/win32-arm64@0.28.2': + optional: true + '@esbuild/win32-ia32@0.25.12': optional: true + '@esbuild/win32-ia32@0.28.2': + optional: true + '@esbuild/win32-x64@0.25.12': optional: true + '@esbuild/win32-x64@0.28.2': + optional: true + '@eslint-community/eslint-plugin-eslint-comments@4.7.2(eslint@10.10.0(jiti@2.7.0)(supports-color@7.2.0))': dependencies: escape-string-regexp: 4.0.0 @@ -3744,8 +4030,6 @@ snapshots: '@ota-meshi/ast-token-store@0.3.0': {} - '@oxc-project/types@0.147.0': {} - '@oxfmt/binding-android-arm-eabi@0.35.0': optional: true @@ -3866,53 +4150,6 @@ snapshots: dependencies: quansync: 1.0.0 - '@rolldown/binding-android-arm-eabi@1.2.6': - optional: true - - '@rolldown/binding-android-arm64@1.2.6': - optional: true - - '@rolldown/binding-darwin-arm64@1.2.6': - optional: true - - '@rolldown/binding-darwin-x64@1.2.6': - optional: true - - '@rolldown/binding-freebsd-x64@1.2.6': - optional: true - - '@rolldown/binding-linux-arm-gnueabihf@1.2.6': - optional: true - - '@rolldown/binding-linux-arm64-gnu@1.2.6': - optional: true - - '@rolldown/binding-linux-arm64-musl@1.2.6': - optional: true - - '@rolldown/binding-linux-ppc64-gnu@1.2.6': - optional: true - - '@rolldown/binding-linux-s390x-gnu@1.2.6': - optional: true - - '@rolldown/binding-linux-x64-gnu@1.2.6': - optional: true - - '@rolldown/binding-linux-x64-musl@1.2.6': - optional: true - - '@rolldown/binding-openharmony-arm64@1.2.6': - optional: true - - '@rolldown/binding-win32-arm64-msvc@1.2.6': - optional: true - - '@rolldown/binding-win32-x64-msvc@1.2.6': - optional: true - - '@rolldown/pluginutils@1.0.1': {} - '@rollup/plugin-alias@5.1.1(rollup@4.63.0)': optionalDependencies: rollup: 4.63.0 @@ -4196,7 +4433,7 @@ snapshots: obug: 2.1.4 std-env: 4.2.0 tinyrainbow: 3.1.1 - vitest: 4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(vite@8.2.2(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(vite@7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0)) '@vitest/eslint-plugin@1.6.27(@typescript-eslint/eslint-plugin@8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.10.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.10.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.10.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3)(vitest@4.1.11)': dependencies: @@ -4206,7 +4443,7 @@ snapshots: optionalDependencies: '@typescript-eslint/eslint-plugin': 8.69.0(@typescript-eslint/parser@8.69.0(eslint@10.10.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3))(eslint@10.10.0(jiti@2.7.0)(supports-color@7.2.0))(supports-color@7.2.0)(typescript@6.0.3) typescript: 6.0.3 - vitest: 4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(vite@8.2.2(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)) + vitest: 4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(vite@7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0)) transitivePeerDependencies: - supports-color @@ -4219,13 +4456,13 @@ snapshots: chai: 6.2.2 tinyrainbow: 3.1.1 - '@vitest/mocker@4.1.11(vite@8.2.2(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0))': + '@vitest/mocker@4.1.11(vite@7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0))': dependencies: '@vitest/spy': 4.1.11 estree-walker: 3.0.3 magic-string: 0.30.21 optionalDependencies: - vite: 8.2.2(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0) + vite: 7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0) '@vitest/pretty-format@4.1.11': dependencies: @@ -4289,6 +4526,12 @@ snapshots: acorn@8.18.0: {} + agent-base@6.0.2(supports-color@7.2.0): + dependencies: + debug: 4.4.3(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + ajv-draft-04@1.0.0(ajv@8.20.0): optionalDependencies: ajv: 8.20.0 @@ -4330,6 +4573,8 @@ snapshots: estree-walker: 3.0.3 js-tokens: 10.0.0 + asynckit@0.4.0: {} + autoprefixer@10.5.4(postcss@8.5.26): dependencies: browserslist: 4.28.8 @@ -4339,6 +4584,16 @@ snapshots: postcss: 8.5.26 postcss-value-parser: 4.2.0 + axios@1.20.0(debug@4.4.3(supports-color@7.2.0))(supports-color@7.2.0): + dependencies: + follow-redirects: 1.16.0(debug@4.4.3(supports-color@7.2.0)) + form-data: 4.0.6 + https-proxy-agent: 5.0.1(supports-color@7.2.0) + proxy-from-env: 2.1.0 + transitivePeerDependencies: + - debug + - supports-color + balanced-match@4.0.4: {} baseline-browser-mapping@2.11.20: {} @@ -4421,6 +4676,11 @@ snapshots: keyv: 5.6.0 qified: 0.10.1 + call-bind-apply-helpers@1.0.2: + dependencies: + es-errors: 1.3.0 + function-bind: 1.1.2 + caniuse-api@3.0.0: dependencies: browserslist: 4.28.8 @@ -4497,6 +4757,10 @@ snapshots: colorette@2.0.20: {} + combined-stream@1.0.8: + dependencies: + delayed-stream: 1.0.0 + commander@11.1.0: {} commander@8.3.0: {} @@ -4628,13 +4892,16 @@ snapshots: defu@6.1.7: {} + delayed-stream@1.0.0: {} + dequal@2.0.3: {} destr@2.0.5: {} detect-indent@7.0.2: {} - detect-libc@2.1.2: {} + detect-libc@2.1.2: + optional: true devlop@1.1.0: dependencies: @@ -4664,6 +4931,12 @@ snapshots: dotenv@17.4.2: {} + dunder-proto@1.0.1: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-errors: 1.3.0 + gopd: 1.2.0 + electron-to-chromium@1.5.415: {} empathic@2.0.1: {} @@ -4679,10 +4952,23 @@ snapshots: entities@8.0.0: {} + es-define-property@1.0.1: {} + es-errors@1.3.0: {} es-module-lexer@2.3.2: {} + es-object-atoms@1.1.2: + dependencies: + es-errors: 1.3.0 + + es-set-tostringtag@2.1.0: + dependencies: + es-errors: 1.3.0 + get-intrinsic: 1.3.0 + has-tostringtag: 1.0.2 + hasown: 2.0.4 + esbuild@0.25.12: optionalDependencies: '@esbuild/aix-ppc64': 0.25.12 @@ -4712,6 +4998,35 @@ snapshots: '@esbuild/win32-ia32': 0.25.12 '@esbuild/win32-x64': 0.25.12 + esbuild@0.28.2: + optionalDependencies: + '@esbuild/aix-ppc64': 0.28.2 + '@esbuild/android-arm': 0.28.2 + '@esbuild/android-arm64': 0.28.2 + '@esbuild/android-x64': 0.28.2 + '@esbuild/darwin-arm64': 0.28.2 + '@esbuild/darwin-x64': 0.28.2 + '@esbuild/freebsd-arm64': 0.28.2 + '@esbuild/freebsd-x64': 0.28.2 + '@esbuild/linux-arm': 0.28.2 + '@esbuild/linux-arm64': 0.28.2 + '@esbuild/linux-ia32': 0.28.2 + '@esbuild/linux-loong64': 0.28.2 + '@esbuild/linux-mips64el': 0.28.2 + '@esbuild/linux-ppc64': 0.28.2 + '@esbuild/linux-riscv64': 0.28.2 + '@esbuild/linux-s390x': 0.28.2 + '@esbuild/linux-x64': 0.28.2 + '@esbuild/netbsd-arm64': 0.28.2 + '@esbuild/netbsd-x64': 0.28.2 + '@esbuild/openbsd-arm64': 0.28.2 + '@esbuild/openbsd-x64': 0.28.2 + '@esbuild/openharmony-arm64': 0.28.2 + '@esbuild/sunos-x64': 0.28.2 + '@esbuild/win32-arm64': 0.28.2 + '@esbuild/win32-ia32': 0.28.2 + '@esbuild/win32-x64': 0.28.2 + escalade@3.2.0: {} escape-string-regexp@4.0.0: {} @@ -5070,6 +5385,11 @@ snapshots: locate-path: 6.0.0 path-exists: 4.0.0 + find-up@6.3.0: + dependencies: + locate-path: 7.2.0 + path-exists: 5.0.0 + fix-dts-default-cjs-exports@1.0.1: dependencies: magic-string: 0.30.21 @@ -5084,6 +5404,18 @@ snapshots: flatted@3.4.4: {} + follow-redirects@1.16.0(debug@4.4.3(supports-color@7.2.0)): + optionalDependencies: + debug: 4.4.3(supports-color@7.2.0) + + form-data@4.0.6: + dependencies: + asynckit: 0.4.0 + combined-stream: 1.0.8 + es-set-tostringtag: 2.1.0 + hasown: 2.0.4 + mime-types: 2.1.35 + format@0.2.2: {} fraction.js@5.3.4: {} @@ -5099,6 +5431,24 @@ snapshots: function-timeout@1.0.2: {} + get-intrinsic@1.3.0: + dependencies: + call-bind-apply-helpers: 1.0.2 + es-define-property: 1.0.1 + es-errors: 1.3.0 + es-object-atoms: 1.1.2 + function-bind: 1.1.2 + get-proto: 1.0.1 + gopd: 1.2.0 + has-symbols: 1.1.0 + hasown: 2.0.4 + math-intrinsics: 1.1.0 + + get-proto@1.0.1: + dependencies: + dunder-proto: 1.0.1 + es-object-atoms: 1.1.2 + get-tsconfig@4.14.3: dependencies: resolve-pkg-maps: 1.0.0 @@ -5131,10 +5481,18 @@ snapshots: globrex@0.1.2: {} + gopd@1.2.0: {} + graceful-fs@4.2.11: {} has-flag@4.0.0: {} + has-symbols@1.1.0: {} + + has-tostringtag@1.0.2: + dependencies: + has-symbols: 1.1.0 + hashery@1.5.1: dependencies: hookified: 1.15.1 @@ -5153,6 +5511,13 @@ snapshots: html-escaper@2.0.2: {} + https-proxy-agent@5.0.1(supports-color@7.2.0): + dependencies: + agent-base: 6.0.2(supports-color@7.2.0) + debug: 4.4.3(supports-color@7.2.0) + transitivePeerDependencies: + - supports-color + identifier-regex@1.1.0: dependencies: reserved-identifiers: 1.2.0 @@ -5315,6 +5680,7 @@ snapshots: lightningcss-linux-x64-musl: 1.33.0 lightningcss-win32-arm64-msvc: 1.33.0 lightningcss-win32-x64-msvc: 1.33.0 + optional: true lilconfig@3.1.3: {} @@ -5336,6 +5702,10 @@ snapshots: dependencies: p-locate: 5.0.0 + locate-path@7.2.0: + dependencies: + p-locate: 6.0.0 + lodash.memoize@4.1.2: {} lodash.uniq@4.5.0: {} @@ -5364,6 +5734,8 @@ snapshots: markdown-table@3.0.4: {} + math-intrinsics@1.1.0: {} + mdast-util-find-and-replace@3.0.2: dependencies: '@types/mdast': 4.0.4 @@ -5703,6 +6075,12 @@ snapshots: transitivePeerDependencies: - supports-color + mime-db@1.52.0: {} + + mime-types@2.1.35: + dependencies: + mime-db: 1.52.0 + minimatch@10.2.6: dependencies: brace-expansion: 5.0.9 @@ -5759,6 +6137,8 @@ snapshots: node-fetch-native@1.6.7: {} + node-gyp-build@4.8.4: {} + node-releases@2.0.54: {} normalize-path@3.0.0: {} @@ -5861,10 +6241,18 @@ snapshots: dependencies: yocto-queue: 0.1.0 + p-limit@4.0.0: + dependencies: + yocto-queue: 1.2.2 + p-locate@5.0.0: dependencies: p-limit: 3.1.0 + p-locate@6.0.0: + dependencies: + p-limit: 4.0.0 + p-timeout@6.1.4: {} package-manager-detector@1.8.0: {} @@ -5879,6 +6267,8 @@ snapshots: path-exists@4.0.0: {} + path-exists@5.0.0: {} + path-key@3.1.1: {} path-parse@1.0.7: {} @@ -6094,6 +6484,8 @@ snapshots: pretty-bytes@7.1.1: {} + proxy-from-env@2.1.0: {} + punycode@2.3.1: {} qified@0.10.1: @@ -6148,27 +6540,6 @@ snapshots: path-parse: 1.0.7 supports-preserve-symlinks-flag: 1.0.0 - rolldown@1.2.6: - dependencies: - '@oxc-project/types': 0.147.0 - '@rolldown/pluginutils': 1.0.1 - optionalDependencies: - '@rolldown/binding-android-arm-eabi': 1.2.6 - '@rolldown/binding-android-arm64': 1.2.6 - '@rolldown/binding-darwin-arm64': 1.2.6 - '@rolldown/binding-darwin-x64': 1.2.6 - '@rolldown/binding-freebsd-x64': 1.2.6 - '@rolldown/binding-linux-arm-gnueabihf': 1.2.6 - '@rolldown/binding-linux-arm64-gnu': 1.2.6 - '@rolldown/binding-linux-arm64-musl': 1.2.6 - '@rolldown/binding-linux-ppc64-gnu': 1.2.6 - '@rolldown/binding-linux-s390x-gnu': 1.2.6 - '@rolldown/binding-linux-x64-gnu': 1.2.6 - '@rolldown/binding-linux-x64-musl': 1.2.6 - '@rolldown/binding-openharmony-arm64': 1.2.6 - '@rolldown/binding-win32-arm64-msvc': 1.2.6 - '@rolldown/binding-win32-x64-msvc': 1.2.6 - rollup-plugin-dts@6.5.1(rollup@4.63.0)(typescript@6.0.3): dependencies: '@jridgewell/remapping': 2.3.5 @@ -6284,6 +6655,8 @@ snapshots: spdx-license-ids@3.0.23: {} + stack-trace@1.0.0-pre2: {} + stackback@0.0.2: {} std-env@3.10.0: {} @@ -6481,23 +6854,25 @@ snapshots: verkit@0.4.0: {} - vite@8.2.2(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0): + vite@7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0): dependencies: - lightningcss: 1.33.0 + esbuild: 0.28.2 + fdir: 6.5.0(picomatch@4.0.7) picomatch: 4.0.7 postcss: 8.5.26 - rolldown: 1.2.6 + rollup: 4.63.0 tinyglobby: 0.2.17 optionalDependencies: '@types/node': 26.4.0 fsevents: 2.3.3 jiti: 2.7.0 + lightningcss: 1.33.0 yaml: 2.9.0 - vitest@4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(vite@8.2.2(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)): + vitest@4.1.11(@types/node@26.4.0)(@vitest/coverage-v8@4.1.11)(vite@7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0)): dependencies: '@vitest/expect': 4.1.11 - '@vitest/mocker': 4.1.11(vite@8.2.2(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0)) + '@vitest/mocker': 4.1.11(vite@7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0)) '@vitest/pretty-format': 4.1.11 '@vitest/runner': 4.1.11 '@vitest/snapshot': 4.1.11 @@ -6514,7 +6889,7 @@ snapshots: tinyexec: 1.3.0 tinyglobby: 0.2.17 tinyrainbow: 3.1.1 - vite: 8.2.2(@types/node@26.4.0)(jiti@2.7.0)(yaml@2.9.0) + vite: 7.3.6(@types/node@26.4.0)(jiti@2.7.0)(lightningcss@1.33.0)(yaml@2.9.0) why-is-node-running: 2.3.0 optionalDependencies: '@types/node': 26.4.0 @@ -6564,4 +6939,6 @@ snapshots: yocto-queue@0.1.0: {} + yocto-queue@1.2.2: {} + zwitch@2.0.4: {} diff --git a/vitest.config.ts b/vitest.config.ts index 8af2e43..5ee7646 100644 --- a/vitest.config.ts +++ b/vitest.config.ts @@ -1,6 +1,8 @@ +import codspeedPlugin from '@codspeed/vitest-plugin' import { defaultExclude, defineConfig } from 'vitest/config' export default defineConfig({ + plugins: [codspeedPlugin()], test: { coverage: { exclude: ['**.bench.*', '**.test-d.*', '**.test.*'], @@ -10,5 +12,9 @@ export default defineConfig({ globals: true, include: ['**/*.test.ts'], passWithNoTests: true, + benchmark: { + include: ['**/*.bench.ts'], + exclude: [...defaultExclude, '**/.claude/**'], + }, }, }) From 10819745c75fe6858841f875dea49ef58ebc1015 Mon Sep 17 00:00:00 2001 From: Claude Date: Fri, 2 Oct 2026 13:17:59 +0000 Subject: [PATCH 2/2] docs: drop the benchmark paragraph from the root README Co-Authored-By: Claude Opus 5.5 Claude-Session: https://claude.ai/code/session_01LjCihASFt61Eqjq9jfAoE5 --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index f610a99..b3e8e8a 100644 --- a/README.md +++ b/README.md @@ -38,8 +38,6 @@ pnpm type:check pnpm bench ``` -`pnpm bench` runs the benchmarks in [`packages/downgrader/benches`](https://github.com/middleapi/openapi-spec/tree/main/packages/downgrader/benches). [CodSpeed](https://app.codspeed.io/middleapi/openapi-spec) runs them on every push to `main` and every pull request, and reports any change in performance on the pull request. - ## Sponsors Like what we build over at [middleapi](https://github.com/middleapi)? You can help keep it going through [GitHub Sponsors](https://github.com/sponsors/dinwwwh) or [Open Collective](https://opencollective.com/middleapi). Every bit helps! 🚀