@relaybus/core 0.3.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,535 @@
1
+ /** Source of the current time. Replace it in tests to control retries and leases. */
2
+ interface Clock {
3
+ now(): Date;
4
+ /**
5
+ * Runs `task.run` after `task.delayMs` milliseconds, again every `delayMs` when `repeat` is set, and
6
+ * returns a function that cancels it. `unref` marks a timer that must not keep the process alive.
7
+ * Optional: without it relaybus uses the platform timers. Implement it to control timers in tests
8
+ * (`FakeClock` does with `controlTimers: true`).
9
+ */
10
+ schedule?(task: {
11
+ readonly run: () => void;
12
+ readonly delayMs: number;
13
+ readonly repeat?: boolean;
14
+ readonly unref?: boolean;
15
+ }): () => void;
16
+ }
17
+ declare const systemClock: Clock;
18
+
19
+ /**
20
+ * A duration in milliseconds, or a string such as `'250ms'`, `'30s'`, `'5m'`,
21
+ * `'1h'` or `'7d'`.
22
+ */
23
+ type Duration = number | `${number}${DurationUnit}`;
24
+ type DurationUnit = 'ms' | 's' | 'm' | 'h' | 'd';
25
+ declare function toMilliseconds(value: Duration, name: string): number;
26
+ /** Largest delay Node.js timers support. Longer values fire after 1ms instead. */
27
+ declare const MAX_TIMER_DELAY_MS = 2147483647;
28
+
29
+ /**
30
+ * The Standard Schema interface (https://standardschema.dev), copied as the
31
+ * specification recommends so relaybus needs no runtime dependency. Zod,
32
+ * Valibot, ArkType and other libraries implement it.
33
+ */
34
+ interface StandardSchemaV1<Input = unknown, Output = Input> {
35
+ readonly '~standard': StandardSchemaV1.Props<Input, Output>;
36
+ }
37
+ declare namespace StandardSchemaV1 {
38
+ interface Props<Input = unknown, Output = Input> {
39
+ readonly version: 1;
40
+ readonly vendor: string;
41
+ readonly validate: (value: unknown) => Result<Output> | Promise<Result<Output>>;
42
+ readonly types?: Types<Input, Output> | undefined;
43
+ }
44
+ type Result<Output> = SuccessResult<Output> | FailureResult;
45
+ interface SuccessResult<Output> {
46
+ readonly value: Output;
47
+ readonly issues?: undefined;
48
+ }
49
+ interface FailureResult {
50
+ readonly issues: ReadonlyArray<Issue>;
51
+ }
52
+ interface Issue {
53
+ readonly message: string;
54
+ readonly path?: ReadonlyArray<PropertyKey | PathSegment> | undefined;
55
+ }
56
+ interface PathSegment {
57
+ readonly key: PropertyKey;
58
+ }
59
+ interface Types<Input = unknown, Output = Input> {
60
+ readonly input: Input;
61
+ readonly output: Output;
62
+ }
63
+ type InferInput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['input'];
64
+ type InferOutput<Schema extends StandardSchemaV1> = NonNullable<Schema['~standard']['types']>['output'];
65
+ }
66
+
67
+ /** String metadata carried with an event, such as `traceparent`. */
68
+ type EventHeaders = Readonly<Record<string, string>>;
69
+ /**
70
+ * An event as stored and delivered. Field names follow CloudEvents where they
71
+ * overlap (`id`, `type`, `source`, `time` as `occurredAt`, `subject` as `key`).
72
+ */
73
+ interface EventEnvelope<TPayload = unknown> {
74
+ /** Globally unique id. Handlers and transports deduplicate on it. */
75
+ readonly id: string;
76
+ /** Event type, for example `order.created.v1`. */
77
+ readonly type: string;
78
+ /** Logical name of the publishing service. */
79
+ readonly source: string;
80
+ /** Ordering and partition key. Events sharing a key are handled in publish order. */
81
+ readonly key: string | null;
82
+ readonly payload: TPayload;
83
+ readonly headers: EventHeaders;
84
+ /** Id shared by every event of one business flow. */
85
+ readonly correlationId: string | null;
86
+ /** Id of the event whose handler published this one. */
87
+ readonly causationId: string | null;
88
+ readonly occurredAt: Date;
89
+ }
90
+ /** An instance of a class created with {@link defineEvent}. */
91
+ interface DomainEvent<TPayload = unknown> {
92
+ readonly type: string;
93
+ readonly payload: TPayload;
94
+ }
95
+ /**
96
+ * Derives the ordering key of an event from its validated payload. Declared bivariantly so an
97
+ * event class stays assignable wherever its payload type is widened.
98
+ */
99
+ type EventKeyFunction<TPayload> = {
100
+ bivarianceHack(payload: TPayload): string;
101
+ }['bivarianceHack'];
102
+ /** A class created with {@link defineEvent}. */
103
+ interface EventClass<TPayload = unknown> {
104
+ new (payload: TPayload): DomainEvent<TPayload>;
105
+ readonly type: string;
106
+ readonly schema: StandardSchemaV1<unknown, TPayload> | undefined;
107
+ /** The `key` given to {@link defineEvent}; undefined for events without one. */
108
+ readonly key?: EventKeyFunction<TPayload> | undefined;
109
+ }
110
+ /** Payload type of an event class: `PayloadOf<typeof OrderPlaced>`. */
111
+ type PayloadOf<TEvent> = TEvent extends EventClass<infer TPayload> ? TPayload : never;
112
+ /** Anything that names an event type: an event class or the type string itself. */
113
+ type EventReference = {
114
+ readonly type: string;
115
+ } | string;
116
+ interface DefineEventOptions<TSchema extends StandardSchemaV1> {
117
+ /** Validates the payload on publish and before every handler call. */
118
+ readonly schema: TSchema;
119
+ /** Ordering key of every event of this type, from its validated payload. See {@link DefineEventKeyOptions}. */
120
+ readonly key?: (payload: StandardSchemaV1.InferOutput<TSchema>) => string;
121
+ }
122
+ interface DefineEventKeyOptions<TPayload> {
123
+ /**
124
+ * Ordering key of every event of this type, from its payload: `(payload) => payload.orderId`.
125
+ * Typed from the payload, so a missing field or a non-string fails to compile. `publish` uses it
126
+ * when it is given no `key`; an explicit `key` option wins (for `publishAll`, the one key of the
127
+ * call applies to every event). It must return a non-empty string.
128
+ */
129
+ readonly key: (payload: TPayload) => string;
130
+ }
131
+ declare function assertEventType(type: string): void;
132
+ /**
133
+ * Defines an event type. Extend the returned class to name it:
134
+ *
135
+ * ```ts
136
+ * export class OrderPlaced extends defineEvent<{ orderId: string }>('order.placed.v1') {}
137
+ * export class OrderShipped extends defineEvent('order.shipped.v1', { schema: orderShippedSchema }) {}
138
+ * export class OrderPaid extends defineEvent('order.paid.v1', {
139
+ * schema: orderPaidSchema,
140
+ * key: (payload) => payload.orderId,
141
+ * }) {}
142
+ * export class OrderCancelled extends defineEvent<{ orderId: string }>('order.cancelled.v1', {
143
+ * key: (payload) => payload.orderId,
144
+ * }) {}
145
+ * ```
146
+ */
147
+ declare function defineEvent<TSchema extends StandardSchemaV1>(type: string, options: DefineEventOptions<TSchema>): EventClass<StandardSchemaV1.InferOutput<TSchema>>;
148
+ declare function defineEvent<TPayload>(type: string, options?: DefineEventKeyOptions<TPayload>): EventClass<TPayload>;
149
+ /** Runs a Standard Schema and returns its output, or throws {@link EventValidationError}. */
150
+ declare function validatePayload<TPayload>(type: string, schema: StandardSchemaV1<unknown, TPayload> | undefined, payload: unknown): Promise<TPayload>;
151
+
152
+ /**
153
+ * Base class of every error thrown by relaybus.
154
+ */
155
+ declare class RelayBusError extends Error {
156
+ name: string;
157
+ /**
158
+ * Stable, machine-readable identifier of the error class, such as `RELAYBUS_LEASE_LOST`.
159
+ * Unlike `name` and `message`, a code is never renamed once released; branch on it in
160
+ * alerts and dashboards. Subclasses declared outside relaybus inherit `RELAYBUS_ERROR`.
161
+ */
162
+ readonly code: string;
163
+ }
164
+ /** Invalid options passed to a relaybus component. */
165
+ declare class ConfigurationError extends RelayBusError {
166
+ name: string;
167
+ readonly code: string;
168
+ }
169
+ /**
170
+ * Thrown by `publish` when no transaction can be found and the bus runs with
171
+ * `transactionMode: 'required'` (the default). Publishing outside a transaction
172
+ * would reintroduce the dual-write problem the outbox exists to prevent.
173
+ */
174
+ declare class TransactionRequiredError extends RelayBusError {
175
+ name: string;
176
+ readonly code: string;
177
+ }
178
+ /**
179
+ * A `bus.transaction` (or `@RelayBusTransaction()` method) ran past its `transactionTimeout` and
180
+ * was rolled back. Its `cause` is the error the database raised when it ended the transaction,
181
+ * when there was one. Usually a slow call to another service made inside the transaction.
182
+ */
183
+ declare class TransactionTimeoutError extends RelayBusError {
184
+ name: string;
185
+ readonly code: string;
186
+ }
187
+ /**
188
+ * Throw from a handler to dead-letter the delivery immediately, skipping the
189
+ * remaining retry attempts.
190
+ */
191
+ declare class NonRetryableError extends RelayBusError {
192
+ name: string;
193
+ readonly code: string;
194
+ }
195
+ /** A payload failed its event schema. Never retried: the payload will not change. */
196
+ declare class EventValidationError extends NonRetryableError {
197
+ readonly issues: readonly ValidationIssue[];
198
+ name: string;
199
+ readonly code: string;
200
+ constructor(message: string, issues: readonly ValidationIssue[]);
201
+ }
202
+ /**
203
+ * A message received from a broker is not a valid event. Never retried:
204
+ * transports should dead-letter it instead of redelivering it forever.
205
+ */
206
+ declare class InvalidEnvelopeError extends NonRetryableError {
207
+ name: string;
208
+ readonly code: string;
209
+ }
210
+ /** The worker no longer owns the delivery it was processing. */
211
+ declare class LeaseLostError extends RelayBusError {
212
+ name: string;
213
+ readonly code: string;
214
+ /**
215
+ * Whether the store said so (a fenced write returned false). A worker that only noticed
216
+ * locally that its lease ran out may still own the delivery in the store and has to give it back.
217
+ */
218
+ readonly storeConfirmed: boolean;
219
+ constructor(message: string, options?: {
220
+ readonly storeConfirmed?: boolean;
221
+ });
222
+ }
223
+ /** A handler did not settle within its configured timeout. Retried like any failure. */
224
+ declare class HandlerTimeoutError extends RelayBusError {
225
+ name: string;
226
+ readonly code: string;
227
+ }
228
+ /**
229
+ * Reason of a handler's abort signal when the bus stops before the handler
230
+ * finished. The delivery is released and runs again without losing an attempt.
231
+ */
232
+ declare class DispatcherStoppedError extends RelayBusError {
233
+ name: string;
234
+ readonly code: string;
235
+ }
236
+ /**
237
+ * A delivery came back after its lease expired on its last attempt, so it is
238
+ * dead-lettered without running its handler again.
239
+ */
240
+ declare class AttemptsExhaustedError extends RelayBusError {
241
+ name: string;
242
+ readonly code: string;
243
+ }
244
+ /** A lifecycle method was called in a state that does not allow it, such as starting a bus twice. */
245
+ declare class LifecycleError extends RelayBusError {
246
+ name: string;
247
+ readonly code: string;
248
+ }
249
+ /** `drain` still found due deliveries after its maximum number of batches. */
250
+ declare class DrainIncompleteError extends RelayBusError {
251
+ name: string;
252
+ readonly code: string;
253
+ }
254
+ interface ValidationIssue {
255
+ readonly message: string;
256
+ readonly path?: readonly PropertyKey[] | undefined;
257
+ }
258
+ /** Serializable snapshot of an error, stored with failed deliveries. */
259
+ interface ErrorInfo {
260
+ readonly name: string;
261
+ readonly message: string;
262
+ readonly stack?: string | undefined;
263
+ /** The {@link RelayBusError.code} of a relaybus error; absent for any other error. */
264
+ readonly code?: string | undefined;
265
+ }
266
+ declare function toErrorInfo(error: unknown): ErrorInfo;
267
+
268
+ /**
269
+ * Lifecycle of one handler's delivery of one event.
270
+ * `pending` (waiting or scheduled for retry) -> `processing` (leased by a worker)
271
+ * -> `completed` | `pending` (retry) | `dead` (exhausted or non-retryable).
272
+ * `dead` -> `pending` only through an explicit requeue.
273
+ *
274
+ * A completed delivery is deleted. `completed` records exist only in stores
275
+ * configured to keep a completion history (`retainCompleted` /
276
+ * `completionHistory`), where they are listed, counted and purged like before.
277
+ */
278
+ type DeliveryStatus = 'pending' | 'processing' | 'completed' | 'dead';
279
+ declare const DELIVERY_STATUSES: readonly DeliveryStatus[];
280
+ interface NewDelivery {
281
+ readonly id: string;
282
+ /** Stable handler id. Together with the event id it is unique. */
283
+ readonly handler: string;
284
+ readonly availableAt: Date;
285
+ }
286
+ interface AppendEntry {
287
+ readonly event: EventEnvelope;
288
+ readonly deliveries: readonly NewDelivery[];
289
+ }
290
+ interface AppendResult {
291
+ /** Events written by this call. */
292
+ readonly appendedEventIds: readonly string[];
293
+ /** Events that already existed. Their missing deliveries were still added. */
294
+ readonly duplicateEventIds: readonly string[];
295
+ /** Deliveries written by this call. Existing (event, handler) pairs are skipped. */
296
+ readonly appendedDeliveryCount: number;
297
+ }
298
+ /**
299
+ * Lease expiry is compared with the `now` the caller passes, taken from the
300
+ * bus clock. Keep worker clocks synchronized (NTP): a skew larger than a third
301
+ * of the lease duration lets another worker reclaim a delivery that is still running.
302
+ *
303
+ * Stores may grant the lease on a group of deliveries (a lane) instead of on
304
+ * each delivery. The group is exclusive to `leaseOwner` while the lease is
305
+ * live, so other owners do not see its pending deliveries until it expires or
306
+ * is relinquished; every delivery of the group carries the group's fencing token.
307
+ */
308
+ interface ClaimRequest {
309
+ /** Only deliveries of these handlers are claimed. */
310
+ readonly handlers: readonly string[];
311
+ readonly limit: number;
312
+ readonly leaseOwner: string;
313
+ readonly leaseExpiresAt: Date;
314
+ readonly now: Date;
315
+ }
316
+ /**
317
+ * Proof of ownership. Every state change after a claim must present it
318
+ * (fencing). A lease stays valid until another claim replaces it, even after
319
+ * its expiry time; expiry only makes the delivery claimable again.
320
+ */
321
+ interface LeaseReference {
322
+ readonly deliveryId: string;
323
+ readonly leaseToken: string;
324
+ }
325
+ interface ClaimedDelivery extends LeaseReference {
326
+ readonly handler: string;
327
+ /** Attempt number of this claim, starting at 1. */
328
+ readonly attempt: number;
329
+ readonly leaseExpiresAt: Date;
330
+ readonly event: EventEnvelope;
331
+ }
332
+ interface DeliveryRecord {
333
+ readonly id: string;
334
+ readonly handler: string;
335
+ readonly status: DeliveryStatus;
336
+ readonly attempts: number;
337
+ readonly availableAt: Date;
338
+ readonly leaseOwner: string | null;
339
+ readonly leaseExpiresAt: Date | null;
340
+ readonly lastError: ErrorInfo | null;
341
+ readonly createdAt: Date;
342
+ readonly updatedAt: Date;
343
+ readonly completedAt: Date | null;
344
+ readonly event: EventEnvelope;
345
+ }
346
+ interface DeliveryQuery {
347
+ readonly status?: DeliveryStatus;
348
+ readonly handler?: string;
349
+ readonly eventType?: string;
350
+ readonly eventId?: string;
351
+ /** Default 100. */
352
+ readonly limit?: number;
353
+ }
354
+ interface PurgeRequest {
355
+ /** Delete completed deliveries completed before this instant. */
356
+ readonly completedBefore?: Date;
357
+ /** Delete dead deliveries last updated before this instant. */
358
+ readonly deadBefore?: Date;
359
+ }
360
+ interface PurgeResult {
361
+ readonly deletedDeliveries: number;
362
+ /** Events deleted because no delivery referenced them any more. */
363
+ readonly deletedEvents: number;
364
+ }
365
+ interface EventStoreStatistics {
366
+ readonly pending: number;
367
+ readonly processing: number;
368
+ readonly completed: number;
369
+ readonly dead: number;
370
+ /** `availableAt` of the oldest delivery that is due but not yet processed. */
371
+ readonly oldestDueAt: Date | null;
372
+ }
373
+ /** How `stop` closes a transport or a store. */
374
+ interface CloseOptions {
375
+ /**
376
+ * Aborted when the shutdown deadline passes (`bus.stop({ timeout })`), possibly before `close` is
377
+ * called. From then on, close what you opened yourself at once (destroy connections, cancel
378
+ * running queries) instead of waiting for it to finish; the bus no longer waits for `close`.
379
+ * Leave alone what the application passed in.
380
+ */
381
+ readonly signal?: AbortSignal;
382
+ }
383
+ /** How a store runs one transaction of `bus.transaction`. */
384
+ interface EventStoreTransactionOptions {
385
+ /**
386
+ * Time budget of the whole transaction, in milliseconds. A store makes the database enforce it
387
+ * where it can (for example a statement or idle-in-transaction timeout), so a transaction that
388
+ * waits on something slow is ended by the server and its locks are released. The bus rolls back
389
+ * a transaction that still ran past the budget, so a store may also ignore it.
390
+ */
391
+ readonly timeoutMs: number;
392
+ }
393
+ /**
394
+ * Storage port. Implementations persist events and deliveries in the same
395
+ * database as the application's business data so that both commit atomically.
396
+ *
397
+ * Every implementation must pass the contract suite in `@relaybus/testing`.
398
+ */
399
+ interface EventStore<TTransaction = unknown> {
400
+ /** Creates tables, collections and indexes when they do not exist. */
401
+ setup?(): Promise<void>;
402
+ /**
403
+ * Runs `work` inside a new database transaction and commits when it resolves. `options` come
404
+ * from `bus.transaction`; the store's own transactions and the dispatcher's pass none.
405
+ */
406
+ transaction<T>(work: (transaction: TTransaction) => Promise<T>, options?: EventStoreTransactionOptions): Promise<T>;
407
+ /**
408
+ * Writes events and their deliveries inside `transaction`. Idempotent on
409
+ * event id and on (event id, handler). Assigns a per-key sequence to keyed
410
+ * events in commit order.
411
+ */
412
+ append(transaction: TTransaction, entries: readonly AppendEntry[], now: Date): Promise<AppendResult>;
413
+ /**
414
+ * Leases up to `limit` deliveries that are due: pending with `availableAt <= now`,
415
+ * or processing with an expired lease. A keyed delivery is only claimable when
416
+ * no earlier delivery of the same handler and key is pending or processing.
417
+ * Counts the attempt (`attempt` of the result; a store may persist the count
418
+ * only when the attempt fails or its lease is lost). Safe to call from many
419
+ * processes at once.
420
+ */
421
+ claim(request: ClaimRequest): Promise<ClaimedDelivery[]>;
422
+ /** Extends a lease the caller still holds. Returns false when the lease was lost. */
423
+ extendLease(lease: LeaseReference, leaseExpiresAt: Date, now: Date): Promise<boolean>;
424
+ /**
425
+ * Marks a leased delivery completed by deleting it (or moving it to the
426
+ * completion history, when the store keeps one). With `transaction` the change
427
+ * commits together with the handler's own writes. Returns false when the lease
428
+ * was lost.
429
+ */
430
+ complete(lease: LeaseReference, now: Date, transaction?: TTransaction): Promise<boolean>;
431
+ /** Returns a leased delivery to pending, due at `availableAt`. */
432
+ reschedule(lease: LeaseReference, availableAt: Date, error: ErrorInfo, now: Date): Promise<boolean>;
433
+ /**
434
+ * Gives a leased delivery back without counting the attempt: pending, due
435
+ * now, attempts decremented. Used when a handler is aborted at shutdown.
436
+ */
437
+ release(lease: LeaseReference, now: Date): Promise<boolean>;
438
+ /**
439
+ * Marks many leased deliveries completed with one round trip. Returns, for
440
+ * every lease in the same order, whether it was completed (false: lease lost
441
+ * or already finished). Each lease is fenced individually, exactly as in
442
+ * {@link EventStore.complete}. Optional: the dispatcher falls back to
443
+ * `complete` when a store does not implement it.
444
+ */
445
+ completeMany?(leases: readonly LeaseReference[], now: Date): Promise<boolean[]>;
446
+ /** Moves a leased delivery to dead. */
447
+ bury(lease: LeaseReference, error: ErrorInfo, now: Date): Promise<boolean>;
448
+ listDeliveries(query: DeliveryQuery): Promise<DeliveryRecord[]>;
449
+ /** Moves dead deliveries back to pending with a fresh attempt budget. Returns how many moved. */
450
+ requeue(deliveryIds: readonly string[], now: Date): Promise<number>;
451
+ purge(request: PurgeRequest): Promise<PurgeResult>;
452
+ statistics(now: Date): Promise<EventStoreStatistics>;
453
+ /**
454
+ * Hands back every lease group that `leaseOwner` holds without running work,
455
+ * so other workers can take them at once instead of after lease expiry.
456
+ * Called at graceful shutdown after the owner's deliveries settled. Groups
457
+ * with running deliveries stay leased. Optional.
458
+ */
459
+ relinquish?(leaseOwner: string, now: Date): Promise<void>;
460
+ /**
461
+ * Calls `listener` soon after a transaction that added deliveries due at once has committed, in this
462
+ * process or in any other one, so an idle dispatcher claims them without waiting for its next poll.
463
+ * A hint, never a guarantee: a report may be late, merged with others, or lost (while a connection
464
+ * is re-established, for instance), and polling still finds every delivery. Resolves with a function
465
+ * that stops listening, or with `undefined` when this store cannot listen. Optional.
466
+ */
467
+ watchNewDeliveries?(listener: () => void): Promise<(() => Promise<void>) | undefined>;
468
+ /** Releases connections the store opened itself; forced once `options.signal` aborts. */
469
+ close?(options?: CloseOptions): Promise<void>;
470
+ }
471
+
472
+ /** Where an incoming message came from, for observers and traces. */
473
+ interface TransportMessage {
474
+ /** Topic, routing key or queue the message arrived on. */
475
+ readonly destination: string;
476
+ }
477
+ /** A message the transport could not turn into an event, so it never reaches the bus. */
478
+ interface InvalidTransportMessage {
479
+ /** Topic, routing key or queue the message arrived on. */
480
+ readonly destination: string;
481
+ /** What the codec or decoder threw. */
482
+ readonly error: unknown;
483
+ }
484
+ /**
485
+ * What the bus offers a transport at `subscribe`, beyond the message handler. Present only when
486
+ * an observer implements the matching hook, so a transport can skip the work otherwise.
487
+ */
488
+ interface TransportSubscriptionHooks {
489
+ /**
490
+ * Call once for each inbound message the transport rejected as undecodable (dead-lettered or
491
+ * skipped) before it reached `onMessage`. Messages the bus rejected itself are reported by
492
+ * `onReceiveFinished` and must not be reported here. Never throws.
493
+ */
494
+ readonly onInvalidMessage: (message: InvalidTransportMessage) => void;
495
+ }
496
+ /**
497
+ * Receives an event from a broker. Resolve only after it is durably stored. Transports pass
498
+ * `message` to tell where the event arrived; it is optional for transports written before it.
499
+ */
500
+ type TransportMessageHandler = (envelope: EventEnvelope, message?: TransportMessage) => Promise<void>;
501
+ /**
502
+ * Broker port used to exchange events between services.
503
+ *
504
+ * Outbound: the bus calls `publish` from a delivery, so a broker outage only
505
+ * delays events; the outbox keeps them. `publish` must resolve only after the
506
+ * broker acknowledged the message.
507
+ *
508
+ * Inbound: `subscribe` must acknowledge a message only after `onMessage`
509
+ * resolved, and redeliver it when `onMessage` rejects (at-least-once).
510
+ */
511
+ interface Transport {
512
+ /** Unique name referenced by routes and subscriptions. */
513
+ readonly name: string;
514
+ /**
515
+ * The messaging system, as OpenTelemetry names it (`kafka`, `rabbitmq`), reported to observers
516
+ * and traces. Default: the transport's name.
517
+ */
518
+ readonly system?: string;
519
+ connect?(): Promise<void>;
520
+ publish(envelope: EventEnvelope, destination: string): Promise<void>;
521
+ subscribe?(destinations: readonly string[], onMessage: TransportMessageHandler, hooks?: TransportSubscriptionHooks): Promise<void>;
522
+ /**
523
+ * Whether the transport can currently publish and, when subscribed, is
524
+ * consuming. Health checks use it to report a dead consumer or a lost
525
+ * connection. Transports without it count as ready.
526
+ */
527
+ isReady?(): boolean;
528
+ /**
529
+ * Releases connections. A closed transport is not reopened. Once `options.signal` aborts (the
530
+ * shutdown deadline passed), stop waiting and drop the connections it opened itself.
531
+ */
532
+ close(options?: CloseOptions): Promise<void>;
533
+ }
534
+
535
+ export { toMilliseconds as $, type AppendEntry as A, type InvalidTransportMessage as B, type ClaimedDelivery as C, type Duration as D, type EventEnvelope as E, LeaseLostError as F, LifecycleError as G, HandlerTimeoutError as H, InvalidEnvelopeError as I, NonRetryableError as J, TransactionRequiredError as K, type LeaseReference as L, MAX_TIMER_DELAY_MS as M, type NewDelivery as N, TransactionTimeoutError as O, type PayloadOf as P, type TransportMessage as Q, RelayBusError as R, StandardSchemaV1 as S, type Transport as T, type TransportMessageHandler as U, type TransportSubscriptionHooks as V, type ValidationIssue as W, assertEventType as X, defineEvent as Y, systemClock as Z, toErrorInfo as _, type DomainEvent as a, validatePayload as a0, type EventHeaders as b, type EventStoreStatistics as c, type ErrorInfo as d, type PurgeResult as e, type EventStore as f, type EventReference as g, type Clock as h, type AppendResult as i, type ClaimRequest as j, type DeliveryQuery as k, type DeliveryRecord as l, type PurgeRequest as m, type EventClass as n, AttemptsExhaustedError as o, type CloseOptions as p, ConfigurationError as q, DELIVERY_STATUSES as r, type DefineEventKeyOptions as s, type DefineEventOptions as t, type DeliveryStatus as u, DispatcherStoppedError as v, DrainIncompleteError as w, type EventKeyFunction as x, type EventStoreTransactionOptions as y, EventValidationError as z };