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..b3e8e8a 100644
--- a/README.md
+++ b/README.md
@@ -7,6 +7,9 @@
+
+
+
@@ -32,6 +35,7 @@ pnpm install
pnpm test
pnpm lint
pnpm type:check
+pnpm bench
```
## Sponsors
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 @@
+
+
+
@@ -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 @@
+
+
+
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/**'],
+ },
},
})