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

@actionforge/graph-ns

v0.1.0

Published

A typed directed-graph namespace over graphlib — single-inheritance successor chains, predecessor/successor queries, and topological/bottom-up ordering

Readme

@actionforge/graph-ns

A typed wrapper around graphlib for directed graphs, with single-inheritance chain queries and topological / bottom-up ordering on top.

Why this exists

This class was originally written to model refract element type hierarchies (stringelementobject), and its docs named everything "element". But the graph operations were never refract-specific — the same code was already being used to drive dependency-graph-ordered release workflows.

So the vocabulary here is plain graph terminology, and the one piece of logic that was refract-specific — a hardcoded root node literally named 'object' — is now inferred or configurable. Nothing else about the behaviour changed except the bug fixes listed below.

Two things it is good at:

  • Type/class hierarchies — single inheritance, "what does this derive from, all the way up".
  • Dependency graphs — "what order do I build/release these in".

Install

npm install @actionforge/graph-ns

Usage

import { GraphNamespace } from '@actionforge/graph-ns'

const ns = new GraphNamespace()
ns.setEdge(['string', 'number', 'boolean'], 'element')
ns.setEdge('element', 'object')

ns.successorChain('string')  // ['element', 'object']
ns.topsort()                 // leaves first
ns.bottomsort()              // ['object', 'element', ...] — root first

As a dependency graph, where an edge means "depends on":

const deps = new GraphNamespace()
deps.setEdge('app', 'ui').setEdge('ui', 'core')

deps.bottomsort()              // ['core', 'ui', 'app'] — safe release order
deps.successorChain('app')     // ['ui', 'core'] — full transitive chain

API

| Member | Purpose | | --- | --- | | new GraphNamespace({ graph? }) | Empty directed graph, or adopt an existing graphlib one | | graph | The underlying graphlib graph, for anything not wrapped here | | nodes / hasNode(n) | Membership | | setEdge(parent, child) | Add edges; either side may be an array (chainable) | | successor(n) | The sole successor, or undefined; throws if ambiguous | | successors(n) / predecessors(n) | Neighbours, always an array | | sources() / sinks() | Nodes with no in / no out edges | | isAcyclic() | Cycle check | | topsort() / bottomsort() | Ordering; throws on a cycle | | successorChain(n, { root? }) | Walk to the root, inclusive |

setEdge accepts arrays on either side and adds every combination:

ns.setEdge(['a', 'b'], ['c', 'd'])  // a→c, a→d, b→c, b→d

successorChain infers the root from the graph's sole sink. Pass root explicitly when the graph has more than one sink.

Bugs fixed during extraction

The JavaScript original had four real defects, each now covered by a test:

  1. The graph setter did nothing. get graph returned the graph, but the matching setter assigned to an unrelated private field, so ns.graph = someGraph silently no-opped. The setter is gone — pass { graph } to the constructor.
  2. successor() threw a TypeError for an unknown node. graphlib returns undefined rather than [], and the original called .length on it directly. It now returns undefined.
  3. successorChain() looped forever on a dead end. The loop condition was successor !== sink; once successor became undefined that stayed true and it pushed undefined indefinitely. It now throws, and also detects cycles.
  4. successorChain() hardcoded the root as 'object' and threw for any hierarchy that did not use that name. The root is now inferred from the graph's sink, or given explicitly.

The lodash-es dependency (used for isArray, head, and isEmpty) is also gone — those are one-liners in modern JavaScript.

Compatibility

Namespace is still exported as a deprecated alias of GraphNamespace, and GraphNamespace is also the default export, so both of these keep working:

import GraphNamespace from '@actionforge/graph-ns'
import { Namespace } from '@actionforge/graph-ns'

License

MIT © Andrew Cates