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

@dev.fast/code-graph

v0.1.15

Published

Semantic code graph extraction for TypeScript repos and broad source-language code graph extraction for JavaScript, Python, Go, Rust, Java, C/C++, Ruby, Kotlin, and Swift. The dev.fast monorepo is the TypeScript regression target, but the extractor, daemo

Readme

@dev.fast/code-graph

Semantic code graph extraction for TypeScript repos and broad source-language code graph extraction for JavaScript, Python, Go, Rust, Java, C/C++, Ruby, Kotlin, and Swift. The dev.fast monorepo is the TypeScript regression target, but the extractor, daemon, editor, and call-tree UI run through a root-aware plugin path that can target external repos with --root.

Quick start

# Refresh the SQLite-backed code graph (~30s, needs 8GB heap)
pnpm --filter @dev.fast/code-graph refresh

# Or target another repo/language
pnpm --filter @dev.fast/code-graph refresh -- --root /path/to/typescript/repo
pnpm --filter @dev.fast/code-graph refresh -- --root /path/to/python/repo --languages python

# Start the singleton daemon and UIs
pnpm --filter @dev.fast/code-graph daemon

refresh extracts into a temporary SQLite database, publishes it atomically to .code-graph/state/graph.sqlite, and asks the daemon to drop any open graph connection around the swap. It does not need Docker or a long-lived graph DB process.

Querying SQLite

Query via bash:

sqlite3 .code-graph/state/graph.sqlite \
  "SELECT label, count(*) FROM nodes GROUP BY label ORDER BY 2 DESC;"

Node types

| Label | Count | Description | | ----------------- | ----- | ---------------------------------------------------------------------------- | | Project | 34 | Each app/package/integration | | File | ~740 | TypeScript source files | | Declaration | ~7900 | Functions, classes, interfaces, types, enums, variables, methods, properties | | ExternalPackage | ~100 | npm dependencies (not walked internally) | | RpcService | 14 | ConnectRPC service definitions from proto | | RpcMethod | 99 | Individual RPC methods |

Edge types

| Type | Count | Meaning | | ---------------- | ----- | ----------------------------------------------- | | CALLS | ~9000 | Function/method directly calls another | | COMPOSES | varies | Declaration structurally composes another declaration, such as JSX component usage | | REGISTERS_CALLBACK | varies | Declaration registers or passes callable behavior, such as a JSX event callback prop | | DECLARES | ~6200 | File declares a symbol | | IMPORTS_SYMBOL | ~6100 | File imports a named symbol | | IMPORTS | ~2900 | File imports from another file | | READS | ~2500 | Function reads a module-level variable | | CONTAINS | ~2400 | Project contains file, or class contains method | | PARAM_TYPE | ~1100 | Function parameter references a type | | REEXPORTS | ~900 | Barrel re-exports | | RETURNS_TYPE | ~700 | Function return type references a type | | PROPERTY_TYPE | ~160 | Property type annotation | | INSTANTIATES | ~160 | new Foo(), targeting a constructor declaration when one exists | | WRITES | ~160 | Function writes a module-level variable | | IMPLEMENTS_RPC | ~114 | Server handler implements an RPC method | | DEFINES_METHOD | 99 | RpcService contains RpcMethod | | EXTENDS | 50 | Class/interface extends | | IMPLEMENTS | 22 | Class implements interface | | CALLS_RPC | 9 | Client calls an RPC method (cross-service) |

Useful queries

-- Most-called functions
SELECT target.id, count(*) AS c
FROM edges e
JOIN nodes target ON target.id = e.to_id
WHERE e.type = 'CALLS' AND target.label = 'Declaration'
GROUP BY target.id
ORDER BY c DESC
LIMIT 15;

-- Cross-project import dependencies
SELECT a.project, b.project, count(*) AS cnt
FROM edges e
JOIN nodes a ON a.id = e.from_id AND a.label = 'File'
JOIN nodes b ON b.id = e.to_id AND b.label = 'File'
WHERE e.type = 'IMPORTS' AND a.project <> b.project
GROUP BY a.project, b.project
ORDER BY cnt DESC
LIMIT 15;

