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

@astrale-os/codegraph

v0.1.6

Published

Headless TypeScript code graph, specification conformance engine, and developer tooling

Readme

Codegraph

Inspect TypeScript projects. Verify module contracts.

Inspect a project · Explore the API · Module contracts

Inspect a project

Use an existing tsconfig.json. No .spec/ required. Install with pnpm add @astrale-os/codegraph.

import { openTypeScriptProject } from '@astrale-os/codegraph/analysis/typescript'

await using project = await openTypeScriptProject({ root: '.' })
await project.refresh()
await using code = await project.open()

const calls = await code.calls({ paths: ['src/routes.ts'] })
console.log({
  completeness: calls.completeness,
  calls: calls.sites.map(({ path, occurrence, call }) => ({
    path,
    span: occurrence.span,
    origin: call.targetOrigin,
    arguments: call.arguments,
    dynamic: call.dynamic,
  })),
})

Calls include unresolved sites. Coverage is complete, partial or unavailable.

await using navigation = await openTypeScriptProject({
  root: '.', capabilities: ['typescript.source', 'typescript.structure'],
})
await navigation.refresh()
await using snapshot = await navigation.open()
const structure = await snapshot.structure()

// A cursor or diagnostic provides the file and its UTF-16 offset.
const selected = await structure.symbolAt({ path: 'src/routes.ts', offset: 120 })
console.log(selected.target, selected.symbols) // Canonical symbols + declaration files/spans.
console.log(await structure.references({ target: { path: 'src/routes.ts', offset: 120 } }))

console.log(await structure.references({
  target: { path: 'src/api.ts', name: 'route' },
}))
console.log(await structure.dependents({ path: 'src/api.ts', transitive: true }))
structure.symbolAt({ path, offset, revision?, signal? })
structure.exports({ path })
structure.references({ target, paths?, includeDeclarations?, signal? })
structure.dependencies({ paths?, signal? })
structure.dependents({ path, transitive?, signal? })
target: { path, offset, revision? } · { path, name } · { symbol } · { origin }

Aliases resolve to their compiler symbol; positions also select local and private bindings. Results retain revision-specific locations, contributing facts and explicit coverage. An expected revision rejects stale cursors. The scope is loaded project-owned sources, excluding .d.ts; computed requests stay uncertain. Structural inspection, position semantics and tracked reuse.

Follow values through helpers and closures

For a project using a library such as @acme/http:

// src/routes.ts
import { route } from '@acme/http'

const health = (status: number) => ({
  path: '/health',
  handler: () => ({ status }),
})

route(health(200))

Continue with the same snapshot:

import { mapValueResult } from '@astrale-os/codegraph/analysis/typescript'

const values = await code.values()
for (const { call } of calls.sites) {
  if (call.targetOrigin?.package !== '@acme/http'
    || call.targetOrigin.path.join('.') !== 'route') continue
  const argument = call.arguments[0]
  if (argument === undefined) continue

  const status = await values.value(argument)
    .property('handler').invoke().property('status').resolve()
  console.log(mapValueResult(status, value =>
    value.kind === 'literal' ? value.value : null))
  // { kind: 'known', value: 200, evidence: [...] }
}

Values retain known, unknown, ambiguous and unsupported outcomes and their evidence. An unknown value or incomplete empty inventory does not establish absence. Authored JavaScript is analyzed without executing it. Library rules also establish callee identity; declaration origins select calls to inspect.

Keep the project open across edits

// After the file watcher reports an edit:
const update = await project.refresh({ changed: ['src/routes.ts'] })
await using current = await project.open()
console.log(update.durationMs, await current.calls({ paths: ['src/routes.ts'] }))

// Or let the compiler discover source, config and resolution changes:
await project.refresh({ discover: true })

Open a new snapshot after refreshing. Earlier readers stay pinned to their version. After the initial load, bare refresh() does not scan the filesystem.

