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

@kodori/topology

v0.1.0

Published

React components for visualising a service topology with live health checks.

Readme

topology

A React component library for visualizing service topologies with live health checks.

Drag-and-drop nodes, automatic axis-aligned connection routing, dark/light themes, and an interactive editor for authoring configs visually.

npm install @komadori/topology
import { Topology, type TopologyConfig } from '@komadori/topology';
import '@komadori/topology/style.css';

const config: TopologyConfig = {
  nodes: [
    { id: 'api', label: 'REST API', color: '#a78bfa', icon: 'server',
      x: 100, y: 100, healthUrl: 'https://api.example.com/health' },
    { id: 'db', label: 'Postgres', color: '#4ade80', icon: 'database',
      x: 100, y: 300, healthUrl: 'https://api.example.com/db/health' },
  ],
  connections: [
    { id: 'c1', from: 'api', to: 'db', label: 'reads / writes' },
  ],
};

export default function StatusPage() {
  return <div style={{ width: '100vw', height: '100vh' }}><Topology config={config} /></div>;
}

Features

  • Live health checks — HTTP-status mode or JSON-path mode (extracts a value from a JSON response and matches it).
  • Three real health stateshealthy (green), error (yellow, e.g. service returned 503), unhealthy (red, network/timeout/CORS).
  • Pan + scroll-to-zoom — cursor-anchored zoom, fit-to-screen with reserved insets so chrome doesn't overlap content.
  • Auto-routed connections — every line is built from axis-aligned segments. Three possible shapes: straight, L-bend, or Z-bend (derived from endpoint positions, no curves, no diagonals).
  • Slot-snapped endpoints — connection endpoints snap to one of 5 positions on each of 4 sides of a node. Drag to slide.
  • Per-segment dragging — Z-bends have a draggable middle handle that slides the perpendicular segment.
  • Auto-sized groups — groups grow and shrink with their members; drag the group label to move all members at once.
  • Dark / light themes, with smooth runtime switching.
  • Visual editorsrc/editor/ is a demo-only authoring tool. Build configs visually, copy the resulting JSON.

Project layout

src/
├── components/         React components (public lib)
│   ├── Topology/       Main component + CSS
│   ├── Node/           Single service card
│   ├── Connections/    Connection lines + endpoint/mid handles
│   ├── Icon/           30 built-in icons
│   └── Form/           Internal form primitives (used by editor)
├── routing/            Pure routing math, no React
│   ├── geometry.ts     Rect helpers, side helpers, types
│   ├── anchors.ts      Slot snapping, fan-out, anchor resolution
│   └── path.ts         Polyline construction with bend offset support
├── utils/              Small pure helpers (jsonPath, snap, time)
├── hooks/              useHealthChecks, usePanZoom
├── types.ts            All public TypeScript types
├── constants.ts        NODE_W, NODE_H, defaults
├── index.ts            Public library entry point
├── editor/             Demo-only visual editor (not bundled)
└── demo/               Demo runner (not bundled)
    └── docs/           Tutorial content — Markdown + TOC derivation

See DEVELOPMENT.md for the routing algorithm and how to extend the library.

Health checks

Status-code mode (default) — set healthUrl or healthCheck.url. Healthy when the response status matches expectStatus (default [200]). A response with a non-matching code shows as error (yellow). A missing response (network, timeout, CORS) shows as unhealthy (red).

JSON-path mode — set healthCheck.jsonPath to extract a value from the response body. Healthy when the value matches expectValue (default ['ok','healthy','up'], case-insensitive).

healthCheck: {
  url: '/api/diagnostics',
  jsonPath: 'databases.pipeline.status',
  expectValue: ['ok', 'healthy'],
  timeoutMs: 5_000,
}

Path syntax accepts dot, bracket, and quoted segments: 'a.b.c', 'a["b"]["c"]', 'items[0].name'.

CORS: health checks run from the browser, so /health endpoints must respond with permissive CORS headers — otherwise the browser blocks the response and the node shows the error code network.

Connections

Connections auto-route as axis-aligned polylines. The shape comes from the endpoint positions:

  • Same exit axis + collinear → straight line.
  • Same exit axis + offset → Z-bend (out, perpendicular middle, in). The middle segment is draggable.
  • Different exit axes → L-bend. If the natural corner falls inside a node body, the router automatically detours around with an extra stub.

To pin where a connection attaches:

{
  id: 'c1', from: 'api', to: 'db',
  fromAnchor: { side: 'right', t: 0.5 },  // middle of the right side
  toAnchor:   { side: 'left',  t: 0.5 },  // middle of the left side
}

t runs 0..1 along the side; the actual rendered position snaps to one of 5 discrete slots.

To override the perpendicular position of a Z-bend's middle segment:

{ id: 'c1', from: 'api', to: 'db', bendOffset: 320 }

For an h-axis Z-bend, bendOffset is the X coordinate of the middle vertical segment. For a v-axis Z-bend, it's the Y coordinate of the middle horizontal segment.

Topology props

<Topology
  config={config}
  theme="dark"          // 'dark' | 'light' (controlled)
  defaultTheme="dark"   // initial theme when uncontrolled
  background="dots"     // 'dots' (default) | 'snap' (square grid)
  snapToGrid            // snap node/group drags to gridSize
  gridSize={20}
  autoHideChrome        // bottom-right controls fade in on hover (default: true)
  hideLegend            // hide the live status-count panel
  hideControls          // hide the zoom/theme/grid control bar
/>

Demo & editor

npm install
npm run dev

http://localhost:5173 — toggle View ↔ Editor ↔ Tutorial. Edits in the editor immediately show in View; reload to start over from sampleConfig.

Design system

The demo, the editor, and topology's own chrome are built on @obento/mono — buttons, inputs, tabs, modals, callouts, code blocks, and the pan/zoom canvas all come from it. Topology defines its palette as --tp-* variables and bridges them to --obento-* in Topology.css, so obento components rendered inside topology pick up its colors and fonts automatically.

The Tutorial tab is a Markdown document (src/demo/docs/tutorial.md) rendered by obento's <Markdown>, which maps every element onto a themed primitive. Its table of contents is derived from the document's own headings, so adding a ## section is the whole edit.

Working on obento at the same time? Check it out as a sibling directory and both npm run dev and tsc resolve it from source — no publish step, no manual switching:

parent/
├── obento/
└── topology/

Set OBENTO_DIR if your checkout lives elsewhere. When the sibling isn't present (CI, Docker), the installed npm package is used instead.

Build the library

npm run build:lib

Outputs dist/topology.js, dist/style.css, and the full .d.ts tree. That directory is the whole published package: @komadori/topology resolves to the bundle, @komadori/topology/style.css to the stylesheet.

The name is scoped because the bare topology on npm is an unrelated 2013 graph library, and installing it gets you that instead of this.

build:lib also runs as the prepare script, which npm invokes both before packing a release and after installing the package straight from git. A consumer can therefore depend on the repository ("@komadori/topology": "github:komadori-dev/topology") and get a built package without a registry release.

React is a peer dependency, so the host app supplies it and there is never a second copy in the bundle. Everything else, obento included, is bundled, which is why @komadori/topology/style.css is the only stylesheet a consumer has to import.