Skip to content

index

@fungi.computer/carrier


@fungi.computer/carrier / index

Stable failures omit email bodies, tokens and raw provider errors.

  • Error

new CarrierError(code): CarrierError

"conflict" | "invalid_input" | "unavailable"

CarrierError

Error.constructor

readonly _tag: "CarrierError" = "CarrierError"

readonly code: "conflict" | "invalid_input" | "unavailable"

Carrier = Readonly<{ send: (submission) => Promise<Receipt>>; get: (id) => Promise<Receipt | undefined>>; tick: () => Promise<void>>; hasPendingWork: () => Promise<boolean>>; }>

Durable email submission and its host-driven recovery door.


Address = string | Readonly<{ email: string; name: string; }>

One recipient address; display names remain part of the requested envelope.


Email = Readonly<{ from: Address; to?: readonly Address[]; cc?: readonly Address[]; bcc?: readonly Address[]; subject: string; html?: string; text?: string; }>

Common content and envelope for one Email.


Submission = Email & Readonly<{ id: string; sendBefore?: number; }>

Source identity and expiry belong to the notification’s producer.


Message = Readonly<{ id: string; recipient: string; roles: readonly ("to" | "cc" | "bcc")[]; status: "unconfirmed"; }>

A recipient Message is distinct from its Email and provider request.


ProviderRejection = Readonly<{ code: string; class: "permanent" | "temporary"; }>

A provider’s definite refusal of a whole request: retryable or final.


Receipt = Readonly<{ id: string; status: "queued" | "dispatching" | "provider_accepted" | "outcome_unknown" | "rejected" | "refused" | "expired" | "superseded"; providerMessageId?: string; providerRejection?: ProviderRejection; messages: readonly Message[]; }>

Durable submission and aggregate dispatch evidence, without credential content. refused means Carrier’s per-recipient cap declined the submission before any provider attempt; rejected means the provider definitely refused it (a permanent rejection, or temporary rejections until retries ran out). providerRejection is the last provider refusal, also while a temporary rejection waits queued for its retry.


SendEvidence = Readonly<{ kind: "provider_accepted"; providerMessageId: string; }> | Readonly<{ kind: "provider_rejected"; }> & ProviderRejection | Readonly<{ kind: "outcome_unknown"; cause?: string; }>

One transport invocation reports only the evidence it obtained. Report provider_rejected only for a documented refusal of the whole request before acceptance; cause is an optional sanitized provider code for logs.


Host = Readonly<{ commit: <A>>(mutation) => Promise<A>>; requestWake: () => Promise<void>>; }>

Mechanical host capabilities; commit must durably arm a wake with its mutation.


Options = Readonly<{ storage: WatchdogSqliteOwner; host: Host; now: () => number; canSend?: (emailId) => Promise<boolean>>; transport: (email) => Promise<SendEvidence>>; }>

Configure a durable owner; business validity remains with the source.

createCarrier(options): Promise<Readonly<{ send: (submission) => Promise<Readonly<{ id: string; status: "rejected" | "queued" | "expired" | "outcome_unknown" | "dispatching" | "provider_accepted" | "refused" | "superseded"; providerMessageId?: string; providerRejection?: Readonly<{ code: string; class: … | …; }>; messages: readonly Readonly<{ id: string; recipient: string; roles: readonly …[]; status: "unconfirmed"; }>[]; }>>; get: (id) => Promise<Readonly<{ id: string; status: "rejected" | "queued" | "expired" | "outcome_unknown" | "dispatching" | "provider_accepted" | "refused" | "superseded"; providerMessageId?: string; providerRejection?: Readonly<{ code: …; class: …; }>; messages: readonly Readonly<{ id: …; recipient: …; roles: …; status: …; }>[]; }> | undefined>>; tick: () => Promise<void>>; hasPendingWork: () => Promise<boolean>>; }>>

Construct exactly one owner per store/runtime lifetime. A replacement may be opened only after its predecessor has stopped; simultaneous owners of the same store are unsupported. Native adapters supply their runtime ownership.

Options

Promise<Readonly<{ send: (submission) => Promise<Readonly<{ id: string; status: "rejected" | "queued" | "expired" | "outcome_unknown" | "dispatching" | "provider_accepted" | "refused" | "superseded"; providerMessageId?: string; providerRejection?: Readonly<{ code: string; class: … | …; }>; messages: readonly Readonly<{ id: string; recipient: string; roles: readonly …[]; status: "unconfirmed"; }>[]; }>>; get: (id) => Promise<Readonly<{ id: string; status: "rejected" | "queued" | "expired" | "outcome_unknown" | "dispatching" | "provider_accepted" | "refused" | "superseded"; providerMessageId?: string; providerRejection?: Readonly<{ code: …; class: …; }>; messages: readonly Readonly<{ id: …; recipient: …; roles: …; status: …; }>[]; }> | undefined>; tick: () => Promise<void>; hasPendingWork: () => Promise<boolean>; }>>