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

wevt

v0.0.2

Published

A TypeScript library for constructing wide events

Readme

wevt - A python and typescript library for constructing wide events

When constructing wide events for my services, I've found myself constructing essentially the same library again and again. I end up constructing a mediocre semi-structured wide event library.

The core idea is taken from a wide array of prior art (see below) on wide events. We have structured logs which will eventually be queried. The structured logging part isn't particularly hard, but I've found that it's nice to have a single place where my log structure is defined.

The structure of a wevt WideEvent

The core idea of this library is that we have two bits of information in our wide log.

  1. WideEventBase: contains the service, eventId (unique per wide event), originator (thing that triggered the wide event, contains the spanId)
  2. Any number of WideEventPartials: structured bits of data which are added to our wide event. You can add partials to add application logic, performance logic, etc. This can be things like user information, session ids, function performance info.

We are opinionated in that we define the types of WideEventPartials and other bits of data upfront. Querying structured logs is useful only if:

  1. you know which fields exist
  2. fields are consistently defined (no simultaneous "user-id", "user.id", and "userId" fields)

Yes, most observability interfaces attempt to discover the schemas for you, but I've found that it's not perfect.

Here is an example wide event:

const evt: WideEventLog<Registry> = {
    // WideEventBase attributes
    service: {
        // base info
        name: "my-rest-service",
        version: "1.0.0"

        // additional user defined service info
        pod_id: "v8a4ad"
    },
    eventId: "evnt_V1StGXR8_Z5jdHi6B-myT",
    originator: {
        // ALWAYS contained on an originator
        type: "http",
        spanId: "span_V1StGXR8_Z5jdHi6B-myT",
        
        // HTTP specific originator data
        method: "POST";
        path: "/foo";
        headers: {
            "User-Agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:147.0) Gecko/20100101 Firefox/147.0"
        };
    },

    // WideEventPartial: user
    user: {
        id: "user_V1StGXR8_Z5jdHi6B-myT",
        tier: "pro",
    }

    // WideEventPartial: chat
    chat: {
        chatId: "chat_V1StGXR8_Z5jdHi6B-myT",
        model: "opus",
        messages: 232,
        tokens: 45822,
    },

    // WideEventPartial: chat
    sandbox: {
        sandboxId: "sbox_V1StGXR8_Z5jdHi6B-myT",
        startedAt: 1768868366748,
        startDuration: 5021,
        liveDuration: 116748,
    }
}

Collectors

Collectors flush wide event logs. The goal is that you can adapt the format and flush the logs wherever you want. We provide a few simple collectors, such as a StdioCollector or a FileCollector. It's generally trivial to implement a collector of your own. Just extend the collector interface and implement a flush function. When implementing your own collector, you most likely will want to implement tail sampling and event buffering here.

/**
 * Simple collector to log the event in the console
 */
class StdioCollector implements LogCollectorClient {
    async flush(eventBase: WideEventBase, partials: Map<string, EventPartial<string>>): Promise<void> {
        console.log({
            ...eventBase,
            ...partials
        })
    }
}

WideEventBase

The WideEventBase type contains 3 fields:

  1. eventId, which uniquely identifies your event
  2. originator which is defined broadly as an external thing that triggered your service to do some action. These can include external HTTP requests, websocket messages, cron triggers, etc. Originators have an id and can cross service boundaries. You can think of this as the thing that connects your metrics across service boundaries, much like a traceId. The difference is that originators attach additional information, like HTTP request information
  3. service is where an event is emitted from. Each service should emit one wide event per originator as defined above. A service has a unique name, and can be provided with additional user defined metadata

WideEventPartial

These are partial bits that can be added to a WideEvent via the wevt.log() or wevt.partial() function. These are predefined in the registry type for the reasons mentioned above.

prior art

  • an open source example of my proto-logging library: https://github.com/cloudflare/mcp-server-cloudflare/tree/eb24e3bba8be7b682aa721d34918ff0954f1254a/packages/mcp-observability
  • https://boristane.com/blog/observability-wide-events-101/
  • https://isburmistrov.substack.com/p/all-you-need-is-wide-events-not-metrics
  • https://jeremymorrell.dev/blog/a-practitioners-guide-to-wide-events/
  • https://charity.wtf/2024/08/07/is-it-time-to-version-observability-signs-point-to-yes/
  • https://loggingsucks.com/