Keep the callback stable; pass variable parameters through input.

import type { TypeScriptSemanticReader } from '@astrale-os/codegraph/analysis/typescript'

async function inspectCalls(read: TypeScriptSemanticReader, input: { paths: string[] }) {
  const calls = await read.calls({ paths: input.paths })
  return {
    completeness: calls.completeness,
    calls: calls.sites.map(({ path, occurrence, call }) => ({
      path, span: occurrence.span, origin: call.targetOrigin, dynamic: call.dynamic,
    })),
  }
}

const report = await current.compute(inspectCalls, { paths: ['src/routes.ts'] })

Reports can be reused when their observed inputs still hold, including across unrelated edits. Return plain data; callback readers and value plans expire when it settles. Values, budgets and reuse.

snapshot.values({ call, limits })
values.value(occurrence).property(name).invoke().resolve({ limits, signal })
values.evaluate(occurrence, { signal? })
values.canReuse(proof)
mapValueResult(result, project, { equals })

limits: maximumDepth · maximumSteps · maximumAlternatives
results: known · unknown · ambiguous · unsupported

call(context)
context.callee() · context.receiver() · context.argument(index)
context.propertyName
operand.property(name) · operand.invoke() · operand.resolve()
model result: atom · unknown · transferred operand · undefined (ordinary evaluation)

Models can describe a library boundary while preserving bindings, closures and proof dependencies. Model operands resolve synchronously within the active call. Complete guide · Interfaces.

snapshot.facts.facts(kind, filter?, page?)
snapshot.facts.factsById(kind, ids)
snapshot.facts.export(kind, filter?)
snapshot.facts.exportAll(filter?)

fact kinds: project · diagnostic · source · symbol · occurrence · structure · body
            body-demand · module · declaration

body: occurrences · relations · blocks · edges · definitions · calls · summary
call: target · targetOrigin · signature · receiver · typeArguments
      arguments · bindings · callbacks · dynamic

Source, symbol, occurrence and body capabilities are enabled by default. Other facts need explicit capabilities. Structural references and file dependencies use typescript.structure; logical module surfaces, dependencies and types use module boundary descriptors.

Project options · Fact readers and payloads · Calls and body IR · Module descriptors.

@astrale-os/codegraph/analysis
createMemoryAnalysisStore · selectAnalysisStore
planPasses · runPortablePasses · runAnalysisPolicies
createNodeSourceTextReader · readVerifiedSourceText
createProcessNativeAnalysisSessionFactory

@astrale-os/codegraph/analysis/sqlite
createSQLiteAnalysisStore

@astrale-os/codegraph/repository
createNodeRepositoryScanner · inventoryRepository · repositoryFacts
analyzeRepositoryStatistics · refreshRepositoryStatistics
createRepositoryPathOwnershipGrouping · createRepositorySourceService

@astrale-os/codegraph/analysis/native
openNativeDecisionSession · resolvePackagedNativeAnalysis · resolvePackagedNativeOxlint
preloadNativeArtifacts({ generic?, signal? })

@astrale-os/codegraph/analysis/typescript
openCapturedTypeScriptReader(source, capture, { capabilities?, signal? })

Use memory by default; supply a caller-owned store for custom retention or persistence. Repository tools inventory, classify, group and measure files. Native decision sessions support specialized tool integrations. All exports, including types.

Captured readers reuse a native session's compiler and fact owner. Their default capabilities are source and body demand; structural reads require an explicit capability. Capture stamps and leased readers.

Explore the API

Import the entrypoint for the task. The root package exposes the module-contract application service.

| Task | @astrale-os/codegraph entrypoint | | --- | --- | | Inspect TypeScript, resolve values, reuse observations | /analysis/typescript | | Compose passes and policies; store/query facts | /analysis | | Persist facts in SQLite | /analysis/sqlite | | Integrate native decision sessions | /analysis/native | | Inventory repositories, measure source, read evidence | /repository | | Author capabilities, laws, states and other contracts | /authoring | | Compile specifications and derive capability status | /specification | | Compose contract conformance profiles | /conformance | | Validate schemas and data | /schema | | Refresh and inspect a module-contract application | root | | Persist workspace checkpoints | /workspace |

