Initial Commit
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
# `repositories/suppression/suppression-internals`
|
||||
|
||||
## Purpose
|
||||
|
||||
This module owns the validation and mapping primitives shared by the two
|
||||
`CampaignSuppressionStore` implementations — `ReasonSchema`,
|
||||
`CreateInputSchema`, `QuerySchema`, the `requireTenant` guard, the
|
||||
`rowToEntry` row mapper, and the `validateCreate` wrapper. Keeping these
|
||||
helpers in a dedicated sibling module is what allows both the SurrealDB
|
||||
implementation (`./suppression.ts`) and the in-memory reference
|
||||
(`./suppression-memory.ts`) to stay under the 300-line hard cap without
|
||||
duplicating their entry-validation logic.
|
||||
|
||||
## Features
|
||||
|
||||
- `ReasonSchema` — Zod enum guard over the five canonical
|
||||
`CampaignSuppressionReason` values (`unsubscribe`, `bounce`,
|
||||
`complaint`, `manual`, `compliance`).
|
||||
- `CreateInputSchema` / `QuerySchema` — strict Zod object guards for the
|
||||
two public input shapes.
|
||||
- `requireTenant(tenantId)` — boundary check that throws
|
||||
`CAMPAIGNS_API.TENANT_REQUIRED` for an empty string.
|
||||
- `validateCreate(input)` — parses with `CreateInputSchema` and throws
|
||||
`CAMPAIGNS_API.INVALID_INPUT` on failure with the underlying `ZodError`
|
||||
attached as `cause`.
|
||||
- `rowToEntry(row)` — maps `CampaignSuppressionRow` ↔ `CampaignSuppressionEntry`
|
||||
with `Date` normalisation and `null` → `undefined` collapsing.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { validateCreate, requireTenant } from "./suppression-internals.js";
|
||||
|
||||
requireTenant("tenant-1");
|
||||
const data = validateCreate({
|
||||
tenantId: "tenant-1",
|
||||
channel: "email",
|
||||
channelValue: "user@example.com",
|
||||
reason: "unsubscribe",
|
||||
});
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { QuerySchema, rowToEntry } from "./suppression-internals.js";
|
||||
|
||||
const parsed = QuerySchema.safeParse({
|
||||
tenantId: "t1",
|
||||
channel: "sms",
|
||||
limit: 25,
|
||||
});
|
||||
if (!parsed.success) {
|
||||
// handle ZodError without going through the repository
|
||||
}
|
||||
|
||||
const entry = rowToEntry({
|
||||
id: "s1",
|
||||
tenant_id: "t1",
|
||||
channel: "sms",
|
||||
channel_value: "+15551234567",
|
||||
reason: "complaint",
|
||||
metadata: null,
|
||||
created_at: "2026-05-24T00:00:00.000Z",
|
||||
});
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `const ReasonSchema: z.ZodEnum`
|
||||
- `const CreateInputSchema: z.ZodObject`
|
||||
- `const QuerySchema: z.ZodObject`
|
||||
- `function requireTenant(tenantId: string): void` — throws on empty.
|
||||
- `function rowToEntry(row: CampaignSuppressionRow): CampaignSuppressionEntry`
|
||||
- `function validateCreate(input: CreateCampaignSuppressionInput): CreateCampaignSuppressionInput`
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
`CreateInputSchema` and `QuerySchema` use `.strict()` so unknown keys
|
||||
fail validation rather than silently flowing through to SurrealDB —
|
||||
this keeps the repository contract honest against evolving HTTP payloads
|
||||
and stops typos from becoming silent feature requests.
|
||||
|
||||
The schemas live here (not in `../../schemas/`) because they are
|
||||
implementation details of the suppression repository, not part of the
|
||||
plugin's public option surface. The plugin's `options` schema in
|
||||
`../../schemas/options.ts` is the user-facing configuration contract; the
|
||||
repository schemas are private guards at a different boundary.
|
||||
Reference in New Issue
Block a user