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 🙏

© 2025 – Pkg Stats / Ryan Hefner

workflow-node

v4.0.1-beta.15

Published

Community maintained Node server helpers for Vercel Workflow DevKit

Readme

workflow-node

workflow-node is the Workflow DevKit adapter for plain Node.js servers. Build .well-known/workflow/v1, restore workflow IDs from the manifest, and mount the Workflow HTTP routes inside any framework that speaks the Node http interface.

npm add workflow workflow-node

Unless your bundler already runs the Workflow SWC transform, always emit the workflow manifest and call annotateWorkflowsFromManifest() before invoking start().

// workflows/handle-greeting.ts
import { sleep } from 'workflow';

export async function handleGreeting(name: string) {
  'use workflow';
  await sayHello(name);
  await sleep('1s');
  await sayHello(`${name}, again`);
}

async function sayHello(name: string) {
  'use step';
  console.log(`[node] Hello ${name}`);
}
npx workflow build --workflow-manifest .well-known/workflow/manifest.json

Prefer scripting over CLI flags? Instantiate the builder directly:

import { createWorkflowNodeBuilder } from 'workflow-node/builder';

await createWorkflowNodeBuilder({
  workflowManifestPath: '.well-known/workflow/manifest.json',
  watch: process.env.NODE_ENV !== 'production',
}).build();
import http from 'node:http';
import { createWorkflowNodeFetchHandler } from 'workflow-node';
import { annotateWorkflowsFromManifest } from 'workflow-node/manifest';
import { start } from 'workflow/api';
import { handleGreeting } from './workflows/handle-greeting';

async function main() {
  await annotateWorkflowsFromManifest({
    manifestPath: '.well-known/workflow/manifest.json',
  });

  const workflowHandler = await createWorkflowNodeFetchHandler();

  const server = http.createServer(async (req, res) => {
    if (await workflowHandler(req, res)) {
      return;
    }

    if (req.method === 'GET' && req.url === '/healthz') {
      res.writeHead(200).end('ok');
      return;
    }

    if (req.method === 'POST' && req.url === '/trigger') {
      const chunks: Uint8Array[] = [];
      for await (const chunk of req) {
        chunks.push(chunk);
      }
      const payload = JSON.parse(Buffer.concat(chunks).toString() || '{}');
      const name =
        typeof payload?.name === 'string' ? payload.name : 'node-user';
      const run = await start(handleGreeting, [name]);
      res
        .writeHead(200, { 'content-type': 'application/json' })
        .end(JSON.stringify({ runId: run.runId }));
      return;
    }

    res.writeHead(404).end('Not Found');
  });

  server.listen(3152, () => {
    console.log('Server listening on http://127.0.0.1:3152');
  });
}

main().catch((error) => {
  console.error(error);
  process.exit(1);
});

API reference

createWorkflowNodeBuilder(options)

Workflow-aware builder that emits .well-known/workflow/v1 and, when workflowManifestPath is provided, writes the workflow manifest JSON. Accepts watch, dirs, workingDir, target, and externalPackages. Automatically switches to the Vercel Build Output API target inside Vercel environments.

createWorkflowNodeFetchHandler({ buildDir, logger })

Loads the generated handlers from buildDir (defaults to ./.well-known/workflow/v1) and returns an async function that you can plug into any Node http server. It inspects the incoming request, handles Workflow routes, and returns true when it writes to the response, letting you fall back to your own routing logic for everything else.

createWorkflowNodeServer({ buildDir, port, hostname, logger, customHandler })

Boots a minimal http.createServer() that only serves Workflow routes unless you pass a customHandler. The helper logs its URL, exposes .close(), and uses the same fetch handler under the hood.

annotateWorkflowsFromManifest({ manifestPath, manifest, workingDir, logger })

Loads the manifest produced during workflow build and writes each workflowId onto the exported workflow functions. Call it once during startup when you aren’t already running the Workflow SWC transform so start() can locate your workflows deterministically.

Docs: https://useworkflow.dev/docs/how-it-works/framework-integrations