UNPKG

@beignet/core

Version:

Core framework primitives for Beignet

143 lines 5.22 kB
import { type EventPublishOptions } from "../events/index.js"; import type { DomainEventDef, EventBusPort, InferEventPayload } from "./events.js"; type MaybePromise<T> = T | Promise<T>; /** * Work function executed inside a Unit of Work. * * `tx` contains transaction-scoped app ports, usually repositories plus * side-effect recorders such as `events`, `jobs`, or `audit`. */ export type UnitOfWorkCallback<TxPorts, Result> = (tx: TxPorts) => MaybePromise<Result>; /** * A transaction boundary for application workflows. * * The transaction ports are app-owned. A database adapter can provide * transaction-scoped repositories, while test or in-memory adapters can use * `createNoopUnitOfWork`. */ export interface UnitOfWorkPort<TxPorts> { /** * Run application work with transaction-scoped ports. * * Durable implementations should commit only if this callback resolves. */ transaction<Result>(work: UnitOfWorkCallback<TxPorts, Result>): Promise<Result>; } /** * Hooks for `createNoopUnitOfWork(...)`. */ export interface NoopUnitOfWorkOptions<TxPorts> { /** * Runs after the callback completes successfully. * * Use this to flush buffered domain events after the work has committed. */ afterCommit?: (tx: TxPorts) => MaybePromise<void>; /** * Runs after the callback throws. * * Use this to clear buffers or release test resources. The original error is * rethrown after this hook runs. */ afterRollback?: (error: unknown, tx: TxPorts) => MaybePromise<void>; } /** * Best-effort observers for `createObservedUnitOfWork(...)`. */ export interface ObservedUnitOfWorkOptions { /** * Runs after the wrapped Unit of Work resolves successfully. * * Observer failures are isolated and never reject the committed operation. */ afterCommit: () => MaybePromise<void>; /** * Receives an `afterCommit` failure. Failures from this observer are also * isolated. */ onObserverError?: (error: unknown) => MaybePromise<void>; } /** * Domain event captured by a buffered event recorder. */ export interface RecordedDomainEvent { /** * Event definition used to validate the payload before publishing. */ event: DomainEventDef; /** * Stable event name. */ eventName: string; /** * Unparsed payload recorded during the transaction. */ payload: unknown; /** Optional metadata propagated when the event is flushed. */ options?: EventPublishOptions; } /** * Transaction-scoped port used to record domain events. * * Use cases record events here during the Unit of Work. The adapter decides * whether to publish after commit, enqueue through an outbox, or buffer for a * test assertion. */ export interface DomainEventRecorderPort { /** * Record a domain event payload. */ record<E extends DomainEventDef>(event: E, payload: InferEventPayload<E>, options?: EventPublishOptions): Promise<void> | void; } /** * In-memory event recorder that can be inspected, cleared, or flushed. */ export interface BufferedDomainEventRecorder extends DomainEventRecorderPort { /** * Return recorded events without clearing them. */ entries(): readonly RecordedDomainEvent[]; /** * Remove all recorded events. */ clear(): void; /** * Validate and publish all recorded events to an event bus in FIFO order. */ flush(eventBus: EventBusPort): Promise<void>; } /** * Create a simple Unit of Work implementation for tests, in-memory adapters, * and infrastructure that already handles transactions elsewhere. * * This helper does not create database transactions. It gives applications the * same UOW shape everywhere and runs commit/rollback hooks around the callback. * * @param txPortsOrFactory - Transaction-scoped ports or a factory that creates * them per transaction call. * @param options - Optional commit and rollback hooks. * @returns A Unit of Work port with no durable transaction semantics. */ export declare function createNoopUnitOfWork<TxPorts>(txPortsOrFactory: TxPorts | (() => TxPorts), options?: NoopUnitOfWorkOptions<TxPorts>): UnitOfWorkPort<TxPorts>; /** * Decorate a Unit of Work with an isolated post-commit observer. * * The observer runs only after the wrapped transaction resolves. Its failure * cannot turn a committed operation into an apparent transaction failure. * Use the observer to schedule best-effort follow-up work; durable side * effects still belong inside the transaction through an outbox. */ export declare function createObservedUnitOfWork<TxPorts>(options: { unitOfWork: UnitOfWorkPort<TxPorts>; } & ObservedUnitOfWorkOptions): UnitOfWorkPort<TxPorts>; /** * Create a recorder that buffers domain events until the caller flushes them. * * Unit of Work adapters commonly flush this recorder from an `afterCommit` * hook so events are not published when the work rolls back. * * @returns A buffered domain event recorder for tests or Unit of Work adapters. */ export declare function createDomainEventRecorder(): BufferedDomainEventRecorder; export {}; //# sourceMappingURL=unit-of-work.d.ts.map