Complete export inventory — every function, class, constant and type, with links to exact interfaces.

Verify module contracts

Optional and independent of the inspection workflow. Conformance connects authored contracts to implementation analysis.

cg init modules/payments
// modules/payments/.spec/api.d.ts
export interface Payment { id: string; amount: number }
export declare function charge(amount: number): Promise<Payment>
cg check .                      # Validate contracts and composition
cg verify . --require-pass      # Once the implementation is bound to its contract
cg dev . --open                 # Browse contracts, source and diagnostics

cg check checks specification validity; cg verify checks implementation conformance. Contracts may exist before implementation. Contract reference.

Export contract-owned types and implement the declared API:

// modules/payments/index.ts
import type { Payment } from './.spec/api.js'
export type { Payment } from './.spec/api.js'

export async function charge(amount: number): Promise<Payment> {
  return { id: 'receipt', amount }
}
// modules/payments/implementation.contract.ts
import type * as contract from './.spec/api.js'
import * as implementation from './index.js'
implementation satisfies typeof contract

Keep both files in the owning TypeScript project. verify also checks the public surface in both directions; the satisfies check alone is not conformance. Implementation discovery and binding.

cg --version
cg preload --viewer             # Prepare native analysis + viewer for offline use
cg check . --select modules/payments --exclude generated --format json
cg check . --require-complete-layout --require-exact-layout --require-law-evidence
cg changed . origin/main
cg changed . origin/main --scope-only
cg test modules/payments --root .
cg test changed origin/main --root .
cg verify . --select modules/payments --schema-root schemas --require-pass --details
cg dev . --port 5173 --open --verify

changed is an advisory targeted check; use a full check as the global gate. test runs attached evidence through the project's test:file script. --quiet is available on check/changed/test/verify; --no-cache on check/changed/test/dev.

Exact commands and gate semantics.

.spec/
  api.d.ts              public contract
  code.ts               shared private entrypoints
  internal.d.ts         internal vocabulary
  ports/**/*.d.ts        required provider interfaces
  capabilities/**/*.ts  independently meaningful abilities
  laws/**/*.ts          falsifiable semantic truths
  states/**/*.ts        lifecycle transitions
  flows/**/*.ts         semantic orchestration
  schemas/*.schema.json portable value representations
  layout.ts             physical paths and observation policy
  limits.ts             measured budgets
  packages/*.ts         reasons for external dependencies
  examples/**/*.ts      canonical public-API usage
  benchmarks/**/*.ts    workloads and metrics
  architecture.md       rationale and diagrams
  icon.svg              visual identity
defineCapability · defineLaw · defineState
transition · statesOf · eventsOf · transitionsOf · illegalTransitionsOf
defineCode · defineLayout · definePackage · definePackagePattern · defineBenchmark

Authoring API · Ownership, grammar and examples. Tests live outside .spec/; .history/ holds explanatory, non-normative context.

createTypeSpecApplicationService(options)
service.refresh(options?) · service.current() · service.open(snapshot?)
service.settle() · service.dispose()
reader.query(universe) · reader.source(request) · reader.dispose()

compileSpecificationSnapshot · qualifySpecification · planConformance
createTypeSpecConformanceProfiles · createModuleConformanceProfiles
loadSchema · validateData · validateSchemaFile · validateModuleSchemaCatalog
createFileWorkspaceCheckpointStore
encodeWorkspaceCheckpointJson · decodeWorkspaceCheckpointJson

Application interfaces · Complete API.

Node 22 (≥22.13), 24 or 26. One npm package; native binaries and the viewer download at first use, with a verified offline cache. Preload and distribution · Qualified artifacts.