@tompsonking/aed
v0.1.0
Published
Typed analytic event definition and dispatch helper for web applications.
Maintainers
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/aedQuick 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()returnsPromise<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 buildLicense
MIT
