9.7 KiB
9.7 KiB
@suaveplan/contacts - Universal contact and group management: hierarchical n-level groups (adjacency + materialized path), channel-agnostic contacts with dedup, many-to-many memberships with ancestor count propagation, audience resolution with descendant walk + dedup + filters, contact merger, CSV/JSON import-export, injectable Clock + IdGenerator, Zod input boundaries, six OTel counters and three histograms, and typed ContactsError hierarchy with stable CONTACTS.* code registry.
Universal contact and group management with hierarchical nesting, audience resolution, contact merger, and CSV/JSON import-export. Multi-tenant, channel-agnostic, deterministic (injectable Clock + IdGenerator), Zod-validated at every public boundary, OTel-instrumented via @suaveplan/opentelemetry, and ships a typed ContactsError hierarchy with a stable CONTACTS.* code registry.
Documentation tree
- audience-resolver —
AudienceResolverflattens a set of groups into a deduplicated, filtered contact list — the typical "send this campaig…- audience-resolver —
AudienceResolverflattens a set of groups into a deduplicated, filtered contact list — the typical "send this campaig…
- audience-resolver —
- contact-manager —
ContactManageris the public CRUD surface for contacts. It validates inputs against the corresponding Zod schemas (`c…- contact-manager —
ContactManageris the public CRUD surface for contacts. It validates inputs against the corresponding Zod schemas (`c…
- contact-manager —
- contact-merger —
ContactMergerconsolidates duplicate contacts into a single primary record. It merges channels (dedup-by-type:value…- contact-merger —
ContactMergerconsolidates duplicate contacts into a single primary record. It merges channels (dedup-by-type:value…
- contact-merger —
- group-manager —
GroupManageris the public surface for hierarchical groups. It manages n-level nesting via a hybrid adjacency-list +…- group-manager —
GroupManageris the public surface for hierarchical groups. It manages n-level nesting via a hybrid adjacency-list +…
- group-manager —
- membership-manager —
MembershipManagerorchestrates many-to-many contact-group memberships. It owns the integrity guarantee that `Group.co…- membership-manager —
MembershipManagerorchestrates many-to-many contact-group memberships. It owns the integrity guarantee that `Group.co…
- membership-manager —
- error-codes — Defines the stable error-code registry and typed
ContactsErrorclass for@suaveplan/contacts. Every failure path th…- error-codes — Defines the stable error-code registry and typed
ContactsErrorclass for@suaveplan/contacts. Every failure path th…
- error-codes — Defines the stable error-code registry and typed
- contact-exporter —
ContactExporterserializes contacts to JSON or CSV with optional field inclusion flags. CSV output follows RFC 4180 q…- contact-exporter —
ContactExporterserializes contacts to JSON or CSV with optional field inclusion flags. CSV output follows RFC 4180 q…
- contact-exporter —
- contact-importer —
ContactImporteringests contacts from already-parsed record arrays or raw CSV content. It applies caller-supplied fie…- contact-importer —
ContactImporteringests contacts from already-parsed record arrays or raw CSV content. It applies caller-supplied fie…
- contact-importer —
- otel — Exposes the bundle of OpenTelemetry metric instruments emitted by
@suaveplan/contacts. The bundle binds lazily agains…- instruments — Exposes the bundle of OpenTelemetry metric instruments emitted by
@suaveplan/contacts. The bundle binds lazily agains…
- instruments — Exposes the bundle of OpenTelemetry metric instruments emitted by
- schemas — Zod schemas for every public input boundary of
@suaveplan/contactsplus theparseOrThrowhelper that converts Zod v…- schemas — Zod schemas for every public input boundary of
@suaveplan/contactsplus theparseOrThrowhelper that converts Zod v…
- schemas — Zod schemas for every public input boundary of
- contact-store — Defines the
ContactStorestorage interface thatContactManagerandAudienceResolverconsume, plus the `InMemoryCo…- contact-store — Defines the
ContactStorestorage interface thatContactManagerandAudienceResolverconsume, plus the `InMemoryCo…
- contact-store — Defines the
- group-store — Defines the
GroupStorestorage interface thatGroupManagerandAudienceResolverconsume, plus the `InMemoryGroupS…- group-store — Defines the
GroupStorestorage interface thatGroupManagerandAudienceResolverconsume, plus the `InMemoryGroupS…
- group-store — Defines the
- membership-store — Defines the
MembershipStorestorage interface thatMembershipManager,ContactMerger, andAudienceResolverconsu…- membership-store — Defines the
MembershipStorestorage interface thatMembershipManager,ContactMerger, andAudienceResolverconsu…
- membership-store — Defines the
- tree — Pure tree utilities for building, flattening, traversing, and inspecting
GroupTreeNode<TMeta>hierarchies. None of th…- tree-utils — Pure tree utilities for building, flattening, traversing, and inspecting
GroupTreeNode<TMeta>hierarchies. None of th…
- tree-utils — Pure tree utilities for building, flattening, traversing, and inspecting
Install
bun add @suaveplan/contacts
Quick start
import {
AudienceResolver,
ContactManager,
GroupManager,
InMemoryContactStore,
InMemoryGroupStore,
InMemoryMembershipStore,
MembershipManager,
} from "@suaveplan/contacts";
const contactStore = new InMemoryContactStore();
const groupStore = new InMemoryGroupStore();
const membershipStore = new InMemoryMembershipStore();
const contacts = new ContactManager({ store: contactStore });
const groups = new GroupManager({ store: groupStore });
const memberships = new MembershipManager({
contactStore,
groupStore,
membershipStore,
});
const resolver = new AudienceResolver({
contactStore,
groupStore,
membershipStore,
});
const vip = await groups.create({ tenantId: "acme", name: "VIP Customers" });
const alice = await contacts.create({
tenantId: "acme",
displayName: "Alice",
channels: [
{ type: "email", value: "alice@example.com", primary: true, verified: true },
],
});
await memberships.addContactToGroup(vip.id, alice.id);
const audience = await resolver.resolve({ groupIds: [vip.id] });
console.log(audience.totalCount); // 1
Architecture
ContactStore GroupStore MembershipStore <- pluggable storage
│ │ │
└─── ContactManager / GroupManager / MembershipManager <- CRUD + validation + OTel
│
┌─────────────┴─────────────┐
│ │
AudienceResolver ContactMerger / ContactImporter / ContactExporter
(group walk + dedup) (data ops + import/export pipelines)
Every public mutating method validates via Zod, raises a typed ContactsError (never a bare Error), and emits on at least one OTel instrument. All temporal and id-generating paths accept injectable Clock and IdGenerator from @suaveplan/types.
Modules
| Module | Documentation |
|---|---|
Error codes (CONTACTS_CODES, ContactsError) |
src/error-codes/error-codes.md |
OTel instruments (getContactsInstruments) |
src/otel/instruments.md |
Zod schemas (createContactInputSchema, …, parseOrThrow) |
src/schemas/schemas.md |
Contact store (InMemoryContactStore) |
src/stores/contact-store/contact-store.md |
Group store (InMemoryGroupStore) |
src/stores/group-store/group-store.md |
Membership store (InMemoryMembershipStore) |
src/stores/membership-store/membership-store.md |
ContactManager |
src/core/contact-manager/contact-manager.md |
GroupManager |
src/core/group-manager/group-manager.md |
MembershipManager |
src/core/membership-manager/membership-manager.md |
ContactMerger |
src/core/contact-merger/contact-merger.md |
AudienceResolver |
src/core/audience-resolver/audience-resolver.md |
ContactExporter |
src/import-export/contact-exporter/contact-exporter.md |
ContactImporter |
src/import-export/contact-importer/contact-importer.md |
Tree utilities (buildGroupTree, …) |
src/tree/tree-utils.md |