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

@vigolium/jstangle

v0.2.0

Published

Deobfuscate, beautify, and AST-parse JavaScript bundles to extract hidden endpoints, API request shapes, and useful information — the JavaScript intelligence engine inside Vigolium

Readme

jstangle

jstangle is the JavaScript intelligence engine inside Vigolium. It deobfuscates and beautifies real-world JavaScript, parses it into an AST, and mines the result for the things that matter to a scanner: hidden HTTP endpoints, API request shapes, GraphQL operations, WebSocket/SSE metadata, client-side routes, browser security flows, and other useful information buried in modern bundles.

Modern front-ends ship their attack surface as minified, obfuscated, tree-shaken JavaScript. A plain regex sweep misses most of it and drowns the rest in noise. jstangle untangles that code first, then reasons over the structure — so Vigolium discovers endpoints and secrets that only exist inside the bundle.

Why?

Static string-grepping over bundled JavaScript is fast but nearly blind — it can't follow how a URL is assembled, which adapter sends it, or whether a match is live code or a comment. jstangle takes the opposite approach: deobfuscate and normalize the source, walk the AST, and resolve request facts with real evidence and confidence. The output is typed and provenance-tracked, so Vigolium knows what is safe to replay and what is only a discovery hint.

The goal is simple: turn opaque JavaScript into precise, actionable facts about a target's real HTTP surface.

Install as a standalone CLI

jstangle ships inside Vigolium, but you can also install it on its own as a standalone CLI:

npm install -g @vigolium/jstangle

This puts a jstangle command on your PATH. See CLI for usage.

Build and test

From the Vigolium repository root:

make ensure-jstangle       # rebuild the host helper only when its source hash changed
make update-jstangle       # build and stage every release target

From this directory:

bun install --linker isolated
bun run build:types
bun run test
bun run build:bin:host

make ensure-jstangle compares the current deterministic source fingerprint to the fingerprint compiled into the staged helper, so an old or incompatible helper can never silently run against newer Go code.

Profiles

Each caller requests only the stages it consumes.

| Profile | Intended consumer | Main output | |---|---|---| | endpoints | endpoint-only API use | HTTP request facts | | dom-security | passive DOM security module | DOM/browser flow facts | | beautify | passive JS beautifier | beautified artifact only | | discovery | normal content discovery | requests, assets, GraphQL, protocols, routes, optional transformed artifact | | discovery-lite | larger discovery assets | discovery facts without transformed code | | full | manual research | all analysis capabilities | | inspect | debugging/evidence | full output plus request evidence |

Skipped stages appear with zero duration and status: "skipped" in stage metrics. Webcrack is loaded lazily only when a beautify stage runs.

CLI

The JavaScript to analyze comes from the first positional argument — which may be either a file path or the raw JS source itself — and falls back to stdin when omitted.

# From a file
jstangle --profile discovery --source-url https://app.test/assets/app.js app.js

# From raw JS passed inline as the first argument
jstangle --profile endpoints 'fetch("/api/v1/users")'

# From stdin (pipe a bundle in)
curl -s https://app.test/assets/app.js | jstangle --profile discovery

# Put transformed/beautified documents in a contained artifact directory
jstangle --profile beautify --artifact-dir /tmp/jstangle-artifacts app.js

# Machine-readable build and capability contract
jstangle --capabilities

# Persistent length-prefixed worker transport (normally owned by Go)
jstangle --worker

Important limits include --max-requests, --max-ast-nodes, --max-output-bytes, --max-artifact-bytes, and --deadline-ms.

Output

--capabilities reports the tool version, deterministic source hash, supported profiles, record schema versions, runtime, framing, and compiled dependency versions.

An analysisResult contains:

  • source: source URL, content SHA-256, size, filename/media type, and bundle format.
  • stats: overall status, record counts, total time, and per-stage metrics.
  • diagnostics: explicit parse, budget, fallback, and artifact degradations.
  • records: compact typed facts.
  • artifacts: contained paths, hashes, lengths, and formats for large output.

Current typed records are:

  • httpRequest: method, URL/query/body/header templates, client adapter, confidence, source span, and resolution evidence.
  • domFlow: binding/order-aware source-to-sink browser flow.
  • assetReference: dynamic/static chunks, workers, service workers, manifests, source maps, Wasm, and config assets.
  • graphqlOperation: parsed operation/document, variables, persisted hash, endpoint, and transport.
  • websocket and eventSource: protocol metadata and message/event behavior.
  • clientRoute: framework-aware routes, guards, and lazy assets.
  • browserSecurityFlow: postMessage trust, open redirect, script/network URL, dynamic execution, sensitive exfiltration, and prototype-pollution evidence.

Unknown future record kinds are retained by the Go decoder under a bounded budget, allowing forward-compatible diagnostics instead of silent loss.

Safety and degradation

  • Per-analysis state is isolated; persistent workers process one framed job at a time and Go supplies bounded parallelism.
  • Content/profile results are byte-bounded and coalesced by content hash.
  • Worker admission is memory-weighted, with job-count and RSS recycling.
  • Oversized discovery input first drops transformed-code work, then uses a bounded lexical endpoint/asset fallback. Hard-limit input is rejected.
  • AST node, resolution, evidence, request, artifact, output, graph, and time budgets produce explicit diagnostics.
  • Artifact paths are verified to remain inside the job directory before Go reads them; all job directories are removed after success, failure, or cancel.

Vigolium integration policy

High-confidence request facts are eligible for exact replay with their observed method, query, body, content type, and safe static headers. Medium-confidence facts are available only in conservative mode. Low-confidence generic strings are discovery hints and never cause direct traffic by default.

Relative requests resolve once against the JavaScript asset that produced them. Authorization, cookies, API keys, CSRF tokens, browser-controlled headers, and dynamic header values are not copied into replay traffic. Authentication comes from Vigolium's configured session instead.

WebSocket and SSE facts never enter the ordinary HTTP variant generator. A bounded handshake is synthesized only when protocol_handshake: true is set.

Source maps are fetched by Go under normal scope/auth/rate limits. Bounded sourcesContent files are analyzed individually and stored as immutable, session-scoped artifacts; source paths are display metadata and never filesystem destinations.

Credits

jstangle stands on the shoulders of the open-source JavaScript deobfuscation, debundling, and beautification community. It is inspired by — and grateful to — these projects:

License

jstangle is made with ♥ by @j3ssie, with @theblackturtle as a core contributor.