@beignet/core
Version:
Core framework primitives for Beignet
273 lines • 9.8 kB
TypeScript
import type { StandardSchemaV1 } from "@standard-schema/spec";
import { type TraceCarrier, type TracingPort } from "../tracing/index.js";
import { type EventTransportValue } from "./transport.js";
export { EventTransportError, type EventTransportErrorReason, type EventTransportValue, } from "./transport.js";
/**
* Any Standard Schema compatible validator.
*/
export type StandardSchema = StandardSchemaV1<unknown, unknown>;
/**
* Value or promise of that value.
*/
export type MaybePromise<T> = T | Promise<T>;
/**
* Infer the parsed output type from a Standard Schema.
*/
export type InferSchemaOutput<T extends StandardSchemaV1> = StandardSchemaV1.InferOutput<T>;
/**
* Minimal event definition shape accepted by event bus helpers.
*/
export interface EventPayloadDef<Name extends string = string, Payload extends StandardSchema = StandardSchema> {
/**
* Stable event name.
*/
readonly name: Name;
/**
* Standard Schema payload validator.
*/
readonly payload: Payload;
/**
* Optional human-readable description for docs and tooling.
*/
readonly description?: string;
}
/**
* Event definition created by `defineEvent(...)`.
*/
export interface EventDef<Name extends string = string, Payload extends StandardSchema = StandardSchema> extends EventPayloadDef<Name, Payload> {
/**
* Discriminator for event definitions.
*/
readonly kind: "event";
}
/**
* Infer the parsed payload type for an event definition.
*/
export type InferEventPayload<E extends EventPayloadDef> = E["payload"] extends StandardSchemaV1<unknown, infer Output> ? Output : never;
/** Metadata propagated with an event delivery. */
export interface EventPublishOptions {
/** Versioned trace context captured by the event producer. */
trace?: TraceCarrier;
}
/**
* Lifecycle handle for one event subscription or a composed listener
* registration.
*
* `ready` proves initial transport readiness. It does not represent ongoing
* connectivity, durability, replay, or handler success after startup.
*/
export interface EventSubscription {
/** Resolves when the subscription can receive events. */
readonly ready: Promise<void>;
/** Stop local delivery and await transport cleanup. Idempotent. */
unsubscribe(): Promise<void>;
}
/** Error used when a subscription closes before initial readiness. */
export declare class EventSubscriptionClosedError extends Error {
constructor(message?: string);
}
/** Error thrown when a listener registry misses its readiness deadline. */
export declare class ListenerRegistrationTimeoutError extends Error {
/** Configured readiness deadline in milliseconds. */
readonly timeoutMs: number;
/** Listener names that were part of the registration. */
readonly listenerNames: readonly string[];
constructor(args: {
timeoutMs: number;
listenerNames: readonly string[];
});
}
/** Error thrown when listener rollback misses the registration deadline. */
export declare class ListenerRegistrationCleanupTimeoutError extends Error {
/** Configured registration deadline in milliseconds. */
readonly timeoutMs: number;
/** Listener names that were part of the registration. */
readonly listenerNames: readonly string[];
constructor(args: {
timeoutMs: number;
listenerNames: readonly string[];
});
}
/**
* Options for `defineEvent(...)`.
*/
export interface DefineEventOptions<Payload extends StandardSchema> {
/**
* Standard Schema payload validator.
*/
payload: Payload;
/**
* Optional human-readable description for docs and tooling.
*/
description?: string;
}
/**
* Arguments passed to a listener handler.
*/
export interface ListenerHandleArgs<E extends EventDef, Ctx> {
/**
* Event definition being handled.
*/
event: E;
/**
* Parsed event payload.
*/
payload: InferEventPayload<E>;
/**
* Listener context.
*/
ctx: Ctx;
}
/**
* Listener definition created by `defineListener(...)`.
*/
export interface ListenerDef<E extends EventDef = EventDef, Ctx = unknown, Name extends string = string> {
/**
* Discriminator for listener definitions.
*/
readonly kind: "listener";
/**
* Stable listener name.
*/
readonly name: Name;
/**
* Event this listener handles.
*/
readonly event: E;
/**
* Handle a parsed event payload.
*/
handle(args: ListenerHandleArgs<E, Ctx>): MaybePromise<void>;
}
/**
* Options for `defineListener(...)`.
*/
export interface DefineListenerOptions<E extends EventDef, Ctx> {
/**
* Event this listener handles.
*/
event: E;
/**
* Handle a parsed event payload.
*/
handle(args: ListenerHandleArgs<E, Ctx>): MaybePromise<void>;
}
/**
* Event bus shape required by Beignet listener registration helpers.
*/
export interface EventBusLike {
/**
* Publish an event payload.
*/
publish<E extends EventPayloadDef>(event: E, payload: InferEventPayload<E>, options?: EventPublishOptions): MaybePromise<void>;
/**
* Subscribe to an event and return its readiness and cleanup handle.
*/
subscribe<E extends EventPayloadDef>(event: E, handler: (payload: InferEventPayload<E>, options?: EventPublishOptions) => MaybePromise<void>): EventSubscription;
}
/**
* Options for `registerListeners(...)`.
*/
export interface RegisterListenersOptions<Ctx> {
/**
* Static listener context or factory evaluated for each delivered event.
*/
ctx?: Ctx | (() => MaybePromise<Ctx>);
/**
* Runtime tracing port used to start the listener span before a lazy context
* factory runs.
*/
tracing?: TracingPort;
/**
* Called when a listener fails. When omitted, listener errors are rethrown to
* the event bus subscription callback.
*/
onError?: (error: unknown, listener: ListenerDef<EventDef, Ctx>) => void;
/**
* Maximum time for the complete listener registry to become ready. The same
* registration deadline bounds automatic rollback after startup failure.
* Defaults to 10 seconds.
*/
readyTimeoutMs?: number;
}
/**
* Context-bound listener helper factory.
*/
export interface Listeners<Ctx> {
/**
* Define a listener with the bound context type.
*/
defineListener<Name extends string, E extends EventDef>(name: Name, options: DefineListenerOptions<E, Ctx>): ListenerDef<E, Ctx, Name>;
}
/**
* Error thrown when event payload validation fails.
*/
export declare class EventValidationError extends Error {
/**
* Raw Standard Schema validation issues.
*/
readonly issues: readonly StandardSchemaV1.Issue[];
constructor(args: {
name: string;
issues: readonly StandardSchemaV1.Issue[];
});
}
/**
* Parsed runtime value and canonical JSON value for one event publication.
*/
export interface PreparedEventPayload<E extends EventPayloadDef> {
/** Parsed Standard Schema output delivered to in-process listeners. */
readonly payload: InferEventPayload<E>;
/** Canonical JSON value written by serialized transports. */
readonly transportValue: EventTransportValue;
/** Complete publish metadata to forward to in-process subscribers. */
readonly publishOptions: EventPublishOptions;
}
/**
* Define a typed event.
*
* Event payloads are validated before publishing through `publishEvent(...)`
* and before registered listeners run. Producer helpers also require parsed
* output to be plain JSON that remains unchanged when validated again after a
* transport round trip.
*/
export declare function defineEvent<Name extends string, Payload extends StandardSchema>(name: Name, options: DefineEventOptions<Payload>): EventDef<Name, Payload>;
/**
* Validate and parse an event payload with the event's Standard Schema.
*/
export declare function parseEventPayload<E extends EventPayloadDef>(event: E, payload: unknown): Promise<InferEventPayload<E>>;
/**
* Parse an event payload and prove that its canonical JSON survives transport.
*
* Custom event-bus providers must call this before publishing. The returned
* runtime payload is suitable for in-process listeners; `transportValue` is
* the exact JSON-safe value to encode for a serialized transport.
*/
export declare function prepareEventPayloadForTransport<E extends EventPayloadDef>(event: E, payload: unknown, options?: EventPublishOptions): Promise<PreparedEventPayload<E>>;
/**
* Validate an event payload, prove transport stability, and publish it through
* an event bus.
*/
export declare function publishEvent<E extends EventPayloadDef>(eventBus: EventBusLike, event: E, payload: InferEventPayload<E>, options?: EventPublishOptions): Promise<void>;
/**
* Register listeners against an event bus and return a composite lifecycle
* handle.
*
* Payloads are validated before listener handlers run. Listener context is
* resolved per delivery when `options.ctx` is a factory. Initial registration
* starts every child cleanup after a synchronous subscribe failure, rejected
* readiness promise, or readiness timeout. Cleanup that cannot finish inside
* the registration deadline is reported without extending startup forever.
*/
export declare function registerListeners<Ctx>(eventBus: EventBusLike, listeners: readonly ListenerDef<EventDef, Ctx>[], options?: RegisterListenersOptions<Ctx>): EventSubscription;
/**
* Create listener helper methods bound to an application context type.
*
* Call it once in `lib/listeners.ts`:
*
* ```ts
* export const { defineListener } = createListeners<AppContext>();
* ```
*/
export declare function createListeners<Ctx>(): Listeners<Ctx>;
//# sourceMappingURL=index.d.ts.map