Files
suaveplan/packages/api-stack/api/api-plugin-campaigns/src/repositories/suppression/suppression-internals.md
2026-05-27 23:29:53 +01:00

3.0 KiB

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

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

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.