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

@tompsonking/aed

v0.1.0

Published

Typed analytic event definition and dispatch helper for web applications.

Readme

AED (Analytic Event Definition)

English | 한국어

AED is a small TypeScript library for defining analytic events, collecting typed context in a store, resolving event payloads, and dispatching them to your analytics transport.

It is designed for web applications that want event payloads to be assembled in a consistent, type-safe way before they are sent.

Features

  • Define analytic events in one place.
  • Store page, session, journey, and entity context.
  • Resolve typed payloads from stored context and per-event parameters.
  • Dispatch with either event-specific handlers or a shared globalDispatch.
  • Preview payloads with inspect() without dispatching.
  • Await async dispatch work with await emit(...).
  • ESM package with bundled JavaScript and TypeScript declarations.

Installation

npm install @tompsonking/aed

Quick Start

import { createAED } from "@tompsonking/aed";

const aed = createAED<{
  page: {
    home: {
      path: string;
    };
  };
  session: {
    anonymous: {
      id: string;
    };
  };
}>()({
  events: {
    page_view: {
      resolve: ({ page, session, events }) => {
        const params = events as { utmSource?: string } | undefined;

        return {
          event: "page_view",
          path: page.home.path,
          anonymousId: session.anonymous.id,
          utmSource: params?.utmSource,
        };
      },
      dispatch: async (payload) => {
        await fetch("/analytics", {
          method: "POST",
          headers: {
            "Content-Type": "application/json",
          },
          body: JSON.stringify(payload),
        });
      },
    },
  },
});

aed.store.page.set("home", {
  path: "/",
});
aed.store.session.set("anonymous", {
  id: "anonymous-1",
});

await aed.emit("page_view", {
  utmSource: "newsletter",
});

Typed Store

Pass a store schema to createAED<TStore>() to make set, get, and upsert type-safe.

const aed = createAED<{
  page: {
    home: {
      path: string;
      title: string;
    };
  };
  session: {
    anonymous: {
      id: string;
    };
  };
  entities: {
    project: Record<
      string,
      {
        projectId: string;
        rating: number;
      }
    >;
  };
}>()({
  events: {
    project_click: {
      resolve: ({ page, session, entities, events }) => {
        const params = events as { projectId: string };

        return {
          event: "project_click",
          path: page.home.path,
          anonymousId: session.anonymous.id,
          project: entities.project[params.projectId],
        };
      },
    },
  },
});

aed.store.page.set("home", {
  path: "/projects",
  title: "Projects",
});

aed.store.entities.upsert("project", "p1", {
  projectId: "p1",
  rating: 4.5,
});

With the schema above, TypeScript rejects unknown store keys and invalid values:

// Type error: "missing" is not defined in page.
aed.store.page.set("missing", { path: "/" });

// Type error: rating must be a number.
aed.store.entities.upsert("project", "p2", {
  projectId: "p2",
  rating: "bad",
});

Event parameters passed to emit(name, params) are currently exposed to resolve() as unknown. Narrow or cast them inside resolve() when you need to read fields from the params object.

Event Dispatch

Each event can define its own dispatch.

const aed = createAED({
  events: {
    click: {
      resolve: () => ({ event: "click" }),
      dispatch: (payload) => {
        console.log(payload);
      },
    },
  },
});

await aed.emit("click");

You can also provide globalDispatch for events that do not have their own dispatch handler.

const aed = createAED({
  events: {
    page_view: {
      resolve: () => ({ event: "page_view" }),
    },
  },
  globalDispatch: async (payload) => {
    await fetch("/analytics", {
      method: "POST",
      body: JSON.stringify(payload),
    });
  },
});

await aed.emit("page_view");

When both an event-specific dispatch and globalDispatch are defined, the event-specific dispatch is used.

Inspect Payloads

Use inspect() to preview the payload produced by resolve() without calling dispatch.

const payload = aed.inspect("page_view");

This is useful for debugging, tests, and analytics payload review.

Store API

page, session, journey

These stores are key-value stores.

aed.store.page.set("home", { path: "/" });
aed.store.page.get("home");
aed.store.page.delete("home");

entities

Entities are stored by entity name and id.

aed.store.entities.upsert("project", "p1", {
  projectId: "p1",
  rating: 4.5,
});

aed.store.entities.get("project", "p1");

Runtime Behavior

  • emit(name, params) resolves the payload and dispatches it.
  • emit() returns Promise<void>, so async dispatch work can be awaited.
  • Dispatch errors are surfaced as rejected promises.
  • inspect(name, params) returns the resolved payload and does not dispatch.
  • Emitting or inspecting an undefined event throws an error.

Development

pnpm install
pnpm typecheck
pnpm lint
pnpm test
pnpm build

License

MIT