import { SmrtObject } from '@happyvertical/smrt-core'; import { AttributionConflictBehavior, AttributionCreditMode, AttributionPolicyOptions, AttributionPolicyStatus } from '../types.js'; /** * Validate a policy's terms. Throws a descriptive error on the first * violation. Called by {@link AttributionPolicy.activate} and by activating * saves so no active policy can carry malformed terms. */ export declare function validateAttributionPolicyTerms(policy: AttributionPolicy): void; export declare class AttributionPolicy extends SmrtObject { /** Tenant ID for multi-tenant isolation (nullable → global policies). */ tenantId: string | null; /** Stable policy identity shared by every version of the policy. */ policyKey: string; /** Monotonic version within `policyKey`. Amendments insert `max + 1`. */ version: number; /** * Lifecycle status — see {@link POLICY_STATUS_TRANSITIONS}. Mutate via * {@link activate} / {@link supersede} / {@link retire} (or a legal * single-step assignment; the save-time guard rejects illegal edges). */ status: AttributionPolicyStatus; /** When this version takes effect. Frozen once the policy activates. */ effectiveFrom: Date | null; /** * Attribution window in days: only touches occurring within `windowDays` * of the resolution instant are credit candidates, and attributed * referrals expire `windowDays` after attribution if never qualified. */ windowDays: number; /** How competing touches are credited. */ creditMode: AttributionCreditMode; /** Whether multi-referrer contention auto-resolves or forces review. */ conflictBehavior: AttributionConflictBehavior; /** * Whether a touch whose referrer IS the prospect (matching * `subjectProfileId`) may earn credit. Default false: self-referrals are * dropped from candidate sets. */ allowSelfReferral: boolean; /** * Whether referrals of already-existing clients are eligible. Default * false: `AttributionService.resolve()` refuses outright when the caller * flags the prospect as an existing client. */ allowExistingClients: boolean; /** * Eligible service keys as a JSON-string array — empty array means ALL * services are eligible. Interpretation belongs to the application layer * that maps its offerings onto service keys; this module records and * validates the list. Use {@link getEligibleServices}/{@link setEligibleServices}. */ eligibleServices: string; /** Eligible campaign keys (JSON-string array; empty = all eligible). */ eligibleCampaigns: string; /** Eligible region codes (JSON-string array; empty = all eligible). */ eligibleRegions: string; /** Additional metadata as a JSON string (not part of the frozen identity). */ metadata: string; constructor(options?: AttributionPolicyOptions); /** * Re-coerce date fields after the framework reapplies raw option values, * record the loaded status for the transition guard, and capture the * frozen snapshot when the row arrived already non-draft (superseded and * retired versions — history — can't be rewritten either). */ initialize(): Promise; isDraft(): boolean; isActive(): boolean; /** Parse {@link eligibleServices}; returns `[]` on empty/invalid JSON. */ getEligibleServices(): string[]; /** Serialize and store {@link eligibleServices}. */ setEligibleServices(services: string[]): void; /** Parse {@link eligibleCampaigns}; returns `[]` on empty/invalid JSON. */ getEligibleCampaigns(): string[]; /** Serialize and store {@link eligibleCampaigns}. */ setEligibleCampaigns(campaigns: string[]): void; /** Parse {@link eligibleRegions}; returns `[]` on empty/invalid JSON. */ getEligibleRegions(): string[]; /** Serialize and store {@link eligibleRegions}. */ setEligibleRegions(regions: string[]): void; /** Parse {@link metadata}; returns `{}` on empty/invalid JSON. */ getMetadata(): Record; /** Serialize and store {@link metadata}. */ setMetadata(data: Record): void; /** * Transition `draft → active`. Validates the terms first so no active * policy can carry malformed window/mode/eligibility values. */ activate(): void; /** Transition `active → superseded` (a newer version took over). */ supersede(): void; /** Transition `draft | active → retired` (terminal). */ retire(): void; /** * Save with two guards (CommissionPlan pattern): * * 1. **Status transition** — the about-to-be-written status must be a * legal edge from the authoritative prior persisted status (re-read * from the DB so a `create({ id: , _skipLoad: true })` upsert * can't sidestep the guard). * 2. **Frozen policy identity** — once the row has been saved non-draft, * every policy-defining field must match the captured snapshot. Amend * by inserting a new version instead. */ save(): Promise; /** * Refuse a save whose `(tenantId, policyKey, version)` natural key * already belongs to a DIFFERENT row — the frozen-identity guard is * instance-local, so a fresh instance would otherwise upsert over the * persisted policy (rewriting attribution rules and rotating the row * id). Edit drafts by hydrating them; change terms with * `AttributionPolicyCollection.createAmendment()`. */ private assertNaturalKeyNotTaken; /** * Resolve the AUTHORITATIVE prior status from the database; fall back to * the loaded-status WeakMap only when the DB is unavailable. `undefined` * means no persisted row exists (genuinely new). */ private resolvePriorStatus; private assertStatusTransition; private assertFrozenIdentityUnchanged; private serializeFrozenSnapshot; private static parseStringArray; private static coerceDate; } export default AttributionPolicy; //# sourceMappingURL=AttributionPolicy.d.ts.map