npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@openapi-spec/downgrader

v0.1.0

Published

Downgrade OpenAPI specifications one minor version at a time: 3.2 to 3.1 and 3.1 to 3.0, for whole documents or individual schemas

Readme

@openapi-spec/downgrader downgrades OpenAPI Specification documents one minor version at a time: 3.2 to 3.1 and 3.1 to 3.0. Use it when you author against a newer version than your tools accept, such as a code generator, gateway, or validator that stops at 3.0 or 3.1. Each converter handles a whole document or a single Schema Object.

Every converter follows the same contract:

  • Never throws. Malformed parts are deep-copied through unchanged instead of failing the whole conversion. Cyclic object graphs, such as the output of a $ref dereferencer, convert with their cycles preserved. Only pathologically deep nesting (thousands of levels) can still exhaust the call stack.
  • Never mutates. The input is left untouched and the result is a new object.
  • Preserves extensions, never invents them. x- keys and unknown keys survive. Constructs the target version cannot express are converted where an equivalent exists and removed otherwise.

Usage

import {
  downgradeSchemaV31ToV30,
  downgradeSchemaV32ToV31,
  downgradeSpecV31ToV30,
  downgradeSpecV32ToV31,
} from '@openapi-spec/downgrader'

const v31 = downgradeSpecV32ToV31(v32Document)
const v30 = downgradeSpecV31ToV30(v31Document)

// There is no direct 3.2 to 3.0 converter on purpose. Compose the steps:
const downgraded = downgradeSpecV31ToV30(downgradeSpecV32ToV31(v32Document))

// Schema Objects convert on their own:
downgradeSchemaV31ToV30({ type: ['string', 'null'] })
// { type: 'string', nullable: true }

| Function | Input | Output | | ------------------------- | ------------------- | --------------------------------------- | | downgradeSpecV32ToV31 | 3.2 OpenAPIObject | 3.1 OpenAPIObject | | downgradeSchemaV32ToV31 | 3.2 SchemaObject | 3.1 SchemaObject | | downgradeSpecV31ToV30 | 3.1 OpenAPIObject | 3.0 OpenAPIObject | | downgradeSchemaV31ToV30 | 3.1 SchemaObject | 3.0 SchemaObject or ReferenceObject |

All types come from @openapi-spec/types.

3.2 → 3.1

Schema Objects pass through unchanged. 3.2 keeps the 3.1 JSON Schema keyword set and only adds two fields to the OAS vocabulary, discriminator.defaultMapping and xml.nodeType, and both are kept. 3.1 tooling ignores them, so a defaultMapping fallback stops taking effect, while nodeType is picked up again on the 3.1 → 3.0 hop. The standard OpenAPI 3.1 document schema accepts them, but the strict OAS 3.1 base-vocabulary meta-schema closes the XML and Discriminator Objects and will flag them.

Converted:

| 3.2 construct | 3.1 result | | -------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | openapi: 3.2.x | openapi: 3.1.2 | | jsonSchemaDialect naming a 3.2 OAS dialect | https://spec.openapis.org/oas/3.1/dialect/base; other dialects pass through | | components.mediaTypes and content-map $refs to it | references inlined and the component map removed. Entries whose target cannot be inlined (external, unknown, or cyclic) are removed, since 3.1 content maps cannot hold references. A parameter or header that loses its entire content that way is removed too, because 3.1 requires exactly one entry there | | media type itemSchema without a sibling schema | schema: { type: "array", items: … }, the sequential media type data model | | response summary without a description | promoted to description; "" when neither exists, since 3.1 requires it | | example dataValue / serializedValue without value or externalValue | promoted to value, dataValue taking precedence | | parameter style: "cookie" | removed so the 3.1 default form applies |

Removed, with no 3.1 equivalent:

  • $self
  • server name
  • tag summary, parent, and kind
  • the Path Item query operation and additionalOperations
  • in: "querystring" parameters, in parameter lists and in components.parameters, together with references to removed component parameters and headers (chains of reference aliases included)
  • allowReserved on non-query parameters
  • media type description
  • prefixEncoding, itemEncoding, and nested encoding on media types and encodings
  • itemSchema beside an existing schema, and response summary beside an existing description
  • OAuth deviceAuthorization flows
  • security scheme oauth2MetadataUrl and deprecated

