mrkeyoor.com_
Sat 08 Aug 21:59 UTC
npmUtilsupdated 08 Aug 2026

@hey-api/json-schema-ref-parser

@hey-api/json-schema-ref-parser is Hey API's ESM-only fork of the familiar JSON Schema reference parser. Version 1.4.4 can parse one JSON or YAML schema from an object, local path, URL, or supplied ArrayBuffer; bundle external references into internal pointers; and merge several OpenAPI-shaped inputs with collision prefixes through bundleMany. It exposes a reference map and structured errors. Despite the package name and README, the published class does not expose public resolve or dereference methods.

Verdict

Install this fork when Hey API integration or its opinionated OpenAPI bundleMany merge is the requirement. For a general reference parser, the missing public dereference and resolver controls, ESM-only Node 22 floor, and unsafe defaults around untrusted external refs make the upstream package a better fit.

API stability2/5The package is only at 1.4.4 and already used 1.4.0 for a breaking minimum-Node bump; the published engine is now Node 22.18.0. Its API differs sharply from the package it forked, using object arguments and omitting public resolve, dereference, callbacks, static helpers, and configurable resolver options while declarations still carry types and comments for internal dereferencing machinery. Recent patches also changed unresolved-reference deletion, whole-file naming, URL encoding, YAML implementation, and sibling-schema bundling, all of which can alter generated output.
Docs2/5The package README explains the reference problem, JSON and YAML mixing, bundling, circular references, raw object input, $id bases, bundleMany, and intended dereference hooks with concise examples. Unfortunately, the most important advertised capability is not callable: 1.4.4 has no public dereference method, so the hook example fails. The README also claims browser compatibility and shared object identity that do not describe this Node-only build, omits the exact Node 22.18 floor and ESM-only export, and does not warn that bundling trusted-looking schemas performs unrestricted file and network reads.
Maintenance5/5Version 1.4.4 was published on 2026-06-22 and the Hey API monorepo was pushed on 2026-08-06. The package changelog shows frequent fixes across URL encoding, YAML parsing, external siblings, schema naming, unresolved references, dependency cleanup, and multi-input merging, backed by TypeScript source and focused tests. The repository has 545 issues and pull requests combined across the entire monorepo, not this package alone; the mismatch between active code and stale inherited documentation is the main maintenance concern.
Ecosystem3/5The package recorded 3,601,354 downloads in the measured week and shares a 5,237-star monorepo with Hey API's widely used OpenAPI generators. It uses familiar JSON Pointer and JSON Reference concepts, js-yaml, structured errors, and @types/json-schema. Much of that traffic is tied to Hey API rather than independent adoption, and the fork is less interoperable than its name suggests because it removes upstream methods and resolver configuration. Package-specific docs, plugins, and examples are sparse outside bundleMany.

Use it if

  • You already use Hey API's Node 22 toolchain and need the exact bundling behavior consumed by that ecosystem
  • You want to combine multi-file OpenAPI inputs while keeping internal $ref pointers instead of expanding every reference
  • You need bundleMany's opinionated prefixing of components, operation ids, conflicting paths, and duplicate tags
  • All schemas and external reference targets are trusted or isolated from sensitive networks and files
Skip it if

Setup reality

Install @hey-api/json-schema-ref-parser only on Node 22.18.0 or newer. Version 1.4.4 is ESM-only, so use import { $RefParser } and do not call require(); the export map contains only an import target and package.json. TypeScript declarations are included. Runtime dependencies are js-yaml, @jsdevtools/ono, and @types/json-schema. Every public operation takes one object argument: parse returns { schema }, while bundle and bundleMany return a schema directly. parse reads only the root input and leaves $ref strings alone. bundle reads the root, recursively opens every external reference, and rewrites the graph to internal pointers. Local paths use fs.promises.readFile; URLs use global fetch with a 60-second per-request abort and no response-size cap. The fetch RequestInit passed to bundle is used for the root URL, but nested external resolution calls the URL resolver without carrying those headers or options. There is no public resolver registry, host allowlist, offline flag, or external:false option in this fork. If input is not fully trusted, use parse only, reject external references yourself, or run bundling in a process with restricted filesystem and network access. Circular structures remain references after bundle and can be serialized. The README's dereference options, circular object behavior, equality claim, and hook example do not match a callable 1.4.4 method. bundleMany is not a neutral JSON Schema concatenator: source shows OpenAPI and Swagger-specific merging of info, servers, paths, tags, operationId, and components, with filenames used as prefixes when names collide. Raw object input with $id is described as setting a reference base, but 1.4.4 reduces that id to its origin, so test relative references under nested URL paths. This library resolves pointers; it does not validate the resulting schema or guarantee that merged APIs keep your intended routing semantics.

Patterns

Parse a local JSON or YAML fileparse-local-schema

import { $RefParser } from '@hey-api/json-schema-ref-parser';

const parser = new $RefParser();
const { schema } = await parser.parse({
  pathOrUrlOrSchema: './schemas/root.yaml',
});
console.log(schema);

parse reads only the root document and returns an object containing schema. It does not resolve, bundle, dereference, or validate $ref targets.

Parse an in-memory schema objectparse-schema-object

const input = {
  $schema: 'https://json-schema.org/draft/2020-12/schema',
  type: 'object',
  properties: { id: { type: 'string' } },
};

const { schema } = await new $RefParser().parse({
  pathOrUrlOrSchema: input,
});

