Files
2026-05-27 23:29:53 +01:00

107 lines
7.6 KiB
Markdown

# @suaveplan/delivery-tracking - Channel-agnostic delivery event tracking for campaigns and messages: lifecycle dedupe, in-memory + SurrealDB stores, time-series aggregation, tracking pixel / link tokens, multi-provider webhook parsing, OTel instrumentation
Channel-agnostic delivery event tracking for campaigns and messages: lifecycle dedupe, in-memory + SurrealDB stores, time-series aggregation, tracking pixel and click-link tokens, multi-provider webhook parsing, and OpenTelemetry instrumentation.
<!-- begin:auto-docs -->
## Documentation tree
- [aggregator](./src/core/aggregator/aggregator.md) — `DeliveryAggregator` reads campaign and contact statistics from any `DeliveryEventStore` and exposes time-series bucket…
- [aggregator](./src/core/aggregator/aggregator.md) — `DeliveryAggregator` reads campaign and contact statistics from any `DeliveryEventStore` and exposes time-series bucket…
- [tracker](./src/core/tracker/tracker.md) — `DeliveryTracker` is the package's primary write-side surface. It validates inbound `CreateDeliveryEventInput`s against…
- [tracker](./src/core/tracker/tracker.md) — `DeliveryTracker` is the package's primary write-side surface. It validates inbound `CreateDeliveryEventInput`s against…
- [tracker.schemas](./src/core/tracker/tracker.schemas.md) — `tracker.schemas` declares the Zod boundary schemas applied to `DeliveryTracker.track` input. Centralising the schemas…
- [tracking-link](./src/core/tracking-link/tracking-link.md) — `TrackingLinkWrapper` rewrites outbound URLs with click-tracking redirects. Each wrapped URL points at the tracking hos…
- [tracking-link](./src/core/tracking-link/tracking-link.md) — `TrackingLinkWrapper` rewrites outbound URLs with click-tracking redirects. Each wrapped URL points at the tracking hos…
- [tracking-pixel](./src/core/tracking-pixel/tracking-pixel.md) — `TrackingPixelGenerator` produces and parses the open-tracking pixel URLs embedded in outbound HTML emails. The pixel U…
- [token-codec](./src/core/tracking-pixel/token-codec.md) — `token-codec` is the shared XOR + base64url encoder/decoder used by both `TrackingPixelGenerator` (open tracking) and `…
- [tracking-pixel](./src/core/tracking-pixel/tracking-pixel.md) — `TrackingPixelGenerator` produces and parses the open-tracking pixel URLs embedded in outbound HTML emails. The pixel U…
- [webhook-parser](./src/core/webhook-parser/webhook-parser.md) — `WebhookEventParser` normalises provider-specific delivery webhooks into `CreateDeliveryEventInput[]` ready for `Delive…
- [webhook-parser](./src/core/webhook-parser/webhook-parser.md) — `WebhookEventParser` normalises provider-specific delivery webhooks into `CreateDeliveryEventInput[]` ready for `Delive…
- [errors](./src/errors/delivery-tracking-error.md) — `DeliveryTrackingError` is the stable typed error class raised by every code path inside `@suaveplan/delivery-tracking`…
- [delivery-tracking-error](./src/errors/delivery-tracking-error.md) — `DeliveryTrackingError` is the stable typed error class raised by every code path inside `@suaveplan/delivery-tracking`…
- [otel](./src/otel/instruments.md) — `getDeliveryTrackingInstruments` lazily constructs and caches the OTel `Counter` set used by every production code path…
- [instruments](./src/otel/instruments.md) — `getDeliveryTrackingInstruments` lazily constructs and caches the OTel `Counter` set used by every production code path…
- [memory](./src/stores/memory/memory-store.md) — `memory-store` defines the `DeliveryEventStore` interface that every persistence backend must satisfy, ships the determ…
- [memory-store](./src/stores/memory/memory-store.md) — `memory-store` defines the `DeliveryEventStore` interface that every persistence backend must satisfy, ships the determ…
- [surreal](./src/stores/surreal/surreal-store.md) — `SurrealDeliveryEventStore` is the SurrealDB-backed implementation of the `DeliveryEventStore` contract. It uses positi…
- [surreal-store](./src/stores/surreal/surreal-store.md) — `SurrealDeliveryEventStore` is the SurrealDB-backed implementation of the `DeliveryEventStore` contract. It uses positi…
<!-- end:auto-docs -->
## Install
```bash
bun add @suaveplan/delivery-tracking
```
## Quick start
```ts
import {
DeliveryAggregator,
DeliveryTracker,
InMemoryDeliveryEventStore,
TrackingPixelGenerator,
WebhookEventParser,
} from "@suaveplan/delivery-tracking";
const store = new InMemoryDeliveryEventStore();
const tracker = new DeliveryTracker(store);
const aggregator = new DeliveryAggregator(store);
const parser = new WebhookEventParser();
const pixel = new TrackingPixelGenerator({
baseUrl: "https://t.example.com",
secret: "tracking-secret",
});
tracker.bus.on("delivery:opened", (e) => {
console.log("opened", e.messageId);
});
const events = parser.parse("sendgrid", { body: webhookBody });
await tracker.trackBatch(events);
const stats = await aggregator.getCampaignStats("c1");
const pixelUrl = pixel.generatePixelUrl("m1", "u1", "c1");
```
## Modules
| Module | Description |
|---|---|
| [`src/core/tracker/tracker.ts`](src/core/tracker/tracker.md) | Validates and records events, dedupes lifecycle types, emits on a typed bus. |
| [`src/core/tracker/tracker.schemas.ts`](src/core/tracker/tracker.schemas.md) | Zod boundary schemas for `CreateDeliveryEventInput`. |
| [`src/core/aggregator/aggregator.ts`](src/core/aggregator/aggregator.md) | Campaign rollups, contact histories, time-series bucketing. |
| [`src/core/tracking-pixel/tracking-pixel.ts`](src/core/tracking-pixel/tracking-pixel.md) | Open-tracking pixel URL generator + parser. |
| [`src/core/tracking-pixel/token-codec.ts`](src/core/tracking-pixel/token-codec.md) | Shared XOR + base64url codec used by pixel and link wrappers. |
| [`src/core/tracking-link/tracking-link.ts`](src/core/tracking-link/tracking-link.md) | Click-tracking URL wrapper, HTML rewrite, token parse. |
| [`src/core/webhook-parser/webhook-parser.ts`](src/core/webhook-parser/webhook-parser.md) | Pluggable provider webhook → input normaliser. |
| [`src/stores/memory/memory-store.ts`](src/stores/memory/memory-store.md) | `DeliveryEventStore` contract + in-memory implementation + `computeStats`. |
| [`src/stores/surreal/surreal-store.ts`](src/stores/surreal/surreal-store.md) | SurrealDB-backed implementation using positional SurQL. |
| [`src/errors/delivery-tracking-error.ts`](src/errors/delivery-tracking-error.md) | `DeliveryTrackingError` + stable code registry. |
| [`src/otel/instruments.ts`](src/otel/instruments.md) | Lazy OTel counter set (`tracked`, `deduped`, `webhook_parsed`, `token_issued`, `token_rejected`). |
## Features
- Lifecycle dedupe per `messageId` for `opened`, `delivered`, `bounced`, `unsubscribed`, `complained`.
- Typed `EventBus<DeliveryTrackerEventMap>` with one topic per `DeliveryEventType`.
- Backend-agnostic via `DeliveryEventStore` — drop-in `InMemoryDeliveryEventStore`, `SurrealDeliveryEventStore`, or your own.
- Time-series bucketing by `hour`/`day`/`week`.
- Pluggable webhook parsers for SendGrid, Mailgun, AWS SES, and a generic shape.
- Zod boundary validation on every event the tracker accepts.
- Counters emitted via `@opentelemetry/api` for ingest, dedupe, parser activity, and token issuance/rejection.
## Subpath exports
`./tracker`, `./aggregator`, `./tracking-pixel`, `./tracking-link`, `./webhook-parser`, `./stores/memory`, `./stores/surreal`, `./errors`, `./otel`.
## Errors
Every failure raised by the package extends `DeliveryTrackingError`. The stable code registry:
- `DELIVERY_TRACKING.INVALID_INPUT`
- `DELIVERY_TRACKING.INVALID_TOKEN`
- `DELIVERY_TRACKING.UNSUPPORTED_PROVIDER`
- `DELIVERY_TRACKING.STORE_FAILURE`
- `DELIVERY_TRACKING.QUERY_FAILURE`