@relaybus/mongodb 0.0.0-stage → 0.0.0

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 @@
1
+ {"version":3,"sources":["../src/claim-scan.ts","../src/documents.ts","../src/mongo-errors.ts","../src/naming.ts","../src/mongo-event-store.ts"],"names":["EventValidationError","ConfigurationError","createUuidV7"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { DeliveryDocument } from './documents.js';\n\n/** What one claim call has learned about the deliveries of a single handler and key. */\ninterface KeyKnowledge {\n /** Lowest sequence known to be unfinished. Every later delivery of the key must wait. */\n openSequence: number | undefined;\n /** Whether some delivery of the key holds a live lease, so none may start. */\n leaseHeld: boolean;\n /** Pending deliveries that waited behind `openSequence`, candidates for parking. */\n waiting: string[];\n}\n\nexport type KeyVerdict = 'open-predecessor' | 'live-lease';\n\n/**\n * Bookkeeping of one claim call. A claim scans due deliveries in due order and\n * meets many deliveries of the same key; whatever it learns about a key from\n * the database once (an unfinished predecessor, a live lease, its own claim)\n * answers every later delivery of that key without another query.\n */\nexport class ClaimScan {\n readonly #keys = new Map<string, KeyKnowledge>();\n\n /** Why the delivery must wait according to what this scan already knows, if it does. */\n verdict(orderingId: string, sequence: number): KeyVerdict | undefined {\n const known = this.#keys.get(orderingId);\n if (known?.openSequence !== undefined && sequence > known.openSequence) {\n return 'open-predecessor';\n }\n return known?.leaseHeld === true ? 'live-lease' : undefined;\n }\n\n /** Records an unfinished delivery of the key with this sequence. */\n noteOpen(orderingId: string, sequence: number): void {\n const known = this.#know(orderingId);\n known.openSequence = Math.min(known.openSequence ?? sequence, sequence);\n }\n\n /** Records that this scan leased the delivery, which is now unfinished and holds a live lease. */\n noteClaimed(orderingId: string, sequence: number): void {\n this.noteOpen(orderingId, sequence);\n this.#know(orderingId).leaseHeld = true;\n }\n\n /** Records that a live lease of the key blocks every delivery of it. */\n noteLeaseHeld(orderingId: string): void {\n this.#know(orderingId).leaseHeld = true;\n }\n\n /** Remembers a delivery that waited behind an unfinished predecessor. */\n noteWaiting(orderingId: string, delivery: DeliveryDocument): void {\n if (delivery.status === 'pending') {\n this.#know(orderingId).waiting.push(delivery._id);\n }\n }\n\n /**\n * Ids of the waiting deliveries of every key that accumulated at least\n * `minimum` of them. Shorter queues stay in the claim index: moving them out\n * and back would cost more than skipping them.\n */\n waitingBacklogs(minimum: number): string[] {\n return [...this.#keys.values()]\n .filter((known) => known.waiting.length >= minimum)\n .flatMap((known) => known.waiting);\n }\n\n #know(orderingId: string): KeyKnowledge {\n let known = this.#keys.get(orderingId);\n if (known === undefined) {\n known = { openSequence: undefined, leaseHeld: false, waiting: [] };\n this.#keys.set(orderingId, known);\n }\n return known;\n }\n}\n\n/** Identity of the ordering lane of a handler and key. */\nexport function orderingIdentity(handler: string, key: string): string {\n return `${handler}\\u0000${key}`;\n}\n","import {\n EventValidationError,\n type DeliveryRecord,\n type DeliveryStatus,\n type ErrorInfo,\n type EventEnvelope,\n type NewDelivery,\n} from '@relaybus/core';\n\n/** Where a delivery sits relative to the claim index. See {@link DeliveryDocument.lane}. */\nexport type DeliveryLane = 'ready' | 'parked';\n\n/** Shape of a document in the events collection. `_id` is the event id. */\nexport interface EventDocument {\n readonly _id: string;\n readonly type: string;\n readonly source: string;\n readonly key: string | null;\n /** Position among the events of the same key, in commit order. Null for unkeyed events. */\n readonly sequence: number | null;\n /** JSON-normalized payload. Absent when the published payload was `undefined`. */\n readonly payload?: unknown;\n readonly headers: Readonly<Record<string, string>>;\n readonly correlationId: string | null;\n readonly causationId: string | null;\n readonly occurredAt: Date;\n /** Incremented when deliveries are added to an already stored event, so a concurrent purge conflicts with it. */\n readonly revision: number;\n}\n\n/**\n * Shape of a document in the deliveries collection.\n *\n * `dueAt` exists exactly while the delivery is `pending` (its `availableAt`) or\n * `processing` (its `leaseExpiresAt`). The ordering index is partial on it, so\n * it only ever contains unfinished work.\n *\n * `lane` exists on the same deliveries. A `ready` delivery is in the claim\n * index. A `parked` delivery is a pending, keyed delivery that waited behind an\n * unfinished earlier delivery of its handler and key; the claim index leaves it\n * out so a long queue behind one slow delivery costs nothing per claim. Claims\n * move the lowest parked delivery of a key back to `ready` once nothing\n * unfinished precedes it.\n */\nexport interface DeliveryDocument {\n readonly _id: string;\n readonly eventId: string;\n readonly eventType: string;\n readonly handler: string;\n /** Ordering key. Absent for unkeyed events. */\n readonly key?: string;\n /** Sequence of the event within its key. Absent for unkeyed events. */\n readonly sequence?: number;\n readonly status: DeliveryStatus;\n readonly lane?: DeliveryLane;\n readonly attempts: number;\n readonly availableAt: Date;\n readonly dueAt?: Date;\n readonly leaseOwner?: string;\n readonly leaseToken?: string;\n readonly leaseExpiresAt?: Date;\n readonly lastError?: ErrorInfo;\n readonly createdAt: Date;\n readonly updatedAt: Date;\n readonly completedAt?: Date;\n}\n\n/** Shape of a document in the key sequences collection. `_id` is the ordering key. */\nexport interface KeySequenceDocument {\n readonly _id: string;\n readonly value: number;\n}\n\n/**\n * Builds the stored form of an event. Payload and headers go through JSON so\n * that values JSON cannot represent (Dates, `undefined`, `NaN`) end up exactly\n * as in every other store.\n *\n * @throws EventValidationError when payload or headers contain a lone UTF-16\n * surrogate. BSON strings are UTF-8, so MongoDB would silently store U+FFFD\n * instead and the consumer would read different data than was published.\n */\nexport function toEventDocument(event: EventEnvelope, sequence: number | null): EventDocument {\n const payloadJson = serializeWellFormed(event.payload, 'payload');\n const headersJson = serializeWellFormed(event.headers, 'headers')!;\n return {\n _id: event.id,\n type: event.type,\n source: event.source,\n key: event.key,\n sequence,\n ...(payloadJson === undefined ? {} : { payload: JSON.parse(payloadJson) as unknown }),\n headers: JSON.parse(headersJson) as Record<string, string>,\n correlationId: event.correlationId,\n causationId: event.causationId,\n occurredAt: event.occurredAt,\n revision: 0,\n };\n}\n\n/**\n * JSON.stringify writes a lone surrogate as a `\\udXXX` escape and a valid pair as\n * the character itself, so an escape in that range is exactly a lone surrogate.\n * The lookbehind and the pair group skip escaped backslashes (`\\\\ud800` is text).\n */\nconst LONE_SURROGATE_ESCAPE = /(?<!\\\\)(?:\\\\\\\\)*\\\\ud[89a-f][0-9a-f]{2}/i;\n\nfunction serializeWellFormed(value: unknown, field: string): string | undefined {\n const json = JSON.stringify(value);\n if (json !== undefined && LONE_SURROGATE_ESCAPE.test(json)) {\n throw new EventValidationError(`The event ${field} contains a lone UTF-16 surrogate`, [\n {\n message:\n 'A lone surrogate cannot be stored as UTF-8 and would be replaced by U+FFFD. Remove it or encode the text first (for example with String.prototype.toWellFormed)',\n path: [field],\n },\n ]);\n }\n return json;\n}\n\nexport function toEnvelope(document: EventDocument): EventEnvelope {\n return {\n id: document._id,\n type: document.type,\n source: document.source,\n key: document.key,\n payload: document.payload,\n headers: document.headers,\n correlationId: document.correlationId,\n causationId: document.causationId,\n occurredAt: document.occurredAt,\n };\n}\n\nexport function toDeliveryDocument(\n delivery: NewDelivery,\n event: Pick<EventEnvelope, 'id' | 'type'>,\n ordering: { readonly key: string | null; readonly sequence: number | null },\n now: Date,\n): DeliveryDocument {\n return {\n _id: delivery.id,\n eventId: event.id,\n eventType: event.type,\n handler: delivery.handler,\n ...(ordering.key === null || ordering.sequence === null\n ? {}\n : { key: ordering.key, sequence: ordering.sequence }),\n status: 'pending',\n lane: 'ready',\n attempts: 0,\n availableAt: delivery.availableAt,\n dueAt: delivery.availableAt,\n createdAt: now,\n updatedAt: now,\n };\n}\n\nexport function toDeliveryRecord(document: DeliveryDocument, event: EventEnvelope): DeliveryRecord {\n return {\n id: document._id,\n handler: document.handler,\n status: document.status,\n attempts: document.attempts,\n availableAt: document.availableAt,\n leaseOwner: document.leaseOwner ?? null,\n leaseExpiresAt: document.leaseExpiresAt ?? null,\n lastError: document.lastError === undefined ? null : toErrorInfo(document.lastError),\n createdAt: document.createdAt,\n updatedAt: document.updatedAt,\n completedAt: document.completedAt ?? null,\n event,\n };\n}\n\n/** Copies an error without `undefined` members, which BSON would store as null. */\nexport function toErrorInfo(error: ErrorInfo): ErrorInfo {\n return error.stack === undefined\n ? { name: error.name, message: error.message }\n : { name: error.name, message: error.message, stack: error.stack };\n}\n","import { ConfigurationError } from '@relaybus/core';\n\nconst ILLEGAL_OPERATION = 20;\n\n/** True for the server error raised when a transaction runs on a standalone mongod. */\nexport function isTransactionsUnsupportedError(error: unknown): boolean {\n return (\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n error.code === ILLEGAL_OPERATION &&\n 'message' in error &&\n typeof error.message === 'string' &&\n error.message.includes('replica set member or mongos')\n );\n}\n\nexport function createTransactionsUnsupportedError(cause: unknown): ConfigurationError {\n return new ConfigurationError(\n 'MongoEventStore needs multi-document transactions, which MongoDB only offers on a replica set or a sharded cluster. Run a single-node replica set for development (mongod --replSet rs0, then rs.initiate())',\n { cause },\n );\n}\n","import { ConfigurationError } from '@relaybus/core';\n\nconst COLLECTION_PREFIX_PATTERN = /^[A-Za-z_][A-Za-z0-9_]{0,39}$/;\nconst DATABASE_NAME_PATTERN = /^[A-Za-z0-9_-]{1,63}$/;\n\n/** Rejects prefixes that are not safe, portable collection name starts. */\nexport function assertCollectionPrefix(prefix: string): void {\n if (!COLLECTION_PREFIX_PATTERN.test(prefix)) {\n throw new ConfigurationError(\n `collectionPrefix '${prefix}' must be 1-40 characters of letters, digits or '_', starting with a letter or '_'`,\n );\n }\n}\n\n/** Rejects database names MongoDB would refuse or that need escaping. */\nexport function assertDatabaseName(name: string): void {\n if (!DATABASE_NAME_PATTERN.test(name)) {\n throw new ConfigurationError(\n `database '${name}' must be 1-63 characters of letters, digits, '_' or '-'`,\n );\n }\n}\n","import {\n ConfigurationError,\n createUuidV7,\n type AppendEntry,\n type AppendResult,\n type ClaimRequest,\n type ClaimedDelivery,\n type DeliveryQuery,\n type DeliveryRecord,\n type DeliveryStatus,\n type ErrorInfo,\n type EventEnvelope,\n type EventStore,\n type EventStoreStatistics,\n type IdentifierGenerator,\n type LeaseReference,\n type PurgeRequest,\n type PurgeResult,\n} from '@relaybus/core';\nimport type {\n ClientSession,\n Collection,\n Db,\n Filter,\n MongoClient,\n TransactionOptions,\n UpdateFilter,\n} from 'mongodb';\nimport { ClaimScan, orderingIdentity } from './claim-scan.js';\nimport {\n toDeliveryDocument,\n toDeliveryRecord,\n toEnvelope,\n toErrorInfo,\n toEventDocument,\n type DeliveryDocument,\n type EventDocument,\n type KeySequenceDocument,\n} from './documents.js';\nimport {\n createTransactionsUnsupportedError,\n isTransactionsUnsupportedError,\n} from './mongo-errors.js';\nimport { assertCollectionPrefix, assertDatabaseName } from './naming.js';\n\nexport interface MongoEventStoreOptions {\n /** Connected client. The store never closes it. */\n readonly client: MongoClient;\n /** Database holding the relaybus collections. Default: the client's default database. */\n readonly database?: string;\n /** Prefix of the three collection names. Default `relaybus_`. */\n readonly collectionPrefix?: string;\n /**\n * Options of the transactions the store opens. Default: snapshot read\n * concern, majority write concern, primary reads.\n */\n readonly transactionOptions?: TransactionOptions;\n /** Rows deleted per purge step. Default 500. */\n readonly purgeBatchSize?: number;\n /** Produces lease tokens. Default UUID v7. */\n readonly generateIdentifier?: IdentifierGenerator;\n}\n\nconst DEFAULT_TRANSACTION_OPTIONS: TransactionOptions = {\n readConcern: { level: 'snapshot' },\n writeConcern: { w: 'majority' },\n readPreference: 'primary',\n};\nconst NAMESPACE_EXISTS = 48;\nconst DEFAULT_PURGE_BATCH_SIZE = 500;\nconst DEFAULT_LIST_LIMIT = 100;\nconst MINIMUM_CANDIDATE_BATCH_SIZE = 32;\n/** Deliveries that waited behind one unfinished predecessor before they are parked. */\nconst PARK_BACKLOG_THRESHOLD = 32;\nconst PARK_UPDATE_CHUNK_SIZE = 1_000;\n\n/** Fields that exist only while a delivery is leased. */\nconst LEASE_FIELDS = { leaseOwner: '', leaseToken: '', leaseExpiresAt: '' } as const;\n/** Fields that exist only while a delivery is unfinished. */\nconst FINISHED_FIELDS = { dueAt: '', lane: '' } as const;\n\n/**\n * Event store on MongoDB 6+ multi-document transactions (replica set or sharded\n * cluster). The transaction handle is the driver's `ClientSession`, so the same\n * session can carry your own writes (native driver or Mongoose).\n *\n * Guarantees:\n * - `append` is atomic with the caller's writes and idempotent on event id and on\n * (event id, handler). Duplicates are detected by reading, never by catching a\n * duplicate-key error, which would abort the surrounding transaction.\n * - Per-key sequences are allocated from a counter document inside the append\n * transaction. Two transactions appending the same key cannot both hold the\n * counter, so the loser conflicts, restarts after the winner committed, and\n * its sequence is higher: sequence order is commit order.\n * - `claim` selects candidates, then takes each with a conditional update that\n * re-checks the exact state it selected, so exactly one claimer wins. A keyed\n * delivery waits while an earlier delivery of its handler and key is\n * unfinished, or while any other delivery of them runs under a live lease;\n * the second rule is re-checked after the update, so a dead letter requeued\n * during a claim cannot run alongside its successor.\n * - Every lease operation is fenced by delivery id, status and lease token.\n *\n * `transaction` may run `work` more than once (see {@link MongoEventStore.transaction}).\n */\nexport class MongoEventStore implements EventStore<ClientSession> {\n readonly #client: MongoClient;\n readonly #database: Db;\n readonly #events: Collection<EventDocument>;\n readonly #deliveries: Collection<DeliveryDocument>;\n readonly #keySequences: Collection<KeySequenceDocument>;\n readonly #transactionOptions: TransactionOptions;\n readonly #purgeBatchSize: number;\n readonly #generateIdentifier: IdentifierGenerator;\n\n constructor(options: MongoEventStoreOptions) {\n const prefix = options.collectionPrefix ?? 'relaybus_';\n assertCollectionPrefix(prefix);\n if (options.database !== undefined) {\n assertDatabaseName(options.database);\n }\n const purgeBatchSize = options.purgeBatchSize ?? DEFAULT_PURGE_BATCH_SIZE;\n if (!Number.isInteger(purgeBatchSize) || purgeBatchSize < 1) {\n throw new ConfigurationError(\n `purgeBatchSize must be a positive integer, received ${String(purgeBatchSize)}`,\n );\n }\n this.#client = options.client;\n const database = options.client.db(options.database);\n this.#database = database;\n // Majority writes make a lease durable; primary reads keep the ordering check fresh.\n const collectionOptions = {\n readPreference: 'primary',\n writeConcern: { w: 'majority' },\n } as const;\n this.#events = database.collection(`${prefix}events`, collectionOptions);\n this.#deliveries = database.collection(`${prefix}deliveries`, collectionOptions);\n this.#keySequences = database.collection(`${prefix}key_sequences`, collectionOptions);\n this.#transactionOptions = options.transactionOptions ?? DEFAULT_TRANSACTION_OPTIONS;\n this.#purgeBatchSize = purgeBatchSize;\n this.#generateIdentifier = options.generateIdentifier ?? (() => createUuidV7());\n }\n\n /**\n * Verifies the deployment supports transactions and creates the indexes.\n * Safe to run repeatedly and from several processes.\n *\n * @throws ConfigurationError when the server is a standalone mongod.\n */\n async setup(): Promise<void> {\n const hello = await this.#client.db('admin').command({ hello: 1 });\n const supportsTransactions =\n typeof hello['setName'] === 'string' || hello['msg'] === 'isdbgrid';\n if (!supportsTransactions) {\n throw createTransactionsUnsupportedError(undefined);\n }\n // Created up front: collections created implicitly inside concurrent transactions conflict.\n for (const collection of [this.#events, this.#deliveries, this.#keySequences]) {\n await this.#createCollectionIfMissing(collection.collectionName);\n }\n await this.#deliveries.createIndexes([\n // Idempotent appends and lookups by event.\n { key: { eventId: 1, handler: 1 }, name: 'event_handler', unique: true },\n // Claim: due work of a handler in due order. Holds ready deliveries only.\n {\n key: { handler: 1, dueAt: 1, _id: 1 },\n name: 'claim',\n partialFilterExpression: { lane: 'ready' },\n },\n // Ordering: unfinished predecessors of a keyed delivery, parked or not.\n {\n key: { handler: 1, key: 1, sequence: 1 },\n name: 'ordering',\n partialFilterExpression: { dueAt: { $exists: true }, sequence: { $exists: true } },\n },\n // Parked deliveries: the lowest parked delivery of each key, to move it back once it is next.\n {\n key: { handler: 1, key: 1, sequence: 1 },\n name: 'parked',\n partialFilterExpression: { lane: 'parked' },\n },\n // Live leases: a keyed delivery may not start while another of its key is running.\n {\n key: { handler: 1, key: 1, dueAt: 1 },\n name: 'running',\n partialFilterExpression: { status: 'processing', key: { $exists: true } },\n },\n // Statistics: oldest due delivery across handlers.\n { key: { dueAt: 1 }, name: 'due', partialFilterExpression: { dueAt: { $exists: true } } },\n // Purge of completed deliveries.\n {\n key: { completedAt: 1 },\n name: 'completed',\n partialFilterExpression: { completedAt: { $exists: true } },\n },\n // Listing and status counts.\n { key: { status: 1, createdAt: 1 }, name: 'status_created' },\n // Purge of dead deliveries.\n { key: { status: 1, updatedAt: 1 }, name: 'status_updated' },\n { key: { handler: 1, createdAt: 1 }, name: 'handler_created' },\n { key: { eventType: 1, createdAt: 1 }, name: 'type_created' },\n ]);\n }\n\n async #createCollectionIfMissing(name: string): Promise<void> {\n try {\n await this.#database.createCollection(name);\n } catch (error) {\n if (!(\n typeof error === 'object' &&\n error !== null &&\n 'code' in error &&\n error.code === NAMESPACE_EXISTS\n )) {\n throw error;\n }\n }\n }\n\n /**\n * Runs `work` in a transaction on a new session and commits when it resolves.\n *\n * `work` can run more than once. The driver restarts the whole callback after\n * a transient failure such as a write conflict, and re-sends only the commit\n * after an unknown commit result. A restart is safe for everything written\n * through the session, because the aborted attempt left nothing behind. It is\n * not safe for side effects outside the session (HTTP calls, other databases),\n * so keep those out of `work`; relaybus handlers are already at-least-once.\n *\n * @throws ConfigurationError when the deployment does not support transactions.\n */\n async transaction<T>(work: (transaction: ClientSession) => Promise<T>): Promise<T> {\n try {\n return await this.#client.withSession(async (session) => {\n let result!: T;\n await session.withTransaction(async () => {\n result = await work(session);\n }, this.#transactionOptions);\n return result;\n });\n } catch (error) {\n if (isTransactionsUnsupportedError(error)) {\n throw createTransactionsUnsupportedError(error);\n }\n throw error;\n }\n }\n\n async append(\n session: ClientSession,\n entries: readonly AppendEntry[],\n now: Date,\n ): Promise<AppendResult> {\n assertInTransaction(session, 'append');\n const eventIds = [...new Set(entries.map((entry) => entry.event.id))];\n const storedEvents = new Map(\n (\n await this.#events\n .find({ _id: { $in: eventIds } }, { session, projection: { key: 1, sequence: 1 } })\n .toArray()\n ).map((stored) => [stored._id, stored]),\n );\n const storedDeliveryKeys = new Set(\n (\n await this.#deliveries\n .find({ eventId: { $in: eventIds } }, { session, projection: { eventId: 1, handler: 1 } })\n .toArray()\n ).map((stored) => deliveryPairKey(stored.eventId, stored.handler)),\n );\n\n const appendedEventIds: string[] = [];\n const duplicateEventIds: string[] = [];\n const newEvents: EventDocument[] = [];\n const newDeliveries: DeliveryDocument[] = [];\n const touchedEventIds = new Set<string>();\n const orderingByEventId = new Map<\n string,\n { readonly key: string | null; readonly sequence: number | null }\n >();\n for (const [eventId, stored] of storedEvents) {\n orderingByEventId.set(eventId, { key: stored.key, sequence: stored.sequence });\n }\n\n for (const { event, deliveries } of entries) {\n let ordering = orderingByEventId.get(event.id);\n if (ordering === undefined) {\n const sequence = event.key === null ? null : await this.#nextSequence(event.key, session);\n ordering = { key: event.key, sequence };\n orderingByEventId.set(event.id, ordering);\n newEvents.push(toEventDocument(event, sequence));\n appendedEventIds.push(event.id);\n } else {\n duplicateEventIds.push(event.id);\n }\n for (const delivery of deliveries) {\n const pairKey = deliveryPairKey(event.id, delivery.handler);\n if (storedDeliveryKeys.has(pairKey)) {\n continue;\n }\n storedDeliveryKeys.add(pairKey);\n newDeliveries.push(toDeliveryDocument(delivery, event, ordering, now));\n if (storedEvents.has(event.id)) {\n touchedEventIds.add(event.id);\n }\n }\n }\n\n if (newEvents.length > 0) {\n // Upserts, not inserts: a duplicate-key error would abort the whole transaction,\n // whereas a concurrent writer of the same id surfaces as a retryable write conflict.\n await this.#events.bulkWrite(\n newEvents.map((document) => ({\n updateOne: {\n filter: { _id: document._id },\n update: { $setOnInsert: document },\n upsert: true,\n },\n })),\n { session, ordered: true },\n );\n }\n if (touchedEventIds.size > 0) {\n // A real write on the event makes a concurrent purge of it conflict with this transaction.\n await this.#events.updateMany(\n { _id: { $in: [...touchedEventIds] } },\n { $inc: { revision: 1 } },\n { session },\n );\n }\n if (newDeliveries.length > 0) {\n await this.#deliveries.bulkWrite(\n newDeliveries.map((document) => ({\n updateOne: {\n filter: { eventId: document.eventId, handler: document.handler },\n update: { $setOnInsert: document },\n upsert: true,\n },\n })),\n { session, ordered: true },\n );\n }\n return { appendedEventIds, duplicateEventIds, appendedDeliveryCount: newDeliveries.length };\n }\n\n async claim(request: ClaimRequest): Promise<ClaimedDelivery[]> {\n if (request.handlers.length === 0 || request.limit <= 0) {\n return [];\n }\n await this.#unparkNextDeliveries(request.handlers);\n const claimed: DeliveryDocument[] = [];\n const scan = new ClaimScan();\n const candidates = this.#deliveries.find(\n { handler: { $in: [...request.handlers] }, dueAt: { $lte: request.now }, lane: 'ready' },\n {\n sort: { dueAt: 1, _id: 1 },\n batchSize: Math.max(request.limit * 2, MINIMUM_CANDIDATE_BATCH_SIZE),\n },\n );\n try {\n for await (const candidate of candidates) {\n const leased = await this.#claimCandidate(candidate, request, scan);\n if (leased !== undefined) {\n claimed.push(leased);\n if (claimed.length >= request.limit) {\n break;\n }\n }\n }\n } finally {\n await candidates.close();\n }\n await this.#parkDeliveries(scan.waitingBacklogs(PARK_BACKLOG_THRESHOLD));\n return this.#toClaimedDeliveries(claimed, request.leaseExpiresAt);\n }\n\n async extendLease(lease: LeaseReference, leaseExpiresAt: Date, now: Date): Promise<boolean> {\n return this.#updateLeased(lease, undefined, {\n $set: { leaseExpiresAt, dueAt: leaseExpiresAt, updatedAt: now },\n });\n }\n\n async complete(lease: LeaseReference, now: Date, session?: ClientSession): Promise<boolean> {\n if (session !== undefined) {\n assertInTransaction(session, 'complete');\n }\n return this.#updateLeased(lease, session, {\n $set: { status: 'completed', completedAt: now, updatedAt: now },\n $unset: { ...LEASE_FIELDS, ...FINISHED_FIELDS },\n });\n }\n\n async reschedule(\n lease: LeaseReference,\n availableAt: Date,\n error: ErrorInfo,\n now: Date,\n ): Promise<boolean> {\n return this.#updateLeased(lease, undefined, {\n $set: {\n status: 'pending',\n availableAt,\n dueAt: availableAt,\n lastError: toErrorInfo(error),\n updatedAt: now,\n },\n $unset: LEASE_FIELDS,\n });\n }\n\n async release(lease: LeaseReference, now: Date): Promise<boolean> {\n return this.#updateLeased(lease, undefined, {\n $set: { status: 'pending', availableAt: now, dueAt: now, updatedAt: now },\n $inc: { attempts: -1 },\n $unset: LEASE_FIELDS,\n });\n }\n\n async bury(lease: LeaseReference, error: ErrorInfo, now: Date): Promise<boolean> {\n return this.#updateLeased(lease, undefined, {\n $set: { status: 'dead', lastError: toErrorInfo(error), updatedAt: now },\n $unset: { ...LEASE_FIELDS, ...FINISHED_FIELDS },\n });\n }\n\n async listDeliveries(query: DeliveryQuery): Promise<DeliveryRecord[]> {\n // Strings only: an object here (say, parsed from an admin request) would be a query operator.\n const filter: Filter<DeliveryDocument> = {\n ...(query.status === undefined ? {} : { status: String(query.status) as DeliveryStatus }),\n ...(query.handler === undefined ? {} : { handler: String(query.handler) }),\n ...(query.eventType === undefined ? {} : { eventType: String(query.eventType) }),\n ...(query.eventId === undefined ? {} : { eventId: String(query.eventId) }),\n };\n const documents = await this.#deliveries\n .find(filter, { sort: { createdAt: 1, _id: 1 }, limit: query.limit ?? DEFAULT_LIST_LIMIT })\n .toArray();\n const events = await this.#readEnvelopes(documents.map((document) => document.eventId));\n return documents.map((document) => toDeliveryRecord(document, events.get(document.eventId)!));\n }\n\n async requeue(deliveryIds: readonly string[], now: Date): Promise<number> {\n const result = await this.#deliveries.updateMany(\n { _id: { $in: deliveryIds.map(String) }, status: 'dead' },\n {\n $set: {\n status: 'pending',\n lane: 'ready',\n attempts: 0,\n availableAt: now,\n dueAt: now,\n updatedAt: now,\n },\n },\n );\n return result.modifiedCount;\n }\n\n async purge(request: PurgeRequest): Promise<PurgeResult> {\n const filters: Filter<DeliveryDocument>[] = [];\n if (request.completedBefore !== undefined) {\n filters.push({ status: 'completed', completedAt: { $lt: request.completedBefore } });\n }\n if (request.deadBefore !== undefined) {\n filters.push({ status: 'dead', updatedAt: { $lt: request.deadBefore } });\n }\n let deletedDeliveries = 0;\n let deletedEvents = 0;\n for (const filter of filters) {\n const result = await this.#purgeMatching(filter);\n deletedDeliveries += result.deletedDeliveries;\n deletedEvents += result.deletedEvents;\n }\n return { deletedDeliveries, deletedEvents };\n }\n\n async statistics(now: Date): Promise<EventStoreStatistics> {\n // Four index-only counts: measured at 300k deliveries they take 27 ms in parallel, against\n // 121 ms for one $group, which has to read every document or index entry.\n const statuses: DeliveryStatus[] = ['pending', 'processing', 'completed', 'dead'];\n const [pending, processing, completed, dead] = await Promise.all(\n statuses.map((status) => this.#deliveries.countDocuments({ status })),\n );\n const oldestDue = await this.#deliveries.findOne(\n { dueAt: { $lte: now } },\n { sort: { dueAt: 1 }, projection: { dueAt: 1 } },\n );\n return {\n pending: pending!,\n processing: processing!,\n completed: completed!,\n dead: dead!,\n oldestDueAt: oldestDue?.dueAt ?? null,\n };\n }\n\n /** Atomically increments the counter of `key`; conflicting appends of the key serialize here. */\n async #nextSequence(key: string, session: ClientSession): Promise<number> {\n const counter = await this.#keySequences.findOneAndUpdate(\n { _id: key },\n { $inc: { value: 1 } },\n { upsert: true, returnDocument: 'after', session },\n );\n return counter!.value;\n }\n\n async #claimCandidate(\n candidate: DeliveryDocument,\n request: ClaimRequest,\n scan: ClaimScan,\n ): Promise<DeliveryDocument | undefined> {\n const { key, sequence } = candidate;\n if (key === undefined) {\n return this.#lease(candidate, request);\n }\n const orderingId = orderingIdentity(candidate.handler, key);\n const known = scan.verdict(orderingId, sequence!);\n if (known === 'open-predecessor') {\n scan.noteWaiting(orderingId, candidate);\n return undefined;\n }\n if (known === 'live-lease') {\n return undefined;\n }\n const predecessor = await this.#findUnfinishedPredecessor(candidate.handler, key, sequence!);\n if (predecessor !== undefined) {\n scan.noteOpen(orderingId, predecessor);\n scan.noteWaiting(orderingId, candidate);\n return undefined;\n }\n if (await this.#hasLiveLease(candidate.handler, key, request.now)) {\n scan.noteLeaseHeld(orderingId);\n return undefined;\n }\n const leased = await this.#lease(candidate, request);\n if (leased === undefined) {\n return undefined;\n }\n // A dead letter requeued after the checks above can be claimed by another worker\n // before this lease is visible to it, and neither check would see the other. Only\n // the later delivery gives way, so exactly one of the two keeps running.\n const lateBlocker = await this.#findUnfinishedPredecessor(candidate.handler, key, sequence!);\n if (lateBlocker !== undefined) {\n await this.#restore(candidate, leased);\n scan.noteOpen(orderingId, lateBlocker);\n return undefined;\n }\n scan.noteClaimed(orderingId, sequence!);\n return leased;\n }\n\n /**\n * Takes the delivery with one conditional update that pins the exact state\n * that was selected, so a competing claimer, a finished lease, a reschedule\n * or a parking since then makes it match nothing.\n */\n async #lease(\n candidate: DeliveryDocument,\n request: ClaimRequest,\n ): Promise<DeliveryDocument | undefined> {\n const leased = await this.#deliveries.findOneAndUpdate(\n {\n _id: candidate._id,\n status: candidate.status,\n lane: 'ready',\n attempts: candidate.attempts,\n dueAt: candidate.dueAt!,\n },\n {\n $set: {\n status: 'processing',\n leaseOwner: request.leaseOwner,\n leaseToken: this.#generateIdentifier(),\n leaseExpiresAt: request.leaseExpiresAt,\n dueAt: request.leaseExpiresAt,\n updatedAt: request.now,\n },\n $inc: { attempts: 1 },\n },\n { returnDocument: 'after' },\n );\n return leased ?? undefined;\n }\n\n /** Puts a delivery that was leased a moment ago back exactly as it was selected. */\n async #restore(selected: DeliveryDocument, leased: DeliveryDocument): Promise<void> {\n const state = {\n status: selected.status,\n attempts: selected.attempts,\n dueAt: selected.dueAt!,\n updatedAt: selected.updatedAt,\n };\n await this.#deliveries.updateOne(\n { _id: leased._id, status: 'processing', leaseToken: leased.leaseToken! },\n selected.status === 'processing'\n ? {\n $set: {\n ...state,\n leaseOwner: selected.leaseOwner!,\n leaseToken: selected.leaseToken!,\n leaseExpiresAt: selected.leaseExpiresAt!,\n },\n }\n : { $set: state, $unset: LEASE_FIELDS },\n );\n }\n\n /** Sequence of the lowest unfinished delivery of the handler and key before `sequence`, if any. */\n async #findUnfinishedPredecessor(\n handler: string,\n key: string,\n sequence: number,\n ): Promise<number | undefined> {\n const predecessor = await this.#deliveries.findOne(\n { handler, key, sequence: { $lt: sequence }, dueAt: { $exists: true } },\n { sort: { sequence: 1 }, projection: { sequence: 1 } },\n );\n return predecessor?.sequence;\n }\n\n /** Whether some delivery of the handler and key runs under a lease that has not expired. */\n async #hasLiveLease(handler: string, key: string, now: Date): Promise<boolean> {\n const running = await this.#deliveries.findOne(\n { handler, key, status: 'processing', dueAt: { $gt: now } },\n { projection: { _id: 1 } },\n );\n return running !== null;\n }\n\n /**\n * Parks pending deliveries that waited behind an unfinished predecessor, which\n * removes them from the claim index until their turn. Parking is a hint, not a\n * guarantee: a predecessor that finishes meanwhile is found by the next\n * {@link MongoEventStore.claim}, which moves the lowest parked delivery back.\n */\n async #parkDeliveries(deliveryIds: readonly string[]): Promise<void> {\n for (let offset = 0; offset < deliveryIds.length; offset += PARK_UPDATE_CHUNK_SIZE) {\n await this.#deliveries.updateMany(\n {\n _id: { $in: deliveryIds.slice(offset, offset + PARK_UPDATE_CHUNK_SIZE) },\n status: 'pending',\n lane: 'ready',\n },\n { $set: { lane: 'parked' } },\n );\n }\n }\n\n /**\n * Moves the lowest parked delivery of every parked key of `handlers` back into\n * the claim index when nothing unfinished precedes it. Level-triggered on\n * purpose: it looks at the current state only, so a crash anywhere, or a\n * predecessor finishing while its followers were being parked, can delay a key\n * until the next claim but never strand it.\n */\n async #unparkNextDeliveries(handlers: readonly string[]): Promise<void> {\n const anyParked = await this.#deliveries.findOne(\n { handler: { $in: [...handlers] }, lane: 'parked' },\n // The sort lets the planner pick the small partial index over the handler's whole history.\n { sort: { handler: 1, key: 1, sequence: 1 }, projection: { _id: 1 } },\n );\n if (anyParked === null) {\n return;\n }\n for (const handler of new Set(handlers)) {\n let afterKey: string | undefined;\n for (;;) {\n const lowest = await this.#deliveries.findOne(\n {\n handler,\n lane: 'parked',\n ...(afterKey === undefined ? {} : { key: { $gt: afterKey } }),\n },\n { sort: { key: 1, sequence: 1 }, projection: { key: 1, sequence: 1 } },\n );\n if (lowest === null) {\n break;\n }\n afterKey = lowest.key!;\n if (\n (await this.#findUnfinishedPredecessor(handler, afterKey, lowest.sequence!)) === undefined\n ) {\n await this.#deliveries.updateOne(\n { _id: lowest._id, lane: 'parked' },\n { $set: { lane: 'ready' } },\n );\n }\n }\n }\n }\n\n async #toClaimedDeliveries(\n leased: readonly DeliveryDocument[],\n leaseExpiresAt: Date,\n ): Promise<ClaimedDelivery[]> {\n const events = await this.#readEnvelopes(leased.map((document) => document.eventId));\n return leased.map((document) => ({\n deliveryId: document._id,\n leaseToken: document.leaseToken!,\n handler: document.handler,\n attempt: document.attempts,\n leaseExpiresAt,\n event: events.get(document.eventId)!,\n }));\n }\n\n async #readEnvelopes(eventIds: readonly string[]): Promise<Map<string, EventEnvelope>> {\n const documents = await this.#events.find({ _id: { $in: [...new Set(eventIds)] } }).toArray();\n return new Map(documents.map((document) => [document._id, toEnvelope(document)]));\n }\n\n async #updateLeased(\n lease: LeaseReference,\n session: ClientSession | undefined,\n update: UpdateFilter<DeliveryDocument>,\n ): Promise<boolean> {\n const result = await this.#deliveries.updateOne(\n { _id: lease.deliveryId, status: 'processing', leaseToken: lease.leaseToken },\n update,\n session === undefined ? {} : { session },\n );\n // Matched, not modified: a repeated renewal with identical values changes nothing but still holds the lease.\n return result.matchedCount === 1;\n }\n\n /**\n * Deletes batches of matching deliveries together with the events no delivery\n * references any more, each batch in one transaction, so a crash can never\n * leave an event without deliveries behind. An append adding a delivery to the\n * same event writes the event document, so the two conflict and one restarts\n * instead of leaving a delivery without event. A delivery requeued since the\n * batch was read conflicts with its deletion and is read again.\n */\n async #purgeMatching(filter: Filter<DeliveryDocument>): Promise<PurgeResult> {\n let deletedDeliveries = 0;\n let deletedEvents = 0;\n for (;;) {\n const step = await this.transaction(async (session) => {\n const batch = await this.#deliveries\n .find(filter, { session, projection: { eventId: 1 }, limit: this.#purgeBatchSize })\n .toArray();\n const eventIds = [...new Set(batch.map((document) => document.eventId))];\n const deliveries = await this.#deliveries.deleteMany(\n { _id: { $in: batch.map((document) => document._id) } },\n { session },\n );\n const stillReferenced = new Set(\n (\n await this.#deliveries\n .find({ eventId: { $in: eventIds } }, { session, projection: { eventId: 1 } })\n .toArray()\n ).map((document) => document.eventId),\n );\n const events = await this.#events.deleteMany(\n { _id: { $in: eventIds.filter((eventId) => !stillReferenced.has(eventId)) } },\n { session },\n );\n return {\n batchSize: batch.length,\n deletedDeliveries: deliveries.deletedCount,\n deletedEvents: events.deletedCount,\n };\n });\n deletedDeliveries += step.deletedDeliveries;\n deletedEvents += step.deletedEvents;\n if (step.batchSize < this.#purgeBatchSize) {\n return { deletedDeliveries, deletedEvents };\n }\n }\n }\n}\n\nfunction deliveryPairKey(eventId: string, handler: string): string {\n return `${eventId}\\u0000${handler}`;\n}\n\nfunction assertInTransaction(session: ClientSession, operation: string): void {\n if (!session.inTransaction()) {\n throw new ConfigurationError(\n `MongoEventStore.${operation} needs a ClientSession inside a started transaction (session.withTransaction or startTransaction). Without one, MongoDB commits each write immediately and the write is no longer atomic with yours`,\n );\n }\n}\n"]}
@@ -0,0 +1,80 @@
1
+ import { EventStore, IdentifierGenerator, AppendEntry, AppendResult, ClaimRequest, ClaimedDelivery, LeaseReference, ErrorInfo, DeliveryQuery, DeliveryRecord, PurgeRequest, PurgeResult, EventStoreStatistics } from '@relaybus/core';
2
+ import { ClientSession, MongoClient, TransactionOptions } from 'mongodb';
3
+
4
+ interface MongoEventStoreOptions {
5
+ /** Connected client. The store never closes it. */
6
+ readonly client: MongoClient;
7
+ /** Database holding the relaybus collections. Default: the client's default database. */
8
+ readonly database?: string;
9
+ /** Prefix of the three collection names. Default `relaybus_`. */
10
+ readonly collectionPrefix?: string;
11
+ /**
12
+ * Options of the transactions the store opens. Default: snapshot read
13
+ * concern, majority write concern, primary reads.
14
+ */
15
+ readonly transactionOptions?: TransactionOptions;
16
+ /** Rows deleted per purge step. Default 500. */
17
+ readonly purgeBatchSize?: number;
18
+ /** Produces lease tokens. Default UUID v7. */
19
+ readonly generateIdentifier?: IdentifierGenerator;
20
+ }
21
+ /**
22
+ * Event store on MongoDB 6+ multi-document transactions (replica set or sharded
23
+ * cluster). The transaction handle is the driver's `ClientSession`, so the same
24
+ * session can carry your own writes (native driver or Mongoose).
25
+ *
26
+ * Guarantees:
27
+ * - `append` is atomic with the caller's writes and idempotent on event id and on
28
+ * (event id, handler). Duplicates are detected by reading, never by catching a
29
+ * duplicate-key error, which would abort the surrounding transaction.
30
+ * - Per-key sequences are allocated from a counter document inside the append
31
+ * transaction. Two transactions appending the same key cannot both hold the
32
+ * counter, so the loser conflicts, restarts after the winner committed, and
33
+ * its sequence is higher: sequence order is commit order.
34
+ * - `claim` selects candidates, then takes each with a conditional update that
35
+ * re-checks the exact state it selected, so exactly one claimer wins. A keyed
36
+ * delivery waits while an earlier delivery of its handler and key is
37
+ * unfinished, or while any other delivery of them runs under a live lease;
38
+ * the second rule is re-checked after the update, so a dead letter requeued
39
+ * during a claim cannot run alongside its successor.
40
+ * - Every lease operation is fenced by delivery id, status and lease token.
41
+ *
42
+ * `transaction` may run `work` more than once (see {@link MongoEventStore.transaction}).
43
+ */
44
+ declare class MongoEventStore implements EventStore<ClientSession> {
45
+ #private;
46
+ constructor(options: MongoEventStoreOptions);
47
+ /**
48
+ * Verifies the deployment supports transactions and creates the indexes.
49
+ * Safe to run repeatedly and from several processes.
50
+ *
51
+ * @throws ConfigurationError when the server is a standalone mongod.
52
+ */
53
+ setup(): Promise<void>;
54
+ /**
55
+ * Runs `work` in a transaction on a new session and commits when it resolves.
56
+ *
57
+ * `work` can run more than once. The driver restarts the whole callback after
58
+ * a transient failure such as a write conflict, and re-sends only the commit
59
+ * after an unknown commit result. A restart is safe for everything written
60
+ * through the session, because the aborted attempt left nothing behind. It is
61
+ * not safe for side effects outside the session (HTTP calls, other databases),
62
+ * so keep those out of `work`; relaybus handlers are already at-least-once.
63
+ *
64
+ * @throws ConfigurationError when the deployment does not support transactions.
65
+ */
66
+ transaction<T>(work: (transaction: ClientSession) => Promise<T>): Promise<T>;
67
+ append(session: ClientSession, entries: readonly AppendEntry[], now: Date): Promise<AppendResult>;
68
+ claim(request: ClaimRequest): Promise<ClaimedDelivery[]>;
69
+ extendLease(lease: LeaseReference, leaseExpiresAt: Date, now: Date): Promise<boolean>;
70
+ complete(lease: LeaseReference, now: Date, session?: ClientSession): Promise<boolean>;
71
+ reschedule(lease: LeaseReference, availableAt: Date, error: ErrorInfo, now: Date): Promise<boolean>;
72
+ release(lease: LeaseReference, now: Date): Promise<boolean>;
73
+ bury(lease: LeaseReference, error: ErrorInfo, now: Date): Promise<boolean>;
74
+ listDeliveries(query: DeliveryQuery): Promise<DeliveryRecord[]>;
75
+ requeue(deliveryIds: readonly string[], now: Date): Promise<number>;
76
+ purge(request: PurgeRequest): Promise<PurgeResult>;
77
+ statistics(now: Date): Promise<EventStoreStatistics>;
78
+ }
79
+
80
+ export { MongoEventStore, type MongoEventStoreOptions };
@@ -0,0 +1,80 @@
1
+ import { EventStore, IdentifierGenerator, AppendEntry, AppendResult, ClaimRequest, ClaimedDelivery, LeaseReference, ErrorInfo, DeliveryQuery, DeliveryRecord, PurgeRequest, PurgeResult, EventStoreStatistics } from '@relaybus/core';
2
+ import { ClientSession, MongoClient, TransactionOptions } from 'mongodb';
3
+
4
+ interface MongoEventStoreOptions {
5
+ /** Connected client. The store never closes it. */
6
+ readonly client: MongoClient;
7
+ /** Database holding the relaybus collections. Default: the client's default database. */
8
+ readonly database?: string;
9
+ /** Prefix of the three collection names. Default `relaybus_`. */
10
+ readonly collectionPrefix?: string;
11
+ /**
12
+ * Options of the transactions the store opens. Default: snapshot read
13
+ * concern, majority write concern, primary reads.
14
+ */
15
+ readonly transactionOptions?: TransactionOptions;
16
+ /** Rows deleted per purge step. Default 500. */
17
+ readonly purgeBatchSize?: number;
18
+ /** Produces lease tokens. Default UUID v7. */
19
+ readonly generateIdentifier?: IdentifierGenerator;
20
+ }
21
+ /**
22
+ * Event store on MongoDB 6+ multi-document transactions (replica set or sharded
23
+ * cluster). The transaction handle is the driver's `ClientSession`, so the same
24
+ * session can carry your own writes (native driver or Mongoose).
25
+ *
26
+ * Guarantees:
27
+ * - `append` is atomic with the caller's writes and idempotent on event id and on
28
+ * (event id, handler). Duplicates are detected by reading, never by catching a
29
+ * duplicate-key error, which would abort the surrounding transaction.
30
+ * - Per-key sequences are allocated from a counter document inside the append
31
+ * transaction. Two transactions appending the same key cannot both hold the
32
+ * counter, so the loser conflicts, restarts after the winner committed, and
33
+ * its sequence is higher: sequence order is commit order.
34
+ * - `claim` selects candidates, then takes each with a conditional update that
35
+ * re-checks the exact state it selected, so exactly one claimer wins. A keyed
36
+ * delivery waits while an earlier delivery of its handler and key is
37
+ * unfinished, or while any other delivery of them runs under a live lease;
38
+ * the second rule is re-checked after the update, so a dead letter requeued
39
+ * during a claim cannot run alongside its successor.
40
+ * - Every lease operation is fenced by delivery id, status and lease token.
41
+ *
42
+ * `transaction` may run `work` more than once (see {@link MongoEventStore.transaction}).
43
+ */
44
+ declare class MongoEventStore implements EventStore<ClientSession> {
45
+ #private;
46
+ constructor(options: MongoEventStoreOptions);
47
+ /**
48
+ * Verifies the deployment supports transactions and creates the indexes.
49
+ * Safe to run repeatedly and from several processes.
50
+ *
51
+ * @throws ConfigurationError when the server is a standalone mongod.
52
+ */
53
+ setup(): Promise<void>;
54
+ /**
55
+ * Runs `work` in a transaction on a new session and commits when it resolves.
56
+ *
57
+ * `work` can run more than once. The driver restarts the whole callback after
58
+ * a transient failure such as a write conflict, and re-sends only the commit
59
+ * after an unknown commit result. A restart is safe for everything written
60
+ * through the session, because the aborted attempt left nothing behind. It is
61
+ * not safe for side effects outside the session (HTTP calls, other databases),
62
+ * so keep those out of `work`; relaybus handlers are already at-least-once.
63
+ *
64
+ * @throws ConfigurationError when the deployment does not support transactions.
65
+ */
66
+ transaction<T>(work: (transaction: ClientSession) => Promise<T>): Promise<T>;
67
+ append(session: ClientSession, entries: readonly AppendEntry[], now: Date): Promise<AppendResult>;
68
+ claim(request: ClaimRequest): Promise<ClaimedDelivery[]>;
69
+ extendLease(lease: LeaseReference, leaseExpiresAt: Date, now: Date): Promise<boolean>;
70
+ complete(lease: LeaseReference, now: Date, session?: ClientSession): Promise<boolean>;
71
+ reschedule(lease: LeaseReference, availableAt: Date, error: ErrorInfo, now: Date): Promise<boolean>;
72
+ release(lease: LeaseReference, now: Date): Promise<boolean>;
73
+ bury(lease: LeaseReference, error: ErrorInfo, now: Date): Promise<boolean>;
74
+ listDeliveries(query: DeliveryQuery): Promise<DeliveryRecord[]>;
75
+ requeue(deliveryIds: readonly string[], now: Date): Promise<number>;
76
+ purge(request: PurgeRequest): Promise<PurgeResult>;
77
+ statistics(now: Date): Promise<EventStoreStatistics>;
78
+ }
79
+
80
+ export { MongoEventStore, type MongoEventStoreOptions };