Without $id, the raw object is used directly and no I/O occurs. Parsing checks that the root is object-like, not that it conforms to a JSON Schema dialect.

Parse a remote root with request headersparse-remote-root

const parser = new $RefParser();
const { schema } = await parser.parse({
  pathOrUrlOrSchema: 'https://api.example.com/private/openapi.yaml',
  fetch: {
    headers: { Authorization: `Bearer ${token}` },
  },
});

The RequestInit applies to this root request. If you switch to bundle, nested remote references are fetched without inheriting these headers in version 1.4.4.

Bundle a multi-file schemabundle-external-references

const parser = new $RefParser();
const bundled = await parser.bundle({
  pathOrUrlOrSchema: './schemas/root.yaml',
});

await fs.writeFile(
  'dist/schema.json',
  JSON.stringify(bundled, null, 2)
);

bundle recursively reads external file and URL references, then rewrites them as internal pointers. Use only trusted inputs or a filesystem and network sandbox.

Bundle from already fetched root bytesbundle-supplied-bytes

const response = await fetch(rootUrl, {
  headers: { Authorization: `Bearer ${token}` },
});
if (!response.ok) throw new Error(`HTTP ${response.status}`);

const bundled = await new $RefParser().bundle({
  pathOrUrlOrSchema: rootUrl,
  arrayBuffer: await response.arrayBuffer(),
});

The URL still establishes the base for relative references. Only the root bytes are supplied; nested references can still trigger unauthenticated network requests.

List every source read during bundlinginspect-resolved-sources

const parser = new $RefParser();
await parser.bundle({ pathOrUrlOrSchema: './schemas/root.yaml' });

console.log(parser.$refs.paths());
console.log(parser.$refs.paths('file'));
console.log(parser.$refs.paths('http'));

Inspecting paths after the operation is useful for audits and reproducible builds, but it does not prevent an unwanted read that already occurred.

Read the parser's reference mapinspect-resolved-values

const parser = new $RefParser();
await parser.bundle({ pathOrUrlOrSchema: './schemas/root.yaml' });

const files = parser.$refs.values('file');
for (const [source, value] of Object.entries(files)) {
  console.log(source, typeof value);
}

$refs contains whole-document values keyed by normalized source URLs. Treat it as operation state; creating a new parse on the same parser resets the map.

Keep recursive schemas serializablebundle-circular-schema

const parser = new $RefParser();
const bundled = await parser.bundle({
  pathOrUrlOrSchema: './schemas/recursive.yaml',
});

const json = JSON.stringify(bundled);

Bundling retains internal $ref pointers, so recursive schemas do not become circular JavaScript object graphs and JSON.stringify remains usable.

Merge and bundle several OpenAPI inputsmerge-openapi-inputs

const parser = new $RefParser();
const merged = await parser.bundleMany({
  pathOrUrlOrSchemas: [
    './specs/catalog.yaml',
    './specs/billing.yaml',
    { openapi: '3.1.0', info: { title: 'Inline', version: '1' }, paths: {} },
  ],
});

bundleMany uses OpenAPI and Swagger-specific merge rules. Components and operation ids gain filename prefixes, and conflicting path methods can move under a prefixed route. Review the resulting API contract.

Restrict parsing to JSON inputsdisable-yaml-parser

const parser = new $RefParser();
parser.options.parse.yaml.canHandle = () => false;
parser.options.parse.text.canHandle = () => false;
parser.options.parse.binary.canHandle = () => false;

const bundled = await parser.bundle({
  pathOrUrlOrSchema: './schemas/root.json',
});

Parser plugins control syntax recognition, not which files or hosts may be read. External JSON references remain enabled and need separate trust controls.

Inspect grouped reference errorshandle-parser-errors

import {
  JSONParserErrorGroup,
  isHandledError,
} from '@hey-api/json-schema-ref-parser';

try {
  await parser.bundle({ pathOrUrlOrSchema: input });
} catch (error) {
  if (error instanceof JSONParserErrorGroup) {
    for (const item of error.errors) {
      console.error(item.code, item.source, item.message);
    }
  } else if (isHandledError(error)) {
    console.error(error.code, error.source, error.message);
  } else {
    throw error;
  }
}

Root read and parse failures can surface directly, while external resolution and bundling can aggregate handled errors. Do not rely on message text alone when code is available.

Reject external references before trusted processingreject-external-references

function assertInternalRefs(value) {
  if (!value || typeof value !== 'object') return;
  if ('$ref' in value && typeof value.$ref === 'string' && !value.$ref.startsWith('#')) {
    throw new Error(`External $ref rejected: ${value.$ref}`);
  }
  for (const child of Object.values(value)) assertInternalRefs(child);
}

const { schema } = await parser.parse({ pathOrUrlOrSchema: upload });
assertInternalRefs(schema);

Version 1.4.4 has no public external:false or resolver allowlist. Parse first and reject external refs before calling bundle on user-controlled schemas.

Alternatives

PackageRegistryPick it when
@apidevtools/json-schema-ref-parsernpmUse the upstream package when you need documented parse, resolve, bundle, and dereference APIs with configurable resolvers
@apidevtools/swagger-parsernpmUse OpenAPI and Swagger parsing plus schema and specification validation instead of generic reference bundling alone
@stoplight/json-ref-resolvernpmUse a resolver designed around custom authority handlers when control over remote lookup is central
json-refsnpmUse lower-level JSON Reference discovery, resolution, and pointer utilities for an established CommonJS workflow