-- Class hierarchy
SELECT child.name, parent.name
FROM edges e
JOIN nodes child ON child.id = e.from_id
JOIN nodes parent ON parent.id = e.to_id
WHERE e.type = 'EXTENDS';

-- Who implements a specific interface?
SELECT impl.name, impl.file
FROM edges e
JOIN nodes impl ON impl.id = e.from_id
JOIN nodes iface ON iface.id = e.to_id
WHERE e.type = 'IMPLEMENTS' AND iface.name = 'SandboxClient';

-- Full RPC trace: caller -> proto method -> server handler
SELECT caller.file, method.name, handler.file
FROM edges call
JOIN nodes caller ON caller.id = call.from_id
JOIN nodes method ON method.id = call.to_id
JOIN edges impl ON impl.type = 'IMPLEMENTS_RPC' AND impl.to_id = method.id
JOIN nodes handler ON handler.id = impl.from_id
WHERE call.type = 'CALLS_RPC';

-- What does a function read and write?
SELECT e.type, variable.name
FROM edges e
JOIN nodes fn ON fn.id = e.from_id
JOIN nodes variable ON variable.id = e.to_id
WHERE fn.name = 'initOtel' AND e.type IN ('READS', 'WRITES');

-- Files with most declarations
SELECT file.id, count(*) AS decls
FROM edges e
JOIN nodes file ON file.id = e.from_id AND file.label = 'File'
JOIN nodes decl ON decl.id = e.to_id AND decl.label = 'Declaration'
WHERE e.type = 'DECLARES'
GROUP BY file.id
ORDER BY decls DESC
LIMIT 10;

Language Plugins

The installed plugins are:

  • typescript: TypeScript Compiler API extraction with declarations, imports, hierarchy, type edges, references/calls, JSX composition, RPC descriptors, and call hierarchy enrichment.
  • javascript, python, go, rust, java, cpp, ruby, kotlin, swift: source-language extraction with project/file discovery, declarations, structural folds, imports, hierarchy edges, calls, and instantiation edges. JavaScript/JSX/MJS/CJS uses the TypeScript parser for declarations, ES/CommonJS/dynamic imports, reexports, local target resolution, direct and receiver/member calls, new expressions, module/class reads and writes, and provenance/confidence metadata on AST-backed reference edges. Python uses a stdlib ast helper for pyproject.toml/setup.* project metadata, package/module resolution through relative imports and __init__.py, declarations, imports/reexports, direct and receiver/member calls, instantiation, inheritance, annotation type edges, state reads/writes, structural folds, and provenance/confidence metadata on resolved local edges. Go uses a stdlib go/parser/go/types helper for go.mod/go.work projects, generated-file detection, public API declarations, local package imports, direct/cross-file calls, selector/member calls, composite literals and new instantiation, embedding/interface implementation edges, return/parameter/field type edges, package/type state reads and writes, folds, and provenance/confidence metadata on resolved local edges. Rust uses Cargo metadata plus a local syn parser helper for Cargo project/crate roots, generated-file detection, mod/use/pub use resolution, public API declarations, direct and cross-file calls, associated function and practical receiver method calls, struct construction, trait conformance, signature/field type edges, static/const reads and writes, folds, and conservative provenance/confidence metadata. Java and Kotlin use a JVM source parser adapter for Maven/Gradle project roots, package/import indexing, generated-file detection, public declarations, direct/cross-file calls, practical receiver/member calls, constructor calls, inheritance/interface conformance, return/parameter/property type edges, static/class-level reads and writes, structural folds, and conservative provenance/confidence metadata. The adapter intentionally leaves ambiguous or unresolved symbols unlinked; it does not require local javac/Kotlin compiler installations, so compiler-only overload and classpath semantics remain medium-confidence gaps. C/C++ prefers local clang/clang++ JSON AST extraction for CMake, Make, and compile database roots, with local include resolution, public/header API declarations, direct/cross-file and receiver member calls, construction, inheritance, signature/field type edges, state read/write edges, folds, and provenance/confidence metadata. Header/member declarations and conservative state/call edges have text fallbacks when clang omits source ownership or a local compiler is unavailable. Ruby uses stdlib Ripper for Gemfile/gemspec project discovery, require/require_relative local resolution, declarations, hierarchy and mixin edges, direct and receiver/member calls, Class.new instantiation, class/module/global state reads and writes, folds, and conservative provenance/confidence metadata for resolved local edges. Swift additionally discovers Swift Package/Xcode roots, resolves local package modules, marks generated files, records public API declarations, hierarchy/protocol conformance, typed member calls, constructor calls, return/parameter/property type edges, state read/write edges, structural folds, and provenance/confidence metadata when swiftc -dump-parse is available.