Known limitations: security requirements keyed by URI, $self-relative reference resolution, and a $schema keyword inside a Schema Object that names the 3.2 dialect all pass through unchanged.

3.1 → 3.0

Converted:

| 3.1 construct | 3.0 result | | ---------------------------------------------------------- | ---------------------------------------------------------------------- | | openapi: 3.1.x | openapi: 3.0.4 | | missing paths | {} (required in 3.0) | | missing operation responses | { "default": { "description": "" } } (required and non-empty in 3.0) | | path parameters without required: true | required: true added (mandatory for in: "path") | | Reference Object summary / description | removed (3.0 references carry no overrides) | | security requirement scopes on apiKey and http schemes | emptied to [] |

Removed, with no 3.0 equivalent:

  • webhooks
  • jsonSchemaDialect
  • info.summary and license.identifier
  • components.pathItems. Path Item $refs to it, in paths and in callbacks, are inlined first, following reference chains, with the referencing Path Item's own fields winning over inlined ones. A reference that cannot be inlined (unknown or cyclic target) is left as is and will dangle.
  • mutualTLS security schemes, reference aliases included. Their names are stripped from every security requirement, a requirement left empty is removed, and a security list left empty is removed entirely, since an explicit empty list means "no security required" and would make the operation public.

Schema Objects:

| 3.1 construct | 3.0 result | | ---------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | true / false boolean schemas | {} / { not: {} } | | $ref with sibling keywords | siblings kept, $ref moved into allOf | | type: ["T", "null"] | type: "T" plus nullable: true | | type with several non-null entries | anyOf of single-type schemas, each nullable when null was listed | | type: "null" | nullable: true plus enum: [null]. A sibling enum or const is intersected with the null type: an enum containing null collapses to [null], and one excluding it yields not: {}, since the source accepted no value | | const | single-value enum, plus nullable: true when the value is null | | numeric exclusiveMinimum / exclusiveMaximum | minimum / maximum plus the boolean flag; a tighter existing bound wins | | examples | first entry becomes example when none exists | | contentEncoding: base64 | format: byte when no format exists | | contentMediaType: application/octet-stream without contentEncoding | format: binary when no format exists | | type: "array" without items | items: {} added (required in 3.0) | | enum: [] | removed (3.0 requires a non-empty enum) | | required: [] / duplicate required entries | removed / deduplicated (3.0 requires a non-empty, unique required) | | XML nodeType, carried over from a 3.2 chain | attribute: true / wrapped: true where expressible, then removed (3.0 forbids unknown XML Object fields) |

Removed, with no 3.0 equivalent: $schema, $id, $defs, $anchor, $dynamicRef, $dynamicAnchor, $vocabulary, $comment, if / then / else, dependentSchemas, dependentRequired, prefixItems (with its trailing items), contains, minContains, maxContains, patternProperties (with its sibling additionalProperties, whose meaning would otherwise tighten onto the pattern-matched keys), propertyNames, unevaluatedItems, unevaluatedProperties, and contentSchema. In positive schema positions dropping these only loosens validation, the safe direction for a downgrade.

Known limitations:

  • $refs into dropped keywords (#/…/$defs/… pointers, $anchor targets, $id-based bases) will dangle. Hoist reusable subschemas into components.schemas before downgrading.
  • Non-standard schema keywords are preserved per the extension contract, even though the official 3.0 schema forbids unknown Schema Object fields.
  • Dropping keywords inside not, where loosening the operand tightens the whole, or inside oneOf branches, where loosening one branch can break exclusivity, can change what validates.

Sponsors

Like what we build over at middleapi? You can help keep it going through GitHub Sponsors or Open Collective. Every bit helps! 🚀

Organization Sponsors

Sponsors

Backers

With thanks to 36 past sponsors who helped get openapi-spec here.

License

Distributed under the MIT License. See LICENSE for more information.