@fbsm/saga-nestjs 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 ADDED
@@ -0,0 +1,506 @@
1
+ # @fbsm/saga-nestjs
2
+
3
+ NestJS integration for the saga choreography library. Provides a dynamic module, decorators for auto-discovery, and injectable providers.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @fbsm/saga-nestjs @fbsm/saga-core @fbsm/saga-transport-kafka
9
+ ```
10
+
11
+ ## API Reference
12
+
13
+ ### `SagaModule`
14
+
15
+ Dynamic NestJS module. Register once globally.
16
+
17
+ ```typescript
18
+ // Synchronous
19
+ SagaModule.forRoot(options: SagaModuleOptions): DynamicModule
20
+
21
+ // Asynchronous (e.g., with ConfigService)
22
+ SagaModule.forRootAsync(options: SagaModuleAsyncOptions): DynamicModule
23
+ ```
24
+
25
+ **`SagaModuleOptions`** (extends `RunnerOptions`):
26
+
27
+ | Field | Type | Default | Description |
28
+ |-------|------|---------|-------------|
29
+ | `serviceName` | `string` | — | Consumer group prefix (`${serviceName}-group`) |
30
+ | `transport` | `SagaTransport` | — | Transport implementation (e.g., `KafkaTransport`) |
31
+ | `retryPolicy.maxRetries` | `number` | `3` | Max retry attempts for `SagaRetryableError` |
32
+ | `retryPolicy.initialDelayMs` | `number` | `200` | Initial retry delay in ms (doubles each attempt) |
33
+ | `fromBeginning` | `boolean` | `false` | Read from beginning of topics |
34
+ | `topicPrefix` | `string` | `''` | Prefix prepended to eventType for topic names |
35
+ | `otel.enabled` | `boolean` | `false` | Enable OpenTelemetry tracing and W3C context propagation |
36
+ | `otel.exporterUrl` | `string` | — | OTel exporter URL |
37
+ | `logger` | `SagaLogger` | `ConsoleSagaLogger` | Custom logger |
38
+
39
+ **Async configuration**:
40
+ ```typescript
41
+ SagaModule.forRootAsync({
42
+ imports: [ConfigModule],
43
+ inject: [ConfigService],
44
+ useFactory: (config: ConfigService) => ({
45
+ serviceName: config.get('SERVICE_NAME'),
46
+ transport: new KafkaTransport({
47
+ brokers: config.get('KAFKA_BROKERS').split(','),
48
+ }),
49
+ }),
50
+ })
51
+ ```
52
+
53
+ ### `@SagaParticipant()`
54
+
55
+ Class decorator. Marks a class for auto-discovery by the saga runner. Must extend `SagaParticipantBase`.
56
+
57
+ ```typescript
58
+ @Injectable()
59
+ @SagaParticipant()
60
+ export class PaymentParticipant extends SagaParticipantBase {
61
+ readonly serviceId = 'payment-service';
62
+ }
63
+ ```
64
+
65
+ ### `@SagaHandler(...eventTypes, options?)`
66
+
67
+ Method decorator. Registers a method as the handler for one or more event types. Accepts an optional options object as the last argument.
68
+
69
+ ```typescript
70
+ // Single event type
71
+ @SagaHandler('order.created')
72
+ async handleOrderCreated(event: IncomingEvent, emit: Emit) {}
73
+
74
+ // Multiple event types
75
+ @SagaHandler('inventory.failed', 'inventory.compensated')
76
+ async handleInventoryIssue(event: IncomingEvent, emit: Emit) {}
77
+ ```
78
+
79
+ **`SagaHandlerOptions`**:
80
+
81
+ | Field | Type | Description |
82
+ |-------|------|-------------|
83
+ | `final` | `boolean` | Marks the handler as the last step. Auto-adds `hint: 'final'` to all emitted events. |
84
+ | `fork` | `boolean \| ForkConfig` | Every `emit()` inside the handler creates a new sub-saga. The framework generates a new `sagaId`, adds `hint: 'fork'`, and propagates `parentSagaId`/`rootSagaId`. |
85
+
86
+ `final` and `fork` are **mutually exclusive** — using both throws `SagaInvalidHandlerConfigError`.
87
+
88
+ **Constraint**: Each event type must have exactly one handler across all participants. Duplicate registrations throw `SagaDuplicateHandlerError`.
89
+
90
+ ### `SagaParticipantBase`
91
+
92
+ Abstract base class for saga participants.
93
+
94
+ | Property / Method | Type | Description |
95
+ |-------------------|------|-------------|
96
+ | `serviceId` | `string` (abstract) | Unique service identifier |
97
+ | `on` | `Record<string, EventHandler>` | Auto-populated handler registry |
98
+ | `onRetryExhausted?()` | `(event, error, emit) => Promise<void>` | Called when `SagaRetryableError` exceeds `maxRetries` |
99
+
100
+ ### `SagaPublisherProvider`
101
+
102
+ Injectable service to initiate sagas or emit events. See [Core Functions](../doc/core-functions.md) for detailed semantics.
103
+
104
+ | Method | Description |
105
+ |--------|-------------|
106
+ | `start(fn, opts?)` | Start a new root saga |
107
+ | `startChild(fn, opts?)` | Start a child saga linked to the current context |
108
+ | `emit(params)` | Emit an event in the current saga context |
109
+ | `emitToParent(params \| fn)` | Emit to the parent saga |
110
+ | `forSaga(sagaId, parentCtx?, causationId?)` | Get a bound `Emit` function for manual use |
111
+
112
+ ### Types
113
+
114
+ ```typescript
115
+ type Emit = <T extends object>(params: EmitParams<T>) => Promise<void>;
116
+
117
+ interface EmitParams<T extends object = Record<string, unknown>> {
118
+ eventType: string; // Event type (also used as topic name)
119
+ stepName: string; // Logical step name for tracing
120
+ stepDescription?: string;
121
+ payload: T; // Event payload
122
+ hint?: EventHint; // 'compensation' | 'final' | 'fork'
123
+ key?: string; // Optional partition key
124
+ }
125
+
126
+ interface IncomingEvent<T = Record<string, unknown>> {
127
+ eventId: string;
128
+ sagaId: string;
129
+ parentSagaId?: string;
130
+ rootSagaId: string;
131
+ causationId: string;
132
+ eventType: string;
133
+ sagaName?: string;
134
+ sagaDescription?: string;
135
+ stepName: string;
136
+ stepDescription?: string;
137
+ occurredAt: string;
138
+ payload: T;
139
+ key?: string;
140
+ }
141
+ ```
142
+
143
+ See [Concepts](../doc/concepts.md) for detailed explanations of each field.
144
+
145
+ ---
146
+
147
+ ## Examples
148
+
149
+ ### 1. Simple Handler + Emit
150
+
151
+ A basic participant that handles one event and emits another.
152
+
153
+ ```typescript
154
+ // payment.participant.ts
155
+ import { Injectable } from '@nestjs/common';
156
+ import {
157
+ SagaParticipant,
158
+ SagaParticipantBase,
159
+ SagaHandler,
160
+ } from '@fbsm/saga-nestjs';
161
+ import type { IncomingEvent, Emit } from '@fbsm/saga-core';
162
+
163
+ @Injectable()
164
+ @SagaParticipant()
165
+ export class PaymentParticipant extends SagaParticipantBase {
166
+ readonly serviceId = 'payment-service';
167
+
168
+ @SagaHandler('order.created')
169
+ async handleOrderCreated(event: IncomingEvent, emit: Emit): Promise<void> {
170
+ const { orderId, amount } = event.payload as {
171
+ orderId: string;
172
+ amount: number;
173
+ };
174
+
175
+ // Process payment...
176
+ const transactionId = `txn-${Date.now()}`;
177
+
178
+ await emit({
179
+ eventType: 'payment.completed',
180
+ stepName: 'process-payment',
181
+ payload: { orderId, transactionId, amount },
182
+ });
183
+ }
184
+ }
185
+ ```
186
+
187
+ ```typescript
188
+ // orders.controller.ts
189
+ import { Controller, Post, Body } from '@nestjs/common';
190
+ import { SagaPublisherProvider } from '@fbsm/saga-nestjs';
191
+
192
+ @Controller('orders')
193
+ export class OrdersController {
194
+ constructor(private readonly sagaPublisher: SagaPublisherProvider) {}
195
+
196
+ @Post()
197
+ async create(@Body() body: { amount: number }) {
198
+ const { sagaId } = await this.sagaPublisher.start(async () => {
199
+ await this.sagaPublisher.emit({
200
+ eventType: 'order.created',
201
+ stepName: 'create-order',
202
+ payload: { orderId: `order-${Date.now()}`, amount: body.amount },
203
+ });
204
+ });
205
+
206
+ return { sagaId };
207
+ }
208
+ }
209
+ ```
210
+
211
+ **Flow**: `POST /orders` → `order.created` → `PaymentParticipant` → `payment.completed`
212
+
213
+ ### 2. Complex: Fork + Fan-Out
214
+
215
+ A handler that forks N sub-sagas and coordinates their completion via `emitToParent()`.
216
+
217
+ ```typescript
218
+ // bulk-orchestration.participant.ts
219
+ import { Injectable } from '@nestjs/common';
220
+ import {
221
+ SagaParticipant,
222
+ SagaParticipantBase,
223
+ SagaHandler,
224
+ SagaPublisherProvider,
225
+ } from '@fbsm/saga-nestjs';
226
+ import type { IncomingEvent, Emit } from '@fbsm/saga-core';
227
+
228
+ @Injectable()
229
+ @SagaParticipant()
230
+ export class BulkOrchestrationParticipant extends SagaParticipantBase {
231
+ readonly serviceId = 'bulk-orchestration';
232
+
233
+ private completionCount = new Map<string, { total: number; done: number }>();
234
+
235
+ constructor(private readonly sagaPublisher: SagaPublisherProvider) {
236
+ super();
237
+ }
238
+
239
+ // Each emit() inside this handler creates a separate sub-saga
240
+ @SagaHandler('bulk.requested', { fork: true })
241
+ async handleBulkRequested(event: IncomingEvent, emit: Emit): Promise<void> {
242
+ const { batchId, items } = event.payload as {
243
+ batchId: string;
244
+ items: string[];
245
+ };
246
+
247
+ this.completionCount.set(batchId, { total: items.length, done: 0 });
248
+
249
+ // N emits = N sub-sagas (each gets its own sagaId)
250
+ for (const item of items) {
251
+ await emit({
252
+ eventType: 'item.processing.requested',
253
+ stepName: 'request-item-processing',
254
+ payload: { batchId, item },
255
+ });
256
+ }
257
+ }
258
+
259
+ // Called when each sub-saga completes
260
+ @SagaHandler('item.processing.completed')
261
+ async handleItemCompleted(event: IncomingEvent): Promise<void> {
262
+ const { batchId } = event.payload as { batchId: string };
263
+
264
+ const counter = this.completionCount.get(batchId);
265
+ if (!counter) return;
266
+
267
+ counter.done++;
268
+
269
+ // Fan-in: when all sub-sagas complete, notify parent
270
+ if (counter.done >= counter.total) {
271
+ this.completionCount.delete(batchId);
272
+
273
+ await this.sagaPublisher.emitToParent({
274
+ eventType: 'bulk.completed',
275
+ stepName: 'complete-bulk',
276
+ payload: { batchId, totalProcessed: counter.total },
277
+ hint: 'final',
278
+ });
279
+ }
280
+ }
281
+ }
282
+ ```
283
+
284
+ ```typescript
285
+ // item-processor.participant.ts
286
+ @Injectable()
287
+ @SagaParticipant()
288
+ export class ItemProcessorParticipant extends SagaParticipantBase {
289
+ readonly serviceId = 'item-processor';
290
+
291
+ @SagaHandler('item.processing.requested', { final: true })
292
+ async handleProcessing(event: IncomingEvent, emit: Emit): Promise<void> {
293
+ const { batchId, item } = event.payload as {
294
+ batchId: string;
295
+ item: string;
296
+ };
297
+
298
+ // Process item...
299
+
300
+ await emit({
301
+ eventType: 'item.processing.completed',
302
+ stepName: 'process-item',
303
+ payload: { batchId, item, status: 'done' },
304
+ });
305
+ // hint: 'final' auto-added by framework
306
+ }
307
+ }
308
+ ```
309
+
310
+ **Flow**:
311
+ ```
312
+ POST /bulk → bulk.requested [fork x N]
313
+ Sub-saga 1: item.processing.requested → item.processing.completed [final]
314
+ Sub-saga 2: item.processing.requested → item.processing.completed [final]
315
+ Sub-saga N: item.processing.requested → item.processing.completed [final]
316
+ ← emitToParent() when all complete
317
+ → bulk.completed [final]
318
+ ```
319
+
320
+ ### 3. AsyncLocalStorage Context (Fork + Final)
321
+
322
+ Full flow showing how AsyncLocalStorage context propagates through `start()` → handler → fork → final → `emitToParent()`.
323
+
324
+ ```typescript
325
+ // orchestration.participant.ts
326
+ @Injectable()
327
+ @SagaParticipant()
328
+ export class OrchestrationParticipant extends SagaParticipantBase {
329
+ readonly serviceId = 'orchestration';
330
+
331
+ // Fork: each emit creates a sub-saga with its own context
332
+ // Inside the handler, SagaContext.current() returns the PARENT saga context
333
+ // The framework wraps each emit in a NEW context for the sub-saga
334
+ @SagaHandler('task.requested', { fork: true })
335
+ async handleTaskRequested(event: IncomingEvent, emit: Emit): Promise<void> {
336
+ const { taskId } = event.payload as { taskId: string };
337
+
338
+ // This emit runs in a sub-saga context automatically:
339
+ // - New sagaId generated
340
+ // - parentSagaId = event.sagaId (the parent)
341
+ // - rootSagaId inherited
342
+ // - hint: 'fork' auto-added
343
+ await emit({
344
+ eventType: 'validation.requested',
345
+ stepName: 'request-validation',
346
+ payload: { taskId },
347
+ });
348
+ }
349
+
350
+ // Parent receives the result when sub-saga calls emitToParent()
351
+ @SagaHandler('task.completed', { final: true })
352
+ async handleTaskCompleted(event: IncomingEvent, emit: Emit): Promise<void> {
353
+ const { taskId, result } = event.payload as {
354
+ taskId: string;
355
+ result: string;
356
+ };
357
+
358
+ await emit({
359
+ eventType: 'task.done',
360
+ stepName: 'finish-task',
361
+ payload: { taskId, result },
362
+ });
363
+ // hint: 'final' auto-added
364
+ }
365
+ }
366
+ ```
367
+
368
+ ```typescript
369
+ // validator.participant.ts
370
+ @Injectable()
371
+ @SagaParticipant()
372
+ export class ValidatorParticipant extends SagaParticipantBase {
373
+ readonly serviceId = 'validator';
374
+
375
+ constructor(private readonly sagaPublisher: SagaPublisherProvider) {
376
+ super();
377
+ }
378
+
379
+ // Final handler in the sub-saga
380
+ @SagaHandler('validation.requested', { final: true })
381
+ async handleValidation(event: IncomingEvent, emit: Emit): Promise<void> {
382
+ const { taskId } = event.payload as { taskId: string };
383
+
384
+ // Emit within the sub-saga (hint: 'final' auto-added)
385
+ await emit({
386
+ eventType: 'validation.completed',
387
+ stepName: 'validate',
388
+ payload: { taskId, valid: true },
389
+ });
390
+
391
+ // Report back to parent saga
392
+ // emitToParent reads parentSagaId from AsyncLocalStorage
393
+ await this.sagaPublisher.emitToParent({
394
+ eventType: 'task.completed',
395
+ stepName: 'report-to-parent',
396
+ payload: { taskId, result: 'validated' },
397
+ });
398
+ }
399
+ }
400
+ ```
401
+
402
+ ```typescript
403
+ // controller
404
+ @Post('tasks')
405
+ async createTask() {
406
+ // start() creates a root saga context in AsyncLocalStorage
407
+ const { sagaId } = await this.sagaPublisher.start(async () => {
408
+ // emit() reads sagaId from ALS automatically
409
+ await this.sagaPublisher.emit({
410
+ eventType: 'task.requested',
411
+ stepName: 'create-task',
412
+ payload: { taskId: `task-${Date.now()}` },
413
+ });
414
+ });
415
+ return { sagaId };
416
+ }
417
+ ```
418
+
419
+ **Context flow**:
420
+ ```
421
+ start() → ALS context: { sagaId: A, rootSagaId: A }
422
+ → task.requested (handler runs in context A)
423
+ → fork creates: { sagaId: B, rootSagaId: A, parentSagaId: A }
424
+ → validation.requested (handler runs in context B)
425
+ → emit() reads from ALS → publishes on saga B
426
+ → emitToParent() reads parentSagaId from ALS → publishes on saga A
427
+ → task.completed (handler runs in context A, { final: true })
428
+ → task.done [final]
429
+ ```
430
+
431
+ ### 4. Manual Mode (Without AsyncLocalStorage)
432
+
433
+ For when you need full control or can't use callbacks (e.g., Express middleware, testing).
434
+
435
+ ```typescript
436
+ import { Controller, Post, Body } from '@nestjs/common';
437
+ import { v7 as uuidv7 } from 'uuid';
438
+ import { SagaPublisherProvider } from '@fbsm/saga-nestjs';
439
+
440
+ @Controller('orders')
441
+ export class ManualOrdersController {
442
+ constructor(private readonly sagaPublisher: SagaPublisherProvider) {}
443
+
444
+ @Post()
445
+ async create(@Body() body: { amount: number }) {
446
+ // Generate your own saga ID
447
+ const sagaId = uuidv7();
448
+
449
+ // Get a bound emit function (no ALS needed)
450
+ const emit = this.sagaPublisher.forSaga(sagaId);
451
+
452
+ await emit({
453
+ eventType: 'order.created',
454
+ stepName: 'create-order',
455
+ payload: { orderId: `order-${Date.now()}`, amount: body.amount },
456
+ });
457
+
458
+ return { sagaId };
459
+ }
460
+
461
+ @Post('with-child')
462
+ async createWithChild(@Body() body: { amount: number }) {
463
+ const sagaId = uuidv7();
464
+ const rootEmit = this.sagaPublisher.forSaga(sagaId);
465
+
466
+ await rootEmit({
467
+ eventType: 'order.created',
468
+ stepName: 'create-order',
469
+ payload: { orderId: `order-${Date.now()}`, amount: body.amount },
470
+ });
471
+
472
+ // Manually create a child saga
473
+ const childSagaId = uuidv7();
474
+ const childEmit = this.sagaPublisher.forSaga(childSagaId, {
475
+ parentSagaId: sagaId,
476
+ rootSagaId: sagaId,
477
+ }, sagaId); // causationId
478
+
479
+ await childEmit({
480
+ eventType: 'fulfillment.started',
481
+ stepName: 'start-fulfillment',
482
+ payload: { orderId: `order-${Date.now()}` },
483
+ });
484
+
485
+ return { sagaId, childSagaId };
486
+ }
487
+ }
488
+ ```
489
+
490
+ **When to use manual mode**:
491
+ - Testing: create emit functions with known saga IDs
492
+ - Non-callback patterns: when wrapping in a callback is impractical
493
+ - Migration: gradually adopting the library in existing code
494
+ - External triggers: when the saga ID is provided externally
495
+
496
+ > **Tip**: Prefer the callback style (`start(fn)`) for new code — it handles context propagation automatically and is less error-prone.
497
+
498
+ ---
499
+
500
+ ## Further Reading
501
+
502
+ - [Concepts](../doc/concepts.md) — sagaId, hint, eventType, and other domain terms
503
+ - [Core Functions](../doc/core-functions.md) — detailed semantics of emit, emitToParent, etc.
504
+ - [@fbsm/saga-core API](../saga-core/README.md) — framework-agnostic core reference
505
+ - [@fbsm/saga-transport-kafka API](../saga-transport-kafka/README.md) — Kafka transport options
506
+ - [Example Projects](../../examples/README.md) — production-realistic demo applications
package/dist/index.cjs ADDED
@@ -0,0 +1,290 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+ var __decorateClass = (decorators, target, key, kind) => {
20
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
21
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
22
+ if (decorator = decorators[i])
23
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
24
+ if (kind && result) __defProp(target, key, result);
25
+ return result;
26
+ };
27
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
28
+
29
+ // src/index.ts
30
+ var index_exports = {};
31
+ __export(index_exports, {
32
+ SAGA_OPTIONS_TOKEN: () => SAGA_OPTIONS_TOKEN,
33
+ SAGA_TRANSPORT_TOKEN: () => SAGA_TRANSPORT_TOKEN,
34
+ SagaDuplicateHandlerError: () => import_saga_core4.SagaDuplicateHandlerError,
35
+ SagaError: () => import_saga_core4.SagaError,
36
+ SagaHandler: () => SagaHandler,
37
+ SagaModule: () => SagaModule,
38
+ SagaParseError: () => import_saga_core4.SagaParseError,
39
+ SagaParticipant: () => SagaParticipant,
40
+ SagaParticipantBase: () => SagaParticipantBase,
41
+ SagaPublisherProvider: () => SagaPublisherProvider,
42
+ SagaRetryableError: () => import_saga_core4.SagaRetryableError,
43
+ SagaTransportNotConnectedError: () => import_saga_core4.SagaTransportNotConnectedError
44
+ });
45
+ module.exports = __toCommonJS(index_exports);
46
+
47
+ // src/saga.module.ts
48
+ var import_common3 = require("@nestjs/common");
49
+ var import_core2 = require("@nestjs/core");
50
+ var import_saga_core3 = require("@fbsm/saga-core");
51
+
52
+ // src/constants.ts
53
+ var SAGA_OPTIONS_TOKEN = /* @__PURE__ */ Symbol("SAGA_OPTIONS_TOKEN");
54
+ var SAGA_TRANSPORT_TOKEN = /* @__PURE__ */ Symbol("SAGA_TRANSPORT_TOKEN");
55
+ var SAGA_PARTICIPANT_METADATA = /* @__PURE__ */ Symbol("SAGA_PARTICIPANT_METADATA");
56
+ var SAGA_HANDLER_METADATA = /* @__PURE__ */ Symbol("SAGA_HANDLER_METADATA");
57
+ var SAGA_HANDLER_OPTIONS_METADATA = /* @__PURE__ */ Symbol("SAGA_HANDLER_OPTIONS_METADATA");
58
+
59
+ // src/providers/saga-runner.provider.ts
60
+ var import_common = require("@nestjs/common");
61
+ var import_core = require("@nestjs/core");
62
+ var import_saga_core = require("@fbsm/saga-core");
63
+ var SagaRunnerProvider = class {
64
+ constructor(discoveryService, registry, runner) {
65
+ this.discoveryService = discoveryService;
66
+ this.registry = registry;
67
+ this.runner = runner;
68
+ }
69
+ logger = new import_common.Logger("SagaRunner");
70
+ async onModuleInit() {
71
+ const providers = this.discoveryService.getProviders();
72
+ for (const wrapper of providers) {
73
+ const instance = wrapper.instance;
74
+ if (!instance || !instance.constructor) {
75
+ continue;
76
+ }
77
+ const isParticipant = Reflect.getMetadata(
78
+ SAGA_PARTICIPANT_METADATA,
79
+ instance.constructor
80
+ );
81
+ if (!isParticipant) {
82
+ continue;
83
+ }
84
+ const handlesMap = Reflect.getMetadata(SAGA_HANDLER_METADATA, instance.constructor);
85
+ if (!handlesMap || handlesMap.size === 0) {
86
+ continue;
87
+ }
88
+ const on = {};
89
+ for (const [eventType, methodName] of handlesMap.entries()) {
90
+ const method = instance[methodName];
91
+ if (typeof method === "function") {
92
+ on[eventType] = method.bind(instance);
93
+ }
94
+ }
95
+ if ("on" in instance && typeof instance.on === "object") {
96
+ Object.assign(instance.on, on);
97
+ }
98
+ const handlerOptionsMap = Reflect.getMetadata(SAGA_HANDLER_OPTIONS_METADATA, instance.constructor);
99
+ const handlerOptions = {};
100
+ if (handlerOptionsMap) {
101
+ for (const [eventType, opts] of handlerOptionsMap.entries()) {
102
+ handlerOptions[eventType] = { final: opts.final, fork: !!opts.fork };
103
+ }
104
+ }
105
+ const serviceId = instance.serviceId ?? "unknown";
106
+ this.logger.log(
107
+ `Registered participant "${serviceId}" handling: [${Object.keys(on).join(", ")}]`
108
+ );
109
+ this.registry.register({
110
+ serviceId,
111
+ on,
112
+ handlerOptions: Object.keys(handlerOptions).length > 0 ? handlerOptions : void 0,
113
+ onRetryExhausted: typeof instance.onRetryExhausted === "function" ? instance.onRetryExhausted.bind(instance) : void 0
114
+ });
115
+ }
116
+ await this.runner.start();
117
+ }
118
+ async onModuleDestroy() {
119
+ await this.runner.stop();
120
+ }
121
+ };
122
+ SagaRunnerProvider = __decorateClass([
123
+ (0, import_common.Injectable)(),
124
+ __decorateParam(0, (0, import_common.Inject)(import_core.DiscoveryService)),
125
+ __decorateParam(1, (0, import_common.Inject)(import_saga_core.SagaRegistry)),
126
+ __decorateParam(2, (0, import_common.Inject)(import_saga_core.SagaRunner))
127
+ ], SagaRunnerProvider);
128
+
129
+ // src/providers/saga-publisher.provider.ts
130
+ var import_common2 = require("@nestjs/common");
131
+ var import_saga_core2 = require("@fbsm/saga-core");
132
+ var SagaPublisherProvider = class {
133
+ constructor(publisher) {
134
+ this.publisher = publisher;
135
+ }
136
+ start(fn, opts) {
137
+ return this.publisher.start(fn, opts);
138
+ }
139
+ startChild(fn, opts) {
140
+ return this.publisher.startChild(fn, opts);
141
+ }
142
+ emit(params) {
143
+ return this.publisher.emit(params);
144
+ }
145
+ emitToParent(paramsOrFn) {
146
+ return this.publisher.emitToParent(paramsOrFn);
147
+ }
148
+ forSaga(sagaId, parentCtx, causationId) {
149
+ return this.publisher.forSaga(sagaId, parentCtx, causationId);
150
+ }
151
+ };
152
+ SagaPublisherProvider = __decorateClass([
153
+ (0, import_common2.Injectable)(),
154
+ __decorateParam(0, (0, import_common2.Inject)(import_saga_core2.SagaPublisher))
155
+ ], SagaPublisherProvider);
156
+
157
+ // src/saga.module.ts
158
+ var SagaModule = class {
159
+ static forRoot(options) {
160
+ const otelCtx = (0, import_saga_core3.createOtelContext)(options.otel?.enabled ?? false);
161
+ const registry = new import_saga_core3.SagaRegistry();
162
+ const parser = new import_saga_core3.SagaParser(otelCtx);
163
+ const publisher = new import_saga_core3.SagaPublisher(options.transport, otelCtx, options.topicPrefix);
164
+ const runner = new import_saga_core3.SagaRunner(registry, options.transport, publisher, parser, options, otelCtx, options.logger);
165
+ return {
166
+ module: SagaModule,
167
+ imports: [import_core2.DiscoveryModule],
168
+ global: true,
169
+ providers: [
170
+ { provide: SAGA_OPTIONS_TOKEN, useValue: options },
171
+ { provide: SAGA_TRANSPORT_TOKEN, useValue: options.transport },
172
+ { provide: import_saga_core3.SagaRegistry, useValue: registry },
173
+ { provide: import_saga_core3.SagaParser, useValue: parser },
174
+ { provide: import_saga_core3.SagaPublisher, useValue: publisher },
175
+ { provide: import_saga_core3.SagaRunner, useValue: runner },
176
+ SagaRunnerProvider,
177
+ SagaPublisherProvider
178
+ ],
179
+ exports: [SagaPublisherProvider, import_saga_core3.SagaPublisher, SAGA_OPTIONS_TOKEN]
180
+ };
181
+ }
182
+ static forRootAsync(options) {
183
+ const asyncProviders = [
184
+ {
185
+ provide: SAGA_OPTIONS_TOKEN,
186
+ useFactory: options.useFactory,
187
+ inject: options.inject ?? []
188
+ },
189
+ {
190
+ provide: SAGA_TRANSPORT_TOKEN,
191
+ useFactory: (opts) => opts.transport,
192
+ inject: [SAGA_OPTIONS_TOKEN]
193
+ },
194
+ {
195
+ provide: import_saga_core3.SagaRegistry,
196
+ useFactory: () => new import_saga_core3.SagaRegistry()
197
+ },
198
+ {
199
+ provide: import_saga_core3.SagaParser,
200
+ useFactory: (opts) => {
201
+ const otelCtx = (0, import_saga_core3.createOtelContext)(opts.otel?.enabled ?? false);
202
+ return new import_saga_core3.SagaParser(otelCtx);
203
+ },
204
+ inject: [SAGA_OPTIONS_TOKEN]
205
+ },
206
+ {
207
+ provide: import_saga_core3.SagaPublisher,
208
+ useFactory: (opts) => {
209
+ const otelCtx = (0, import_saga_core3.createOtelContext)(opts.otel?.enabled ?? false);
210
+ return new import_saga_core3.SagaPublisher(opts.transport, otelCtx, opts.topicPrefix);
211
+ },
212
+ inject: [SAGA_OPTIONS_TOKEN]
213
+ },
214
+ {
215
+ provide: import_saga_core3.SagaRunner,
216
+ useFactory: (registry, publisher, parser, opts) => {
217
+ const otelCtx = (0, import_saga_core3.createOtelContext)(opts.otel?.enabled ?? false);
218
+ return new import_saga_core3.SagaRunner(registry, opts.transport, publisher, parser, opts, otelCtx, opts.logger);
219
+ },
220
+ inject: [import_saga_core3.SagaRegistry, import_saga_core3.SagaPublisher, import_saga_core3.SagaParser, SAGA_OPTIONS_TOKEN]
221
+ }
222
+ ];
223
+ return {
224
+ module: SagaModule,
225
+ imports: [...options.imports ?? [], import_core2.DiscoveryModule],
226
+ global: true,
227
+ providers: [...asyncProviders, SagaRunnerProvider, SagaPublisherProvider],
228
+ exports: [SagaPublisherProvider, import_saga_core3.SagaPublisher, SAGA_OPTIONS_TOKEN]
229
+ };
230
+ }
231
+ };
232
+ SagaModule = __decorateClass([
233
+ (0, import_common3.Module)({})
234
+ ], SagaModule);
235
+
236
+ // src/decorators/saga-handler.decorator.ts
237
+ function SagaHandler(...args) {
238
+ let eventTypes;
239
+ let options = {};
240
+ const lastArg = args[args.length - 1];
241
+ if (typeof lastArg === "object" && lastArg !== null) {
242
+ options = lastArg;
243
+ eventTypes = args.slice(0, -1);
244
+ } else {
245
+ eventTypes = args;
246
+ }
247
+ return (target, propertyKey) => {
248
+ const existingMap = Reflect.getMetadata(SAGA_HANDLER_METADATA, target.constructor) ?? /* @__PURE__ */ new Map();
249
+ const existingOptions = Reflect.getMetadata(SAGA_HANDLER_OPTIONS_METADATA, target.constructor) ?? /* @__PURE__ */ new Map();
250
+ for (const eventType of eventTypes) {
251
+ existingMap.set(eventType, propertyKey);
252
+ if (options.final || options.fork) {
253
+ existingOptions.set(eventType, options);
254
+ }
255
+ }
256
+ Reflect.defineMetadata(SAGA_HANDLER_METADATA, existingMap, target.constructor);
257
+ Reflect.defineMetadata(SAGA_HANDLER_OPTIONS_METADATA, existingOptions, target.constructor);
258
+ };
259
+ }
260
+
261
+ // src/decorators/saga-participant.decorator.ts
262
+ function SagaParticipant() {
263
+ return (target) => {
264
+ Reflect.defineMetadata(SAGA_PARTICIPANT_METADATA, true, target);
265
+ };
266
+ }
267
+
268
+ // src/saga-participant-base.ts
269
+ var SagaParticipantBase = class {
270
+ on = {};
271
+ };
272
+
273
+ // src/index.ts
274
+ var import_saga_core4 = require("@fbsm/saga-core");
275
+ // Annotate the CommonJS export names for ESM import in node:
276
+ 0 && (module.exports = {
277
+ SAGA_OPTIONS_TOKEN,
278
+ SAGA_TRANSPORT_TOKEN,
279
+ SagaDuplicateHandlerError,
280
+ SagaError,
281
+ SagaHandler,
282
+ SagaModule,
283
+ SagaParseError,
284
+ SagaParticipant,
285
+ SagaParticipantBase,
286
+ SagaPublisherProvider,
287
+ SagaRetryableError,
288
+ SagaTransportNotConnectedError
289
+ });
290
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/saga.module.ts","../src/constants.ts","../src/providers/saga-runner.provider.ts","../src/providers/saga-publisher.provider.ts","../src/decorators/saga-handler.decorator.ts","../src/decorators/saga-participant.decorator.ts","../src/saga-participant-base.ts"],"sourcesContent":["// Module\nexport { SagaModule } from './saga.module';\n\n// Provider\nexport { SagaPublisherProvider } from './providers/saga-publisher.provider';\n\n// Decorators\nexport { SagaHandler } from './decorators/saga-handler.decorator';\nexport type { SagaHandlerOptions } from './decorators/saga-handler.decorator';\nexport { SagaParticipant } from './decorators/saga-participant.decorator';\n\n// Base class\nexport { SagaParticipantBase } from './saga-participant-base';\n\n// Constants (tokens for advanced usage)\nexport { SAGA_OPTIONS_TOKEN, SAGA_TRANSPORT_TOKEN } from './constants';\n\n// Options\nexport type { SagaModuleOptions, SagaModuleAsyncOptions } from './saga-module-options.interface';\n\n// Re-exports from core for consumer convenience\nexport {\n SagaError,\n SagaRetryableError,\n SagaDuplicateHandlerError,\n SagaParseError,\n SagaTransportNotConnectedError,\n} from '@fbsm/saga-core';\nexport type {\n SagaEvent,\n IncomingEvent,\n Emit,\n EmitParams,\n EventHint,\n EventHandler,\n ParentSagaContext,\n HandlerConfig,\n SagaTransport,\n} from '@fbsm/saga-core';\n","import { Module, DynamicModule, type Provider } from '@nestjs/common';\nimport { DiscoveryModule } from '@nestjs/core';\nimport {\n SagaRunner,\n SagaRegistry,\n SagaPublisher,\n SagaParser,\n createOtelContext,\n} from '@fbsm/saga-core';\nimport { SAGA_OPTIONS_TOKEN, SAGA_TRANSPORT_TOKEN } from './constants';\nimport type { SagaModuleOptions, SagaModuleAsyncOptions } from './saga-module-options.interface';\nimport { SagaRunnerProvider } from './providers/saga-runner.provider';\nimport { SagaPublisherProvider } from './providers/saga-publisher.provider';\n\n@Module({})\nexport class SagaModule {\n static forRoot(options: SagaModuleOptions): DynamicModule {\n const otelCtx = createOtelContext(options.otel?.enabled ?? false);\n const registry = new SagaRegistry();\n const parser = new SagaParser(otelCtx);\n const publisher = new SagaPublisher(options.transport, otelCtx, options.topicPrefix);\n const runner = new SagaRunner(registry, options.transport, publisher, parser, options, otelCtx, options.logger);\n\n return {\n module: SagaModule,\n imports: [DiscoveryModule],\n global: true,\n providers: [\n { provide: SAGA_OPTIONS_TOKEN, useValue: options },\n { provide: SAGA_TRANSPORT_TOKEN, useValue: options.transport },\n { provide: SagaRegistry, useValue: registry },\n { provide: SagaParser, useValue: parser },\n { provide: SagaPublisher, useValue: publisher },\n { provide: SagaRunner, useValue: runner },\n SagaRunnerProvider,\n SagaPublisherProvider,\n ],\n exports: [SagaPublisherProvider, SagaPublisher, SAGA_OPTIONS_TOKEN],\n };\n }\n\n static forRootAsync(options: SagaModuleAsyncOptions): DynamicModule {\n const asyncProviders: Provider[] = [\n {\n provide: SAGA_OPTIONS_TOKEN,\n useFactory: options.useFactory,\n inject: options.inject ?? [],\n },\n {\n provide: SAGA_TRANSPORT_TOKEN,\n useFactory: (opts: SagaModuleOptions) => opts.transport,\n inject: [SAGA_OPTIONS_TOKEN],\n },\n {\n provide: SagaRegistry,\n useFactory: () => new SagaRegistry(),\n },\n {\n provide: SagaParser,\n useFactory: (opts: SagaModuleOptions) => {\n const otelCtx = createOtelContext(opts.otel?.enabled ?? false);\n return new SagaParser(otelCtx);\n },\n inject: [SAGA_OPTIONS_TOKEN],\n },\n {\n provide: SagaPublisher,\n useFactory: (opts: SagaModuleOptions) => {\n const otelCtx = createOtelContext(opts.otel?.enabled ?? false);\n return new SagaPublisher(opts.transport, otelCtx, opts.topicPrefix);\n },\n inject: [SAGA_OPTIONS_TOKEN],\n },\n {\n provide: SagaRunner,\n useFactory: (\n registry: SagaRegistry,\n publisher: SagaPublisher,\n parser: SagaParser,\n opts: SagaModuleOptions,\n ) => {\n const otelCtx = createOtelContext(opts.otel?.enabled ?? false);\n return new SagaRunner(registry, opts.transport, publisher, parser, opts, otelCtx, opts.logger);\n },\n inject: [SagaRegistry, SagaPublisher, SagaParser, SAGA_OPTIONS_TOKEN],\n },\n ];\n\n return {\n module: SagaModule,\n imports: [...(options.imports ?? []), DiscoveryModule],\n global: true,\n providers: [...asyncProviders, SagaRunnerProvider, SagaPublisherProvider],\n exports: [SagaPublisherProvider, SagaPublisher, SAGA_OPTIONS_TOKEN],\n };\n }\n}\n","export const SAGA_OPTIONS_TOKEN = Symbol('SAGA_OPTIONS_TOKEN');\nexport const SAGA_TRANSPORT_TOKEN = Symbol('SAGA_TRANSPORT_TOKEN');\nexport const SAGA_PARTICIPANT_METADATA = Symbol('SAGA_PARTICIPANT_METADATA');\nexport const SAGA_HANDLER_METADATA = Symbol('SAGA_HANDLER_METADATA');\nexport const SAGA_HANDLER_OPTIONS_METADATA = Symbol('SAGA_HANDLER_OPTIONS_METADATA');\n","import { Inject, Injectable, Logger, OnModuleInit, OnModuleDestroy } from '@nestjs/common';\nimport { DiscoveryService } from '@nestjs/core';\nimport { SagaRunner, SagaRegistry } from '@fbsm/saga-core';\nimport type { EventHandler } from '@fbsm/saga-core';\nimport { SAGA_PARTICIPANT_METADATA, SAGA_HANDLER_METADATA, SAGA_HANDLER_OPTIONS_METADATA } from '../constants';\nimport type { SagaHandlerOptions } from '../decorators/saga-handler.decorator';\nimport type { HandlerConfig } from '@fbsm/saga-core';\n\n@Injectable()\nexport class SagaRunnerProvider implements OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger('SagaRunner');\n\n constructor(\n @Inject(DiscoveryService) private readonly discoveryService: DiscoveryService,\n @Inject(SagaRegistry) private readonly registry: SagaRegistry,\n @Inject(SagaRunner) private readonly runner: SagaRunner,\n ) {}\n\n async onModuleInit(): Promise<void> {\n const providers = this.discoveryService.getProviders();\n\n for (const wrapper of providers) {\n const instance = wrapper.instance;\n if (!instance || !instance.constructor) {\n continue;\n }\n\n const isParticipant = Reflect.getMetadata(\n SAGA_PARTICIPANT_METADATA,\n instance.constructor,\n );\n\n if (!isParticipant) {\n continue;\n }\n\n const handlesMap: Map<string, string | symbol> | undefined =\n Reflect.getMetadata(SAGA_HANDLER_METADATA, instance.constructor);\n\n if (!handlesMap || handlesMap.size === 0) {\n continue;\n }\n\n const on: Record<string, EventHandler<any>> = {};\n \n for (const [eventType, methodName] of handlesMap.entries()) {\n const method = (instance as any)[methodName];\n if (typeof method === 'function') {\n on[eventType] = method.bind(instance);\n }\n }\n\n // Populate the `on` property if instance extends SagaParticipantBase\n if ('on' in instance && typeof instance.on === 'object') {\n Object.assign(instance.on, on);\n }\n\n // Extract handler options (final, fork, etc.) from decorator metadata\n const handlerOptionsMap: Map<string, SagaHandlerOptions> | undefined =\n Reflect.getMetadata(SAGA_HANDLER_OPTIONS_METADATA, instance.constructor);\n\n const handlerOptions: Record<string, HandlerConfig> = {};\n if (handlerOptionsMap) {\n for (const [eventType, opts] of handlerOptionsMap.entries()) {\n handlerOptions[eventType] = { final: opts.final, fork: !!opts.fork };\n }\n }\n\n const serviceId = (instance as any).serviceId ?? 'unknown';\n this.logger.log(\n `Registered participant \"${serviceId}\" handling: [${Object.keys(on).join(', ')}]`,\n );\n\n this.registry.register({\n serviceId,\n on,\n handlerOptions: Object.keys(handlerOptions).length > 0 ? handlerOptions : undefined,\n onRetryExhausted:\n typeof (instance as any).onRetryExhausted === 'function'\n ? (instance as any).onRetryExhausted.bind(instance)\n : undefined,\n });\n }\n\n await this.runner.start();\n }\n\n async onModuleDestroy(): Promise<void> {\n await this.runner.stop();\n }\n}\n","import { Inject, Injectable } from '@nestjs/common';\nimport type { Emit, EmitParams, ParentSagaContext, SagaStartOptions } from '@fbsm/saga-core';\nimport { SagaPublisher } from '@fbsm/saga-core';\n\n@Injectable()\nexport class SagaPublisherProvider {\n constructor(@Inject(SagaPublisher) private readonly publisher: SagaPublisher) {}\n\n start<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{ sagaId: string; result: Awaited<R> }> {\n return this.publisher.start(fn, opts);\n }\n\n startChild<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{ sagaId: string; result: Awaited<R> }> {\n return this.publisher.startChild(fn, opts);\n }\n\n emit<T extends object>(params: EmitParams<T>): Promise<void> {\n return this.publisher.emit(params);\n }\n\n emitToParent<T extends object>(paramsOrFn: EmitParams<T> | (() => void | Promise<void>)): Promise<void> {\n return this.publisher.emitToParent(paramsOrFn);\n }\n\n forSaga(sagaId: string, parentCtx?: ParentSagaContext, causationId?: string): Emit {\n return this.publisher.forSaga(sagaId, parentCtx, causationId);\n }\n}\n","import { SAGA_HANDLER_METADATA, SAGA_HANDLER_OPTIONS_METADATA } from '../constants';\n\nimport type { ForkConfig } from '@fbsm/saga-core';\n\nexport interface SagaHandlerOptions {\n final?: boolean;\n fork?: boolean | ForkConfig;\n}\n\nexport function SagaHandler(\n ...args: [...string[]] | [...string[], SagaHandlerOptions]\n): MethodDecorator {\n let eventTypes: string[];\n let options: SagaHandlerOptions = {};\n\n const lastArg = args[args.length - 1];\n if (typeof lastArg === 'object' && lastArg !== null) {\n options = lastArg as SagaHandlerOptions;\n eventTypes = args.slice(0, -1) as string[];\n } else {\n eventTypes = args as string[];\n }\n\n return (target, propertyKey) => {\n const existingMap: Map<string, string | symbol> =\n Reflect.getMetadata(SAGA_HANDLER_METADATA, target.constructor) ?? new Map();\n const existingOptions: Map<string, SagaHandlerOptions> =\n Reflect.getMetadata(SAGA_HANDLER_OPTIONS_METADATA, target.constructor) ?? new Map();\n\n for (const eventType of eventTypes) {\n existingMap.set(eventType, propertyKey);\n if (options.final || options.fork) {\n existingOptions.set(eventType, options);\n }\n }\n\n Reflect.defineMetadata(SAGA_HANDLER_METADATA, existingMap, target.constructor);\n Reflect.defineMetadata(SAGA_HANDLER_OPTIONS_METADATA, existingOptions, target.constructor);\n };\n}\n","import { SAGA_PARTICIPANT_METADATA } from '../constants';\n\nexport function SagaParticipant(): ClassDecorator {\n return (target) => {\n Reflect.defineMetadata(SAGA_PARTICIPANT_METADATA, true, target);\n };\n}\n","import type {\n SagaParticipant,\n EventHandler,\n IncomingEvent,\n Emit,\n} from '@fbsm/saga-core';\nimport { SagaRetryableError } from '@fbsm/saga-core';\n\nexport abstract class SagaParticipantBase implements SagaParticipant {\n abstract readonly serviceId: string;\n\n readonly on: Record<string, EventHandler<any>> = {};\n\n onRetryExhausted?(\n event: IncomingEvent,\n error: SagaRetryableError,\n emit: Emit,\n ): Promise<void>;\n}\n"],"mappings":"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","names":["import_common","import_core","import_saga_core","import_common","import_saga_core","import_saga_core"]}
@@ -0,0 +1,57 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { RunnerOptions, SagaTransport, SagaLogger, SagaPublisher, SagaStartOptions, EmitParams, ParentSagaContext, Emit, ForkConfig, SagaParticipant as SagaParticipant$1, EventHandler, IncomingEvent, SagaRetryableError } from '@fbsm/saga-core';
3
+ export { Emit, EmitParams, EventHandler, EventHint, HandlerConfig, IncomingEvent, ParentSagaContext, SagaDuplicateHandlerError, SagaError, SagaEvent, SagaParseError, SagaRetryableError, SagaTransport, SagaTransportNotConnectedError } from '@fbsm/saga-core';
4
+
5
+ interface SagaModuleOptions extends RunnerOptions {
6
+ transport: SagaTransport;
7
+ otel?: {
8
+ enabled: boolean;
9
+ exporterUrl?: string;
10
+ };
11
+ logger?: SagaLogger;
12
+ }
13
+ interface SagaModuleAsyncOptions {
14
+ useFactory: (...args: any[]) => Promise<SagaModuleOptions> | SagaModuleOptions;
15
+ inject?: any[];
16
+ imports?: any[];
17
+ }
18
+
19
+ declare class SagaModule {
20
+ static forRoot(options: SagaModuleOptions): DynamicModule;
21
+ static forRootAsync(options: SagaModuleAsyncOptions): DynamicModule;
22
+ }
23
+
24
+ declare class SagaPublisherProvider {
25
+ private readonly publisher;
26
+ constructor(publisher: SagaPublisher);
27
+ start<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{
28
+ sagaId: string;
29
+ result: Awaited<R>;
30
+ }>;
31
+ startChild<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{
32
+ sagaId: string;
33
+ result: Awaited<R>;
34
+ }>;
35
+ emit<T extends object>(params: EmitParams<T>): Promise<void>;
36
+ emitToParent<T extends object>(paramsOrFn: EmitParams<T> | (() => void | Promise<void>)): Promise<void>;
37
+ forSaga(sagaId: string, parentCtx?: ParentSagaContext, causationId?: string): Emit;
38
+ }
39
+
40
+ interface SagaHandlerOptions {
41
+ final?: boolean;
42
+ fork?: boolean | ForkConfig;
43
+ }
44
+ declare function SagaHandler(...args: [...string[]] | [...string[], SagaHandlerOptions]): MethodDecorator;
45
+
46
+ declare function SagaParticipant(): ClassDecorator;
47
+
48
+ declare abstract class SagaParticipantBase implements SagaParticipant$1 {
49
+ abstract readonly serviceId: string;
50
+ readonly on: Record<string, EventHandler<any>>;
51
+ onRetryExhausted?(event: IncomingEvent, error: SagaRetryableError, emit: Emit): Promise<void>;
52
+ }
53
+
54
+ declare const SAGA_OPTIONS_TOKEN: unique symbol;
55
+ declare const SAGA_TRANSPORT_TOKEN: unique symbol;
56
+
57
+ export { SAGA_OPTIONS_TOKEN, SAGA_TRANSPORT_TOKEN, SagaHandler, type SagaHandlerOptions, SagaModule, type SagaModuleAsyncOptions, type SagaModuleOptions, SagaParticipant, SagaParticipantBase, SagaPublisherProvider };
@@ -0,0 +1,57 @@
1
+ import { DynamicModule } from '@nestjs/common';
2
+ import { RunnerOptions, SagaTransport, SagaLogger, SagaPublisher, SagaStartOptions, EmitParams, ParentSagaContext, Emit, ForkConfig, SagaParticipant as SagaParticipant$1, EventHandler, IncomingEvent, SagaRetryableError } from '@fbsm/saga-core';
3
+ export { Emit, EmitParams, EventHandler, EventHint, HandlerConfig, IncomingEvent, ParentSagaContext, SagaDuplicateHandlerError, SagaError, SagaEvent, SagaParseError, SagaRetryableError, SagaTransport, SagaTransportNotConnectedError } from '@fbsm/saga-core';
4
+
5
+ interface SagaModuleOptions extends RunnerOptions {
6
+ transport: SagaTransport;
7
+ otel?: {
8
+ enabled: boolean;
9
+ exporterUrl?: string;
10
+ };
11
+ logger?: SagaLogger;
12
+ }
13
+ interface SagaModuleAsyncOptions {
14
+ useFactory: (...args: any[]) => Promise<SagaModuleOptions> | SagaModuleOptions;
15
+ inject?: any[];
16
+ imports?: any[];
17
+ }
18
+
19
+ declare class SagaModule {
20
+ static forRoot(options: SagaModuleOptions): DynamicModule;
21
+ static forRootAsync(options: SagaModuleAsyncOptions): DynamicModule;
22
+ }
23
+
24
+ declare class SagaPublisherProvider {
25
+ private readonly publisher;
26
+ constructor(publisher: SagaPublisher);
27
+ start<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{
28
+ sagaId: string;
29
+ result: Awaited<R>;
30
+ }>;
31
+ startChild<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{
32
+ sagaId: string;
33
+ result: Awaited<R>;
34
+ }>;
35
+ emit<T extends object>(params: EmitParams<T>): Promise<void>;
36
+ emitToParent<T extends object>(paramsOrFn: EmitParams<T> | (() => void | Promise<void>)): Promise<void>;
37
+ forSaga(sagaId: string, parentCtx?: ParentSagaContext, causationId?: string): Emit;
38
+ }
39
+
40
+ interface SagaHandlerOptions {
41
+ final?: boolean;
42
+ fork?: boolean | ForkConfig;
43
+ }
44
+ declare function SagaHandler(...args: [...string[]] | [...string[], SagaHandlerOptions]): MethodDecorator;
45
+
46
+ declare function SagaParticipant(): ClassDecorator;
47
+
48
+ declare abstract class SagaParticipantBase implements SagaParticipant$1 {
49
+ abstract readonly serviceId: string;
50
+ readonly on: Record<string, EventHandler<any>>;
51
+ onRetryExhausted?(event: IncomingEvent, error: SagaRetryableError, emit: Emit): Promise<void>;
52
+ }
53
+
54
+ declare const SAGA_OPTIONS_TOKEN: unique symbol;
55
+ declare const SAGA_TRANSPORT_TOKEN: unique symbol;
56
+
57
+ export { SAGA_OPTIONS_TOKEN, SAGA_TRANSPORT_TOKEN, SagaHandler, type SagaHandlerOptions, SagaModule, type SagaModuleAsyncOptions, type SagaModuleOptions, SagaParticipant, SagaParticipantBase, SagaPublisherProvider };
package/dist/index.js ADDED
@@ -0,0 +1,267 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
3
+ var __decorateClass = (decorators, target, key, kind) => {
4
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
5
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
6
+ if (decorator = decorators[i])
7
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
8
+ if (kind && result) __defProp(target, key, result);
9
+ return result;
10
+ };
11
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
12
+
13
+ // src/saga.module.ts
14
+ import { Module } from "@nestjs/common";
15
+ import { DiscoveryModule } from "@nestjs/core";
16
+ import {
17
+ SagaRunner as SagaRunner2,
18
+ SagaRegistry as SagaRegistry2,
19
+ SagaPublisher as SagaPublisher2,
20
+ SagaParser,
21
+ createOtelContext
22
+ } from "@fbsm/saga-core";
23
+
24
+ // src/constants.ts
25
+ var SAGA_OPTIONS_TOKEN = /* @__PURE__ */ Symbol("SAGA_OPTIONS_TOKEN");
26
+ var SAGA_TRANSPORT_TOKEN = /* @__PURE__ */ Symbol("SAGA_TRANSPORT_TOKEN");
27
+ var SAGA_PARTICIPANT_METADATA = /* @__PURE__ */ Symbol("SAGA_PARTICIPANT_METADATA");
28
+ var SAGA_HANDLER_METADATA = /* @__PURE__ */ Symbol("SAGA_HANDLER_METADATA");
29
+ var SAGA_HANDLER_OPTIONS_METADATA = /* @__PURE__ */ Symbol("SAGA_HANDLER_OPTIONS_METADATA");
30
+
31
+ // src/providers/saga-runner.provider.ts
32
+ import { Inject, Injectable, Logger } from "@nestjs/common";
33
+ import { DiscoveryService } from "@nestjs/core";
34
+ import { SagaRunner, SagaRegistry } from "@fbsm/saga-core";
35
+ var SagaRunnerProvider = class {
36
+ constructor(discoveryService, registry, runner) {
37
+ this.discoveryService = discoveryService;
38
+ this.registry = registry;
39
+ this.runner = runner;
40
+ }
41
+ logger = new Logger("SagaRunner");
42
+ async onModuleInit() {
43
+ const providers = this.discoveryService.getProviders();
44
+ for (const wrapper of providers) {
45
+ const instance = wrapper.instance;
46
+ if (!instance || !instance.constructor) {
47
+ continue;
48
+ }
49
+ const isParticipant = Reflect.getMetadata(
50
+ SAGA_PARTICIPANT_METADATA,
51
+ instance.constructor
52
+ );
53
+ if (!isParticipant) {
54
+ continue;
55
+ }
56
+ const handlesMap = Reflect.getMetadata(SAGA_HANDLER_METADATA, instance.constructor);
57
+ if (!handlesMap || handlesMap.size === 0) {
58
+ continue;
59
+ }
60
+ const on = {};
61
+ for (const [eventType, methodName] of handlesMap.entries()) {
62
+ const method = instance[methodName];
63
+ if (typeof method === "function") {
64
+ on[eventType] = method.bind(instance);
65
+ }
66
+ }
67
+ if ("on" in instance && typeof instance.on === "object") {
68
+ Object.assign(instance.on, on);
69
+ }
70
+ const handlerOptionsMap = Reflect.getMetadata(SAGA_HANDLER_OPTIONS_METADATA, instance.constructor);
71
+ const handlerOptions = {};
72
+ if (handlerOptionsMap) {
73
+ for (const [eventType, opts] of handlerOptionsMap.entries()) {
74
+ handlerOptions[eventType] = { final: opts.final, fork: !!opts.fork };
75
+ }
76
+ }
77
+ const serviceId = instance.serviceId ?? "unknown";
78
+ this.logger.log(
79
+ `Registered participant "${serviceId}" handling: [${Object.keys(on).join(", ")}]`
80
+ );
81
+ this.registry.register({
82
+ serviceId,
83
+ on,
84
+ handlerOptions: Object.keys(handlerOptions).length > 0 ? handlerOptions : void 0,
85
+ onRetryExhausted: typeof instance.onRetryExhausted === "function" ? instance.onRetryExhausted.bind(instance) : void 0
86
+ });
87
+ }
88
+ await this.runner.start();
89
+ }
90
+ async onModuleDestroy() {
91
+ await this.runner.stop();
92
+ }
93
+ };
94
+ SagaRunnerProvider = __decorateClass([
95
+ Injectable(),
96
+ __decorateParam(0, Inject(DiscoveryService)),
97
+ __decorateParam(1, Inject(SagaRegistry)),
98
+ __decorateParam(2, Inject(SagaRunner))
99
+ ], SagaRunnerProvider);
100
+
101
+ // src/providers/saga-publisher.provider.ts
102
+ import { Inject as Inject2, Injectable as Injectable2 } from "@nestjs/common";
103
+ import { SagaPublisher } from "@fbsm/saga-core";
104
+ var SagaPublisherProvider = class {
105
+ constructor(publisher) {
106
+ this.publisher = publisher;
107
+ }
108
+ start(fn, opts) {
109
+ return this.publisher.start(fn, opts);
110
+ }
111
+ startChild(fn, opts) {
112
+ return this.publisher.startChild(fn, opts);
113
+ }
114
+ emit(params) {
115
+ return this.publisher.emit(params);
116
+ }
117
+ emitToParent(paramsOrFn) {
118
+ return this.publisher.emitToParent(paramsOrFn);
119
+ }
120
+ forSaga(sagaId, parentCtx, causationId) {
121
+ return this.publisher.forSaga(sagaId, parentCtx, causationId);
122
+ }
123
+ };
124
+ SagaPublisherProvider = __decorateClass([
125
+ Injectable2(),
126
+ __decorateParam(0, Inject2(SagaPublisher))
127
+ ], SagaPublisherProvider);
128
+
129
+ // src/saga.module.ts
130
+ var SagaModule = class {
131
+ static forRoot(options) {
132
+ const otelCtx = createOtelContext(options.otel?.enabled ?? false);
133
+ const registry = new SagaRegistry2();
134
+ const parser = new SagaParser(otelCtx);
135
+ const publisher = new SagaPublisher2(options.transport, otelCtx, options.topicPrefix);
136
+ const runner = new SagaRunner2(registry, options.transport, publisher, parser, options, otelCtx, options.logger);
137
+ return {
138
+ module: SagaModule,
139
+ imports: [DiscoveryModule],
140
+ global: true,
141
+ providers: [
142
+ { provide: SAGA_OPTIONS_TOKEN, useValue: options },
143
+ { provide: SAGA_TRANSPORT_TOKEN, useValue: options.transport },
144
+ { provide: SagaRegistry2, useValue: registry },
145
+ { provide: SagaParser, useValue: parser },
146
+ { provide: SagaPublisher2, useValue: publisher },
147
+ { provide: SagaRunner2, useValue: runner },
148
+ SagaRunnerProvider,
149
+ SagaPublisherProvider
150
+ ],
151
+ exports: [SagaPublisherProvider, SagaPublisher2, SAGA_OPTIONS_TOKEN]
152
+ };
153
+ }
154
+ static forRootAsync(options) {
155
+ const asyncProviders = [
156
+ {
157
+ provide: SAGA_OPTIONS_TOKEN,
158
+ useFactory: options.useFactory,
159
+ inject: options.inject ?? []
160
+ },
161
+ {
162
+ provide: SAGA_TRANSPORT_TOKEN,
163
+ useFactory: (opts) => opts.transport,
164
+ inject: [SAGA_OPTIONS_TOKEN]
165
+ },
166
+ {
167
+ provide: SagaRegistry2,
168
+ useFactory: () => new SagaRegistry2()
169
+ },
170
+ {
171
+ provide: SagaParser,
172
+ useFactory: (opts) => {
173
+ const otelCtx = createOtelContext(opts.otel?.enabled ?? false);
174
+ return new SagaParser(otelCtx);
175
+ },
176
+ inject: [SAGA_OPTIONS_TOKEN]
177
+ },
178
+ {
179
+ provide: SagaPublisher2,
180
+ useFactory: (opts) => {
181
+ const otelCtx = createOtelContext(opts.otel?.enabled ?? false);
182
+ return new SagaPublisher2(opts.transport, otelCtx, opts.topicPrefix);
183
+ },
184
+ inject: [SAGA_OPTIONS_TOKEN]
185
+ },
186
+ {
187
+ provide: SagaRunner2,
188
+ useFactory: (registry, publisher, parser, opts) => {
189
+ const otelCtx = createOtelContext(opts.otel?.enabled ?? false);
190
+ return new SagaRunner2(registry, opts.transport, publisher, parser, opts, otelCtx, opts.logger);
191
+ },
192
+ inject: [SagaRegistry2, SagaPublisher2, SagaParser, SAGA_OPTIONS_TOKEN]
193
+ }
194
+ ];
195
+ return {
196
+ module: SagaModule,
197
+ imports: [...options.imports ?? [], DiscoveryModule],
198
+ global: true,
199
+ providers: [...asyncProviders, SagaRunnerProvider, SagaPublisherProvider],
200
+ exports: [SagaPublisherProvider, SagaPublisher2, SAGA_OPTIONS_TOKEN]
201
+ };
202
+ }
203
+ };
204
+ SagaModule = __decorateClass([
205
+ Module({})
206
+ ], SagaModule);
207
+
208
+ // src/decorators/saga-handler.decorator.ts
209
+ function SagaHandler(...args) {
210
+ let eventTypes;
211
+ let options = {};
212
+ const lastArg = args[args.length - 1];
213
+ if (typeof lastArg === "object" && lastArg !== null) {
214
+ options = lastArg;
215
+ eventTypes = args.slice(0, -1);
216
+ } else {
217
+ eventTypes = args;
218
+ }
219
+ return (target, propertyKey) => {
220
+ const existingMap = Reflect.getMetadata(SAGA_HANDLER_METADATA, target.constructor) ?? /* @__PURE__ */ new Map();
221
+ const existingOptions = Reflect.getMetadata(SAGA_HANDLER_OPTIONS_METADATA, target.constructor) ?? /* @__PURE__ */ new Map();
222
+ for (const eventType of eventTypes) {
223
+ existingMap.set(eventType, propertyKey);
224
+ if (options.final || options.fork) {
225
+ existingOptions.set(eventType, options);
226
+ }
227
+ }
228
+ Reflect.defineMetadata(SAGA_HANDLER_METADATA, existingMap, target.constructor);
229
+ Reflect.defineMetadata(SAGA_HANDLER_OPTIONS_METADATA, existingOptions, target.constructor);
230
+ };
231
+ }
232
+
233
+ // src/decorators/saga-participant.decorator.ts
234
+ function SagaParticipant() {
235
+ return (target) => {
236
+ Reflect.defineMetadata(SAGA_PARTICIPANT_METADATA, true, target);
237
+ };
238
+ }
239
+
240
+ // src/saga-participant-base.ts
241
+ var SagaParticipantBase = class {
242
+ on = {};
243
+ };
244
+
245
+ // src/index.ts
246
+ import {
247
+ SagaError,
248
+ SagaRetryableError,
249
+ SagaDuplicateHandlerError,
250
+ SagaParseError,
251
+ SagaTransportNotConnectedError
252
+ } from "@fbsm/saga-core";
253
+ export {
254
+ SAGA_OPTIONS_TOKEN,
255
+ SAGA_TRANSPORT_TOKEN,
256
+ SagaDuplicateHandlerError,
257
+ SagaError,
258
+ SagaHandler,
259
+ SagaModule,
260
+ SagaParseError,
261
+ SagaParticipant,
262
+ SagaParticipantBase,
263
+ SagaPublisherProvider,
264
+ SagaRetryableError,
265
+ SagaTransportNotConnectedError
266
+ };
267
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/saga.module.ts","../src/constants.ts","../src/providers/saga-runner.provider.ts","../src/providers/saga-publisher.provider.ts","../src/decorators/saga-handler.decorator.ts","../src/decorators/saga-participant.decorator.ts","../src/saga-participant-base.ts","../src/index.ts"],"sourcesContent":["import { Module, DynamicModule, type Provider } from '@nestjs/common';\nimport { DiscoveryModule } from '@nestjs/core';\nimport {\n SagaRunner,\n SagaRegistry,\n SagaPublisher,\n SagaParser,\n createOtelContext,\n} from '@fbsm/saga-core';\nimport { SAGA_OPTIONS_TOKEN, SAGA_TRANSPORT_TOKEN } from './constants';\nimport type { SagaModuleOptions, SagaModuleAsyncOptions } from './saga-module-options.interface';\nimport { SagaRunnerProvider } from './providers/saga-runner.provider';\nimport { SagaPublisherProvider } from './providers/saga-publisher.provider';\n\n@Module({})\nexport class SagaModule {\n static forRoot(options: SagaModuleOptions): DynamicModule {\n const otelCtx = createOtelContext(options.otel?.enabled ?? false);\n const registry = new SagaRegistry();\n const parser = new SagaParser(otelCtx);\n const publisher = new SagaPublisher(options.transport, otelCtx, options.topicPrefix);\n const runner = new SagaRunner(registry, options.transport, publisher, parser, options, otelCtx, options.logger);\n\n return {\n module: SagaModule,\n imports: [DiscoveryModule],\n global: true,\n providers: [\n { provide: SAGA_OPTIONS_TOKEN, useValue: options },\n { provide: SAGA_TRANSPORT_TOKEN, useValue: options.transport },\n { provide: SagaRegistry, useValue: registry },\n { provide: SagaParser, useValue: parser },\n { provide: SagaPublisher, useValue: publisher },\n { provide: SagaRunner, useValue: runner },\n SagaRunnerProvider,\n SagaPublisherProvider,\n ],\n exports: [SagaPublisherProvider, SagaPublisher, SAGA_OPTIONS_TOKEN],\n };\n }\n\n static forRootAsync(options: SagaModuleAsyncOptions): DynamicModule {\n const asyncProviders: Provider[] = [\n {\n provide: SAGA_OPTIONS_TOKEN,\n useFactory: options.useFactory,\n inject: options.inject ?? [],\n },\n {\n provide: SAGA_TRANSPORT_TOKEN,\n useFactory: (opts: SagaModuleOptions) => opts.transport,\n inject: [SAGA_OPTIONS_TOKEN],\n },\n {\n provide: SagaRegistry,\n useFactory: () => new SagaRegistry(),\n },\n {\n provide: SagaParser,\n useFactory: (opts: SagaModuleOptions) => {\n const otelCtx = createOtelContext(opts.otel?.enabled ?? false);\n return new SagaParser(otelCtx);\n },\n inject: [SAGA_OPTIONS_TOKEN],\n },\n {\n provide: SagaPublisher,\n useFactory: (opts: SagaModuleOptions) => {\n const otelCtx = createOtelContext(opts.otel?.enabled ?? false);\n return new SagaPublisher(opts.transport, otelCtx, opts.topicPrefix);\n },\n inject: [SAGA_OPTIONS_TOKEN],\n },\n {\n provide: SagaRunner,\n useFactory: (\n registry: SagaRegistry,\n publisher: SagaPublisher,\n parser: SagaParser,\n opts: SagaModuleOptions,\n ) => {\n const otelCtx = createOtelContext(opts.otel?.enabled ?? false);\n return new SagaRunner(registry, opts.transport, publisher, parser, opts, otelCtx, opts.logger);\n },\n inject: [SagaRegistry, SagaPublisher, SagaParser, SAGA_OPTIONS_TOKEN],\n },\n ];\n\n return {\n module: SagaModule,\n imports: [...(options.imports ?? []), DiscoveryModule],\n global: true,\n providers: [...asyncProviders, SagaRunnerProvider, SagaPublisherProvider],\n exports: [SagaPublisherProvider, SagaPublisher, SAGA_OPTIONS_TOKEN],\n };\n }\n}\n","export const SAGA_OPTIONS_TOKEN = Symbol('SAGA_OPTIONS_TOKEN');\nexport const SAGA_TRANSPORT_TOKEN = Symbol('SAGA_TRANSPORT_TOKEN');\nexport const SAGA_PARTICIPANT_METADATA = Symbol('SAGA_PARTICIPANT_METADATA');\nexport const SAGA_HANDLER_METADATA = Symbol('SAGA_HANDLER_METADATA');\nexport const SAGA_HANDLER_OPTIONS_METADATA = Symbol('SAGA_HANDLER_OPTIONS_METADATA');\n","import { Inject, Injectable, Logger, OnModuleInit, OnModuleDestroy } from '@nestjs/common';\nimport { DiscoveryService } from '@nestjs/core';\nimport { SagaRunner, SagaRegistry } from '@fbsm/saga-core';\nimport type { EventHandler } from '@fbsm/saga-core';\nimport { SAGA_PARTICIPANT_METADATA, SAGA_HANDLER_METADATA, SAGA_HANDLER_OPTIONS_METADATA } from '../constants';\nimport type { SagaHandlerOptions } from '../decorators/saga-handler.decorator';\nimport type { HandlerConfig } from '@fbsm/saga-core';\n\n@Injectable()\nexport class SagaRunnerProvider implements OnModuleInit, OnModuleDestroy {\n private readonly logger = new Logger('SagaRunner');\n\n constructor(\n @Inject(DiscoveryService) private readonly discoveryService: DiscoveryService,\n @Inject(SagaRegistry) private readonly registry: SagaRegistry,\n @Inject(SagaRunner) private readonly runner: SagaRunner,\n ) {}\n\n async onModuleInit(): Promise<void> {\n const providers = this.discoveryService.getProviders();\n\n for (const wrapper of providers) {\n const instance = wrapper.instance;\n if (!instance || !instance.constructor) {\n continue;\n }\n\n const isParticipant = Reflect.getMetadata(\n SAGA_PARTICIPANT_METADATA,\n instance.constructor,\n );\n\n if (!isParticipant) {\n continue;\n }\n\n const handlesMap: Map<string, string | symbol> | undefined =\n Reflect.getMetadata(SAGA_HANDLER_METADATA, instance.constructor);\n\n if (!handlesMap || handlesMap.size === 0) {\n continue;\n }\n\n const on: Record<string, EventHandler<any>> = {};\n \n for (const [eventType, methodName] of handlesMap.entries()) {\n const method = (instance as any)[methodName];\n if (typeof method === 'function') {\n on[eventType] = method.bind(instance);\n }\n }\n\n // Populate the `on` property if instance extends SagaParticipantBase\n if ('on' in instance && typeof instance.on === 'object') {\n Object.assign(instance.on, on);\n }\n\n // Extract handler options (final, fork, etc.) from decorator metadata\n const handlerOptionsMap: Map<string, SagaHandlerOptions> | undefined =\n Reflect.getMetadata(SAGA_HANDLER_OPTIONS_METADATA, instance.constructor);\n\n const handlerOptions: Record<string, HandlerConfig> = {};\n if (handlerOptionsMap) {\n for (const [eventType, opts] of handlerOptionsMap.entries()) {\n handlerOptions[eventType] = { final: opts.final, fork: !!opts.fork };\n }\n }\n\n const serviceId = (instance as any).serviceId ?? 'unknown';\n this.logger.log(\n `Registered participant \"${serviceId}\" handling: [${Object.keys(on).join(', ')}]`,\n );\n\n this.registry.register({\n serviceId,\n on,\n handlerOptions: Object.keys(handlerOptions).length > 0 ? handlerOptions : undefined,\n onRetryExhausted:\n typeof (instance as any).onRetryExhausted === 'function'\n ? (instance as any).onRetryExhausted.bind(instance)\n : undefined,\n });\n }\n\n await this.runner.start();\n }\n\n async onModuleDestroy(): Promise<void> {\n await this.runner.stop();\n }\n}\n","import { Inject, Injectable } from '@nestjs/common';\nimport type { Emit, EmitParams, ParentSagaContext, SagaStartOptions } from '@fbsm/saga-core';\nimport { SagaPublisher } from '@fbsm/saga-core';\n\n@Injectable()\nexport class SagaPublisherProvider {\n constructor(@Inject(SagaPublisher) private readonly publisher: SagaPublisher) {}\n\n start<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{ sagaId: string; result: Awaited<R> }> {\n return this.publisher.start(fn, opts);\n }\n\n startChild<R>(fn: () => R | Promise<R>, opts?: SagaStartOptions): Promise<{ sagaId: string; result: Awaited<R> }> {\n return this.publisher.startChild(fn, opts);\n }\n\n emit<T extends object>(params: EmitParams<T>): Promise<void> {\n return this.publisher.emit(params);\n }\n\n emitToParent<T extends object>(paramsOrFn: EmitParams<T> | (() => void | Promise<void>)): Promise<void> {\n return this.publisher.emitToParent(paramsOrFn);\n }\n\n forSaga(sagaId: string, parentCtx?: ParentSagaContext, causationId?: string): Emit {\n return this.publisher.forSaga(sagaId, parentCtx, causationId);\n }\n}\n","import { SAGA_HANDLER_METADATA, SAGA_HANDLER_OPTIONS_METADATA } from '../constants';\n\nimport type { ForkConfig } from '@fbsm/saga-core';\n\nexport interface SagaHandlerOptions {\n final?: boolean;\n fork?: boolean | ForkConfig;\n}\n\nexport function SagaHandler(\n ...args: [...string[]] | [...string[], SagaHandlerOptions]\n): MethodDecorator {\n let eventTypes: string[];\n let options: SagaHandlerOptions = {};\n\n const lastArg = args[args.length - 1];\n if (typeof lastArg === 'object' && lastArg !== null) {\n options = lastArg as SagaHandlerOptions;\n eventTypes = args.slice(0, -1) as string[];\n } else {\n eventTypes = args as string[];\n }\n\n return (target, propertyKey) => {\n const existingMap: Map<string, string | symbol> =\n Reflect.getMetadata(SAGA_HANDLER_METADATA, target.constructor) ?? new Map();\n const existingOptions: Map<string, SagaHandlerOptions> =\n Reflect.getMetadata(SAGA_HANDLER_OPTIONS_METADATA, target.constructor) ?? new Map();\n\n for (const eventType of eventTypes) {\n existingMap.set(eventType, propertyKey);\n if (options.final || options.fork) {\n existingOptions.set(eventType, options);\n }\n }\n\n Reflect.defineMetadata(SAGA_HANDLER_METADATA, existingMap, target.constructor);\n Reflect.defineMetadata(SAGA_HANDLER_OPTIONS_METADATA, existingOptions, target.constructor);\n };\n}\n","import { SAGA_PARTICIPANT_METADATA } from '../constants';\n\nexport function SagaParticipant(): ClassDecorator {\n return (target) => {\n Reflect.defineMetadata(SAGA_PARTICIPANT_METADATA, true, target);\n };\n}\n","import type {\n SagaParticipant,\n EventHandler,\n IncomingEvent,\n Emit,\n} from '@fbsm/saga-core';\nimport { SagaRetryableError } from '@fbsm/saga-core';\n\nexport abstract class SagaParticipantBase implements SagaParticipant {\n abstract readonly serviceId: string;\n\n readonly on: Record<string, EventHandler<any>> = {};\n\n onRetryExhausted?(\n event: IncomingEvent,\n error: SagaRetryableError,\n emit: Emit,\n ): Promise<void>;\n}\n","// Module\nexport { SagaModule } from './saga.module';\n\n// Provider\nexport { SagaPublisherProvider } from './providers/saga-publisher.provider';\n\n// Decorators\nexport { SagaHandler } from './decorators/saga-handler.decorator';\nexport type { SagaHandlerOptions } from './decorators/saga-handler.decorator';\nexport { SagaParticipant } from './decorators/saga-participant.decorator';\n\n// Base class\nexport { SagaParticipantBase } from './saga-participant-base';\n\n// Constants (tokens for advanced usage)\nexport { SAGA_OPTIONS_TOKEN, SAGA_TRANSPORT_TOKEN } from './constants';\n\n// Options\nexport type { SagaModuleOptions, SagaModuleAsyncOptions } from './saga-module-options.interface';\n\n// Re-exports from core for consumer convenience\nexport {\n SagaError,\n SagaRetryableError,\n SagaDuplicateHandlerError,\n SagaParseError,\n SagaTransportNotConnectedError,\n} from '@fbsm/saga-core';\nexport type {\n SagaEvent,\n IncomingEvent,\n Emit,\n EmitParams,\n EventHint,\n EventHandler,\n ParentSagaContext,\n HandlerConfig,\n SagaTransport,\n} from '@fbsm/saga-core';\n"],"mappings":"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","names":["SagaRunner","SagaRegistry","SagaPublisher","Inject","Injectable","Injectable","Inject","SagaRegistry","SagaPublisher","SagaRunner"]}
package/package.json ADDED
@@ -0,0 +1,61 @@
1
+ {
2
+ "name": "@fbsm/saga-nestjs",
3
+ "version": "0.0.1-beta.0",
4
+ "description": "NestJS integration for saga choreography: dynamic module, decorators, auto-discovery",
5
+ "license": "MIT",
6
+ "author": "fbsm",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/fbsm/saga-library",
10
+ "directory": "packages/saga-nestjs"
11
+ },
12
+ "keywords": [
13
+ "saga",
14
+ "nestjs",
15
+ "choreography",
16
+ "microservices",
17
+ "event-driven"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "type": "module",
23
+ "main": "./dist/index.cjs",
24
+ "module": "./dist/index.js",
25
+ "types": "./dist/index.d.ts",
26
+ "exports": {
27
+ ".": {
28
+ "import": {
29
+ "types": "./dist/index.d.ts",
30
+ "default": "./dist/index.js"
31
+ },
32
+ "require": {
33
+ "types": "./dist/index.d.cts",
34
+ "default": "./dist/index.cjs"
35
+ }
36
+ }
37
+ },
38
+ "files": [
39
+ "dist"
40
+ ],
41
+ "dependencies": {
42
+ "@fbsm/saga-core": "0.0.1-beta.0"
43
+ },
44
+ "peerDependencies": {
45
+ "@nestjs/common": "^10.0.0",
46
+ "@nestjs/core": "^10.0.0",
47
+ "reflect-metadata": "^0.1.13 || ^0.2.0"
48
+ },
49
+ "devDependencies": {
50
+ "@nestjs/common": "^10.0.0",
51
+ "@nestjs/core": "^10.0.0",
52
+ "@nestjs/testing": "^10.0.0",
53
+ "reflect-metadata": "^0.2.0",
54
+ "rxjs": "^7.8.0"
55
+ },
56
+ "scripts": {
57
+ "build": "tsup",
58
+ "dev": "tsup --watch",
59
+ "typecheck": "tsc --noEmit"
60
+ }
61
+ }