@fbsm/saga-core 0.0.1-beta.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.
- package/README.md +221 -0
- package/dist/index.cjs +726 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +269 -0
- package/dist/index.d.ts +269 -0
- package/dist/index.js +690 -0
- package/dist/index.js.map +1 -0
- package/package.json +57 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/errors/saga.error.ts","../src/errors/saga-retryable.error.ts","../src/logger/saga-logger.ts","../src/context/saga-context.ts","../src/errors/saga-context-not-found.error.ts","../src/runner/saga-runner.ts","../src/publisher/saga-publisher.ts","../src/errors/saga-no-parent.error.ts","../src/publisher/message-builder.ts","../src/parser/saga-parser.ts","../src/errors/saga-duplicate-handler.error.ts","../src/errors/saga-invalid-handler-config.error.ts","../src/registry/saga-registry.ts","../src/errors/saga-parse.error.ts","../src/errors/saga-transport-not-connected.error.ts","../src/otel/otel-context.ts"],"sourcesContent":["// Classes\nexport { SagaRunner } from './runner/saga-runner';\nexport { SagaPublisher } from './publisher/saga-publisher';\nexport type { SagaStartOptions } from './publisher/saga-publisher';\nexport { SagaParser } from './parser/saga-parser';\nexport { SagaRegistry } from './registry/saga-registry';\nexport { SagaContext } from './context/saga-context';\nexport type { SagaContextData } from './context/saga-context';\n\n// Errors\nexport { SagaError } from './errors/saga.error';\nexport { SagaRetryableError } from './errors/saga-retryable.error';\nexport { SagaDuplicateHandlerError } from './errors/saga-duplicate-handler.error';\nexport { SagaParseError } from './errors/saga-parse.error';\nexport { SagaTransportNotConnectedError } from './errors/saga-transport-not-connected.error';\nexport { SagaContextNotFoundError } from './errors/saga-context-not-found.error';\nexport { SagaNoParentError } from './errors/saga-no-parent.error';\nexport { SagaInvalidHandlerConfigError } from './errors/saga-invalid-handler-config.error';\n\n// Logger\nexport type { SagaLogger } from './logger/saga-logger';\nexport { ConsoleSagaLogger } from './logger/saga-logger';\n\n// OTel\nexport type { OtelContext } from './otel/otel-context';\nexport { NoopOtelContext, W3cOtelContext, createOtelContext } from './otel/otel-context';\n\n// Transport interfaces\nexport type {\n SagaTransport,\n OutboundMessage,\n InboundMessage,\n TransportSubscribeOptions,\n} from './transport/transport.interface';\n\n// Domain interfaces\nexport type { SagaEvent } from './interfaces/saga-event.interface';\nexport type { IncomingEvent } from './interfaces/incoming-event.interface';\nexport type { Emit, EmitParams, EventHint } from './interfaces/emit.type';\nexport type { EventHandler } from './interfaces/event-handler.type';\nexport type { SagaParticipant, HandlerConfig, ForkConfig } from './interfaces/saga-participant.interface';\nexport type { ParentSagaContext } from './interfaces/parent-saga-context.interface';\nexport type { RunnerOptions } from './interfaces/runner-options.interface';\n","export class SagaError extends Error {\n public isSagaError = true;\n \n constructor(message: string) {\n super(message);\n this.name = 'SagaError';\n }\n}\n","import { SagaError } from './saga.error';\n\nexport class SagaRetryableError extends SagaError {\n constructor(\n message: string,\n readonly maxRetries = 3,\n ) {\n super(message);\n this.name = 'SagaRetryableError';\n }\n}\n","export interface SagaLogger {\n info(message: string, ...args: unknown[]): void;\n warn(message: string, ...args: unknown[]): void;\n error(message: string, ...args: unknown[]): void;\n}\n\nexport class ConsoleSagaLogger implements SagaLogger {\n info(message: string, ...args: unknown[]): void {\n console.log(message, ...args);\n }\n\n warn(message: string, ...args: unknown[]): void {\n console.warn(message, ...args);\n }\n\n error(message: string, ...args: unknown[]): void {\n console.error(message, ...args);\n }\n}\n","import { AsyncLocalStorage } from 'node:async_hooks';\nimport { SagaContextNotFoundError } from '../errors/saga-context-not-found.error';\n\nexport interface SagaContextData {\n sagaId: string;\n rootSagaId: string;\n parentSagaId?: string;\n causationId: string;\n key?: string;\n sagaName?: string;\n sagaDescription?: string;\n}\n\nexport class SagaContext {\n private static storage = new AsyncLocalStorage<SagaContextData>();\n\n static run<T>(data: SagaContextData, fn: () => T): T {\n return SagaContext.storage.run(data, fn);\n }\n\n static current(): SagaContextData | undefined {\n return SagaContext.storage.getStore();\n }\n\n static require(): SagaContextData {\n const ctx = SagaContext.current();\n if (!ctx) {\n throw new SagaContextNotFoundError();\n }\n return ctx;\n }\n}\n","import { SagaError } from './saga.error';\n\nexport class SagaContextNotFoundError extends SagaError {\n constructor() {\n super(\n 'No saga context found. Ensure you are inside a saga handler or after sagaPublisher.start().',\n );\n this.name = 'SagaContextNotFoundError';\n }\n}\n","import type { SagaTransport, InboundMessage } from '../transport/transport.interface';\nimport type { IncomingEvent } from '../interfaces/incoming-event.interface';\nimport type { Emit } from '../interfaces/emit.type';\nimport type { EventHandler } from '../interfaces/event-handler.type';\nimport type { SagaParticipant } from '../interfaces/saga-participant.interface';\nimport type { RunnerOptions } from '../interfaces/runner-options.interface';\nimport { SagaRetryableError } from '../errors/saga-retryable.error';\nimport { SagaRegistry, type RouteEntry } from '../registry/saga-registry';\nimport { SagaPublisher } from '../publisher/saga-publisher';\nimport { SagaParser } from '../parser/saga-parser';\nimport type { OtelContext } from '../otel/otel-context';\nimport type { SagaLogger } from '../logger/saga-logger';\nimport { ConsoleSagaLogger } from '../logger/saga-logger';\nimport { SagaContext } from '../context/saga-context';\nimport { v7 as uuidv7 } from 'uuid';\n\nexport class SagaRunner {\n private routeMap!: Map<string, RouteEntry>;\n\n constructor(\n private registry: SagaRegistry,\n private transport: SagaTransport,\n private publisher: SagaPublisher,\n private parser: SagaParser,\n private options: RunnerOptions,\n private otelCtx?: OtelContext,\n private logger: SagaLogger = new ConsoleSagaLogger(),\n ) {}\n\n async start(): Promise<void> {\n this.routeMap = this.registry.buildRouteMap();\n\n const prefix = this.options.topicPrefix ?? '';\n const topics = Array.from(this.routeMap.keys()).map((et) => `${prefix}${et}`);\n\n await this.transport.connect();\n\n if (topics.length > 0) {\n this.logger.info(`[SagaRunner] Subscribing to ${topics.length} topic(s): [${topics.join(', ')}]`);\n await this.transport.subscribe(\n topics,\n (message) => this.handleMessage(message),\n {\n fromBeginning: this.options.fromBeginning,\n groupId: `${this.options.serviceName}-group`,\n },\n );\n this.logger.info('[SagaRunner] Consumer running');\n } else {\n this.logger.warn('[SagaRunner] No handlers registered — nothing to subscribe');\n }\n }\n\n async stop(): Promise<void> {\n await this.transport.disconnect();\n }\n\n private async handleMessage(message: InboundMessage): Promise<void> {\n const event = this.parser.parse<Record<string, unknown>>(message);\n if (!event) return;\n\n const route = this.routeMap.get(event.eventType);\n if (!route) return;\n\n const isFinalHandler = route.options?.final === true;\n\n const incoming: IncomingEvent = {\n sagaId: event.sagaId,\n eventId: event.eventId,\n causationId: event.causationId,\n eventType: event.eventType,\n stepName: event.stepName,\n stepDescription: event.stepDescription,\n occurredAt: event.occurredAt,\n parentSagaId: event.parentSagaId,\n rootSagaId: event.rootSagaId,\n payload: event.payload,\n key: event.key,\n sagaName: event.sagaName,\n sagaDescription: event.sagaDescription,\n };\n\n const emit = this.publisher.forSaga(event.sagaId, {\n parentSagaId: event.parentSagaId,\n rootSagaId: event.rootSagaId,\n }, event.eventId, event.key);\n\n // Wrap emit: if handler is final, auto-add hint\n const wrappedEmit: Emit = async (params) => {\n const finalParams = isFinalHandler\n ? { ...params, hint: 'final' as const }\n : params;\n return emit(finalParams);\n };\n\n // Fork layer: if handler has fork config, wrap emit to auto-create sub-sagas\n const forkConfig = route.options?.fork;\n const finalEmit: Emit = forkConfig\n ? async (params) => {\n const subSagaId = uuidv7();\n\n const subEmit = this.publisher.forSaga(subSagaId, {\n parentSagaId: event.sagaId,\n rootSagaId: event.rootSagaId,\n }, event.eventId, event.key);\n\n const forkMeta = typeof forkConfig === 'object' ? forkConfig : {};\n const forkCtx = {\n sagaId: subSagaId,\n rootSagaId: event.rootSagaId,\n parentSagaId: event.sagaId,\n causationId: event.eventId,\n key: event.key,\n sagaName: forkMeta.sagaName,\n sagaDescription: forkMeta.sagaDescription,\n };\n await SagaContext.run(forkCtx, () => subEmit({ ...params, hint: 'fork' }));\n }\n : wrappedEmit;\n\n const spanAttrs: Record<string, string> = {\n 'saga.id': event.sagaId,\n 'saga.event.type': event.eventType,\n 'saga.step.name': event.stepName,\n 'saga.event.id': event.eventId,\n 'saga.root.id': event.rootSagaId,\n 'saga.handler.service': route.participant.serviceId,\n };\n if (event.sagaName) spanAttrs['saga.name'] = event.sagaName;\n if (event.sagaDescription) spanAttrs['saga.description'] = event.sagaDescription;\n if (event.stepDescription) spanAttrs['saga.step.description'] = event.stepDescription;\n if (event.parentSagaId) spanAttrs['saga.parent.id'] = event.parentSagaId;\n\n const sagaCtxData = {\n sagaId: event.sagaId,\n rootSagaId: event.rootSagaId,\n parentSagaId: event.parentSagaId,\n causationId: event.eventId,\n key: event.key,\n sagaName: event.sagaName,\n sagaDescription: event.sagaDescription,\n };\n\n const runHandler = () =>\n SagaContext.run(sagaCtxData, () =>\n this.runWithRetry(route.handler, route.participant, incoming, finalEmit),\n );\n\n if (this.otelCtx) {\n await this.otelCtx.withExtractedSpan(`saga.handle ${event.eventType}`, spanAttrs, message.headers, runHandler);\n } else {\n await runHandler();\n }\n }\n\n private async runWithRetry(\n handler: EventHandler,\n participant: SagaParticipant,\n event: IncomingEvent,\n emit: Emit,\n ): Promise<void> {\n const maxRetries = this.options.retryPolicy?.maxRetries ?? 3;\n const initialDelayMs = this.options.retryPolicy?.initialDelayMs ?? 200;\n\n for (let attempt = 0; attempt <= maxRetries; attempt++) {\n try {\n await handler(event, emit);\n return;\n } catch (error) {\n if (error instanceof SagaRetryableError) {\n if (attempt < maxRetries) {\n const delay = initialDelayMs * Math.pow(2, attempt);\n await this.sleep(delay);\n continue;\n }\n if (participant.onRetryExhausted) {\n await participant.onRetryExhausted(event, error, emit);\n }\n return;\n }\n this.logger.error(\n `[SagaRunner] Non-retryable error in handler for ${event.eventType}:`,\n error,\n );\n return;\n }\n }\n }\n\n private sleep(ms: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, ms));\n }\n}\n","import { v7 as uuidv7 } from 'uuid';\nimport type { SagaEvent } from '../interfaces/saga-event.interface';\nimport type { Emit, EmitParams } from '../interfaces/emit.type';\nimport type { ParentSagaContext } from '../interfaces/parent-saga-context.interface';\nimport type { SagaTransport } from '../transport/transport.interface';\nimport type { OtelContext } from '../otel/otel-context';\nimport { SagaContext } from '../context/saga-context';\nimport { SagaNoParentError } from '../errors/saga-no-parent.error';\nimport { buildOutboundMessage } from './message-builder';\n\nexport interface SagaStartOptions {\n sagaName?: string;\n sagaDescription?: string;\n key?: string;\n}\n\nexport class SagaPublisher {\n constructor(\n private transport: SagaTransport,\n private otelCtx: OtelContext,\n private topicPrefix = '',\n ) {}\n\n async start<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{ sagaId: string; result: Awaited<R> }> {\n const sagaId = uuidv7();\n const ctxData = {\n sagaId, rootSagaId: sagaId, causationId: sagaId,\n key: opts?.key,\n sagaName: opts?.sagaName, sagaDescription: opts?.sagaDescription,\n };\n const result = await SagaContext.run(ctxData, fn);\n return { sagaId, result: result as Awaited<R> };\n }\n\n async emit<T extends object>(params: EmitParams<T>): Promise<void> {\n const ctx = SagaContext.require();\n const boundEmit = this.forSaga(ctx.sagaId, {\n parentSagaId: ctx.parentSagaId,\n rootSagaId: ctx.rootSagaId,\n }, ctx.causationId, ctx.key);\n return boundEmit(params);\n }\n\n async startChild<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{ sagaId: string; result: Awaited<R> }> {\n const ctx = SagaContext.require();\n const sagaId = uuidv7();\n const childCtx = {\n sagaId,\n rootSagaId: ctx.rootSagaId,\n parentSagaId: ctx.sagaId,\n causationId: ctx.causationId,\n key: opts?.key ?? ctx.key,\n sagaName: opts?.sagaName ?? ctx.sagaName,\n sagaDescription: opts?.sagaDescription ?? ctx.sagaDescription,\n };\n const result = await SagaContext.run(childCtx, fn);\n return { sagaId, result: result as Awaited<R> };\n }\n\n async emitToParent<T extends object>(paramsOrFn: EmitParams<T> | (() => void | Promise<void>)): Promise<void> {\n const ctx = SagaContext.require();\n if (!ctx.parentSagaId) {\n throw new SagaNoParentError();\n }\n\n if (typeof paramsOrFn === 'function') {\n const parentCtx = {\n sagaId: ctx.parentSagaId,\n rootSagaId: ctx.rootSagaId,\n parentSagaId: ctx.parentSagaId,\n causationId: ctx.causationId,\n key: ctx.key,\n };\n await SagaContext.run(parentCtx, paramsOrFn);\n return;\n }\n\n const parentEmit = this.forSaga(ctx.parentSagaId, {\n parentSagaId: ctx.parentSagaId,\n rootSagaId: ctx.rootSagaId,\n }, ctx.causationId, ctx.key);\n return parentEmit(paramsOrFn);\n }\n\n forSaga(sagaId: string, parentCtx?: ParentSagaContext, causationId?: string, baseKey?: string): Emit {\n const rootSagaId = parentCtx?.rootSagaId ?? sagaId;\n const parentSagaId = parentCtx?.parentSagaId;\n const baseCausationId = causationId ?? sagaId;\n return async <T extends object>({\n eventType,\n stepName,\n stepDescription,\n payload,\n hint,\n key,\n }: EmitParams<T>): Promise<void> => {\n const ctx = SagaContext.current();\n const resolvedKey = key ?? baseKey ?? ctx?.key;\n const now = new Date().toISOString();\n const event: SagaEvent<T> = {\n sagaId,\n causationId: baseCausationId,\n eventId: uuidv7(),\n eventType,\n stepName,\n stepDescription,\n occurredAt: now,\n publishedAt: now,\n schemaVersion: 1,\n rootSagaId,\n parentSagaId,\n payload,\n hint,\n key: resolvedKey,\n sagaName: ctx?.sagaName,\n sagaDescription: ctx?.sagaDescription,\n };\n\n await this.publish(event);\n };\n }\n\n async publish<T>(event: SagaEvent<T>): Promise<void> {\n this.otelCtx.injectBaggage(event.sagaId, event.rootSagaId, event.parentSagaId);\n\n const attrs: Record<string, string> = {\n 'saga.id': event.sagaId,\n 'saga.event.type': event.eventType,\n 'saga.step.name': event.stepName,\n 'saga.root.id': event.rootSagaId,\n };\n if (event.sagaName) {\n attrs['saga.name'] = event.sagaName;\n }\n if (event.sagaDescription) {\n attrs['saga.description'] = event.sagaDescription;\n }\n if (event.stepDescription) {\n attrs['saga.step.description'] = event.stepDescription;\n }\n if (event.parentSagaId) {\n attrs['saga.parent.id'] = event.parentSagaId;\n }\n\n this.otelCtx.enrichSpan(attrs);\n\n const message = buildOutboundMessage(event, this.topicPrefix);\n\n this.otelCtx.injectTraceContext(message.headers);\n\n await this.otelCtx.withSpan(`saga.publish ${event.eventType}`, attrs, () =>\n this.transport.publish(message),\n );\n }\n}\n","import { SagaError } from './saga.error';\n\nexport class SagaNoParentError extends SagaError {\n constructor() {\n super('No parentSagaId in current saga context.');\n this.name = 'SagaNoParentError';\n }\n}\n","import type { SagaEvent } from '../interfaces/saga-event.interface';\nimport type { OutboundMessage } from '../transport/transport.interface';\n\nexport function buildOutboundMessage<T>(event: SagaEvent<T>, topicPrefix = ''): OutboundMessage {\n const topic = `${topicPrefix}${event.eventType}`;\n const key = event.key ?? event.rootSagaId;\n\n const headers: Record<string, string> = {\n 'saga-id': event.sagaId,\n 'saga-causation-id': event.causationId,\n 'saga-event-id': event.eventId,\n 'saga-step-name': event.stepName,\n 'saga-published-at': event.publishedAt,\n 'saga-schema-version': String(event.schemaVersion),\n 'saga-root-id': event.rootSagaId,\n };\n\n if (event.parentSagaId) {\n headers['saga-parent-id'] = event.parentSagaId;\n }\n\n if (event.hint) {\n headers['saga-event-hint'] = event.hint;\n }\n\n if (event.sagaName) {\n headers['saga-name'] = event.sagaName;\n }\n\n if (event.sagaDescription) {\n headers['saga-description'] = event.sagaDescription;\n }\n\n if (event.stepDescription) {\n headers['saga-step-description'] = event.stepDescription;\n }\n\n if (event.key) {\n headers['saga-key'] = event.key;\n }\n\n const value = JSON.stringify({\n eventType: event.eventType,\n occurredAt: event.occurredAt,\n payload: event.payload,\n });\n\n return { topic, key, value, headers };\n}\n","import { v7 as uuidv7 } from 'uuid';\nimport type { SagaEvent } from '../interfaces/saga-event.interface';\nimport type { InboundMessage } from '../transport/transport.interface';\nimport type { OtelContext } from '../otel/otel-context';\n\nexport class SagaParser {\n constructor(private otelCtx: OtelContext) {}\n\n parse<T>(message: InboundMessage): SagaEvent<T> | null {\n try {\n if (message.headers['saga-id']) {\n return this.parseFromHeaders<T>(message);\n }\n\n const baggageResult = this.parseFromBaggage<T>(message);\n if (baggageResult) return baggageResult;\n\n const body = JSON.parse(message.value);\n if (body && body.sagaId) {\n return body as SagaEvent<T>;\n }\n\n return null;\n } catch {\n return null;\n }\n }\n\n private parseFromHeaders<T>(message: InboundMessage): SagaEvent<T> | null {\n const headers = message.headers;\n const body = JSON.parse(message.value);\n\n const sagaId = headers['saga-id'];\n if (!sagaId) {\n return null;\n }\n\n return {\n sagaId,\n causationId: headers['saga-causation-id'] ?? sagaId,\n eventId: headers['saga-event-id'] ?? uuidv7(),\n eventType: body.eventType,\n stepName: headers['saga-step-name'] ?? '',\n occurredAt: body.occurredAt ?? new Date().toISOString(),\n publishedAt: headers['saga-published-at'] ?? new Date().toISOString(),\n schemaVersion: 1,\n rootSagaId: headers['saga-root-id'] ?? sagaId,\n parentSagaId: headers['saga-parent-id'] || undefined,\n payload: body.payload as T,\n sagaName: headers['saga-name'] || undefined,\n sagaDescription: headers['saga-description'] || undefined,\n stepDescription: headers['saga-step-description'] || undefined,\n key: headers['saga-key'] || undefined,\n };\n }\n\n private parseFromBaggage<T>(message: InboundMessage): SagaEvent<T> | null {\n let sagaId: string | undefined;\n let rootSagaId: string | undefined;\n let parentSagaId: string | undefined;\n\n const baggageHeader = message.headers['baggage'];\n if (baggageHeader) {\n const entries = this.parseBaggageHeader(baggageHeader);\n sagaId = entries['saga.id'];\n rootSagaId = entries['saga.root.id'];\n parentSagaId = entries['saga.parent.id'];\n }\n\n // Fallback to OTel context extraction\n if (!sagaId) {\n const extracted = this.otelCtx.extractBaggage();\n sagaId = extracted.sagaId;\n rootSagaId = extracted.rootSagaId;\n parentSagaId = extracted.parentSagaId;\n }\n\n if (!sagaId) return null;\n\n const body = JSON.parse(message.value);\n\n return {\n sagaId,\n causationId: sagaId,\n eventId: uuidv7(),\n eventType: body.eventType,\n stepName: '',\n occurredAt: body.occurredAt ?? new Date().toISOString(),\n publishedAt: new Date().toISOString(),\n schemaVersion: 1,\n rootSagaId: rootSagaId ?? sagaId,\n parentSagaId: parentSagaId || undefined,\n payload: body.payload as T,\n };\n }\n\n private parseBaggageHeader(baggage: string): Record<string, string> {\n const result: Record<string, string> = {};\n for (const entry of baggage.split(',')) {\n const [key, value] = entry.trim().split('=');\n if (key && value) {\n result[key.trim()] = decodeURIComponent(value.trim());\n }\n }\n return result;\n }\n}\n","import { SagaError } from './saga.error';\n\nexport class SagaDuplicateHandlerError extends SagaError {\n constructor(eventType: string, existingServiceId: string, newServiceId: string) {\n super(\n `Duplicate handler for event type \"${eventType}\": ` +\n `registered by \"${existingServiceId}\" and \"${newServiceId}\"`,\n );\n this.name = 'SagaDuplicateHandlerError';\n }\n}\n","import { SagaError } from './saga.error';\n\nexport class SagaInvalidHandlerConfigError extends SagaError {\n constructor(eventType: string, serviceId: string, reason: string) {\n super(\n `Invalid handler config for \"${eventType}\" in \"${serviceId}\": ${reason}`,\n );\n this.name = 'SagaInvalidHandlerConfigError';\n }\n}\n","import type { SagaParticipant, HandlerConfig } from '../interfaces/saga-participant.interface';\nimport type { EventHandler } from '../interfaces/event-handler.type';\nimport { SagaDuplicateHandlerError } from '../errors/saga-duplicate-handler.error';\nimport { SagaInvalidHandlerConfigError } from '../errors/saga-invalid-handler-config.error';\n\nexport interface RouteEntry {\n participant: SagaParticipant;\n handler: EventHandler;\n options?: HandlerConfig;\n}\n\nexport class SagaRegistry {\n private participants: SagaParticipant[] = [];\n\n register(participant: SagaParticipant): void {\n this.participants.push(participant);\n }\n\n getAll(): SagaParticipant[] {\n return [...this.participants];\n }\n\n buildRouteMap(): Map<string, RouteEntry> {\n const map = new Map<string, RouteEntry>();\n\n for (const participant of this.participants) {\n for (const [eventType, handler] of Object.entries(participant.on)) {\n if (map.has(eventType)) {\n const existing = map.get(eventType)!;\n throw new SagaDuplicateHandlerError(\n eventType,\n existing.participant.serviceId,\n participant.serviceId,\n );\n }\n const options = participant.handlerOptions?.[eventType];\n if (options?.final && options?.fork) {\n throw new SagaInvalidHandlerConfigError(\n eventType,\n participant.serviceId,\n 'cannot have both final and fork options',\n );\n }\n map.set(eventType, { participant, handler, options });\n }\n }\n\n return map;\n }\n}\n","import { SagaError } from './saga.error';\n\nexport class SagaParseError extends SagaError {\n constructor(message: string) {\n super(message);\n this.name = 'SagaParseError';\n }\n}\n","import { SagaError } from './saga.error';\n\nexport class SagaTransportNotConnectedError extends SagaError {\n constructor() {\n super('Transport not connected');\n this.name = 'SagaTransportNotConnectedError';\n }\n}\n","export interface OtelContext {\n injectBaggage(sagaId: string, rootSagaId: string, parentSagaId?: string): void;\n extractBaggage(): { sagaId?: string; rootSagaId?: string; parentSagaId?: string };\n enrichSpan(attrs: Record<string, string>): void;\n withSpan<T>(name: string, attrs: Record<string, string>, fn: () => Promise<T>): Promise<T>;\n injectTraceContext(headers: Record<string, string>): void;\n withExtractedSpan<T>(name: string, attrs: Record<string, string>, headers: Record<string, string>, fn: () => Promise<T>): Promise<T>;\n}\n\nexport class NoopOtelContext implements OtelContext {\n injectBaggage(): void {}\n extractBaggage(): { sagaId?: string; rootSagaId?: string; parentSagaId?: string } {\n return {};\n }\n enrichSpan(): void {}\n async withSpan<T>(_name: string, _attrs: Record<string, string>, fn: () => Promise<T>): Promise<T> {\n return fn();\n }\n injectTraceContext(): void {}\n async withExtractedSpan<T>(_name: string, _attrs: Record<string, string>, _headers: Record<string, string>, fn: () => Promise<T>): Promise<T> {\n return fn();\n }\n}\n\ntype OtelAPI = typeof import('@opentelemetry/api');\n\nexport class W3cOtelContext implements OtelContext {\n private api: OtelAPI;\n\n constructor(api: OtelAPI) {\n this.api = api;\n }\n\n injectBaggage(sagaId: string, rootSagaId: string, parentSagaId?: string): void {\n const entries: Record<string, { value: string }> = {\n 'saga.id': { value: sagaId },\n 'saga.root.id': { value: rootSagaId },\n };\n if (parentSagaId) {\n entries['saga.parent.id'] = { value: parentSagaId };\n }\n\n const baggage = this.api.propagation.createBaggage(entries);\n const ctx = this.api.propagation.setBaggage(this.api.context.active(), baggage);\n this.api.context.with(ctx, () => {});\n }\n\n extractBaggage(): { sagaId?: string; rootSagaId?: string; parentSagaId?: string } {\n const baggage = this.api.propagation.getBaggage(this.api.context.active());\n if (!baggage) return {};\n\n return {\n sagaId: baggage.getEntry('saga.id')?.value,\n rootSagaId: baggage.getEntry('saga.root.id')?.value,\n parentSagaId: baggage.getEntry('saga.parent.id')?.value,\n };\n }\n\n enrichSpan(attrs: Record<string, string>): void {\n const span = this.api.trace.getActiveSpan();\n if (span) {\n span.setAttributes(attrs);\n }\n }\n\n async withSpan<T>(name: string, attrs: Record<string, string>, fn: () => Promise<T>): Promise<T> {\n const tracer = this.api.trace.getTracer('@fbsm/saga-core');\n return tracer.startActiveSpan(name, async (span) => {\n span.setAttributes(attrs);\n try {\n const result = await fn();\n span.setStatus({ code: this.api.SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.setStatus({\n code: this.api.SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n span.recordException(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n span.end();\n }\n });\n }\n\n injectTraceContext(headers: Record<string, string>): void {\n this.api.propagation.inject(this.api.context.active(), headers);\n }\n\n async withExtractedSpan<T>(\n name: string,\n attrs: Record<string, string>,\n headers: Record<string, string>,\n fn: () => Promise<T>,\n ): Promise<T> {\n const parentCtx = this.api.propagation.extract(this.api.ROOT_CONTEXT, headers);\n const tracer = this.api.trace.getTracer('@fbsm/saga-core');\n\n return this.api.context.with(parentCtx, () =>\n tracer.startActiveSpan(name, { kind: this.api.SpanKind.CONSUMER }, async (span) => {\n span.setAttributes(attrs);\n try {\n const result = await fn();\n span.setStatus({ code: this.api.SpanStatusCode.OK });\n return result;\n } catch (error) {\n span.setStatus({\n code: this.api.SpanStatusCode.ERROR,\n message: error instanceof Error ? error.message : String(error),\n });\n span.recordException(error instanceof Error ? error : new Error(String(error)));\n throw error;\n } finally {\n span.end();\n }\n }),\n );\n }\n}\n\nexport function createOtelContext(enabled: boolean): OtelContext {\n if (!enabled) return new NoopOtelContext();\n\n try {\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n const api = require('@opentelemetry/api');\n return new W3cOtelContext(api);\n } catch {\n return new NoopOtelContext();\n }\n}\n"],"mappings":"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","names":["uuidv7","import_uuid","uuidv7","import_uuid","uuidv7"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import * as _opentelemetry_api from '@opentelemetry/api';
|
|
2
|
+
|
|
3
|
+
interface SagaTransport {
|
|
4
|
+
connect(): Promise<void>;
|
|
5
|
+
disconnect(): Promise<void>;
|
|
6
|
+
publish(message: OutboundMessage): Promise<void>;
|
|
7
|
+
subscribe(topics: string[], handler: (message: InboundMessage) => Promise<void>, options?: TransportSubscribeOptions): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
interface OutboundMessage {
|
|
10
|
+
topic: string;
|
|
11
|
+
key: string;
|
|
12
|
+
value: string;
|
|
13
|
+
headers: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
interface InboundMessage {
|
|
16
|
+
topic: string;
|
|
17
|
+
key: string;
|
|
18
|
+
value: string;
|
|
19
|
+
headers: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
interface TransportSubscribeOptions {
|
|
22
|
+
fromBeginning?: boolean;
|
|
23
|
+
groupId?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface RunnerOptions {
|
|
27
|
+
serviceName: string;
|
|
28
|
+
fromBeginning?: boolean;
|
|
29
|
+
/** Prefix prepended to eventType to form Kafka topic names. Default: '' (no prefix). */
|
|
30
|
+
topicPrefix?: string;
|
|
31
|
+
retryPolicy?: {
|
|
32
|
+
maxRetries?: number;
|
|
33
|
+
initialDelayMs?: number;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface IncomingEvent<T = Record<string, unknown>> {
|
|
38
|
+
eventId: string;
|
|
39
|
+
sagaId: string;
|
|
40
|
+
parentSagaId?: string;
|
|
41
|
+
rootSagaId: string;
|
|
42
|
+
causationId: string;
|
|
43
|
+
eventType: string;
|
|
44
|
+
sagaName?: string;
|
|
45
|
+
sagaDescription?: string;
|
|
46
|
+
stepName: string;
|
|
47
|
+
stepDescription?: string;
|
|
48
|
+
occurredAt: string;
|
|
49
|
+
payload: T;
|
|
50
|
+
key?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type EventHint = 'compensation' | 'final' | 'fork';
|
|
54
|
+
interface EmitParams<T extends object = Record<string, unknown>> {
|
|
55
|
+
eventType: string;
|
|
56
|
+
stepName: string;
|
|
57
|
+
stepDescription?: string;
|
|
58
|
+
payload: T;
|
|
59
|
+
hint?: EventHint;
|
|
60
|
+
key?: string;
|
|
61
|
+
}
|
|
62
|
+
type Emit = <T extends object>(params: EmitParams<T>) => Promise<void>;
|
|
63
|
+
|
|
64
|
+
type EventHandler<T = Record<string, unknown>> = (event: IncomingEvent<T>, emit: Emit) => Promise<void>;
|
|
65
|
+
|
|
66
|
+
declare class SagaError extends Error {
|
|
67
|
+
isSagaError: boolean;
|
|
68
|
+
constructor(message: string);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
declare class SagaRetryableError extends SagaError {
|
|
72
|
+
readonly maxRetries: number;
|
|
73
|
+
constructor(message: string, maxRetries?: number);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface ForkConfig {
|
|
77
|
+
sagaName?: string;
|
|
78
|
+
sagaDescription?: string;
|
|
79
|
+
}
|
|
80
|
+
interface HandlerConfig {
|
|
81
|
+
final?: boolean;
|
|
82
|
+
fork?: boolean | ForkConfig;
|
|
83
|
+
}
|
|
84
|
+
interface SagaParticipant {
|
|
85
|
+
readonly serviceId: string;
|
|
86
|
+
readonly on: Record<string, EventHandler<any>>;
|
|
87
|
+
readonly handlerOptions?: Record<string, HandlerConfig>;
|
|
88
|
+
onRetryExhausted?(event: IncomingEvent, error: SagaRetryableError, emit: Emit): Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface RouteEntry {
|
|
92
|
+
participant: SagaParticipant;
|
|
93
|
+
handler: EventHandler;
|
|
94
|
+
options?: HandlerConfig;
|
|
95
|
+
}
|
|
96
|
+
declare class SagaRegistry {
|
|
97
|
+
private participants;
|
|
98
|
+
register(participant: SagaParticipant): void;
|
|
99
|
+
getAll(): SagaParticipant[];
|
|
100
|
+
buildRouteMap(): Map<string, RouteEntry>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface SagaEvent<TPayload = Record<string, unknown>> {
|
|
104
|
+
eventId: string;
|
|
105
|
+
eventType: string;
|
|
106
|
+
sagaId: string;
|
|
107
|
+
causationId: string;
|
|
108
|
+
stepName: string;
|
|
109
|
+
stepDescription?: string;
|
|
110
|
+
sagaName?: string;
|
|
111
|
+
sagaDescription?: string;
|
|
112
|
+
occurredAt: string;
|
|
113
|
+
publishedAt: string;
|
|
114
|
+
schemaVersion: 1;
|
|
115
|
+
parentSagaId?: string;
|
|
116
|
+
rootSagaId: string;
|
|
117
|
+
payload: TPayload;
|
|
118
|
+
hint?: EventHint;
|
|
119
|
+
key?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
interface ParentSagaContext {
|
|
123
|
+
parentSagaId?: string;
|
|
124
|
+
rootSagaId: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
interface OtelContext {
|
|
128
|
+
injectBaggage(sagaId: string, rootSagaId: string, parentSagaId?: string): void;
|
|
129
|
+
extractBaggage(): {
|
|
130
|
+
sagaId?: string;
|
|
131
|
+
rootSagaId?: string;
|
|
132
|
+
parentSagaId?: string;
|
|
133
|
+
};
|
|
134
|
+
enrichSpan(attrs: Record<string, string>): void;
|
|
135
|
+
withSpan<T>(name: string, attrs: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
136
|
+
injectTraceContext(headers: Record<string, string>): void;
|
|
137
|
+
withExtractedSpan<T>(name: string, attrs: Record<string, string>, headers: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
138
|
+
}
|
|
139
|
+
declare class NoopOtelContext implements OtelContext {
|
|
140
|
+
injectBaggage(): void;
|
|
141
|
+
extractBaggage(): {
|
|
142
|
+
sagaId?: string;
|
|
143
|
+
rootSagaId?: string;
|
|
144
|
+
parentSagaId?: string;
|
|
145
|
+
};
|
|
146
|
+
enrichSpan(): void;
|
|
147
|
+
withSpan<T>(_name: string, _attrs: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
148
|
+
injectTraceContext(): void;
|
|
149
|
+
withExtractedSpan<T>(_name: string, _attrs: Record<string, string>, _headers: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
150
|
+
}
|
|
151
|
+
type OtelAPI = typeof _opentelemetry_api;
|
|
152
|
+
declare class W3cOtelContext implements OtelContext {
|
|
153
|
+
private api;
|
|
154
|
+
constructor(api: OtelAPI);
|
|
155
|
+
injectBaggage(sagaId: string, rootSagaId: string, parentSagaId?: string): void;
|
|
156
|
+
extractBaggage(): {
|
|
157
|
+
sagaId?: string;
|
|
158
|
+
rootSagaId?: string;
|
|
159
|
+
parentSagaId?: string;
|
|
160
|
+
};
|
|
161
|
+
enrichSpan(attrs: Record<string, string>): void;
|
|
162
|
+
withSpan<T>(name: string, attrs: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
163
|
+
injectTraceContext(headers: Record<string, string>): void;
|
|
164
|
+
withExtractedSpan<T>(name: string, attrs: Record<string, string>, headers: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
165
|
+
}
|
|
166
|
+
declare function createOtelContext(enabled: boolean): OtelContext;
|
|
167
|
+
|
|
168
|
+
interface SagaStartOptions {
|
|
169
|
+
sagaName?: string;
|
|
170
|
+
sagaDescription?: string;
|
|
171
|
+
key?: string;
|
|
172
|
+
}
|
|
173
|
+
declare class SagaPublisher {
|
|
174
|
+
private transport;
|
|
175
|
+
private otelCtx;
|
|
176
|
+
private topicPrefix;
|
|
177
|
+
constructor(transport: SagaTransport, otelCtx: OtelContext, topicPrefix?: string);
|
|
178
|
+
start<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{
|
|
179
|
+
sagaId: string;
|
|
180
|
+
result: Awaited<R>;
|
|
181
|
+
}>;
|
|
182
|
+
emit<T extends object>(params: EmitParams<T>): Promise<void>;
|
|
183
|
+
startChild<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{
|
|
184
|
+
sagaId: string;
|
|
185
|
+
result: Awaited<R>;
|
|
186
|
+
}>;
|
|
187
|
+
emitToParent<T extends object>(paramsOrFn: EmitParams<T> | (() => void | Promise<void>)): Promise<void>;
|
|
188
|
+
forSaga(sagaId: string, parentCtx?: ParentSagaContext, causationId?: string, baseKey?: string): Emit;
|
|
189
|
+
publish<T>(event: SagaEvent<T>): Promise<void>;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
declare class SagaParser {
|
|
193
|
+
private otelCtx;
|
|
194
|
+
constructor(otelCtx: OtelContext);
|
|
195
|
+
parse<T>(message: InboundMessage): SagaEvent<T> | null;
|
|
196
|
+
private parseFromHeaders;
|
|
197
|
+
private parseFromBaggage;
|
|
198
|
+
private parseBaggageHeader;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
interface SagaLogger {
|
|
202
|
+
info(message: string, ...args: unknown[]): void;
|
|
203
|
+
warn(message: string, ...args: unknown[]): void;
|
|
204
|
+
error(message: string, ...args: unknown[]): void;
|
|
205
|
+
}
|
|
206
|
+
declare class ConsoleSagaLogger implements SagaLogger {
|
|
207
|
+
info(message: string, ...args: unknown[]): void;
|
|
208
|
+
warn(message: string, ...args: unknown[]): void;
|
|
209
|
+
error(message: string, ...args: unknown[]): void;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
declare class SagaRunner {
|
|
213
|
+
private registry;
|
|
214
|
+
private transport;
|
|
215
|
+
private publisher;
|
|
216
|
+
private parser;
|
|
217
|
+
private options;
|
|
218
|
+
private otelCtx?;
|
|
219
|
+
private logger;
|
|
220
|
+
private routeMap;
|
|
221
|
+
constructor(registry: SagaRegistry, transport: SagaTransport, publisher: SagaPublisher, parser: SagaParser, options: RunnerOptions, otelCtx?: OtelContext | undefined, logger?: SagaLogger);
|
|
222
|
+
start(): Promise<void>;
|
|
223
|
+
stop(): Promise<void>;
|
|
224
|
+
private handleMessage;
|
|
225
|
+
private runWithRetry;
|
|
226
|
+
private sleep;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
interface SagaContextData {
|
|
230
|
+
sagaId: string;
|
|
231
|
+
rootSagaId: string;
|
|
232
|
+
parentSagaId?: string;
|
|
233
|
+
causationId: string;
|
|
234
|
+
key?: string;
|
|
235
|
+
sagaName?: string;
|
|
236
|
+
sagaDescription?: string;
|
|
237
|
+
}
|
|
238
|
+
declare class SagaContext {
|
|
239
|
+
private static storage;
|
|
240
|
+
static run<T>(data: SagaContextData, fn: () => T): T;
|
|
241
|
+
static current(): SagaContextData | undefined;
|
|
242
|
+
static require(): SagaContextData;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
declare class SagaDuplicateHandlerError extends SagaError {
|
|
246
|
+
constructor(eventType: string, existingServiceId: string, newServiceId: string);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
declare class SagaParseError extends SagaError {
|
|
250
|
+
constructor(message: string);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
declare class SagaTransportNotConnectedError extends SagaError {
|
|
254
|
+
constructor();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
declare class SagaContextNotFoundError extends SagaError {
|
|
258
|
+
constructor();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
declare class SagaNoParentError extends SagaError {
|
|
262
|
+
constructor();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
declare class SagaInvalidHandlerConfigError extends SagaError {
|
|
266
|
+
constructor(eventType: string, serviceId: string, reason: string);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export { ConsoleSagaLogger, type Emit, type EmitParams, type EventHandler, type EventHint, type ForkConfig, type HandlerConfig, type InboundMessage, type IncomingEvent, NoopOtelContext, type OtelContext, type OutboundMessage, type ParentSagaContext, type RunnerOptions, SagaContext, type SagaContextData, SagaContextNotFoundError, SagaDuplicateHandlerError, SagaError, type SagaEvent, SagaInvalidHandlerConfigError, type SagaLogger, SagaNoParentError, SagaParseError, SagaParser, type SagaParticipant, SagaPublisher, SagaRegistry, SagaRetryableError, SagaRunner, type SagaStartOptions, type SagaTransport, SagaTransportNotConnectedError, type TransportSubscribeOptions, W3cOtelContext, createOtelContext };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
import * as _opentelemetry_api from '@opentelemetry/api';
|
|
2
|
+
|
|
3
|
+
interface SagaTransport {
|
|
4
|
+
connect(): Promise<void>;
|
|
5
|
+
disconnect(): Promise<void>;
|
|
6
|
+
publish(message: OutboundMessage): Promise<void>;
|
|
7
|
+
subscribe(topics: string[], handler: (message: InboundMessage) => Promise<void>, options?: TransportSubscribeOptions): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
interface OutboundMessage {
|
|
10
|
+
topic: string;
|
|
11
|
+
key: string;
|
|
12
|
+
value: string;
|
|
13
|
+
headers: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
interface InboundMessage {
|
|
16
|
+
topic: string;
|
|
17
|
+
key: string;
|
|
18
|
+
value: string;
|
|
19
|
+
headers: Record<string, string>;
|
|
20
|
+
}
|
|
21
|
+
interface TransportSubscribeOptions {
|
|
22
|
+
fromBeginning?: boolean;
|
|
23
|
+
groupId?: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface RunnerOptions {
|
|
27
|
+
serviceName: string;
|
|
28
|
+
fromBeginning?: boolean;
|
|
29
|
+
/** Prefix prepended to eventType to form Kafka topic names. Default: '' (no prefix). */
|
|
30
|
+
topicPrefix?: string;
|
|
31
|
+
retryPolicy?: {
|
|
32
|
+
maxRetries?: number;
|
|
33
|
+
initialDelayMs?: number;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
interface IncomingEvent<T = Record<string, unknown>> {
|
|
38
|
+
eventId: string;
|
|
39
|
+
sagaId: string;
|
|
40
|
+
parentSagaId?: string;
|
|
41
|
+
rootSagaId: string;
|
|
42
|
+
causationId: string;
|
|
43
|
+
eventType: string;
|
|
44
|
+
sagaName?: string;
|
|
45
|
+
sagaDescription?: string;
|
|
46
|
+
stepName: string;
|
|
47
|
+
stepDescription?: string;
|
|
48
|
+
occurredAt: string;
|
|
49
|
+
payload: T;
|
|
50
|
+
key?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
type EventHint = 'compensation' | 'final' | 'fork';
|
|
54
|
+
interface EmitParams<T extends object = Record<string, unknown>> {
|
|
55
|
+
eventType: string;
|
|
56
|
+
stepName: string;
|
|
57
|
+
stepDescription?: string;
|
|
58
|
+
payload: T;
|
|
59
|
+
hint?: EventHint;
|
|
60
|
+
key?: string;
|
|
61
|
+
}
|
|
62
|
+
type Emit = <T extends object>(params: EmitParams<T>) => Promise<void>;
|
|
63
|
+
|
|
64
|
+
type EventHandler<T = Record<string, unknown>> = (event: IncomingEvent<T>, emit: Emit) => Promise<void>;
|
|
65
|
+
|
|
66
|
+
declare class SagaError extends Error {
|
|
67
|
+
isSagaError: boolean;
|
|
68
|
+
constructor(message: string);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
declare class SagaRetryableError extends SagaError {
|
|
72
|
+
readonly maxRetries: number;
|
|
73
|
+
constructor(message: string, maxRetries?: number);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
interface ForkConfig {
|
|
77
|
+
sagaName?: string;
|
|
78
|
+
sagaDescription?: string;
|
|
79
|
+
}
|
|
80
|
+
interface HandlerConfig {
|
|
81
|
+
final?: boolean;
|
|
82
|
+
fork?: boolean | ForkConfig;
|
|
83
|
+
}
|
|
84
|
+
interface SagaParticipant {
|
|
85
|
+
readonly serviceId: string;
|
|
86
|
+
readonly on: Record<string, EventHandler<any>>;
|
|
87
|
+
readonly handlerOptions?: Record<string, HandlerConfig>;
|
|
88
|
+
onRetryExhausted?(event: IncomingEvent, error: SagaRetryableError, emit: Emit): Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
interface RouteEntry {
|
|
92
|
+
participant: SagaParticipant;
|
|
93
|
+
handler: EventHandler;
|
|
94
|
+
options?: HandlerConfig;
|
|
95
|
+
}
|
|
96
|
+
declare class SagaRegistry {
|
|
97
|
+
private participants;
|
|
98
|
+
register(participant: SagaParticipant): void;
|
|
99
|
+
getAll(): SagaParticipant[];
|
|
100
|
+
buildRouteMap(): Map<string, RouteEntry>;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
interface SagaEvent<TPayload = Record<string, unknown>> {
|
|
104
|
+
eventId: string;
|
|
105
|
+
eventType: string;
|
|
106
|
+
sagaId: string;
|
|
107
|
+
causationId: string;
|
|
108
|
+
stepName: string;
|
|
109
|
+
stepDescription?: string;
|
|
110
|
+
sagaName?: string;
|
|
111
|
+
sagaDescription?: string;
|
|
112
|
+
occurredAt: string;
|
|
113
|
+
publishedAt: string;
|
|
114
|
+
schemaVersion: 1;
|
|
115
|
+
parentSagaId?: string;
|
|
116
|
+
rootSagaId: string;
|
|
117
|
+
payload: TPayload;
|
|
118
|
+
hint?: EventHint;
|
|
119
|
+
key?: string;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
interface ParentSagaContext {
|
|
123
|
+
parentSagaId?: string;
|
|
124
|
+
rootSagaId: string;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
interface OtelContext {
|
|
128
|
+
injectBaggage(sagaId: string, rootSagaId: string, parentSagaId?: string): void;
|
|
129
|
+
extractBaggage(): {
|
|
130
|
+
sagaId?: string;
|
|
131
|
+
rootSagaId?: string;
|
|
132
|
+
parentSagaId?: string;
|
|
133
|
+
};
|
|
134
|
+
enrichSpan(attrs: Record<string, string>): void;
|
|
135
|
+
withSpan<T>(name: string, attrs: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
136
|
+
injectTraceContext(headers: Record<string, string>): void;
|
|
137
|
+
withExtractedSpan<T>(name: string, attrs: Record<string, string>, headers: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
138
|
+
}
|
|
139
|
+
declare class NoopOtelContext implements OtelContext {
|
|
140
|
+
injectBaggage(): void;
|
|
141
|
+
extractBaggage(): {
|
|
142
|
+
sagaId?: string;
|
|
143
|
+
rootSagaId?: string;
|
|
144
|
+
parentSagaId?: string;
|
|
145
|
+
};
|
|
146
|
+
enrichSpan(): void;
|
|
147
|
+
withSpan<T>(_name: string, _attrs: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
148
|
+
injectTraceContext(): void;
|
|
149
|
+
withExtractedSpan<T>(_name: string, _attrs: Record<string, string>, _headers: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
150
|
+
}
|
|
151
|
+
type OtelAPI = typeof _opentelemetry_api;
|
|
152
|
+
declare class W3cOtelContext implements OtelContext {
|
|
153
|
+
private api;
|
|
154
|
+
constructor(api: OtelAPI);
|
|
155
|
+
injectBaggage(sagaId: string, rootSagaId: string, parentSagaId?: string): void;
|
|
156
|
+
extractBaggage(): {
|
|
157
|
+
sagaId?: string;
|
|
158
|
+
rootSagaId?: string;
|
|
159
|
+
parentSagaId?: string;
|
|
160
|
+
};
|
|
161
|
+
enrichSpan(attrs: Record<string, string>): void;
|
|
162
|
+
withSpan<T>(name: string, attrs: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
163
|
+
injectTraceContext(headers: Record<string, string>): void;
|
|
164
|
+
withExtractedSpan<T>(name: string, attrs: Record<string, string>, headers: Record<string, string>, fn: () => Promise<T>): Promise<T>;
|
|
165
|
+
}
|
|
166
|
+
declare function createOtelContext(enabled: boolean): OtelContext;
|
|
167
|
+
|
|
168
|
+
interface SagaStartOptions {
|
|
169
|
+
sagaName?: string;
|
|
170
|
+
sagaDescription?: string;
|
|
171
|
+
key?: string;
|
|
172
|
+
}
|
|
173
|
+
declare class SagaPublisher {
|
|
174
|
+
private transport;
|
|
175
|
+
private otelCtx;
|
|
176
|
+
private topicPrefix;
|
|
177
|
+
constructor(transport: SagaTransport, otelCtx: OtelContext, topicPrefix?: string);
|
|
178
|
+
start<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{
|
|
179
|
+
sagaId: string;
|
|
180
|
+
result: Awaited<R>;
|
|
181
|
+
}>;
|
|
182
|
+
emit<T extends object>(params: EmitParams<T>): Promise<void>;
|
|
183
|
+
startChild<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{
|
|
184
|
+
sagaId: string;
|
|
185
|
+
result: Awaited<R>;
|
|
186
|
+
}>;
|
|
187
|
+
emitToParent<T extends object>(paramsOrFn: EmitParams<T> | (() => void | Promise<void>)): Promise<void>;
|
|
188
|
+
forSaga(sagaId: string, parentCtx?: ParentSagaContext, causationId?: string, baseKey?: string): Emit;
|
|
189
|
+
publish<T>(event: SagaEvent<T>): Promise<void>;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
declare class SagaParser {
|
|
193
|
+
private otelCtx;
|
|
194
|
+
constructor(otelCtx: OtelContext);
|
|
195
|
+
parse<T>(message: InboundMessage): SagaEvent<T> | null;
|
|
196
|
+
private parseFromHeaders;
|
|
197
|
+
private parseFromBaggage;
|
|
198
|
+
private parseBaggageHeader;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
interface SagaLogger {
|
|
202
|
+
info(message: string, ...args: unknown[]): void;
|
|
203
|
+
warn(message: string, ...args: unknown[]): void;
|
|
204
|
+
error(message: string, ...args: unknown[]): void;
|
|
205
|
+
}
|
|
206
|
+
declare class ConsoleSagaLogger implements SagaLogger {
|
|
207
|
+
info(message: string, ...args: unknown[]): void;
|
|
208
|
+
warn(message: string, ...args: unknown[]): void;
|
|
209
|
+
error(message: string, ...args: unknown[]): void;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
declare class SagaRunner {
|
|
213
|
+
private registry;
|
|
214
|
+
private transport;
|
|
215
|
+
private publisher;
|
|
216
|
+
private parser;
|
|
217
|
+
private options;
|
|
218
|
+
private otelCtx?;
|
|
219
|
+
private logger;
|
|
220
|
+
private routeMap;
|
|
221
|
+
constructor(registry: SagaRegistry, transport: SagaTransport, publisher: SagaPublisher, parser: SagaParser, options: RunnerOptions, otelCtx?: OtelContext | undefined, logger?: SagaLogger);
|
|
222
|
+
start(): Promise<void>;
|
|
223
|
+
stop(): Promise<void>;
|
|
224
|
+
private handleMessage;
|
|
225
|
+
private runWithRetry;
|
|
226
|
+
private sleep;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
interface SagaContextData {
|
|
230
|
+
sagaId: string;
|
|
231
|
+
rootSagaId: string;
|
|
232
|
+
parentSagaId?: string;
|
|
233
|
+
causationId: string;
|
|
234
|
+
key?: string;
|
|
235
|
+
sagaName?: string;
|
|
236
|
+
sagaDescription?: string;
|
|
237
|
+
}
|
|
238
|
+
declare class SagaContext {
|
|
239
|
+
private static storage;
|
|
240
|
+
static run<T>(data: SagaContextData, fn: () => T): T;
|
|
241
|
+
static current(): SagaContextData | undefined;
|
|
242
|
+
static require(): SagaContextData;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
declare class SagaDuplicateHandlerError extends SagaError {
|
|
246
|
+
constructor(eventType: string, existingServiceId: string, newServiceId: string);
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
declare class SagaParseError extends SagaError {
|
|
250
|
+
constructor(message: string);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
declare class SagaTransportNotConnectedError extends SagaError {
|
|
254
|
+
constructor();
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
declare class SagaContextNotFoundError extends SagaError {
|
|
258
|
+
constructor();
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
declare class SagaNoParentError extends SagaError {
|
|
262
|
+
constructor();
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
declare class SagaInvalidHandlerConfigError extends SagaError {
|
|
266
|
+
constructor(eventType: string, serviceId: string, reason: string);
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export { ConsoleSagaLogger, type Emit, type EmitParams, type EventHandler, type EventHint, type ForkConfig, type HandlerConfig, type InboundMessage, type IncomingEvent, NoopOtelContext, type OtelContext, type OutboundMessage, type ParentSagaContext, type RunnerOptions, SagaContext, type SagaContextData, SagaContextNotFoundError, SagaDuplicateHandlerError, SagaError, type SagaEvent, SagaInvalidHandlerConfigError, type SagaLogger, SagaNoParentError, SagaParseError, SagaParser, type SagaParticipant, SagaPublisher, SagaRegistry, SagaRetryableError, SagaRunner, type SagaStartOptions, type SagaTransport, SagaTransportNotConnectedError, type TransportSubscribeOptions, W3cOtelContext, createOtelContext };
|