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

script2builtins-runtime

v0.1.1

Published

Runtime instrumentation companion to script2builtins. Drives a real browser, traps every catalog API + sink + dynamic-execution point, and emits findings in the same shape the static analyzer produces.

Readme

script2builtins-runtime

Runtime instrumentation companion to script2builtins. Drives a real Chromium against a URL, traps every catalog API + every network sink + every dynamic-execution point, and emits findings in the same shape the static analyzer produces.

Why

The static analyzer is fast and cheap but has four hard-baked blind spots: code inside eval / Function strings, fully dynamic property keys, Reflect.get / descriptor-getter trampolines, and anti-debug checks. This package closes all four by running the script in an instrumented browser and emitting the same RawAccess / NetworkSink structs the static pass produces, so the two reports compose into one.

Install

npm install -g script2builtins-runtime
# dynamic mode only — skip if you'll only run static analysis:
npm install -g playwright
npx playwright install chromium

Requires Node 20+. playwright is a peer dependency — install it yourself only when you need dynamic mode. Static-only users can skip it and avoid the ~300 MB browser download. Installing this package transitively installs script2builtins, so you don't need both — the unified s2b CLI ships here.

Quick start

One CLI, dispatched by what you give it. Static mode never launches a browser:

s2b detector.js                       # static (file)
s2b -                                 # static (stdin)
s2b detector.js --dynamic             # wrap file in HTML harness, drive it
s2b https://target.example/           # dynamic (browser + traps + auto-static
                                      # on every captured script)
s2b https://target.example/fp.js --static-only
                                      # fetch URL, run static, no browser

Common flags: --json, --out <dir>, --min-severity, --no-color. Dynamic-only: --headless, --nav-timeout, --idle, --ua, --harness-mode data|file|http-harness, --trap-reflect-get. s2b --help for the full list.

Harness modes

When running against a file (s2b detector.js --dynamic), pick how the harness HTML is served:

| mode | origin | when to use | |------------------|-----------------------|-------------| | data (default) | opaque data: | cheapest; storage APIs behave differently from a real site | | file | opaque file:// | want relative imports to resolve from disk | | http-harness | real http://127.0.0.1 | the script needs cookies, localStorage, or same-origin fetches |

The HTTP server is started per-run on an ephemeral port and shut down on completion.

Library

Same import surface for both modes:

import { analyze, run, analyzeUrl, renderRuntimeText } from "script2builtins-runtime";

// Static — no browser
const r1 = analyze(source, { name: "detector.js" });

// Static on a URL — fetch + analyze, no browser
const r2 = await analyzeUrl("https://example.com/fp.js");

// Dynamic — drives a browser, also runs static on every captured script
const r3 = await run({
  url: "https://target.example/",
  outDir: "./runs/automated",
  headless: true,
});

console.log(renderRuntimeText(r3, { minSeverity: "medium" }));

for (const f of r3.findings) {
  if (f.provenance === "runtime" && f.api.botDetectionTell) {
    console.log("RUNTIME-ONLY TELL:", f.api.key, f.callSites, "sites");
  }
}

// Inspect runtime exfiltration: now populated thanks to the runtime
// body re-parser (parseRuntimeBody from script2builtins/analyze).
for (const s of r3.reconstructedSinks) {
  for (const a of s.payload?.leakedApis ?? []) {
    console.log("LEAK", s.kind, s.url, "→", a.key);
  }
}

Coverage flags

A few opt-in / opt-out levers tune the trap surface:

  • channelName — the trap installs its drain channel under a random window.__s2b_<6 hex bytes> per attach. Session.channelName exposes the chosen name. Override with attach({ channelName: "…" }) for tests / external observation.
  • trapWorkers (default true) — wraps classic new Worker(url) to bootstrap the trap inside worker scope via importScripts(<trap blob>). Module workers and SharedWorker pass through unchanged.
  • trapReflectGet (default false) — wraps Reflect.get so introspection trampolines that hold non-Proxy root references still surface accesses. Off by default because engine internals call Reflect.get heavily. Enable for high-coverage forensic runs: s2b <url> --trap-reflect-get.
  • trapDynamicExec (default true) — eval, Function, setTimeout("string", …), setInterval("string", …).
  • useProxyRoots (default true) — install root Proxies for the curated navigator, screen, document, … set. Set false to fall back to descriptor-only patching.
  • hardenIntrospection (default true) — Function.prototype.toString masking so wrapped functions still look native.

Sources the runtime captures

Each entry in RuntimeReport.scripts carries an acquisition tag:

  • network — fetched as a JS response (text/javascript, .js, etc.).
  • inline<script> tag without a src attribute.
  • srcdoc — inline <script> inside an <iframe srcdoc> attribute.
  • eval / function-ctor / settimeout-string — code captured from the dynamic-execution traps.

summary.networkScripts, inlineScripts, srcdocScripts, and evalScripts are the headline counts.

Docs

Full docs live in docs/ and are served via GitHub Pages at https://StackedQueries.github.io/script2builtins-runtime/.

Roadmap

See ROADMAP.md for phase status, open design questions, and per-task tracking.

License

MIT