Enable one or more plugins with --languages or CODE_GRAPH_LANGUAGES:

pnpm --filter @dev.fast/code-graph extract -- --root /tmp/requests --languages python
CODE_GRAPH_LANGUAGES=go pnpm --filter @dev.fast/code-graph extract -- --root /tmp/mux

Real-world smoke coverage is repeatable with:

pnpm --filter @dev.fast/code-graph run validate:source-languages
pnpm --filter @dev.fast/code-graph run validate:source-languages -- --languages python,go

The validation script clones representative public repos into /tmp/code-graph-hairy when missing, extracts each non-TypeScript language, emits Cypher to /tmp/code-graph-hairy-output/<language>, and enforces semantic coverage minimums so silent no-op or declaration-only extraction fails loudly. Use --languages or CODE_GRAPH_VALIDATE_LANGUAGES for targeted validator runs while iterating.

Canvas whiteboard

The canvas is a blank React Flow app that an agent draws on via MCP tools. The intended workflow is: query the SQLite graph store to understand the code, then throw nodes/edges onto the canvas to explain architecture visually.

Setup

# Start the canvas React app
pnpm --filter @dev.fast/code-graph canvas    # http://localhost:5555

# Register the MCP server with Claude Code
claude mcp add code-graph-canvas -- pnpm --filter @dev.fast/code-graph mcp

MCP tools

| Tool | Args | Description | | -------------- | ---------------------------- | ------------------------------------------------- | | add_node | id, label, sublabel? | Add a card to the canvas | | remove_node | id | Remove a node and its edges | | add_edge | source, target, label? | Connect two nodes (directed, with optional label) | | remove_edge | source, target | Disconnect two nodes | | clear_canvas | | Wipe everything |

Nodes are auto-positioned by dagre (left-to-right layout). Edges show direction arrows and optional labels. Click a node to highlight its connections.

Tips

  • The canvas and graph are not linked. You query SQLite via bash, then manually add the interesting parts to the canvas.
  • Use sublabel for context like file paths or descriptions.
  • Use label on edges for relationship semantics like "calls", "implements", "imports".
  • Multiple diagrams can coexist on the same canvas (dagre lays out connected components separately).
  • To fully reset, call clear_canvas.

Architecture notes

  • Target context is shared across CLI, daemon, refresh, editor/source loading, and call-tree flows. By default each target stores local state under .code-graph/{state,output,work} at the target repo root.
  • Graph store is a local SQLite database at .code-graph/state/graph.sqlite. Refresh writes a complete replacement database under .code-graph/work first, then atomically renames it into place.
  • Extraction runs through installed language plugins. TypeScript uses the TypeScript Compiler API (ts.Program + ts.TypeChecker) per project, plus ts.LanguageService for call hierarchy enrichment. Source-language plugins use language-specific project markers, declaration forms, import forms, inheritance syntax, and call/instantiation patterns while emitting the same graph node and edge model. The shared plugin boundary keeps project identity language-neutral and stores language-only data, such as tsconfigPath, in each plugin's project config.
  • RPC extraction is two-pass: first pass extracts proto service descriptors from *_pb.ts files, second pass matches router.service() implementations and createClient() call sites.
  • Memory: projects are loaded sequentially (one ts.Program at a time) but all kept alive for the RPC second pass. Needs --max-old-space-size=8192.
  • Historical spike: ~/monorepo/repos/code-graph remains a read-only reference for future Go/Python/SCIP plugin ideas; this package does not import that implementation.