
Security News
New Study Identifies 53 Slopsquatting Targets Across 5 Frontier LLMs
Five frontier LLMs generated the same nonexistent package names, leaving 53 available for potential slopsquatting across PyPI and npm.
@amritk/resolve-refs
Advanced tools
Resolve and inline JSON Schema / OpenAPI $refs — internal, cross-file, and remote — with session caching and a default-deny SSRF guard.
Resolve and inline JSON Schema / OpenAPI $refs — internal pointers, cross-file
refs, and remote (http/https) documents — into a single dereferenced document.
$ref that resolves within the output document (a
cross-file cycle target is hoisted into the root's $defs), so recursive
schemas survive dereferencing intact.$id-scoped. Beyond JSON-pointer $refs,
plain-name $anchor references (#node), $dynamicRef/$dynamicAnchor
(2020-12), and $recursiveRef/$recursiveAnchor (2019-09) are dereferenced
too. $id base-URI scoping is modelled for the bundled-document case: a ref
whose URI matches an embedded resource's $id resolves to it without
fetching, and anchors bind within the resource that declares them (falling
back to a document-global search). See $id scoping below for the exact
subset.169.254.169.254) hosts are refused unless you opt in.$ref whose only siblings are summary /
description inlines the target with those annotations overriding — matching
OpenAPI 3.1 Reference Object semantics, where an allOf wrapper would be
invalid. Any other sibling keyword keeps the spec-correct allOf combination.import { resolveRefs, resolveRefsFromFile } from '@amritk/resolve-refs'
// In-memory, internal (#/...) refs only. External refs (another file or an
// http(s) URL) are left in place and reported on `errors`, since this resolver
// can't load other documents — use resolveRefsFromFile for those:
const { resolved, errors } = resolveRefs(myDocument)
// From disk or a URL, including cross-file and remote refs:
const result = await resolveRefsFromFile('./schema.json')
const remote = await resolveRefsFromFile('https://api.example.com/schema.json', {
allowedHosts: ['api.example.com'],
})
resolveRefsFromFile)| Option | Default | Description |
|---|---|---|
remote | true | Whether http(s) refs may be fetched at all. |
allowedHosts | [] | If non-empty, only these hosts may be fetched. An explicit entry bypasses the private-host guard. |
allowPrivateHosts | false | Allow loopback/private/link-local targets. Left off, these are refused as an SSRF guard. |
headers | — | Extra headers for remote requests (record, or (url) => headers for per-host credentials). Never sent across a cross-origin redirect. |
fetch | global fetch | Custom fetch implementation. The SSRF guard still evaluates every hop before it is called. |
timeoutMs | 30_000 | Abort an unresponsive remote fetch after this many milliseconds. |
maxRedirects | 5 | Redirect hops to follow per remote document (each hop re-runs the SSRF guard). |
maxBytes | 16 MiB | Refuse to buffer a remote document larger than this. |
cache | true | Pass false to bypass the process-wide session cache for this call — everything is re-fetched, nothing is stored. |
parse | JSON.parse | Custom content parser (e.g. YAML-aware). |
trackOrigins | false | Record a per-node origin map on the result. |
Errors (a missing file, a refused host, a bad URL) are collected on
result.errors rather than thrown; the corresponding ref resolves to {} so the
rest of the document still resolves.
clearRemoteCache() drops every cached remote document — useful in tests or
long-lived sessions where remote schemas may change.
$id scopingThe supported subset, chosen for the bundled-document reality rather than the full spec:
$id is an embedded resource: its $id (resolved
against the enclosing base) becomes the base URI for everything inside it.$id resolves to that resource without fetching. A pointer or
anchor fragment on such a ref applies within that resource.#/pointer fragment stays document-root-relative — the behavior
bundled real-world documents rely on — even inside an embedded resource.$dynamicRef prefers a $dynamicAnchor in scope, then degrades to $ref
semantics. The full dynamic-scope algorithm (outermost anchor along the
runtime reference chain) is not modelled.$id —
a root $id naming a remote URL cannot turn a local sibling-file ref into a
network fetch.Every document — local file or remote — is parsed as JSON. mjst works with JSON Schema documents only, so this resolver stays JSON-only and dependency-free. (The Loupe linter's sibling resolver additionally accepts YAML.)
resolveRefs memoizes: every unique $ref string is resolved once per scope,
with a sentinel that breaks cycles by keeping the reference node in place. But it
is no longer only a memoized inliner — before resolving anything it walks the
whole document once to build a resource registry ($id/$anchor scoping), keeps
recursive cycles intact, and records a diagnostic for every external ref. The
bench/ suite pits it against a bare naive inliner that does none of that — no
registry, no scoping, no diagnostics — and re-resolves each ref on every
encounter, so the gap is the production resolver's total per-call cost against
the cheapest thing that produces the same inlined shape. Both are asserted to
produce byte-identical output before either is timed. Representative numbers
(Bun 1.3, Linux x64 — your hardware will differ, run bun run bench yourself):
| schema | cached | naive | speedup |
|---|---|---|---|
chain (40 $ref → $ref links) | ~2.6k ops/s | ~0.8k ops/s | ~3.2× |
| reuse-heavy (50 refs → 1 def) | ~4.5k ops/s | ~8k ops/s | ~0.5× |
| cyclic tree | ~27k ops/s | ~74k ops/s | ~0.37× |
| wide-distinct (60 defs, each used once) | ~2.3k ops/s | ~7.3k ops/s | ~0.32× |
Memoization overtakes the naive walk only on the chain shape, where a long
indirection path is expensive to re-resolve and the cache collapses it to one
pass. On every other shape here the fixed cost of the up-front registry walk (paid
once per call, no matter how the refs reuse) outweighs what memoization saves, and
the bare inliner is faster — these are small schemas where that one document walk
dominates. The takeaway is practical: the resolver's per-call floor is a full
document traversal, so in a hot loop resolve a document once and reuse the
result rather than re-resolving. The reuse-heavy, cyclic, and wide-distinct
rows are kept in the table precisely to show that trade honestly rather than
cherry-picking the one shape the cache wins.
Opting into trackOrigins (which records where each inlined value came from) adds
roughly 0–20% on top, within run-to-run noise on these small schemas.
FAQs
Resolve and inline JSON Schema / OpenAPI $refs — internal, cross-file, and remote — with session caching and a default-deny SSRF guard.
The npm package @amritk/resolve-refs receives a total of 543 weekly downloads. As such, @amritk/resolve-refs popularity was classified as not popular.
We found that @amritk/resolve-refs demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Five frontier LLMs generated the same nonexistent package names, leaving 53 available for potential slopsquatting across PyPI and npm.

Security News
The White House’s Gold Eagle Initiative aims to coordinate AI-discovered vulnerabilities, validate findings, and accelerate patching across critical software.

Security News
A Shai-Hulud infection exposed Suno's source code, which shows the AI music startup stream-ripped tracks to train its models.