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

execution-engine

v4.0.1

Published

A TypeScript library for tracing and visualizing code execution workflows.

Downloads

2,748

Readme


Execution Engine records what your code did at runtime — inputs, outputs, errors and timing — without asking you to rewrite the functions themselves. It runs in your own process, adds no dependencies, and returns plain JSON you can visualize, assert on in tests, or store and resume later.

Features ✨

Two independent parts. Use either one without adopting the other.

1. Execution — one function at a time

No engine and no graph: wrap a single call to see what it did, or to stop it from happening twice.

  • Trace: Capture inputs, outputs, errors and timing of a single call.
  • Cache: Reuse a result for a configurable TTL.
  • Memoize: Collapse duplicate concurrent calls into one.
  • Timer: Measure a code block, in ms and in words.

2. Engine — the whole run as a graph

Route related calls through an engine, and the graph assembles itself while they run.

  • Nodes and edges: Each call becomes a node, and the edges are inferred from order, nesting and parallelism — you never draw them yourself.
  • Timing: Every node carries its own start, end, duration and elapsed time.
  • Portable JSON: A Cytoscape-compatible shape you can assert on in tests, store and resume, or open in the json-to-graph viewer.

Every feature ships twice — a decorator for classes, a plain function for everything else. See Which API to use.

Installation 📦

Use npm package manager:

npm install execution-engine

Or use the yarn package manager:

yarn add execution-engine

Requires Node.js 18+. Decorators need "experimentalDecorators": true in your tsconfig.json; the plain functions work without it — see Getting Started.

Usage 📚

1. Execution: trace one function

import { trace } from "execution-engine";

class MathOperations {
  @trace(console.log) // logs inputs, outputs and duration on every call
  add(a: number, b: number): number {
    return a + b;
  }
}

new MathOperations().add(2, 3); // still returns 5

2. Engine: get the whole run as a graph

import { ExecutionEngine } from "execution-engine";

const engine = new ExecutionEngine();

const res1 = engine.run((param) => `result1 for ${param}`, ['param1']);
await engine.run(async (param) => `result2 for ${param}`, [res1.outputs]);

const trace = engine.getTrace(); // a flat array of nodes and edges

Each call becomes a node holding what it received, what it returned and how long it took. You never create the edges: the engine works them out from how the calls actually ran.

[
  {
    "data": {
      "id": "fetchUser_…",
      "label": "fetchUser",
      "inputs": ["u_42"],
      "outputs": { "id": "u_42", "plan": "pro" },
      "duration": 58.37,
      "elapsedTime": "58.370 ms"
    },
    "group": "nodes"
  },
  {
    "data": { "id": "fetchUser_…->chargeCard_…", "source": "fetchUser_…", "target": "chargeCard_…" },
    "group": "edges"
  }
]

Caching, memoization, decorators, engine context and the full trace format are covered in the documentation.

Examples 📘

Runnable examples live in the /examples directory, each with the trace it produced — and the main ones are shown beside their graphs on the Examples page.

  • execution-trace.ts — one call, recorded as a plain record. No engine, no graph.
  • engine-sequential.ts — the smallest graph there is: four calls, four nodes, three inferred edges.
  • engine-checkout.ts — one checkout that exercises everything at once: a chain, nesting, recursion, a cache hit, a memoized call, and a fork and join. See its graph →

Documentation 📔

Explore the comprehensive documentation for this project:

Changelog 📝

For a detailed list of changes, enhancements, and bug fixes, please refer to our Changelog.

Contributing 🤝

If you find any issues or have suggestions for improvement, feel free to open an issue or submit a pull request. Contributions are welcome!

Before getting started, please read our Contribution Guidelines.

Community 👥

Love execution-engine? Give our repo a star ⭐ ⬆️.

License 📄

This project is licensed under the MIT License - see the LICENSE file for details.