# store _(no submodules)_ ## Purpose `store.ts` defines the `SegmentStore` interface that abstracts segment persistence behind a six-method contract (`create`, `getById`, `update`, `delete`, `list`, `updateCache`) and ships `InMemorySegmentStore` — a single-process, map-backed implementation suitable for development, tests, and lightweight production deployments. The in-memory store is built around injectable `Clock` and `IdGenerator` primitives from `@suaveplan/types`, so production paths never call `Date.now()` / `new Date()` directly or mutate a module-scope counter. ## Features - `SegmentStore` interface — six async methods, all returning the persisted `Segment` (or `undefined` when the identifier does not exist). - `InMemorySegmentStore` — single-process map-backed implementation. - `InMemorySegmentStoreOptions { clock?, idGenerator? }` — both injection points are optional with sensible defaults. - Zod boundary on `create` and `update` — invalid input raises `AudienceRulesError` with code `AUDIENCE_RULES.INVALID_INPUT` (never a raw `ZodError`). - Multi-tenant isolation on `list(tenantId)` — segments owned by other tenants are invisible. - `updateCache(id, contactIds)` updates `cachedContactIds`, `cachedCount`, `lastRefreshedAt`, and `updatedAt` atomically. ## Usage: Basic Example ```ts import { InMemorySegmentStore } from "@suaveplan/audience-rules"; const store = new InMemorySegmentStore(); const segment = await store.create({ tenantId: "tenant-1", name: "Active VIPs", rules: [{ field: "tags", operator: "contains", value: "vip" }], refreshMode: "manual", }); ``` ## Usage: Advanced Example ```ts import { InMemorySegmentStore } from "@suaveplan/audience-rules"; // Deterministic store for tests: pinned clock + monotonic ID generator let n = 0; const store = new InMemorySegmentStore({ clock: () => 1_700_000_000_000, idGenerator: () => { n += 1; return `test_seg_${n}`; }, }); const a = await store.create({ tenantId: "t1", name: "A", rules: [], refreshMode: "manual", }); // a.id === "test_seg_1"; a.createdAt.getTime() === 1_700_000_000_000 ``` ## API Reference - `interface SegmentStore` — see Features. - `interface InMemorySegmentStoreOptions` — `clock?: Clock`, `idGenerator?: IdGenerator` (both from `@suaveplan/types`). - `class InMemorySegmentStore implements SegmentStore` — constructor accepts `InMemorySegmentStoreOptions`. Throws `AudienceRulesError` with `AUDIENCE_RULES.INVALID_INPUT` on Zod failure in `create` / `update`, and on `list` with an empty `tenantId`. ## Implementation Notes - The default `IdGenerator` is a per-instance closure, so two separate stores in the same process produce independent ID sequences. This matches the `@suaveplan/contacts` `InMemoryContactStore` convention. - `create` and `update` validate input with `parseOrThrow` before mutating the internal map — failure leaves the store untouched. - `list` takes an `O(n)` scan; the package is a development-tier store and multi-tenant filtering happens in-memory. Production stores backed by a database can index on `tenantId` directly. - Every mutation updates `updatedAt` via the injected clock, so OTel histograms and snapshot diffs in consumers stay deterministic under `FakeClock`.