@relaybus/core 0.4.1 → 1.0.0-next.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.
- package/README.md +4 -0
- package/dist/{chunk-J76M7XTS.cjs → chunk-2E6NSHGE.cjs} +27 -2
- package/dist/chunk-2E6NSHGE.cjs.map +1 -0
- package/dist/{chunk-NOR5JHVN.js → chunk-6PQ673MW.js} +23 -3
- package/dist/chunk-6PQ673MW.js.map +1 -0
- package/dist/index.cjs +567 -215
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +111 -11
- package/dist/index.d.ts +111 -11
- package/dist/index.js +418 -89
- package/dist/index.js.map +1 -1
- package/dist/internal/index.cjs +77 -37
- package/dist/internal/index.cjs.map +1 -1
- package/dist/internal/index.d.cts +24 -2
- package/dist/internal/index.d.ts +24 -2
- package/dist/internal/index.js +41 -3
- package/dist/internal/index.js.map +1 -1
- package/dist/{transport-DIFdeXQY.d.cts → transport-CXoZgh5u.d.cts} +77 -2
- package/dist/{transport-DIFdeXQY.d.ts → transport-CXoZgh5u.d.ts} +77 -2
- package/package.json +1 -1
- package/dist/chunk-J76M7XTS.cjs.map +0 -1
- package/dist/chunk-NOR5JHVN.js.map +0 -1
|
@@ -166,6 +166,35 @@ declare class ConfigurationError extends RelayBusError {
|
|
|
166
166
|
name: string;
|
|
167
167
|
readonly code: string;
|
|
168
168
|
}
|
|
169
|
+
/**
|
|
170
|
+
* A catalog or a catalog route names an event that is not part of the catalog, for example a wire
|
|
171
|
+
* name for an event the catalog does not have.
|
|
172
|
+
*/
|
|
173
|
+
declare class UnknownCatalogEventError extends ConfigurationError {
|
|
174
|
+
name: string;
|
|
175
|
+
readonly code: string;
|
|
176
|
+
}
|
|
177
|
+
/** A catalog route sends an event to a destination that another route already sends it to. */
|
|
178
|
+
declare class DuplicateRouteEventError extends ConfigurationError {
|
|
179
|
+
name: string;
|
|
180
|
+
readonly code: string;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Wire names clash: one event type has two wire names on a transport, or two event types share one,
|
|
184
|
+
* whether they come from catalogs, routes or the `wireTypes` of a codec.
|
|
185
|
+
*/
|
|
186
|
+
declare class WireTypeCollisionError extends ConfigurationError {
|
|
187
|
+
name: string;
|
|
188
|
+
readonly code: string;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* A route or catalog declares wire names for a transport whose codec cannot carry them: the
|
|
192
|
+
* transport has no `declareWireTypes`, or its codec is not a `jsonEnvelope` with a type to map.
|
|
193
|
+
*/
|
|
194
|
+
declare class WireTypesUnsupportedError extends ConfigurationError {
|
|
195
|
+
name: string;
|
|
196
|
+
readonly code: string;
|
|
197
|
+
}
|
|
169
198
|
/**
|
|
170
199
|
* Thrown by `publish` when no transaction can be found and the bus runs with
|
|
171
200
|
* `transactionMode: 'required'` (the default). Publishing outside a transaction
|
|
@@ -184,6 +213,16 @@ declare class TransactionTimeoutError extends RelayBusError {
|
|
|
184
213
|
name: string;
|
|
185
214
|
readonly code: string;
|
|
186
215
|
}
|
|
216
|
+
/**
|
|
217
|
+
* A `@RelayBusTransaction({ isolationLevel })` method was called inside a transaction that was not
|
|
218
|
+
* opened by relaybus at that same level. The isolation level of a running transaction cannot be
|
|
219
|
+
* changed, so the method cannot join it: open the outer transaction at the level, or leave the
|
|
220
|
+
* level off the inner method.
|
|
221
|
+
*/
|
|
222
|
+
declare class TransactionIsolationConflictError extends RelayBusError {
|
|
223
|
+
name: string;
|
|
224
|
+
readonly code: string;
|
|
225
|
+
}
|
|
187
226
|
/**
|
|
188
227
|
* Throw from a handler to dead-letter the delivery immediately, skipping the
|
|
189
228
|
* remaining retry attempts.
|
|
@@ -277,6 +316,13 @@ declare function toErrorInfo(error: unknown): ErrorInfo;
|
|
|
277
316
|
*/
|
|
278
317
|
type DeliveryStatus = 'pending' | 'processing' | 'completed' | 'dead';
|
|
279
318
|
declare const DELIVERY_STATUSES: readonly DeliveryStatus[];
|
|
319
|
+
/**
|
|
320
|
+
* Isolation level of a `bus.transaction`, in the vocabulary of SQL. `repeatable read` and
|
|
321
|
+
* `serializable` can fail with a serialization failure that succeeds when the transaction runs
|
|
322
|
+
* again; the bus then reruns `work` (see {@link TransactionOptions}).
|
|
323
|
+
*/
|
|
324
|
+
type TransactionIsolationLevel = 'read committed' | 'repeatable read' | 'serializable';
|
|
325
|
+
declare const TRANSACTION_ISOLATION_LEVELS: readonly TransactionIsolationLevel[];
|
|
280
326
|
interface NewDelivery {
|
|
281
327
|
readonly id: string;
|
|
282
328
|
/** Stable handler id. Together with the event id it is unique. */
|
|
@@ -389,6 +435,12 @@ interface EventStoreTransactionOptions {
|
|
|
389
435
|
* a transaction that still ran past the budget, so a store may also ignore it.
|
|
390
436
|
*/
|
|
391
437
|
readonly timeoutMs: number;
|
|
438
|
+
/**
|
|
439
|
+
* Isolation level the transaction runs at, set before its first statement. Only passed when
|
|
440
|
+
* `bus.transaction` was given one, and only to a store that lists it in
|
|
441
|
+
* {@link EventStore.isolationLevels}.
|
|
442
|
+
*/
|
|
443
|
+
readonly isolationLevel?: TransactionIsolationLevel;
|
|
392
444
|
}
|
|
393
445
|
/**
|
|
394
446
|
* Storage port. Implementations persist events and deliveries in the same
|
|
@@ -404,6 +456,19 @@ interface EventStore<TTransaction = unknown> {
|
|
|
404
456
|
* from `bus.transaction`; the store's own transactions and the dispatcher's pass none.
|
|
405
457
|
*/
|
|
406
458
|
transaction<T>(work: (transaction: TTransaction) => Promise<T>, options?: EventStoreTransactionOptions): Promise<T>;
|
|
459
|
+
/**
|
|
460
|
+
* Optional. The isolation levels `transaction` can run at. `bus.transaction` with another
|
|
461
|
+
* `isolationLevel` is rejected with a {@link ConfigurationError} before it opens a transaction;
|
|
462
|
+
* a store without the list supports none. A store lists a level only when the database gives
|
|
463
|
+
* the guarantee the name promises.
|
|
464
|
+
*/
|
|
465
|
+
readonly isolationLevels?: readonly TransactionIsolationLevel[];
|
|
466
|
+
/**
|
|
467
|
+
* Optional. True when `error`, raised by `transaction` (by `work`, or by the commit), means the
|
|
468
|
+
* database rolled the transaction back because of a conflict with a concurrent one and running
|
|
469
|
+
* it again can succeed (PostgreSQL SQLSTATE `40001`). Without it `bus.transaction` never reruns.
|
|
470
|
+
*/
|
|
471
|
+
isSerializationFailure?(error: unknown): boolean;
|
|
407
472
|
/**
|
|
408
473
|
* Writes events and their deliveries inside `transaction`. Idempotent on
|
|
409
474
|
* event id and on (event id, handler). Assigns a per-key sequence to keyed
|
|
@@ -517,6 +582,16 @@ interface Transport {
|
|
|
517
582
|
*/
|
|
518
583
|
readonly system?: string;
|
|
519
584
|
connect?(): Promise<void>;
|
|
585
|
+
/**
|
|
586
|
+
* Offered the wire names that routes and catalogs declare (event type to the name the wire
|
|
587
|
+
* format uses), once when the bus is created, before `connect` and `subscribe`. Check them
|
|
588
|
+
* without changing anything and return the function that applies them to the codec, so the bus
|
|
589
|
+
* can refuse a configuration before any transport changed. Throw
|
|
590
|
+
* {@link WireTypeCollisionError} when a name clashes with one the codec already has and
|
|
591
|
+
* {@link WireTypesUnsupportedError} when the codec cannot map type names or the transport
|
|
592
|
+
* already started. A transport without it refuses declared wire names at boot.
|
|
593
|
+
*/
|
|
594
|
+
declareWireTypes?(wireTypes: Readonly<Record<string, string>>): () => void;
|
|
520
595
|
publish(envelope: EventEnvelope, destination: string): Promise<void>;
|
|
521
596
|
subscribe?(destinations: readonly string[], onMessage: TransportMessageHandler, hooks?: TransportSubscriptionHooks): Promise<void>;
|
|
522
597
|
/**
|
|
@@ -532,5 +607,5 @@ interface Transport {
|
|
|
532
607
|
close(options?: CloseOptions): Promise<void>;
|
|
533
608
|
}
|
|
534
609
|
|
|
535
|
-
export {
|
|
536
|
-
export type { AppendEntry as A,
|
|
610
|
+
export { EventValidationError as F, HandlerTimeoutError as H, InvalidEnvelopeError as I, LeaseLostError as J, LifecycleError as K, MAX_TIMER_DELAY_MS as M, NonRetryableError as O, TRANSACTION_ISOLATION_LEVELS as Q, RelayBusError as R, StandardSchemaV1 as S, TransactionIsolationConflictError as U, TransactionRequiredError as V, TransactionTimeoutError as W, UnknownCatalogEventError as _, WireTypeCollisionError as a0, WireTypesUnsupportedError as a1, assertEventType as a2, defineEvent as a3, systemClock as a4, toErrorInfo as a5, toMilliseconds as a6, validatePayload as a7, AttemptsExhaustedError as p, ConfigurationError as r, DELIVERY_STATUSES as s, DispatcherStoppedError as w, DrainIncompleteError as x, DuplicateRouteEventError as y };
|
|
611
|
+
export type { ValidationIssue as $, AppendEntry as A, EventStoreTransactionOptions as B, ClaimedDelivery as C, Duration as D, EventEnvelope as E, InvalidTransportMessage as G, LeaseReference as L, NewDelivery as N, PayloadOf as P, Transport as T, TransportMessage as X, TransportMessageHandler as Y, TransportSubscriptionHooks as Z, DomainEvent as a, EventHeaders as b, EventStoreStatistics as c, ErrorInfo as d, PurgeResult as e, EventReference as f, EventStore as g, Clock as h, TransactionIsolationLevel as i, AppendResult as j, ClaimRequest as k, DeliveryQuery as l, DeliveryRecord as m, PurgeRequest as n, EventClass as o, CloseOptions as q, DefineEventKeyOptions as t, DefineEventOptions as u, DeliveryStatus as v, EventKeyFunction as z };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@relaybus/core",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "1.0.0-next.1",
|
|
4
4
|
"description": "Reliable event bus for Node.js: a transactional outbox with per-handler deliveries, retries with jitter, dead letters and per-key ordering on top of your own database.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Berkcan Şavur <berkcansavur@gmail.com>",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/duration.ts","../src/event.ts","../src/store-kit/lease-settlement.ts","../src/values/composite-key.ts","../src/internal/timers.ts","../src/values/milliseconds.ts","../src/values/delivery-lease-identity.ts","../src/values/positive-integer.ts"],"names":[],"mappings":"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","file":"chunk-J76M7XTS.cjs","sourcesContent":["/**\n * Base class of every error thrown by relaybus.\n */\nexport class RelayBusError extends Error {\n // Explicit names survive minification, unlike `new.target.name`.\n override name = 'RelayBusError';\n /**\n * Stable, machine-readable identifier of the error class, such as `RELAYBUS_LEASE_LOST`.\n * Unlike `name` and `message`, a code is never renamed once released; branch on it in\n * alerts and dashboards. Subclasses declared outside relaybus inherit `RELAYBUS_ERROR`.\n */\n readonly code: string = 'RELAYBUS_ERROR';\n}\n\n/** Invalid options passed to a relaybus component. */\nexport class ConfigurationError extends RelayBusError {\n override name = 'ConfigurationError';\n override readonly code: string = 'RELAYBUS_CONFIGURATION';\n}\n\n/**\n * Thrown by `publish` when no transaction can be found and the bus runs with\n * `transactionMode: 'required'` (the default). Publishing outside a transaction\n * would reintroduce the dual-write problem the outbox exists to prevent.\n */\nexport class TransactionRequiredError extends RelayBusError {\n override name = 'TransactionRequiredError';\n override readonly code: string = 'RELAYBUS_TRANSACTION_REQUIRED';\n}\n\n/**\n * A `bus.transaction` (or `@RelayBusTransaction()` method) ran past its `transactionTimeout` and\n * was rolled back. Its `cause` is the error the database raised when it ended the transaction,\n * when there was one. Usually a slow call to another service made inside the transaction.\n */\nexport class TransactionTimeoutError extends RelayBusError {\n override name = 'TransactionTimeoutError';\n override readonly code: string = 'RELAYBUS_TRANSACTION_TIMEOUT';\n}\n\n/**\n * Throw from a handler to dead-letter the delivery immediately, skipping the\n * remaining retry attempts.\n */\nexport class NonRetryableError extends RelayBusError {\n override name = 'NonRetryableError';\n override readonly code: string = 'RELAYBUS_NON_RETRYABLE';\n}\n\n/** A payload failed its event schema. Never retried: the payload will not change. */\nexport class EventValidationError extends NonRetryableError {\n override name = 'EventValidationError';\n override readonly code: string = 'RELAYBUS_EVENT_VALIDATION';\n\n constructor(\n message: string,\n readonly issues: readonly ValidationIssue[],\n ) {\n super(message);\n }\n}\n\n/**\n * A message received from a broker is not a valid event. Never retried:\n * transports should dead-letter it instead of redelivering it forever.\n */\nexport class InvalidEnvelopeError extends NonRetryableError {\n override name = 'InvalidEnvelopeError';\n override readonly code: string = 'RELAYBUS_INVALID_ENVELOPE';\n}\n\n/** The worker no longer owns the delivery it was processing. */\nexport class LeaseLostError extends RelayBusError {\n override name = 'LeaseLostError';\n override readonly code: string = 'RELAYBUS_LEASE_LOST';\n /**\n * Whether the store said so (a fenced write returned false). A worker that only noticed\n * locally that its lease ran out may still own the delivery in the store and has to give it back.\n */\n readonly storeConfirmed: boolean;\n\n constructor(message: string, options: { readonly storeConfirmed?: boolean } = {}) {\n super(message);\n this.storeConfirmed = options.storeConfirmed ?? false;\n }\n}\n\n/** A handler did not settle within its configured timeout. Retried like any failure. */\nexport class HandlerTimeoutError extends RelayBusError {\n override name = 'HandlerTimeoutError';\n override readonly code: string = 'RELAYBUS_HANDLER_TIMEOUT';\n}\n\n/**\n * Reason of a handler's abort signal when the bus stops before the handler\n * finished. The delivery is released and runs again without losing an attempt.\n */\nexport class DispatcherStoppedError extends RelayBusError {\n override name = 'DispatcherStoppedError';\n override readonly code: string = 'RELAYBUS_DISPATCHER_STOPPED';\n}\n\n/**\n * A delivery came back after its lease expired on its last attempt, so it is\n * dead-lettered without running its handler again.\n */\nexport class AttemptsExhaustedError extends RelayBusError {\n override name = 'AttemptsExhaustedError';\n override readonly code: string = 'RELAYBUS_ATTEMPTS_EXHAUSTED';\n}\n\n/** A lifecycle method was called in a state that does not allow it, such as starting a bus twice. */\nexport class LifecycleError extends RelayBusError {\n override name = 'LifecycleError';\n override readonly code: string = 'RELAYBUS_LIFECYCLE';\n}\n\n/** `drain` still found due deliveries after its maximum number of batches. */\nexport class DrainIncompleteError extends RelayBusError {\n override name = 'DrainIncompleteError';\n override readonly code: string = 'RELAYBUS_DRAIN_INCOMPLETE';\n}\n\nexport interface ValidationIssue {\n readonly message: string;\n readonly path?: readonly PropertyKey[] | undefined;\n}\n\n/** Serializable snapshot of an error, stored with failed deliveries. */\nexport interface ErrorInfo {\n readonly name: string;\n readonly message: string;\n readonly stack?: string | undefined;\n /** The {@link RelayBusError.code} of a relaybus error; absent for any other error. */\n readonly code?: string | undefined;\n}\n\nexport function toErrorInfo(error: unknown): ErrorInfo {\n if (error instanceof RelayBusError) {\n return { name: error.name, message: error.message, stack: error.stack, code: error.code };\n }\n if (error instanceof Error) {\n return { name: error.name, message: error.message, stack: error.stack };\n }\n return { name: 'NonError', message: safeStringify(error) };\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n","import { ConfigurationError } from './errors.js';\n\n/**\n * A duration in milliseconds, or a string such as `'250ms'`, `'30s'`, `'5m'`,\n * `'1h'` or `'7d'`.\n */\nexport type Duration = number | `${number}${DurationUnit}`;\n\ntype DurationUnit = 'ms' | 's' | 'm' | 'h' | 'd';\n\nconst MILLISECONDS_PER_UNIT: Record<DurationUnit, number> = {\n ms: 1,\n s: 1_000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n};\n\nconst DURATION_PATTERN = /^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d)$/;\n\nexport function toMilliseconds(value: Duration, name: string): number {\n if (typeof value === 'number') {\n if (!Number.isFinite(value) || value < 0) {\n throw new ConfigurationError(\n `${name} must be a non-negative finite number of milliseconds, received ${value}`,\n );\n }\n return value;\n }\n const match = DURATION_PATTERN.exec(value);\n if (match === null) {\n throw new ConfigurationError(\n `${name} must look like '500ms', '30s', '5m', '1h' or '7d', received '${value}'`,\n );\n }\n const [, amount, unit] = match as unknown as [string, string, DurationUnit];\n return Number(amount) * MILLISECONDS_PER_UNIT[unit];\n}\n\n/** Largest delay Node.js timers support. Longer values fire after 1ms instead. */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\n","import { ConfigurationError, EventValidationError } from './errors.js';\nimport type { StandardSchemaV1 } from './standard-schema.js';\n\n/** String metadata carried with an event, such as `traceparent`. */\nexport type EventHeaders = Readonly<Record<string, string>>;\n\n/**\n * An event as stored and delivered. Field names follow CloudEvents where they\n * overlap (`id`, `type`, `source`, `time` as `occurredAt`, `subject` as `key`).\n */\nexport interface EventEnvelope<TPayload = unknown> {\n /** Globally unique id. Handlers and transports deduplicate on it. */\n readonly id: string;\n /** Event type, for example `order.created.v1`. */\n readonly type: string;\n /** Logical name of the publishing service. */\n readonly source: string;\n /** Ordering and partition key. Events sharing a key are handled in publish order. */\n readonly key: string | null;\n readonly payload: TPayload;\n readonly headers: EventHeaders;\n /** Id shared by every event of one business flow. */\n readonly correlationId: string | null;\n /** Id of the event whose handler published this one. */\n readonly causationId: string | null;\n readonly occurredAt: Date;\n}\n\n/** An instance of a class created with {@link defineEvent}. */\nexport interface DomainEvent<TPayload = unknown> {\n readonly type: string;\n readonly payload: TPayload;\n}\n\n/**\n * Derives the ordering key of an event from its validated payload. Declared bivariantly so an\n * event class stays assignable wherever its payload type is widened.\n */\nexport type EventKeyFunction<TPayload> = {\n bivarianceHack(payload: TPayload): string;\n}['bivarianceHack'];\n\n/** A class created with {@link defineEvent}. */\nexport interface EventClass<TPayload = unknown> {\n new (payload: TPayload): DomainEvent<TPayload>;\n readonly type: string;\n readonly schema: StandardSchemaV1<unknown, TPayload> | undefined;\n /** The `key` given to {@link defineEvent}; undefined for events without one. */\n readonly key?: EventKeyFunction<TPayload> | undefined;\n}\n\n/** Payload type of an event class: `PayloadOf<typeof OrderPlaced>`. */\nexport type PayloadOf<TEvent> = TEvent extends EventClass<infer TPayload> ? TPayload : never;\n\n/** Anything that names an event type: an event class or the type string itself. */\nexport type EventReference = { readonly type: string } | string;\n\nexport interface DefineEventOptions<TSchema extends StandardSchemaV1> {\n /** Validates the payload on publish and before every handler call. */\n readonly schema: TSchema;\n /** Ordering key of every event of this type, from its validated payload. See {@link DefineEventKeyOptions}. */\n readonly key?: (payload: StandardSchemaV1.InferOutput<TSchema>) => string;\n}\n\nexport interface DefineEventKeyOptions<TPayload> {\n /**\n * Ordering key of every event of this type, from its payload: `(payload) => payload.orderId`.\n * Typed from the payload, so a missing field or a non-string fails to compile. `publish` uses it\n * when it is given no `key`; an explicit `key` option wins (for `publishAll`, the one key of the\n * call applies to every event). It must return a non-empty string.\n */\n readonly key: (payload: TPayload) => string;\n}\n\nconst EVENT_TYPE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,254}$/;\n\nexport function assertEventType(type: string): void {\n if (!EVENT_TYPE_PATTERN.test(type)) {\n throw new ConfigurationError(\n `Event type '${type}' must be 1-255 characters of letters, digits, '.', '_', ':', '/' or '-', starting with a letter or digit`,\n );\n }\n}\n\n/**\n * Defines an event type. Extend the returned class to name it:\n *\n * ```ts\n * export class OrderPlaced extends defineEvent<{ orderId: string }>('order.placed.v1') {}\n * export class OrderShipped extends defineEvent('order.shipped.v1', { schema: orderShippedSchema }) {}\n * export class OrderPaid extends defineEvent('order.paid.v1', {\n * schema: orderPaidSchema,\n * key: (payload) => payload.orderId,\n * }) {}\n * export class OrderCancelled extends defineEvent<{ orderId: string }>('order.cancelled.v1', {\n * key: (payload) => payload.orderId,\n * }) {}\n * ```\n */\nexport function defineEvent<TSchema extends StandardSchemaV1>(\n type: string,\n options: DefineEventOptions<TSchema>,\n): EventClass<StandardSchemaV1.InferOutput<TSchema>>;\nexport function defineEvent<TPayload>(\n type: string,\n options?: DefineEventKeyOptions<TPayload>,\n): EventClass<TPayload>;\nexport function defineEvent(\n type: string,\n options?: Partial<DefineEventOptions<StandardSchemaV1>>,\n): EventClass<unknown> {\n assertEventType(type);\n const schema = options?.schema;\n const key = options?.key;\n return class DefinedEvent implements DomainEvent<unknown> {\n static readonly type = type;\n static readonly schema = schema;\n static readonly key = key;\n readonly type = type;\n constructor(readonly payload: unknown) {}\n };\n}\n\n/** Runs a Standard Schema and returns its output, or throws {@link EventValidationError}. */\n// eslint-disable-next-line relaybus/max-two-params -- exported API validatePayload keeps its public signature\nexport async function validatePayload<TPayload>(\n type: string,\n schema: StandardSchemaV1<unknown, TPayload> | undefined,\n payload: unknown,\n): Promise<TPayload> {\n if (schema === undefined) {\n return payload as TPayload;\n }\n const result = await schema['~standard'].validate(payload);\n if (result.issues !== undefined) {\n const issues = result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((segment) => (typeof segment === 'object' ? segment.key : segment)),\n }));\n throw new EventValidationError(\n `Payload of '${type}' failed validation: ${issues.map((issue) => issue.message).join('; ')}`,\n issues,\n );\n }\n return result.value;\n}\n\n/**\n * The ordering key an event of `event`'s class takes from its definition, or null when the class\n * defines no key.\n *\n * @throws ConfigurationError when the key function returns an empty string or no string.\n */\nexport function keyFromDefinition(event: DomainEvent, payload: unknown): string | null {\n const keyOf = (event.constructor as Partial<EventClass>).key;\n if (keyOf === undefined) {\n return null;\n }\n const key: unknown = keyOf(payload);\n if (typeof key !== 'string' || key.length === 0) {\n throw new ConfigurationError(\n `The key function of '${event.type}' must return a non-empty string | returned=${typeof key === 'string' ? \"''\" : typeof key}`,\n );\n }\n return key;\n}\n","import type { ErrorInfo } from '../errors.js';\nimport type { LeaseReference } from '../event-store.js';\n\n/** How a claim ends without completing: retried later, given back, or dead-lettered. */\nexport type SettlementChange =\n | {\n readonly kind: 'reschedule';\n readonly availableAt: Date;\n readonly error: ErrorInfo;\n readonly now: Date;\n }\n | { readonly kind: 'release'; readonly now: Date }\n | { readonly kind: 'bury'; readonly error: ErrorInfo; readonly now: Date };\n\n/** A change of the claim a lease names. */\nexport type LeaseChange = { readonly lease: LeaseReference; readonly change: SettlementChange };\n\n/** A lease renewal; `now` for a store that records when it happened. */\nexport type LeaseExtension = {\n readonly lease: LeaseReference;\n readonly leaseExpiresAt: Date;\n readonly now?: Date;\n};\n\n/**\n * What a store answers about a lease: at once when it answers from memory, later when it asks a\n * database. Answering at once keeps the in-memory store as fast (in microtasks) as it always was.\n */\nexport type StoreAnswer = boolean | Promise<boolean>;\n\n/**\n * The fenced settlement skeleton every event store shares: find the claim a lease names (a lease\n * this store cannot have issued, or whose claim ended, is not held and changes nothing), apply the\n * change fenced by the lease, then forget the lease as handed out once the store answered.\n * A store supplies only how it finds a held claim, how it writes a change and a renewal, and its\n * bookkeeping of handed-out leases.\n */\nexport abstract class LeaseSettlement<THeld> {\n /** Renews the lease when it is still held; false otherwise. */\n extendLease(extension: LeaseExtension): StoreAnswer {\n const held = this.findHeld(extension.lease);\n return held === undefined ? false : this.writeExtension(held, extension);\n }\n\n /**\n * Applies `change` when the lease is still held. Once the store answered (either way) the lease\n * is forgotten as handed out; when the write throws it stays registered, since the caller may\n * retry with the same lease.\n */\n changeClaim(request: LeaseChange): StoreAnswer {\n const held = this.findHeld(request.lease);\n if (held === undefined) {\n return false;\n }\n const changed = this.writeChange(held, request);\n if (typeof changed === 'boolean') {\n this.forgetHandedOut(request.lease);\n return changed;\n }\n return this.#forgetOnceAnswered(request.lease, changed);\n }\n\n /** The claim `lease` names, when this store issued the lease; undefined otherwise. */\n protected abstract findHeld(lease: LeaseReference): THeld | undefined;\n\n protected abstract writeChange(held: THeld, request: LeaseChange): StoreAnswer;\n\n protected abstract writeExtension(held: THeld, extension: LeaseExtension): StoreAnswer;\n\n /** Drops `lease` from the store's handed-out bookkeeping; nothing for a store that keeps none. */\n protected abstract forgetHandedOut(lease: LeaseReference): void;\n\n async #forgetOnceAnswered(lease: LeaseReference, answer: Promise<boolean>): Promise<boolean> {\n const changed = await answer;\n this.forgetHandedOut(lease);\n return changed;\n }\n}\n","/** Separates the parts of a composite key: no identifier, handler id or ordering key contains it. */\nconst SEPARATOR = '\\u0000';\n\n/**\n * Two identifiers joined into one map or set key, such as an event id and a handler id, or a\n * handler id and an ordering key. The NUL separator keeps `('a:b', 'c')` and `('a', 'b:c')` apart.\n * Keys are plain strings, so they cost nothing more than the template literal they replace.\n */\nexport abstract class CompositeKey {\n static of(first: string, second: string): string {\n return `${first}${SEPARATOR}${second}`;\n }\n\n /** The start every key of `first` shares, to find them all by prefix. */\n static startOf(first: string): string {\n return `${first}${SEPARATOR}`;\n }\n}\n","import type { Clock } from '../clock.js';\n\n/** A task for {@link schedule}: what runs, after how long, whether it repeats and keeps the process alive. */\nexport type ScheduledTask = Parameters<NonNullable<Clock['schedule']>>[0];\n\n/** Cancels a scheduled task; harmless once it ran or was cancelled. */\nexport type CancelTimer = () => void;\n\n/**\n * The one place relaybus starts timers: through `clock.schedule` when the clock controls timers,\n * else with the platform timers.\n */\nexport function schedule(clock: Clock, task: ScheduledTask): CancelTimer {\n return clock.schedule === undefined ? scheduleOnPlatform(task) : clock.schedule(task);\n}\n\n/** Resolves after `milliseconds` on the timers of `clock`. */\nexport function sleep(clock: Clock, milliseconds: number): Promise<void> {\n return new Promise((resolve) => {\n schedule(clock, { run: resolve, delayMs: milliseconds });\n });\n}\n\nfunction scheduleOnPlatform(task: ScheduledTask): CancelTimer {\n if (task.repeat === true) {\n const interval = setInterval(task.run, task.delayMs);\n if (task.unref === true) {\n interval.unref();\n }\n return () => clearInterval(interval);\n }\n const timeout = setTimeout(task.run, task.delayMs);\n if (task.unref === true) {\n timeout.unref();\n }\n return () => clearTimeout(timeout);\n}\n","import { MAX_TIMER_DELAY_MS, toMilliseconds, type Duration } from '../duration.js';\nimport { ConfigurationError } from '../errors.js';\n\n/**\n * A configured length of time, converted once from a {@link Duration} option. Each factory names\n * the option, so its refusal says which one was wrong.\n */\nexport abstract class Milliseconds {\n /** Zero or more milliseconds. */\n static of(value: Duration, name: string): number {\n return toMilliseconds(value, name);\n }\n\n /** More than zero milliseconds: a wait, a timeout or an age that must pass at all. */\n static positive(value: Duration, name: string): number {\n const milliseconds = toMilliseconds(value, name);\n if (milliseconds === 0) {\n throw new ConfigurationError(`${name} must be greater than zero`);\n }\n return milliseconds;\n }\n\n /** A duration that drives a timer: more than zero, and no longer than timers can represent. */\n static forTimer(value: Duration, name: string): number {\n const milliseconds = Milliseconds.positive(value, name);\n if (milliseconds > MAX_TIMER_DELAY_MS) {\n throw new ConfigurationError(\n `${name} must not exceed ${MAX_TIMER_DELAY_MS}ms (about 24.8 days), received ${milliseconds}ms`,\n );\n }\n return milliseconds;\n }\n}\n","import { CompositeKey } from './composite-key.js';\n\n/**\n * Identifies one claim of a delivery: the delivery id with the exact lease token it was handed out\n * with. Two claims of the same delivery (an expired one and the current one) have different\n * identities, so bookkeeping of the older can never replace or remove the newer one's.\n */\nexport abstract class DeliveryLeaseIdentity {\n static of(deliveryId: string, leaseToken: string): string {\n return CompositeKey.of(deliveryId, leaseToken);\n }\n\n /** The start of the identity of every claim of `deliveryId`. */\n static prefixOf(deliveryId: string): string {\n return CompositeKey.startOf(deliveryId);\n }\n}\n","import { ConfigurationError } from '../errors.js';\n\n/** A count option that must be a whole number of at least 1: a batch size, attempts, a limit. */\nexport abstract class PositiveInteger {\n /** Returns `value` when it is an integer of at least 1, else throws a {@link ConfigurationError} naming the option. */\n static of(value: number, name: string): number {\n if (!Number.isInteger(value) || value < 1) {\n throw new ConfigurationError(`${name} must be a positive integer, received ${String(value)}`);\n }\n return value;\n }\n}\n"]}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/errors.ts","../src/duration.ts","../src/event.ts","../src/store-kit/lease-settlement.ts","../src/values/composite-key.ts","../src/internal/timers.ts","../src/values/milliseconds.ts","../src/values/delivery-lease-identity.ts","../src/values/positive-integer.ts"],"names":[],"mappings":"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","file":"chunk-NOR5JHVN.js","sourcesContent":["/**\n * Base class of every error thrown by relaybus.\n */\nexport class RelayBusError extends Error {\n // Explicit names survive minification, unlike `new.target.name`.\n override name = 'RelayBusError';\n /**\n * Stable, machine-readable identifier of the error class, such as `RELAYBUS_LEASE_LOST`.\n * Unlike `name` and `message`, a code is never renamed once released; branch on it in\n * alerts and dashboards. Subclasses declared outside relaybus inherit `RELAYBUS_ERROR`.\n */\n readonly code: string = 'RELAYBUS_ERROR';\n}\n\n/** Invalid options passed to a relaybus component. */\nexport class ConfigurationError extends RelayBusError {\n override name = 'ConfigurationError';\n override readonly code: string = 'RELAYBUS_CONFIGURATION';\n}\n\n/**\n * Thrown by `publish` when no transaction can be found and the bus runs with\n * `transactionMode: 'required'` (the default). Publishing outside a transaction\n * would reintroduce the dual-write problem the outbox exists to prevent.\n */\nexport class TransactionRequiredError extends RelayBusError {\n override name = 'TransactionRequiredError';\n override readonly code: string = 'RELAYBUS_TRANSACTION_REQUIRED';\n}\n\n/**\n * A `bus.transaction` (or `@RelayBusTransaction()` method) ran past its `transactionTimeout` and\n * was rolled back. Its `cause` is the error the database raised when it ended the transaction,\n * when there was one. Usually a slow call to another service made inside the transaction.\n */\nexport class TransactionTimeoutError extends RelayBusError {\n override name = 'TransactionTimeoutError';\n override readonly code: string = 'RELAYBUS_TRANSACTION_TIMEOUT';\n}\n\n/**\n * Throw from a handler to dead-letter the delivery immediately, skipping the\n * remaining retry attempts.\n */\nexport class NonRetryableError extends RelayBusError {\n override name = 'NonRetryableError';\n override readonly code: string = 'RELAYBUS_NON_RETRYABLE';\n}\n\n/** A payload failed its event schema. Never retried: the payload will not change. */\nexport class EventValidationError extends NonRetryableError {\n override name = 'EventValidationError';\n override readonly code: string = 'RELAYBUS_EVENT_VALIDATION';\n\n constructor(\n message: string,\n readonly issues: readonly ValidationIssue[],\n ) {\n super(message);\n }\n}\n\n/**\n * A message received from a broker is not a valid event. Never retried:\n * transports should dead-letter it instead of redelivering it forever.\n */\nexport class InvalidEnvelopeError extends NonRetryableError {\n override name = 'InvalidEnvelopeError';\n override readonly code: string = 'RELAYBUS_INVALID_ENVELOPE';\n}\n\n/** The worker no longer owns the delivery it was processing. */\nexport class LeaseLostError extends RelayBusError {\n override name = 'LeaseLostError';\n override readonly code: string = 'RELAYBUS_LEASE_LOST';\n /**\n * Whether the store said so (a fenced write returned false). A worker that only noticed\n * locally that its lease ran out may still own the delivery in the store and has to give it back.\n */\n readonly storeConfirmed: boolean;\n\n constructor(message: string, options: { readonly storeConfirmed?: boolean } = {}) {\n super(message);\n this.storeConfirmed = options.storeConfirmed ?? false;\n }\n}\n\n/** A handler did not settle within its configured timeout. Retried like any failure. */\nexport class HandlerTimeoutError extends RelayBusError {\n override name = 'HandlerTimeoutError';\n override readonly code: string = 'RELAYBUS_HANDLER_TIMEOUT';\n}\n\n/**\n * Reason of a handler's abort signal when the bus stops before the handler\n * finished. The delivery is released and runs again without losing an attempt.\n */\nexport class DispatcherStoppedError extends RelayBusError {\n override name = 'DispatcherStoppedError';\n override readonly code: string = 'RELAYBUS_DISPATCHER_STOPPED';\n}\n\n/**\n * A delivery came back after its lease expired on its last attempt, so it is\n * dead-lettered without running its handler again.\n */\nexport class AttemptsExhaustedError extends RelayBusError {\n override name = 'AttemptsExhaustedError';\n override readonly code: string = 'RELAYBUS_ATTEMPTS_EXHAUSTED';\n}\n\n/** A lifecycle method was called in a state that does not allow it, such as starting a bus twice. */\nexport class LifecycleError extends RelayBusError {\n override name = 'LifecycleError';\n override readonly code: string = 'RELAYBUS_LIFECYCLE';\n}\n\n/** `drain` still found due deliveries after its maximum number of batches. */\nexport class DrainIncompleteError extends RelayBusError {\n override name = 'DrainIncompleteError';\n override readonly code: string = 'RELAYBUS_DRAIN_INCOMPLETE';\n}\n\nexport interface ValidationIssue {\n readonly message: string;\n readonly path?: readonly PropertyKey[] | undefined;\n}\n\n/** Serializable snapshot of an error, stored with failed deliveries. */\nexport interface ErrorInfo {\n readonly name: string;\n readonly message: string;\n readonly stack?: string | undefined;\n /** The {@link RelayBusError.code} of a relaybus error; absent for any other error. */\n readonly code?: string | undefined;\n}\n\nexport function toErrorInfo(error: unknown): ErrorInfo {\n if (error instanceof RelayBusError) {\n return { name: error.name, message: error.message, stack: error.stack, code: error.code };\n }\n if (error instanceof Error) {\n return { name: error.name, message: error.message, stack: error.stack };\n }\n return { name: 'NonError', message: safeStringify(error) };\n}\n\nfunction safeStringify(value: unknown): string {\n if (typeof value === 'string') {\n return value;\n }\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n}\n","import { ConfigurationError } from './errors.js';\n\n/**\n * A duration in milliseconds, or a string such as `'250ms'`, `'30s'`, `'5m'`,\n * `'1h'` or `'7d'`.\n */\nexport type Duration = number | `${number}${DurationUnit}`;\n\ntype DurationUnit = 'ms' | 's' | 'm' | 'h' | 'd';\n\nconst MILLISECONDS_PER_UNIT: Record<DurationUnit, number> = {\n ms: 1,\n s: 1_000,\n m: 60_000,\n h: 3_600_000,\n d: 86_400_000,\n};\n\nconst DURATION_PATTERN = /^(\\d+(?:\\.\\d+)?)(ms|s|m|h|d)$/;\n\nexport function toMilliseconds(value: Duration, name: string): number {\n if (typeof value === 'number') {\n if (!Number.isFinite(value) || value < 0) {\n throw new ConfigurationError(\n `${name} must be a non-negative finite number of milliseconds, received ${value}`,\n );\n }\n return value;\n }\n const match = DURATION_PATTERN.exec(value);\n if (match === null) {\n throw new ConfigurationError(\n `${name} must look like '500ms', '30s', '5m', '1h' or '7d', received '${value}'`,\n );\n }\n const [, amount, unit] = match as unknown as [string, string, DurationUnit];\n return Number(amount) * MILLISECONDS_PER_UNIT[unit];\n}\n\n/** Largest delay Node.js timers support. Longer values fire after 1ms instead. */\nexport const MAX_TIMER_DELAY_MS = 2_147_483_647;\n","import { ConfigurationError, EventValidationError } from './errors.js';\nimport type { StandardSchemaV1 } from './standard-schema.js';\n\n/** String metadata carried with an event, such as `traceparent`. */\nexport type EventHeaders = Readonly<Record<string, string>>;\n\n/**\n * An event as stored and delivered. Field names follow CloudEvents where they\n * overlap (`id`, `type`, `source`, `time` as `occurredAt`, `subject` as `key`).\n */\nexport interface EventEnvelope<TPayload = unknown> {\n /** Globally unique id. Handlers and transports deduplicate on it. */\n readonly id: string;\n /** Event type, for example `order.created.v1`. */\n readonly type: string;\n /** Logical name of the publishing service. */\n readonly source: string;\n /** Ordering and partition key. Events sharing a key are handled in publish order. */\n readonly key: string | null;\n readonly payload: TPayload;\n readonly headers: EventHeaders;\n /** Id shared by every event of one business flow. */\n readonly correlationId: string | null;\n /** Id of the event whose handler published this one. */\n readonly causationId: string | null;\n readonly occurredAt: Date;\n}\n\n/** An instance of a class created with {@link defineEvent}. */\nexport interface DomainEvent<TPayload = unknown> {\n readonly type: string;\n readonly payload: TPayload;\n}\n\n/**\n * Derives the ordering key of an event from its validated payload. Declared bivariantly so an\n * event class stays assignable wherever its payload type is widened.\n */\nexport type EventKeyFunction<TPayload> = {\n bivarianceHack(payload: TPayload): string;\n}['bivarianceHack'];\n\n/** A class created with {@link defineEvent}. */\nexport interface EventClass<TPayload = unknown> {\n new (payload: TPayload): DomainEvent<TPayload>;\n readonly type: string;\n readonly schema: StandardSchemaV1<unknown, TPayload> | undefined;\n /** The `key` given to {@link defineEvent}; undefined for events without one. */\n readonly key?: EventKeyFunction<TPayload> | undefined;\n}\n\n/** Payload type of an event class: `PayloadOf<typeof OrderPlaced>`. */\nexport type PayloadOf<TEvent> = TEvent extends EventClass<infer TPayload> ? TPayload : never;\n\n/** Anything that names an event type: an event class or the type string itself. */\nexport type EventReference = { readonly type: string } | string;\n\nexport interface DefineEventOptions<TSchema extends StandardSchemaV1> {\n /** Validates the payload on publish and before every handler call. */\n readonly schema: TSchema;\n /** Ordering key of every event of this type, from its validated payload. See {@link DefineEventKeyOptions}. */\n readonly key?: (payload: StandardSchemaV1.InferOutput<TSchema>) => string;\n}\n\nexport interface DefineEventKeyOptions<TPayload> {\n /**\n * Ordering key of every event of this type, from its payload: `(payload) => payload.orderId`.\n * Typed from the payload, so a missing field or a non-string fails to compile. `publish` uses it\n * when it is given no `key`; an explicit `key` option wins (for `publishAll`, the one key of the\n * call applies to every event). It must return a non-empty string.\n */\n readonly key: (payload: TPayload) => string;\n}\n\nconst EVENT_TYPE_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,254}$/;\n\nexport function assertEventType(type: string): void {\n if (!EVENT_TYPE_PATTERN.test(type)) {\n throw new ConfigurationError(\n `Event type '${type}' must be 1-255 characters of letters, digits, '.', '_', ':', '/' or '-', starting with a letter or digit`,\n );\n }\n}\n\n/**\n * Defines an event type. Extend the returned class to name it:\n *\n * ```ts\n * export class OrderPlaced extends defineEvent<{ orderId: string }>('order.placed.v1') {}\n * export class OrderShipped extends defineEvent('order.shipped.v1', { schema: orderShippedSchema }) {}\n * export class OrderPaid extends defineEvent('order.paid.v1', {\n * schema: orderPaidSchema,\n * key: (payload) => payload.orderId,\n * }) {}\n * export class OrderCancelled extends defineEvent<{ orderId: string }>('order.cancelled.v1', {\n * key: (payload) => payload.orderId,\n * }) {}\n * ```\n */\nexport function defineEvent<TSchema extends StandardSchemaV1>(\n type: string,\n options: DefineEventOptions<TSchema>,\n): EventClass<StandardSchemaV1.InferOutput<TSchema>>;\nexport function defineEvent<TPayload>(\n type: string,\n options?: DefineEventKeyOptions<TPayload>,\n): EventClass<TPayload>;\nexport function defineEvent(\n type: string,\n options?: Partial<DefineEventOptions<StandardSchemaV1>>,\n): EventClass<unknown> {\n assertEventType(type);\n const schema = options?.schema;\n const key = options?.key;\n return class DefinedEvent implements DomainEvent<unknown> {\n static readonly type = type;\n static readonly schema = schema;\n static readonly key = key;\n readonly type = type;\n constructor(readonly payload: unknown) {}\n };\n}\n\n/** Runs a Standard Schema and returns its output, or throws {@link EventValidationError}. */\n// eslint-disable-next-line relaybus/max-two-params -- exported API validatePayload keeps its public signature\nexport async function validatePayload<TPayload>(\n type: string,\n schema: StandardSchemaV1<unknown, TPayload> | undefined,\n payload: unknown,\n): Promise<TPayload> {\n if (schema === undefined) {\n return payload as TPayload;\n }\n const result = await schema['~standard'].validate(payload);\n if (result.issues !== undefined) {\n const issues = result.issues.map((issue) => ({\n message: issue.message,\n path: issue.path?.map((segment) => (typeof segment === 'object' ? segment.key : segment)),\n }));\n throw new EventValidationError(\n `Payload of '${type}' failed validation: ${issues.map((issue) => issue.message).join('; ')}`,\n issues,\n );\n }\n return result.value;\n}\n\n/**\n * The ordering key an event of `event`'s class takes from its definition, or null when the class\n * defines no key.\n *\n * @throws ConfigurationError when the key function returns an empty string or no string.\n */\nexport function keyFromDefinition(event: DomainEvent, payload: unknown): string | null {\n const keyOf = (event.constructor as Partial<EventClass>).key;\n if (keyOf === undefined) {\n return null;\n }\n const key: unknown = keyOf(payload);\n if (typeof key !== 'string' || key.length === 0) {\n throw new ConfigurationError(\n `The key function of '${event.type}' must return a non-empty string | returned=${typeof key === 'string' ? \"''\" : typeof key}`,\n );\n }\n return key;\n}\n","import type { ErrorInfo } from '../errors.js';\nimport type { LeaseReference } from '../event-store.js';\n\n/** How a claim ends without completing: retried later, given back, or dead-lettered. */\nexport type SettlementChange =\n | {\n readonly kind: 'reschedule';\n readonly availableAt: Date;\n readonly error: ErrorInfo;\n readonly now: Date;\n }\n | { readonly kind: 'release'; readonly now: Date }\n | { readonly kind: 'bury'; readonly error: ErrorInfo; readonly now: Date };\n\n/** A change of the claim a lease names. */\nexport type LeaseChange = { readonly lease: LeaseReference; readonly change: SettlementChange };\n\n/** A lease renewal; `now` for a store that records when it happened. */\nexport type LeaseExtension = {\n readonly lease: LeaseReference;\n readonly leaseExpiresAt: Date;\n readonly now?: Date;\n};\n\n/**\n * What a store answers about a lease: at once when it answers from memory, later when it asks a\n * database. Answering at once keeps the in-memory store as fast (in microtasks) as it always was.\n */\nexport type StoreAnswer = boolean | Promise<boolean>;\n\n/**\n * The fenced settlement skeleton every event store shares: find the claim a lease names (a lease\n * this store cannot have issued, or whose claim ended, is not held and changes nothing), apply the\n * change fenced by the lease, then forget the lease as handed out once the store answered.\n * A store supplies only how it finds a held claim, how it writes a change and a renewal, and its\n * bookkeeping of handed-out leases.\n */\nexport abstract class LeaseSettlement<THeld> {\n /** Renews the lease when it is still held; false otherwise. */\n extendLease(extension: LeaseExtension): StoreAnswer {\n const held = this.findHeld(extension.lease);\n return held === undefined ? false : this.writeExtension(held, extension);\n }\n\n /**\n * Applies `change` when the lease is still held. Once the store answered (either way) the lease\n * is forgotten as handed out; when the write throws it stays registered, since the caller may\n * retry with the same lease.\n */\n changeClaim(request: LeaseChange): StoreAnswer {\n const held = this.findHeld(request.lease);\n if (held === undefined) {\n return false;\n }\n const changed = this.writeChange(held, request);\n if (typeof changed === 'boolean') {\n this.forgetHandedOut(request.lease);\n return changed;\n }\n return this.#forgetOnceAnswered(request.lease, changed);\n }\n\n /** The claim `lease` names, when this store issued the lease; undefined otherwise. */\n protected abstract findHeld(lease: LeaseReference): THeld | undefined;\n\n protected abstract writeChange(held: THeld, request: LeaseChange): StoreAnswer;\n\n protected abstract writeExtension(held: THeld, extension: LeaseExtension): StoreAnswer;\n\n /** Drops `lease` from the store's handed-out bookkeeping; nothing for a store that keeps none. */\n protected abstract forgetHandedOut(lease: LeaseReference): void;\n\n async #forgetOnceAnswered(lease: LeaseReference, answer: Promise<boolean>): Promise<boolean> {\n const changed = await answer;\n this.forgetHandedOut(lease);\n return changed;\n }\n}\n","/** Separates the parts of a composite key: no identifier, handler id or ordering key contains it. */\nconst SEPARATOR = '\\u0000';\n\n/**\n * Two identifiers joined into one map or set key, such as an event id and a handler id, or a\n * handler id and an ordering key. The NUL separator keeps `('a:b', 'c')` and `('a', 'b:c')` apart.\n * Keys are plain strings, so they cost nothing more than the template literal they replace.\n */\nexport abstract class CompositeKey {\n static of(first: string, second: string): string {\n return `${first}${SEPARATOR}${second}`;\n }\n\n /** The start every key of `first` shares, to find them all by prefix. */\n static startOf(first: string): string {\n return `${first}${SEPARATOR}`;\n }\n}\n","import type { Clock } from '../clock.js';\n\n/** A task for {@link schedule}: what runs, after how long, whether it repeats and keeps the process alive. */\nexport type ScheduledTask = Parameters<NonNullable<Clock['schedule']>>[0];\n\n/** Cancels a scheduled task; harmless once it ran or was cancelled. */\nexport type CancelTimer = () => void;\n\n/**\n * The one place relaybus starts timers: through `clock.schedule` when the clock controls timers,\n * else with the platform timers.\n */\nexport function schedule(clock: Clock, task: ScheduledTask): CancelTimer {\n return clock.schedule === undefined ? scheduleOnPlatform(task) : clock.schedule(task);\n}\n\n/** Resolves after `milliseconds` on the timers of `clock`. */\nexport function sleep(clock: Clock, milliseconds: number): Promise<void> {\n return new Promise((resolve) => {\n schedule(clock, { run: resolve, delayMs: milliseconds });\n });\n}\n\nfunction scheduleOnPlatform(task: ScheduledTask): CancelTimer {\n if (task.repeat === true) {\n const interval = setInterval(task.run, task.delayMs);\n if (task.unref === true) {\n interval.unref();\n }\n return () => clearInterval(interval);\n }\n const timeout = setTimeout(task.run, task.delayMs);\n if (task.unref === true) {\n timeout.unref();\n }\n return () => clearTimeout(timeout);\n}\n","import { MAX_TIMER_DELAY_MS, toMilliseconds, type Duration } from '../duration.js';\nimport { ConfigurationError } from '../errors.js';\n\n/**\n * A configured length of time, converted once from a {@link Duration} option. Each factory names\n * the option, so its refusal says which one was wrong.\n */\nexport abstract class Milliseconds {\n /** Zero or more milliseconds. */\n static of(value: Duration, name: string): number {\n return toMilliseconds(value, name);\n }\n\n /** More than zero milliseconds: a wait, a timeout or an age that must pass at all. */\n static positive(value: Duration, name: string): number {\n const milliseconds = toMilliseconds(value, name);\n if (milliseconds === 0) {\n throw new ConfigurationError(`${name} must be greater than zero`);\n }\n return milliseconds;\n }\n\n /** A duration that drives a timer: more than zero, and no longer than timers can represent. */\n static forTimer(value: Duration, name: string): number {\n const milliseconds = Milliseconds.positive(value, name);\n if (milliseconds > MAX_TIMER_DELAY_MS) {\n throw new ConfigurationError(\n `${name} must not exceed ${MAX_TIMER_DELAY_MS}ms (about 24.8 days), received ${milliseconds}ms`,\n );\n }\n return milliseconds;\n }\n}\n","import { CompositeKey } from './composite-key.js';\n\n/**\n * Identifies one claim of a delivery: the delivery id with the exact lease token it was handed out\n * with. Two claims of the same delivery (an expired one and the current one) have different\n * identities, so bookkeeping of the older can never replace or remove the newer one's.\n */\nexport abstract class DeliveryLeaseIdentity {\n static of(deliveryId: string, leaseToken: string): string {\n return CompositeKey.of(deliveryId, leaseToken);\n }\n\n /** The start of the identity of every claim of `deliveryId`. */\n static prefixOf(deliveryId: string): string {\n return CompositeKey.startOf(deliveryId);\n }\n}\n","import { ConfigurationError } from '../errors.js';\n\n/** A count option that must be a whole number of at least 1: a batch size, attempts, a limit. */\nexport abstract class PositiveInteger {\n /** Returns `value` when it is an integer of at least 1, else throws a {@link ConfigurationError} naming the option. */\n static of(value: number, name: string): number {\n if (!Number.isInteger(value) || value < 1) {\n throw new ConfigurationError(`${name} must be a positive integer, received ${String(value)}`);\n }\n return value;\n }\n}\n"]}
|