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

webhookr-relay

v0.1.5

Published

Local CLI and SDK for polling Webhookr relay events and forwarding them to localhost.

Readme

webhookr-relay

Local CLI and SDK for Webhookr — relay webhooks to your local dev server in real time, no tunnels needed.

Quick start

npm install -g webhookr-relay

webhookr init    # authenticate + pick your project
webhookr relay   # start forwarding webhooks to localhost

The interactive setup writes a profile-based .webhookr.json, so one checkout can keep separate relay targets for local, staging, or team-specific environments.

Commands

| Command | Description | |---------|-------------| | webhookr init | Interactive setup wizard — authenticates via browser, picks a project/channel, detects your framework, asks how to route locally, and saves a profile-based .webhookr.json config | | webhookr relay | Start relaying webhooks to your local server (reads .webhookr.json, optionally with --profile) | | webhookr login | Re-authenticate with Webhookr via browser | | webhookr logout | Revoke the saved CLI token and remove local authentication | | webhookr status | Show current config and connection status |

Saved config format

webhookr init now writes a canonical versioned config:

{
  "version": 2,
  "activeProfile": "my-project-frederik-macbook",
  "profiles": [
    {
      "name": "my-project-frederik-macbook",
      "serverUrl": "https://webhookr.test",
      "project": "my-project",
      "relays": [
        {
          "channel": "stripe",
          "apiKey": "whrk_...",
          "targetUrl": "http://127.0.0.1:8000/webhooks",
          "targetStrategy": "preserve-path"
        }
      ]
    }
  ]
}

Older flat .webhookr.json files are still read and normalized automatically.

Manual relay (without init)

If you prefer flags over the interactive wizard:

webhookr relay \
  --server https://webhookr.co \
  --api-key whrk_... \
  --target http://localhost:8000/webhooks \
  --target-strategy preserve-path

All relay flags

| Flag | Description | Default | |------|-------------|---------| | --profile <name> | Use a saved profile from .webhookr.json | active profile | | --server <url> | Webhookr server URL | — | | --api-key <key> | Your API key | — | | --channel <slug> | Restrict polling to a single channel | all channels visible to the key | | --target <url> | Local URL or base URL to forward webhooks to | — | | --target-strategy <fixed\|preserve-path> | Keep the target fixed, or append the original request path and query to the target base URL | fixed | | --interval-ms <ms> | Poll interval in milliseconds | 2000 | | --retry-delay-ms <ms> | Initial retry delay for poll, ack, and local-forward failures | interval-ms | | --max-retry-delay-ms <ms> | Maximum retry delay before exponential backoff stops growing | retry-delay-ms × 5 | | --batch-size <n> | Events per poll, max 100 | 20 | | --timeout-ms <ms> | Local forward timeout | 10000 | | --header <name:value> | Static header added to forwarded requests (repeatable) | — | | --verbose | Enable debug logging | false |

If you pass --server, --api-key, and --target, the CLI runs in direct single-relay mode and bypasses .webhookr.json. If you omit those flags, it reads the saved config and starts every relay in the selected profile.

SDK usage

You can also use webhookr-relay as a library:

import { createRelayClient } from 'webhookr-relay';

const relay = createRelayClient({
  serverUrl: 'https://webhookr.co',
  apiKey: 'whrk_...',
  targetUrl: 'http://localhost:3000/webhooks',
  targetStrategy: 'preserve-path',
});

await relay.start();

// Later, to gracefully shut down:
await relay.stop();

Options

| Option | Type | Description | Default | |--------|------|-------------|---------| | serverUrl | string | Webhookr server URL | required | | apiKey | string | Your API key | required | | targetUrl | string | Local URL to forward to | required | | targetStrategy | 'fixed' \| 'preserve-path' | Reuse the target as-is, or append the original request path and query to it | 'fixed' | | channel | string | Optional channel slug filter for polling | unset | | pollIntervalMs | number | Poll interval in ms | 2000 | | retryDelayMs | number | Initial retry delay for poll, ack, and local-forward failures | pollIntervalMs | | maxRetryDelayMs | number | Maximum retry delay before exponential backoff stops growing | retryDelayMs × 5 | | batchSize | number | Events per poll (max 100) | 20 | | timeoutMs | number | Forward timeout in ms | 10000 | | staticHeaders | Record<string, string> | Headers added to forwarded requests | {} | | logger | RelayLogger | Custom logger implementation | noop |

How it works

  1. Your webhook provider (Stripe, GitHub, etc.) sends events to your Webhookr ingest URL
  2. Webhookr stores the events
  3. The CLI polls for new events and forwards them to your local server
  4. Events are acknowledged after successful local delivery

When targetStrategy is preserve-path, the local forwarded URL is rebuilt from:

  • the configured targetUrl path as the base
  • the original webhook request_path
  • the original query_string, appended to any existing target query params

Forwarded requests also include relay metadata headers such as:

  • x-webhookr-event-id
  • x-webhookr-delivery-attempt
  • x-webhookr-received-at
  • x-webhookr-original-path
  • x-webhookr-original-query
  • x-webhookr-source-ip when available

x-webhookr-event-id stays stable across retries and reconnects, so local handlers can use it as an idempotency key. x-webhookr-delivery-attempt increments when the same event is retried within the current relay process.

Requirements

  • Node.js 20+

Releasing

The npm publish workflow is tag-driven. A normal branch push does not publish the CLI.

To release a new version:

  1. bump packages/webhookr-relay-client/package.json
  2. push the commit to your branch or main
  3. create and push a matching tag in the form relay-vX.Y.Z

Example:

git tag relay-v0.1.3
git push origin relay-v0.1.3

The GitHub Actions publish-relay workflow verifies that the relay-vX.Y.Z tag exactly matches the package version before it runs npm publish.

License

MIT